svn commit: r246296 - head/usr.sbin/crunch/crunchide

Pedro F. Giffuni pfg at FreeBSD.org
Sun Feb 3 20:35:38 UTC 2013


Author: pfg
Date: Sun Feb  3 20:35:37 2013
New Revision: 246296
URL: http://svnweb.freebsd.org/changeset/base/246296

Log:
  crunchide(1): support non-custom elf object layout
  
  The crunchide utility presumes the last 3 chunks of an ELF object
  layout are section headers, symbol table, and then string table.
  However, this is  not specified in the ELF standards, and linkers
  may generate different layouts when doing partial linking (-r).
  
  This change is required to build FreeBSD with mclinker or the
  gold linker.
  
  PR:		bin/174011
  Submitted by:	Pete Chou
  Reviewed by:	Cristoph Mallon
  MFC after:	2 weeks

Modified:
  head/usr.sbin/crunch/crunchide/exec_elf32.c

Modified: head/usr.sbin/crunch/crunchide/exec_elf32.c
==============================================================================
--- head/usr.sbin/crunch/crunchide/exec_elf32.c	Sun Feb  3 20:13:33 2013	(r246295)
+++ head/usr.sbin/crunch/crunchide/exec_elf32.c	Sun Feb  3 20:35:37 2013	(r246296)
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/stat.h>
 
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -82,11 +83,9 @@ __FBSDID("$FreeBSD$");
 #define	xe32toh(x)	((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
 #define	htoxe32(x)	((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
 
