text: /*	$OpenBSD: clean-elf.c,v 1.2 2003/11/03 07:01:33 david Exp $	*/
  /*
   * Public domain. I don't even want my name on this.
   */
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <sys/types.h>
  #include <sys/mman.h>
  #include <err.h>
  #include <elf_abi.h>
  #include <fcntl.h>
  
  int
  elf_is_okay(Elf_Ehdr *ehdr)
  {
  	int retval = 0;
  
  	/*
  	 * We need to check magic, class size, endianess,
  	 * and version before we look at the rest of the
  	 * Elf_Ehdr structure.  These few elements are
  	 * represented in a machine independent fashion.
  	 */
  
  	if (IS_ELF(*ehdr) &&
  	    ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
  	    ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
  	    ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
  		/* Now check the machine dependant header */
  		if (ehdr->e_machine == ELF_TARG_MACH &&
  		    ehdr->e_version == ELF_TARG_VER)
  			retval = 1;
  	}
  
  	return retval;
  }
  
  void
  cleanit(caddr_t addr)
  {
  	Elf_Ehdr *ehdr;
  	Elf_Shdr *shdr;
  	char *strtab;
  	int i;
  
  	ehdr = (Elf_Ehdr *)addr;
  	shdr = (Elf_Shdr *)(addr + ehdr->e_shoff);
  
  	strtab = shdr[ehdr->e_shstrndx].sh_offset + addr;
  
  	/*
  	 * Simple. find a .text section, verify that the next section is
  	 * .rodata and merge them.
  	 */
  
  	for (i = 0; i < ehdr->e_shnum; i++) {
  		Elf_Shdr *t = &shdr[i];
  		Elf_Shdr *r = &shdr[i + 1];
  
  #if 0
  		printf("foo: %s %d\n", strtab + t->sh_name, t->sh_type);
  		continue;
  #endif
  		if (strcmp(strtab + t->sh_name, ".text"))
  			continue;
  		if (strcmp(strtab + r->sh_name, ".rodata"))
  			errx(1, "sorry, rodata merge not possible.");
  
  		t->sh_size += r->sh_size + (r->sh_offset - t->sh_offset - t->sh_size);
  		r->sh_type = SHT_NULL;
  		r->sh_name = 0;
  	}
  }
  
  int
  main(int argc, char **argv)
  {
  	int fd;
  	void *addr;
  	off_t len;
  	int pgsz = getpagesize();
  
  	if (argc != 2)
  		errx(1, "usage");
  
  	if ((fd = open(argv[1], O_RDWR)) < 0)
  		err(1, "open");
  
  	if ((len = lseek(fd, 0, SEEK_END)) < 0)
  		err(1, "lseek");
  
  	len = ((len + pgsz - 1) & ~(pgsz - 1));
  
  	if ((addr = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) ==
  	    MAP_FAILED)
  		err(1, "mmap");
  
  	if (!elf_is_okay((Elf_Ehdr *)addr))
  		errx(1, "not an elf file");
  
  	cleanit(addr);
  
  	msync(addr, len, MS_SYNC|MS_INVALIDATE);
  
  	close(fd);
  	return (0);
  }
  
  