summaryrefslogtreecommitdiff
path: root/rts/linker/Elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'rts/linker/Elf.c')
-rw-r--r--rts/linker/Elf.c166
1 files changed, 162 insertions, 4 deletions
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index 9d60b393a0..c1caf9af23 100644
--- a/rts/linker/Elf.c
+++ b/rts/linker/Elf.c
@@ -155,6 +155,160 @@ get_shndx_table(Elf_Ehdr* ehdr)
#endif
/*
+ * ocInit and ocDeinit
+ */
+
+void
+ocInit_ELF(ObjectCode * oc)
+{
+ oc->info = (ObjectCodeFormatInfo*)stgCallocBytes(
+ 1, sizeof(ObjectCodeFormatInfo),
+ "ocInit_Elf(ObjectCodeFormatInfo)");
+ // TODO: fill info
+ oc->info->elfHeader = (Elf_Ehdr *)oc->image;
+ oc->info->programHeader = (Elf_Phdr *) ((uint8_t*)oc->image
+ + oc->info->elfHeader->e_phoff);
+ oc->info->sectionHeader = (Elf_Shdr *) ((uint8_t*)oc->image
+ + oc->info->elfHeader->e_shoff);
+
+ oc->n_sections = elf_shnum(oc->info->elfHeader);
+
+ /* get the symbol table(s) */
+ for(int i=0; i < oc->n_sections; i++) {
+ if(SHT_REL == oc->info->sectionHeader[i].sh_type) {
+ ElfRelocationTable *relTab = (ElfRelocationTable *)stgCallocBytes(
+ 1, sizeof(ElfRelocationTable),
+ "ocInit_Elf(ElfRelocationTable");
+ relTab->index = i;
+
+ relTab->relocations =
+ (Elf_Rel*) ((uint8_t*)oc->info->elfHeader
+ + oc->info->sectionHeader[i].sh_offset);
+ relTab->n_relocations = oc->info->sectionHeader[i].sh_size
+ / sizeof(Elf_Rel);
+ relTab->targetSectionIndex = oc->info->sectionHeader[i].sh_info;
+
+ relTab->sectionHeader = &oc->info->sectionHeader[i];
+
+ if(oc->info->relTable == NULL) {
+ oc->info->relTable = relTab;
+ } else {
+ ElfRelocationTable * tail = oc->info->relTable;
+ while(tail->next != NULL) tail = tail->next;
+ tail->next = relTab;
+ }
+
+ } else if(SHT_RELA == oc->info->sectionHeader[i].sh_type) {
+ ElfRelocationATable *relTab = (ElfRelocationATable *)stgCallocBytes(
+ 1, sizeof(ElfRelocationATable),
+ "ocInit_Elf(ElfRelocationTable");
+ relTab->index = i;
+
+ relTab->relocations =
+ (Elf_Rela*) ((uint8_t*)oc->info->elfHeader
+ + oc->info->sectionHeader[i].sh_offset);
+ relTab->n_relocations = oc->info->sectionHeader[i].sh_size
+ / sizeof(Elf_Rela);
+ relTab->targetSectionIndex = oc->info->sectionHeader[i].sh_info;
+
+ relTab->sectionHeader = &oc->info->sectionHeader[i];
+
+ if(oc->info->relaTable == NULL) {
+ oc->info->relaTable = relTab;
+ } else {
+ ElfRelocationATable * tail = oc->info->relaTable;
+ while(tail->next != NULL) tail = tail->next;
+ tail->next = relTab;
+ }
+
+ } else if(SHT_SYMTAB == oc->info->sectionHeader[i].sh_type) {
+
+ ElfSymbolTable *symTab = (ElfSymbolTable *)stgCallocBytes(
+ 1, sizeof(ElfSymbolTable),
+ "ocInit_Elf(ElfSymbolTable");
+
+ symTab->index = i; /* store the original index, so we can later
+ * find or assert that we are dealing with the
+ * correct symbol table */
+
+ Elf_Sym *stab = (Elf_Sym*)((uint8_t*)oc->info->elfHeader
+ + oc->info->sectionHeader[i].sh_offset);
+ symTab->n_symbols = oc->info->sectionHeader[i].sh_size
+ / sizeof(Elf_Sym);
+ symTab->symbols = (ElfSymbol *)stgCallocBytes(
+ symTab->n_symbols, sizeof(ElfSymbol),
+ "ocInit_Elf(ElfSymbol)");
+
+ /* get the strings table */
+ size_t lnkIdx = oc->info->sectionHeader[i].sh_link;
+ symTab->names = (char*)(uint8_t*)oc->info->elfHeader
+ + oc->info->sectionHeader[lnkIdx].sh_offset;
+
+ /* build the ElfSymbols from the symbols */
+ for(size_t j=0; j < symTab->n_symbols; j++) {
+
+ symTab->symbols[j].name = stab[j].st_name == 0
+ ? "(noname)"
+ : symTab->names + stab[j].st_name;
+ symTab->symbols[j].elf_sym = &stab[j];
+ /* we don't have an address for this symbol yet; this will be
+ * populated during ocGetNames. hence addr = NULL.
+ */
+ symTab->symbols[j].addr = NULL;
+ symTab->symbols[j].got_addr = NULL;
+ }
+
+ /* append the ElfSymbolTable */
+ if(oc->info->symbolTables == NULL) {
+ oc->info->symbolTables = symTab;
+ } else {
+ ElfSymbolTable * tail = oc->info->symbolTables;
+ while(tail->next != NULL) tail = tail->next;
+ tail->next = symTab;
+ }
+ }
+ }
+}
+
+void
+ocDeinit_ELF(ObjectCode * oc)
+{
+ /* free all ElfSymbolTables, and their associated
+ * ElfSymbols
+ */
+ if(oc->info != NULL) {
+ ElfSymbolTable * last = oc->info->symbolTables;
+
+ while(last != NULL) {
+ ElfSymbolTable * t = last;
+ last = last->next;
+ stgFree(t->symbols);
+ stgFree(t);
+ }
+
+ {
+ ElfRelocationTable *last = oc->info->relTable;
+ while (last != NULL) {
+ ElfRelocationTable *t = last;
+ last = last->next;
+ stgFree(t);
+ }
+ }
+
+ {
+ ElfRelocationATable *last = oc->info->relaTable;
+ while (last != NULL) {
+ ElfRelocationATable *t = last;
+ last = last->next;
+ stgFree(t);
+ }
+ }
+
+ stgFree(oc->info);
+ }
+}
+
+/*
* Generic ELF functions
*/
@@ -1074,7 +1228,8 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
#if defined(SHN_XINDEX)
Elf_Word* shndx_table = get_shndx_table((Elf_Ehdr*)ehdrC);
#endif
-#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) \
+ || defined(x86_64_HOST_ARCH)
/* This #if def only serves to avoid unused-var warnings. */
Elf_Addr targ = (Elf_Addr) oc->sections[target_shndx].start;
#endif
@@ -1092,13 +1247,15 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
}
for (j = 0; j < nent; j++) {
-#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+#if defined(DEBUG) || defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) \
+ || defined(x86_64_HOST_ARCH)
/* This #if def only serves to avoid unused-var warnings. */
Elf_Addr offset = rtab[j].r_offset;
Elf_Addr P = targ + offset;
Elf_Addr A = rtab[j].r_addend;
#endif
-#if defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+#if defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) \
+ || defined(x86_64_HOST_ARCH)
Elf_Addr value;
#endif
Elf_Addr info = rtab[j].r_info;
@@ -1153,7 +1310,8 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
checkProddableBlock(oc, (void*)P, sizeof(Elf_Word));
#endif
-#if defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
+#if defined(sparc_HOST_ARCH) || defined(powerpc_HOST_ARCH) \
+ || defined(x86_64_HOST_ARCH)
value = S + A;
#endif