-struct listelem {
-	struct listelem *next;
-	void *mem;
-	off_t file;
-	size_t size;
+struct shlayout {
+	Elf_Shdr *shdr;
+	void *bufp;
 };
 
 static ssize_t
@@ -235,17 +234,20 @@ int
 ELFNAMEEND(hide)(int fd, const char *fn)
 {
 	Elf_Ehdr ehdr;
-	Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr;
+	struct shlayout *layoutp = NULL;
+	Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr, *shstrtabshdr;
+	Elf_Shdr shdrshdr;
 	Elf_Sym *symtabp = NULL;
-	char *strtabp = NULL;
-	Elf_Size  nsyms, ewi;
+	char *shstrtabp = NULL, *strtabp = NULL;
+	Elf_Size nsyms, ewi;
+	Elf_Off off;
 	ssize_t shdrsize;
-	int rv, i, weird;
-	size_t nstrtab_size, nstrtab_nextoff, fn_size;
+	int rv, i, weird, l, m, r, strtabidx;
+	size_t nstrtab_size, nstrtab_nextoff, fn_size, size;
 	char *nstrtabp = NULL;
 	unsigned char data;
-	Elf_Off maxoff, stroff;
 	const char *weirdreason = NULL;
+	void *buf;
 
 	rv = 0;
 	if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
@@ -260,62 +262,123 @@ ELFNAMEEND(hide)(int fd, const char *fn)
 	    shdrsize)
 		goto bad;
 
-	symtabshdr = strtabshdr = NULL;
+	symtabshdr = strtabshdr = shstrtabshdr = NULL;
 	weird = 0;
-	maxoff = stroff = 0;
 	for (i = 0; i < xe16toh(ehdr.e_shnum); i++) {
-		if (xewtoh(shdrp[i].sh_offset) > maxoff)
-			maxoff = xewtoh(shdrp[i].sh_offset);
 		switch (xe32toh(shdrp[i].sh_type)) {
 		case SHT_SYMTAB:
-			if (symtabshdr != NULL)
+			if (symtabshdr != NULL) {
 				weird = 1;
+				weirdreason = "multiple symbol tables";
+			}
 			symtabshdr = &shdrp[i];
 			strtabshdr = &shdrp[xe32toh(shdrp[i].sh_link)];
-
-			/* Check whether the string table is the last section */
-			stroff = xewtoh(shdrp[xe32toh(shdrp[i].sh_link)].sh_offset);
-			if (!weird && xe32toh(shdrp[i].sh_link) != (xe16toh(ehdr.e_shnum) - 1)) {
-				weird = 1;
-				weirdreason = "string table not last section";
-			}
+			break;
+		case SHT_STRTAB:
+			if (i == xe16toh(ehdr.e_shstrndx))
+				shstrtabshdr = &shdrp[i];
 			break;
 		}
 	}
-	if (! weirdreason)
-		weirdreason = "unsupported";
 	if (symtabshdr == NULL)
 		goto out;
-	if (strtabshdr == NULL)
+	if (strtabshdr == NULL) {
 		weird = 1;
-	if (!weird && stroff != maxoff) {
+		weirdreason = "string table does not exist";
+	}
+	if (shstrtabshdr == NULL) {
 		weird = 1;
-		weirdreason = "string table section not last in file";
-	}   
+		weirdreason = "section header string table does not exist";
+	}
+	if (weirdreason == NULL)
+		weirdreason = "unsupported";
 	if (weird) {
 		fprintf(stderr, "%s: weird executable (%s)\n", fn, weirdreason);
 		goto bad;
 	}
 
 	/*
+	 * sort section layout table by offset
+	 */
+	layoutp = xmalloc(sizeof(struct shlayout) * (xe16toh(ehdr.e_shnum) + 1),
+	    fn, "layout table");
+	if (layoutp == NULL)
+		goto bad;
+
+	/* add a pseudo entry to represent the section header table */
+	shdrshdr.sh_offset = ehdr.e_shoff;
+	shdrshdr.sh_size = htoxew(shdrsize);
+	shdrshdr.sh_addralign = htoxew(ELFSIZE / 8);
+	layoutp[xe16toh(ehdr.e_shnum)].shdr = &shdrshdr;
+
+	/* insert and sort normal section headers */
+	for (i = xe16toh(ehdr.e_shnum) - 1; i >= 0; i--) {
+		l = i + 1;
+		r = xe16toh(ehdr.e_shnum);
+		while (l <= r) {
+			m = ( l + r) / 2;
+			if (xewtoh(shdrp[i].sh_offset) >
+			    xewtoh(layoutp[m].shdr->sh_offset))
+				l = m + 1;
+			else
+				r = m - 1;
+		}
+
+		if (r != i) {
+			memmove(&layoutp[i], &layoutp[i + 1],
+			    sizeof(struct shlayout) * (r - i));
+		}
+
+		layoutp[r].shdr = &shdrp[i];
+		layoutp[r].bufp = NULL;
+	}
+
+	/*
 	 * load up everything we need
 	 */
 
-	/* symbol table */
-	if ((symtabp = xmalloc(xewtoh(symtabshdr->sh_size), fn, "symbol table"))
-	    == NULL)
-		goto bad;
-	if ((size_t)xreadatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset),
-	    xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size))
+	/* load section string table for debug use */
+	if ((shstrtabp = xmalloc(xewtoh(shstrtabshdr->sh_size), fn,
+	    "section string table")) == NULL)
+		goto bad;
+	if ((size_t)xreadatoff(fd, shstrtabp, xewtoh(shstrtabshdr->sh_offset),
+	    xewtoh(shstrtabshdr->sh_size), fn) != xewtoh(shstrtabshdr->sh_size))
 		goto bad;
 
-	/* string table */
-	if ((strtabp = xmalloc(xewtoh(strtabshdr->sh_size), fn, "string table"))
-	    == NULL)
-		goto bad;
-	if ((size_t)xreadatoff(fd, strtabp, xewtoh(strtabshdr->sh_offset),
-	    xewtoh(strtabshdr->sh_size), fn) != xewtoh(strtabshdr->sh_size))
-		goto bad;
+	/* we need symtab, strtab, and everything behind strtab */
+	strtabidx = INT_MAX;
+	for (i = 0; i < xe16toh(ehdr.e_shnum) + 1; i++) {
+		if (layoutp[i].shdr == &shdrshdr) {
+			/* not load section header again */
+			layoutp[i].bufp = shdrp;
+			continue;
+		}
+		if (layoutp[i].shdr == shstrtabshdr) {
+			/* not load section string table again */
+			layoutp[i].bufp = shstrtabp;
+			continue;
+		}
+
+		if (layoutp[i].shdr == strtabshdr)
+			strtabidx = i;
+		if (layoutp[i].shdr == symtabshdr || i >= strtabidx) {
+			off = xewtoh(layoutp[i].shdr->sh_offset);
+			size = xewtoh(layoutp[i].shdr->sh_size);
+			layoutp[i].bufp = xmalloc(size, fn,
+			    shstrtabp + xewtoh(layoutp[i].shdr->sh_name));
+			if (layoutp[i].bufp == NULL)
+				goto bad;
+			if ((size_t)xreadatoff(fd, layoutp[i].bufp, off, size, fn) !=
+			    size)
+				goto bad;
+
+			/* set symbol table and string table */
+			if (layoutp[i].shdr == symtabshdr)
+				symtabp = layoutp[i].bufp;
+			else if (layoutp[i].shdr == strtabshdr)
+				strtabp = layoutp[i].bufp;
+		}
+	}
 
 	nstrtab_size = 256;
 	nstrtabp = xmalloc(nstrtab_size, fn, "new string table");
