summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornorly <ny-git@enpas.org>2013-06-15 21:42:53 +0100
committernorly <ny-git@enpas.org>2013-06-15 22:02:26 +0100
commit825613b8e4f141a82d2b8be22d7fba68fed5ef96 (patch)
tree8ade4e195c1a77a3814c44109c4f5cc9e1a5ced7
parent5868bb32246367139f0d17a989650964f90a7958 (diff)
Basic x86-64 support, not very usable in practice
Turns out that x86-64 aligns LOAD segments to 0x200000 bytes. Given that the mapping starts at 0x400000, there is not much room to expand... so there will be a need to add additional LOAD headers.
-rw-r--r--src/elfops/check.c4
-rw-r--r--src/modelops/fromFile.c100
-rw-r--r--src/modelops/relocate.c74
-rw-r--r--src/modelops/toFile.c30
4 files changed, 153 insertions, 55 deletions
diff --git a/src/elfops/check.c b/src/elfops/check.c
index 6e56bae..e184b26 100644
--- a/src/elfops/check.c
+++ b/src/elfops/check.c
@@ -24,8 +24,8 @@ int elfu_eCheck(Elf *e)
goto ERROR;
}
- if (ehdr.e_machine != EM_386) {
- ELFU_WARN("Sorry, only x86-32 ELF files are supported at the moment.\n");
+ if (ehdr.e_machine != EM_386 && ehdr.e_machine != EM_X86_64) {
+ ELFU_WARN("Sorry, only x86-32 and x86-64 ELF files are supported at the moment.\n");
goto ERROR;
}
diff --git a/src/modelops/fromFile.c b/src/modelops/fromFile.c
index 28ecb85..bc089bf 100644
--- a/src/modelops/fromFile.c
+++ b/src/modelops/fromFile.c
@@ -5,41 +5,69 @@
#include <libelfu/libelfu.h>
-static void parseSymtab32(ElfuScn *ms, ElfuScn**origScnArr)
+static void parseSymtab(ElfuElf *me, ElfuScn *ms, ElfuScn**origScnArr)
{
+ ElfuSym *sym;
size_t i;
assert(ms);
assert(ms->data.d_buf);
assert(origScnArr);
+ /* Parse symbols from their elfclass-specific format */
+ if (me->elfclass == ELFCLASS32) {
+ for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
+ Elf32_Sym *cursym = ((Elf32_Sym*)ms->data.d_buf) + i;
+ ElfuSym *newsym = malloc(sizeof(*sym));
+ assert(newsym);
- for (i = 1; (i + 1) * sizeof(Elf32_Sym) <= ms->shdr.sh_size; i++) {
- Elf32_Sym *cursym = &(((Elf32_Sym*)ms->data.d_buf)[i]);
- ElfuSym *sym = malloc(sizeof(*sym));
- assert(sym);
+ newsym->name = cursym->st_name;
+ newsym->value = cursym->st_value;
+ newsym->size = cursym->st_size;
+ newsym->bind = ELF32_ST_BIND(cursym->st_info);
+ newsym->type = ELF32_ST_TYPE(cursym->st_info);
+ newsym->other = cursym->st_other;
+ newsym->shndx = cursym->st_shndx;
- sym->name = cursym->st_name;
- sym->value = cursym->st_value;
- sym->size = cursym->st_size;
- sym->bind = ELF32_ST_BIND(cursym->st_info);
- sym->type = ELF32_ST_TYPE(cursym->st_info);
- sym->other = cursym->st_other;
- sym->shndx = cursym->st_shndx;
- switch (cursym->st_shndx) {
+
+ CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
+ }
+ } else if (me->elfclass == ELFCLASS64) {
+ for (i = 1; (i + 1) * sizeof(Elf64_Sym) <= ms->shdr.sh_size; i++) {
+ Elf64_Sym *cursym = ((Elf64_Sym*)ms->data.d_buf) + i;
+ ElfuSym *newsym = malloc(sizeof(*sym));
+ assert(newsym);
+
+ newsym->name = cursym->st_name;
+ newsym->value = cursym->st_value;
+ newsym->size = cursym->st_size;
+ newsym->bind = ELF64_ST_BIND(cursym->st_info);
+ newsym->type = ELF64_ST_TYPE(cursym->st_info);
+ newsym->other = cursym->st_other;
+ newsym->shndx = cursym->st_shndx;
+
+
+
+ CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, newsym, elem);
+ }
+ } else {
+ // Unknown elfclass
+ assert(0);
+ }
+
+ /* For each section, find the section it points to if any. */
+ CIRCLEQ_FOREACH(sym, &ms->symtab.syms, elem) {
+ switch (sym->shndx) {
case SHN_UNDEF:
case SHN_ABS:
case SHN_COMMON:
sym->scnptr = NULL;
break;
default:
- sym->scnptr = origScnArr[cursym->st_shndx - 1];
+ sym->scnptr = origScnArr[sym->shndx - 1];
break;
}
-
-
- CIRCLEQ_INSERT_TAIL(&ms->symtab.syms, sym, elem);
}
}
@@ -60,10 +88,8 @@ static void parseReltab32(ElfuScn *ms)
assert(rel);
rel->offset = currel->r_offset;
-
rel->sym = ELF32_R_SYM(currel->r_info);
rel->type = ELF32_R_TYPE(currel->r_info);
-
rel->addendUsed = 0;
rel->addend = 0;
@@ -72,6 +98,32 @@ static void parseReltab32(ElfuScn *ms)
}
+static void parseRelatab64(ElfuScn *ms)
+{
+ size_t i;
+
+ assert(ms);
+ assert(ms->data.d_buf);
+
+
+ for (i = 0; (i + 1) * sizeof(Elf64_Rela) <= ms->shdr.sh_size; i++) {
+ Elf64_Rela *currel = &(((Elf64_Rela*)ms->data.d_buf)[i]);
+ ElfuRel *rel;
+
+ rel = malloc(sizeof(*rel));
+ assert(rel);
+
+ rel->offset = currel->r_offset;
+ rel->sym = ELF64_R_SYM(currel->r_info);
+ rel->type = ELF64_R_TYPE(currel->r_info);
+ rel->addendUsed = 1;
+ rel->addend = currel->r_addend;
+
+ CIRCLEQ_INSERT_TAIL(&ms->reltab.rels, rel, elem);
+ }
+}
+
+
static int cmpScnOffs(const void *ms1, const void *ms2)
{
assert(ms1);
@@ -360,11 +412,7 @@ ElfuElf* elfu_mFromElf(Elf *e)
case SHT_SYMTAB:
me->symtab = ms;
case SHT_DYNSYM:
- if (me->elfclass == ELFCLASS32) {
- parseSymtab32(ms, secArray);
- } else if (me->elfclass == ELFCLASS64) {
- // TODO
- }
+ parseSymtab(me, ms, secArray);
break;
}
}
@@ -379,14 +427,14 @@ ElfuElf* elfu_mFromElf(Elf *e)
if (me->elfclass == ELFCLASS32) {
parseReltab32(ms);
} else if (me->elfclass == ELFCLASS64) {
- // TODO
+ // Not used on x86-64
}
break;
case SHT_RELA:
if (me->elfclass == ELFCLASS32) {
// TODO
} else if (me->elfclass == ELFCLASS64) {
- // TODO
+ parseRelatab64(ms);
}
break;
}
diff --git a/src/modelops/relocate.c b/src/modelops/relocate.c
index ea84937..2c9873c 100644
--- a/src/modelops/relocate.c
+++ b/src/modelops/relocate.c
@@ -57,7 +57,8 @@ static GElf_Word pltLookupVal(ElfuElf *metarget, char *name)
* Technically, these relocations write the functions' addresses
* to the GOT, not the PLT, after the dynamic linker has found
* them. */
- if (rel->type != R_386_JMP_SLOT) {
+ if ((metarget->elfclass == ELFCLASS32 && rel->type != R_386_JMP_SLOT)
+ || (metarget->elfclass == ELFCLASS64 && rel->type != R_X86_64_JUMP_SLOT)) {
continue;
}
@@ -148,29 +149,54 @@ void elfu_mRelocate32(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
mstarget->shdr.sh_size);
CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) {
- Elf32_Word *dest = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
- Elf32_Word a = rel->addendUsed ? rel->addend : *dest;
- Elf32_Addr p = mstarget->shdr.sh_addr + rel->offset;
- Elf32_Addr s = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
- Elf32_Word newval = *dest;
-
- switch(rel->type) {
- case R_386_NONE:
- ELFU_DEBUG("Skipping relocation: R_386_NONE");
- break;
- case R_386_32:
- ELFU_DEBUG("Relocation: R_386_32");
- newval = s + a;
- break;
- case R_386_PC32:
- ELFU_DEBUG("Relocation: R_386_PC32");
- newval = s + a - p;
- break;
-
- default:
- ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
+ Elf32_Word *dest32 = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
+ Elf64_Word *dest64 = (Elf64_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
+
+
+ if (metarget->elfclass == ELFCLASS32) {
+ Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32;
+ Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset;
+ Elf32_Addr s32 = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
+ switch(rel->type) {
+ case R_386_NONE:
+ ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
+ break;
+ case R_386_32:
+ *dest32 = s32 + a32;
+ break;
+ case R_386_PC32:
+ *dest32 = s32 + a32 - p32;
+ break;
+
+ default:
+ ELFU_DEBUG("Skipping relocation: Unknown type %d\n", rel->type);
+ }
+ } else if (metarget->elfclass == ELFCLASS64) {
+ /* x86-64 only uses RELA with explicit addend. */
+ assert(rel->addendUsed);
+ Elf64_Word a64 = rel->addend;
+ Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset;
+ Elf64_Addr s64 = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
+
+ switch(rel->type) {
+ case R_X86_64_NONE:
+ ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
+ break;
+ case R_X86_64_64:
+ *dest64 = s64 + a64;
+ break;
+ case R_X86_64_PC32:
+ *dest32 = s64 + a64 - p64;
+ break;
+ case R_X86_64_32:
+ *dest32 = s64 + a64;
+ break;
+
+ default:
+ ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
+ }
}
- ELFU_DEBUG(", overwriting %x with %x.\n", *dest, newval);
- *dest = newval;
+
+
}
}
diff --git a/src/modelops/toFile.c b/src/modelops/toFile.c
index 434130e..90dc247 100644
--- a/src/modelops/toFile.c
+++ b/src/modelops/toFile.c
@@ -49,10 +49,34 @@ static void flattenSymtab(ElfuElf *me)
i++;
}
} else if (me->elfclass == ELFCLASS64) {
- // TODO
- assert(0);
+ size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym);
+ size_t i;
+
+ if (me->symtab->data.d_buf) {
+ free(me->symtab->data.d_buf);
+ }
+ me->symtab->data.d_buf = malloc(newsize);
+ assert(me->symtab->data.d_buf);
+
+ me->symtab->data.d_size = newsize;
+ me->symtab->shdr.sh_size = newsize;
+ memset(me->symtab->data.d_buf, 0, newsize);
+
+ i = 1;
+ CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
+ Elf64_Sym *es = ((Elf64_Sym*)me->symtab->data.d_buf) + i;
+
+ es->st_name = sym->name;
+ es->st_value = sym->value;
+ es->st_size = sym->size;
+ es->st_info = ELF64_ST_INFO(sym->bind, sym->type);
+ es->st_other = sym->other;
+ es->st_shndx = sym->shndx;
+
+ i++;
+ }
} else {
- // Never reached
+ // Unknown elfclass
assert(0);
}