elf32: more portable implementation.

The old implementation only worked on little-endian machines, and
relied on a particular struct layout.
This commit is contained in:
Daniel Beer 2012-05-10 10:00:58 +12:00
parent 6fd161faa7
commit f44d9d5281
1 changed files with 105 additions and 36 deletions

View File

@ -44,11 +44,93 @@ struct elf32_info {
int string_len; int string_len;
}; };
static int parse_ehdr(Elf32_Ehdr *e, FILE *in)
{
uint8_t data[52];
if (fread(data, sizeof(data), 1, in) != 1)
return -1;
memcpy(e->e_ident, data, EI_NIDENT);
e->e_type = LE_WORD(data, 16);
e->e_machine = LE_WORD(data, 18);
e->e_version = LE_LONG(data, 20);
e->e_entry = LE_LONG(data, 24);
e->e_phoff = LE_LONG(data, 28);
e->e_shoff = LE_LONG(data, 32);
e->e_flags = LE_LONG(data, 36);
e->e_ehsize = LE_WORD(data, 40);
e->e_phentsize = LE_WORD(data, 42);
e->e_phnum = LE_WORD(data, 44);
e->e_shentsize = LE_WORD(data, 46);
e->e_shnum = LE_WORD(data, 48);
e->e_shstrndx = LE_WORD(data, 50);
return 0;
}
static int parse_phdr(Elf32_Phdr *p, FILE *in)
{
uint8_t data[32];
if (fread(data, sizeof(data), 1, in) != 1)
return -1;
p->p_type = LE_LONG(data, 0);
p->p_offset = LE_LONG(data, 4);
p->p_vaddr = LE_LONG(data, 8);
p->p_paddr = LE_LONG(data, 12);
p->p_filesz = LE_LONG(data, 16);
p->p_memsz = LE_LONG(data, 20);
p->p_flags = LE_LONG(data, 24);
p->p_align = LE_LONG(data, 28);
return 0;
}
static int parse_shdr(Elf32_Shdr *s, FILE *in)
{
uint8_t data[40];
if (fread(data, sizeof(data), 1, in) != 1)
return -1;
s->sh_name = LE_LONG(data, 0);
s->sh_type = LE_LONG(data, 4);
s->sh_flags = LE_LONG(data, 8);
s->sh_addr = LE_LONG(data, 12);
s->sh_offset = LE_LONG(data, 16);
s->sh_size = LE_LONG(data, 20);
s->sh_link = LE_LONG(data, 24);
s->sh_info = LE_LONG(data, 28);
s->sh_addralign = LE_LONG(data, 32);
s->sh_entsize = LE_LONG(data, 36);
return 0;
}
static int parse_sym(Elf32_Sym *s, FILE *in)
{
uint8_t data[16];
if (fread(data, sizeof(data), 1, in) != 1)
return -1;
s->st_name = LE_LONG(data, 0);
s->st_value = LE_LONG(data, 4);
s->st_size = LE_LONG(data, 8);
s->st_info = data[12];
s->st_other = data[13];
s->st_shndx = LE_WORD(data, 14);
return 0;
}
static int read_ehdr(struct elf32_info *info, FILE *in) static int read_ehdr(struct elf32_info *info, FILE *in)
{ {
/* Read and check the ELF header */ /* Read and check the ELF header */
rewind(in); rewind(in);
if (fread(&info->file_ehdr, sizeof(info->file_ehdr), 1, in) == 0) { if (parse_ehdr(&info->file_ehdr, in) < 0) {
pr_error("elf32: couldn't read ELF header"); pr_error("elf32: couldn't read ELF header");
return -1; return -1;
} }
@ -79,8 +161,7 @@ static int read_phdr(struct elf32_info *info, FILE *in)
return -1; return -1;
} }
if (fread(&info->file_phdrs[i], if (parse_phdr(&info->file_phdrs[i], in) < 0) {
sizeof(info->file_phdrs[0]), 1, in) == 0) {
printc_err("elf32: can't read phdr %d: %s\n", printc_err("elf32: can't read phdr %d: %s\n",
i, last_error()); i, last_error());
return -1; return -1;
@ -108,8 +189,7 @@ static int read_shdr(struct elf32_info *info, FILE *in)
return -1; return -1;
} }
if (fread(&info->file_shdrs[i], if (parse_shdr(&info->file_shdrs[i], in) < 0) {
sizeof(info->file_shdrs[0]), 1, in) == 0) {
printc_err("elf32: can't read shdr %d: %s\n", printc_err("elf32: can't read shdr %d: %s\n",
i, last_error()); i, last_error());
return -1; return -1;
@ -217,7 +297,7 @@ static int load_strings(struct elf32_info *info, FILE *in, Elf32_Shdr *s)
return -1; return -1;
} }
if (!fread(info->string_tab, 1, info->string_len, in)) { if (!fread(info->string_tab, info->string_len, 1, in)) {
if (ferror(in)) { if (ferror(in)) {
pr_error("elf32: error reading strings"); pr_error("elf32: error reading strings");
return -1; return -1;
@ -296,50 +376,39 @@ static Elf32_Shdr *find_shdr(struct elf32_info *info, Elf32_Word type)
static int syms_load_syms(struct elf32_info *info, FILE *in, static int syms_load_syms(struct elf32_info *info, FILE *in,
Elf32_Shdr *s) Elf32_Shdr *s)
{ {
Elf32_Sym syms[N_SYMS]; int len = s->sh_size / 16;
int len = s->sh_size / sizeof(syms[0]); int i;
if (fseek(in, s->sh_offset, SEEK_SET) < 0) { if (fseek(in, s->sh_offset, SEEK_SET) < 0) {
pr_error("elf32: can't seek to symbols"); pr_error("elf32: can't seek to symbols");
return -1; return -1;
} }
while (len) { for (i = 0; i < len; i++) {
int req = N_SYMS > len ? len : N_SYMS; Elf32_Sym y;
int count = fread(syms, sizeof(syms[0]), req, in); int st;
int i; const char *name;
if (!count) { if (parse_sym(&y, in) < 0) {
printc_err("elf32: eof reading symbols\n");
return -1;
}
if (count < 0) {
pr_error("elf32: error reading symbols"); pr_error("elf32: error reading symbols");
return -1; return -1;
} }
for (i = 0; i < count; i++) { st = ELF32_ST_TYPE(y.st_info);
Elf32_Sym *y = &syms[i]; name = info->string_tab + y.st_name;
int st = ELF32_ST_TYPE(y->st_info);
const char *name = info->string_tab + y->st_name;
if (y->st_name > info->string_len) { if (y.st_name > info->string_len) {
printc_err("elf32: symbol out of " printc_err("elf32: symbol out of bounds\n");
"bounds\n"); return -1;
return -1;
}
if (name[0] &&
(st == STT_OBJECT || st == STT_FUNC ||
st == STT_SECTION || st == STT_COMMON ||
st == STT_TLS) &&
stab_set(info->string_tab + y->st_name,
y->st_value) < 0)
return -1;
} }
len -= count; if (name[0] &&
(st == STT_OBJECT || st == STT_FUNC ||
st == STT_SECTION || st == STT_COMMON ||
st == STT_TLS) &&
stab_set(info->string_tab + y.st_name,
y.st_value) < 0)
return -1;
} }
return 0; return 0;