@@ -365,28 +428,62 @@ ELFNAMEEND(hide)(int fd, const char *fn)
 	strtabshdr->sh_size = htoxew(nstrtab_nextoff);
 
 	/*
-	 * write new tables to the file
+	 * update section header table in ascending order of offset
 	 */
-	if (xwriteatoff(fd, shdrp, xewtoh(ehdr.e_shoff), shdrsize, fn) !=
-	    shdrsize)
-		goto bad;
-	if ((size_t)xwriteatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset),
-	    xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size))
-		goto bad;
-	/* write new symbol table strings */
-	if ((size_t)xwriteatoff(fd, nstrtabp, xewtoh(strtabshdr->sh_offset),
-	    xewtoh(strtabshdr->sh_size), fn) != xewtoh(strtabshdr->sh_size))
-		goto bad;
+	for (i = strtabidx + 1; i < xe16toh(ehdr.e_shnum) + 1; i++) {
+		Elf_Off off, align;
+		off = xewtoh(layoutp[i - 1].shdr->sh_offset) +
+		    xewtoh(layoutp[i - 1].shdr->sh_size);
+		align = xewtoh(layoutp[i].shdr->sh_addralign);
+		off = (off + (align - 1)) & ~(align - 1);
+		layoutp[i].shdr->sh_offset = htoxew(off);
+	}
+
+	/*
+	 * write data to the file in descending order of offset
+	 */
+	for (i = xe16toh(ehdr.e_shnum); i >= 0; i--) {
+		if (layoutp[i].shdr == strtabshdr) {
+			/* new string table */
+			buf = nstrtabp;
+		} else
+			buf = layoutp[i].bufp;
+
+		if (layoutp[i].shdr == &shdrshdr ||
+		    layoutp[i].shdr == symtabshdr || i >= strtabidx) {
+			if (buf == NULL)
+				goto bad;
+
+			/*
+			 * update the offset of section header table in elf
+			 * header if needed.
+			 */
+			if (layoutp[i].shdr == &shdrshdr &&
+			    ehdr.e_shoff != shdrshdr.sh_offset) {
+				ehdr.e_shoff = shdrshdr.sh_offset;
+				off = (ELFSIZE == 32) ? 32 : 44;
+				size = sizeof(Elf_Off);
+				if ((size_t)xwriteatoff(fd, &ehdr.e_shoff, off, size,
+				    fn) != size)
+					goto bad;
+			}
+
+			off = xewtoh(layoutp[i].shdr->sh_offset);
+			size = xewtoh(layoutp[i].shdr->sh_size);
+			if ((size_t)xwriteatoff(fd, buf, off, size, fn) != size)
+				goto bad;
+		}
+	}
 
 out:
-	if (shdrp != NULL)
-		free(shdrp);
-	if (symtabp != NULL)
-		free(symtabp);
-	if (strtabp != NULL)
-		free(strtabp);
-	if (nstrtabp != NULL)
-		free(nstrtabp);
+	if (layoutp != NULL) {
+		for (i = 0; i < xe16toh(ehdr.e_shnum) + 1; i++) {
+			if (layoutp[i].bufp != NULL)
+				free(layoutp[i].bufp);
+		}
+		free(layoutp);
+	}
+	free(nstrtabp);
 	return (rv);
 
 bad:


More information about the svn-src-head mailing list