summaryrefslogtreecommitdiffstats
path: root/usr.sbin/crunch/crunchide
diff options
context:
space:
mode:
authorpfg <pfg@FreeBSD.org>2013-02-03 20:35:37 +0000
committerpfg <pfg@FreeBSD.org>2013-02-03 20:35:37 +0000
commitd70abf9adce8e2057e1a370cb35308c2b7749794 (patch)
treee3432232a2e405c70fb5966d4b29494f24da26b3 /usr.sbin/crunch/crunchide
parent2d2c37fb592dfc24f15e4bf14c2f109b5d4b5a83 (diff)
downloadFreeBSD-src-d70abf9adce8e2057e1a370cb35308c2b7749794.zip
FreeBSD-src-d70abf9adce8e2057e1a370cb35308c2b7749794.tar.gz
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
Diffstat (limited to 'usr.sbin/crunch/crunchide')
-rw-r--r--usr.sbin/crunch/crunchide/exec_elf32.c217
1 files changed, 157 insertions, 60 deletions
diff --git a/usr.sbin/crunch/crunchide/exec_elf32.c b/usr.sbin/crunch/crunchide/exec_elf32.c
index 9274f89..59ef41f 100644
--- a/usr.sbin/crunch/crunchide/exec_elf32.c
+++ b/usr.sbin/crunch/crunchide/exec_elf32.c
@@ -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)
+ /* 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, symtabp, xewtoh(symtabshdr->sh_offset),
- xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size))
+ 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:
OpenPOWER on IntegriCloud