x86, relocs: Generalize ELF structure names

In preparation for making the reloc tool operate on 64-bit relocations,
generalize the structure names for easy recompilation via #defines.

Based on work by Neill Clift and Michael Davidson.

Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1365797627-20874-2-git-send-email-keescook@chromium.org
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
Kees Cook 2013-04-12 13:13:42 -07:00 committed by H. Peter Anvin
parent 4eefbe792b
commit bf11655cf2

View File

@ -12,20 +12,42 @@
#include <regex.h>
#include <tools/le_byteshift.h>
#define ElfW(type) _ElfW(ELF_BITS, type)
#define _ElfW(bits, type) __ElfW(bits, type)
#define __ElfW(bits, type) Elf##bits##_##type
#define ELF_BITS 32
#define ELF_MACHINE EM_386
#define ELF_MACHINE_NAME "i386"
#define SHT_REL_TYPE SHT_REL
#define ELF_CLASS ELFCLASS32
#define ELF_R_SYM(val) ELF32_R_SYM(val)
#define ELF_R_TYPE(val) ELF32_R_TYPE(val)
#define ELF_ST_TYPE(o) ELF32_ST_TYPE(o)
#define ELF_ST_BIND(o) ELF32_ST_BIND(o)
#define ELF_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o)
#define Elf_Rel ElfW(Rel)
#define Elf_Ehdr ElfW(Ehdr)
#define Elf_Phdr ElfW(Phdr)
#define Elf_Shdr ElfW(Shdr)
#define Elf_Sym ElfW(Sym)
static void die(char *fmt, ...);
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
static Elf32_Ehdr ehdr;
static Elf_Ehdr ehdr;
static unsigned long reloc_count, reloc_idx;
static unsigned long *relocs;
static unsigned long reloc16_count, reloc16_idx;
static unsigned long *relocs16;
struct section {
Elf32_Shdr shdr;
Elf_Shdr shdr;
struct section *link;
Elf32_Sym *symtab;
Elf32_Rel *reltab;
Elf_Sym *symtab;
Elf_Rel *reltab;
char *strtab;
};
static struct section *secs;
@ -240,7 +262,7 @@ static const char *sec_name(unsigned shndx)
return name;
}
static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
{
const char *name;
name = "<noname>";
@ -274,6 +296,12 @@ static uint32_t elf32_to_cpu(uint32_t val)
return le32_to_cpu(val);
}
#define elf_half_to_cpu(x) elf16_to_cpu(x)
#define elf_word_to_cpu(x) elf32_to_cpu(x)
#define elf_addr_to_cpu(x) elf32_to_cpu(x)
#define elf_off_to_cpu(x) elf32_to_cpu(x)
#define elf_xword_to_cpu(x) elf32_to_cpu(x)
static void read_ehdr(FILE *fp)
{
if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
@ -283,8 +311,8 @@ static void read_ehdr(FILE *fp)
if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
die("No ELF magic\n");
}
if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
die("Not a 32 bit executable\n");
if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) {
die("Not a %d bit executable\n", ELF_BITS);
}
if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
die("Not a LSB ELF executable\n");
@ -293,36 +321,36 @@ static void read_ehdr(FILE *fp)
die("Unknown ELF version\n");
}
/* Convert the fields to native endian */
ehdr.e_type = elf16_to_cpu(ehdr.e_type);
ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
ehdr.e_version = elf32_to_cpu(ehdr.e_version);
ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
ehdr.e_type = elf_half_to_cpu(ehdr.e_type);
ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine);
ehdr.e_version = elf_word_to_cpu(ehdr.e_version);
ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry);
ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff);
ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff);
ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags);
ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize);
ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum);
ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum);
ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx);
if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
die("Unsupported ELF header type\n");
}
if (ehdr.e_machine != EM_386) {
die("Not for x86\n");
if (ehdr.e_machine != ELF_MACHINE) {
die("Not for %s\n", ELF_MACHINE_NAME);
}
if (ehdr.e_version != EV_CURRENT) {
die("Unknown ELF version\n");
}
if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) {
die("Bad Elf header size\n");
}
if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
die("Bad program header entry\n");
}
if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
if (ehdr.e_shentsize != sizeof(Elf_Shdr)) {
die("Bad section header entry\n");
}
if (ehdr.e_shstrndx >= ehdr.e_shnum) {
@ -333,7 +361,7 @@ static void read_ehdr(FILE *fp)
static void read_shdrs(FILE *fp)
{
int i;
Elf32_Shdr shdr;
Elf_Shdr shdr;
secs = calloc(ehdr.e_shnum, sizeof(struct section));
if (!secs) {
@ -349,16 +377,16 @@ static void read_shdrs(FILE *fp)
if (fread(&shdr, sizeof shdr, 1, fp) != 1)
die("Cannot read ELF section headers %d/%d: %s\n",
i, ehdr.e_shnum, strerror(errno));
sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name);
sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type);
sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags);
sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr);
sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset);
sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size);
sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link);
sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info);
sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize);
sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name);
sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type);
sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags);
sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr);
sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset);
sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size);
sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link);
sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info);
sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize);
if (sec->shdr.sh_link < ehdr.e_shnum)
sec->link = &secs[sec->shdr.sh_link];
}
@ -412,12 +440,12 @@ static void read_symtabs(FILE *fp)
die("Cannot read symbol table: %s\n",
strerror(errno));
}
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
Elf32_Sym *sym = &sec->symtab[j];
sym->st_name = elf32_to_cpu(sym->st_name);
sym->st_value = elf32_to_cpu(sym->st_value);
sym->st_size = elf32_to_cpu(sym->st_size);
sym->st_shndx = elf16_to_cpu(sym->st_shndx);
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
Elf_Sym *sym = &sec->symtab[j];
sym->st_name = elf_word_to_cpu(sym->st_name);
sym->st_value = elf_addr_to_cpu(sym->st_value);
sym->st_size = elf_xword_to_cpu(sym->st_size);
sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
}
}
}
@ -428,7 +456,7 @@ static void read_relocs(FILE *fp)
int i,j;
for (i = 0; i < ehdr.e_shnum; i++) {
struct section *sec = &secs[i];
if (sec->shdr.sh_type != SHT_REL) {
if (sec->shdr.sh_type != SHT_REL_TYPE) {
continue;
}
sec->reltab = malloc(sec->shdr.sh_size);
@ -445,10 +473,10 @@ static void read_relocs(FILE *fp)
die("Cannot read symbol table: %s\n",
strerror(errno));
}
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
Elf32_Rel *rel = &sec->reltab[j];
rel->r_offset = elf32_to_cpu(rel->r_offset);
rel->r_info = elf32_to_cpu(rel->r_info);
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
Elf_Rel *rel = &sec->reltab[j];
rel->r_offset = elf_addr_to_cpu(rel->r_offset);
rel->r_info = elf_xword_to_cpu(rel->r_info);
}
}
}
@ -468,8 +496,8 @@ static void print_absolute_symbols(void)
continue;
}
sym_strtab = sec->link->strtab;
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
Elf32_Sym *sym;
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
Elf_Sym *sym;
const char *name;
sym = &sec->symtab[j];
name = sym_name(sym_strtab, sym);
@ -478,9 +506,9 @@ static void print_absolute_symbols(void)
}
printf("%5d %08x %5d %10s %10s %12s %s\n",
j, sym->st_value, sym->st_size,
sym_type(ELF32_ST_TYPE(sym->st_info)),
sym_bind(ELF32_ST_BIND(sym->st_info)),
sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
sym_type(ELF_ST_TYPE(sym->st_info)),
sym_bind(ELF_ST_BIND(sym->st_info)),
sym_visibility(ELF_ST_VISIBILITY(sym->st_other)),
name);
}
}
@ -495,9 +523,9 @@ static void print_absolute_relocs(void)
struct section *sec = &secs[i];
struct section *sec_applies, *sec_symtab;
char *sym_strtab;
Elf32_Sym *sh_symtab;
Elf_Sym *sh_symtab;
int j;
if (sec->shdr.sh_type != SHT_REL) {
if (sec->shdr.sh_type != SHT_REL_TYPE) {
continue;
}
sec_symtab = sec->link;
@ -507,12 +535,12 @@ static void print_absolute_relocs(void)
}
sh_symtab = sec_symtab->symtab;
sym_strtab = sec_symtab->link->strtab;
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
Elf32_Rel *rel;
Elf32_Sym *sym;
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
Elf_Rel *rel;
Elf_Sym *sym;
const char *name;
rel = &sec->reltab[j];
sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
name = sym_name(sym_strtab, sym);
if (sym->st_shndx != SHN_ABS) {
continue;
@ -545,7 +573,7 @@ static void print_absolute_relocs(void)
printf("%08x %08x %10s %08x %s\n",
rel->r_offset,
rel->r_info,
rel_type(ELF32_R_TYPE(rel->r_info)),
rel_type(ELF_R_TYPE(rel->r_info)),
sym->st_value,
name);
}
@ -555,19 +583,19 @@ static void print_absolute_relocs(void)
printf("\n");
}
static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
static void walk_relocs(void (*visit)(Elf_Rel *rel, Elf_Sym *sym),
int use_real_mode)
{
int i;
/* Walk through the relocations */
for (i = 0; i < ehdr.e_shnum; i++) {
char *sym_strtab;
Elf32_Sym *sh_symtab;
Elf_Sym *sh_symtab;
struct section *sec_applies, *sec_symtab;
int j;
struct section *sec = &secs[i];
if (sec->shdr.sh_type != SHT_REL) {
if (sec->shdr.sh_type != SHT_REL_TYPE) {
continue;
}
sec_symtab = sec->link;
@ -577,16 +605,16 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
}
sh_symtab = sec_symtab->symtab;
sym_strtab = sec_symtab->link->strtab;
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
Elf32_Rel *rel;
Elf32_Sym *sym;
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
Elf_Rel *rel;
Elf_Sym *sym;
unsigned r_type;
const char *symname;
int shn_abs;
rel = &sec->reltab[j];
sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
r_type = ELF32_R_TYPE(rel->r_info);
sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
r_type = ELF_R_TYPE(rel->r_info);
shn_abs = sym->st_shndx == SHN_ABS;
@ -647,18 +675,18 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
}
}
static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
static void count_reloc(Elf_Rel *rel, Elf_Sym *sym)
{
if (ELF32_R_TYPE(rel->r_info) == R_386_16)
if (ELF_R_TYPE(rel->r_info) == R_386_16)
reloc16_count++;
else
reloc_count++;
}
static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
static void collect_reloc(Elf_Rel *rel, Elf_Sym *sym)
{
/* Remember the address that needs to be adjusted. */
if (ELF32_R_TYPE(rel->r_info) == R_386_16)
if (ELF_R_TYPE(rel->r_info) == R_386_16)
relocs16[reloc16_idx++] = rel->r_offset;
else
relocs[reloc_idx++] = rel->r_offset;