+/**
+ * \fn int ElfGetSymbol(Uint Base, const char *name, void **ret)
+ */
+int ElfGetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
+{
+ Elf32_Ehdr *hdr = Base;
+
+ switch(hdr->e_ident[4])
+ {
+ case ELFCLASS32:
+ return Elf32_GetSymbol(Base, Name, ret, Size);
+#ifdef SUPPORT_ELF64
+ case ELFCLASS64:
+ return Elf64_GetSymbol(Base, Name, ret, Size);
+#endif
+ default:
+ SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]);
+ return 0;
+ }
+}
+
+// --------------------------------------------------------------------
+// Elf32 support
+// --------------------------------------------------------------------
+#define ELFTYPE Elf32
+#include "elf_impl.c"
+#undef ELFTYPE
+
+Elf32_RelocFcn elf_doRelocate_386;
+Elf32_RelocFcn elf_doRelocate_arm;
+
+int elf_doRelocate_386(const Elf32_RelocInfo *Info, Elf32_Word r_info, Elf32_Word* ptr, Elf32_Addr addend, bool bRela)
+{
+ const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ];
+ void *symval = (void*)(intptr_t)sym->st_value;
+ size_t size = sym->st_size;
+ TRACE("%i '%s'", ELF32_R_TYPE(r_info), Info->strtab + sym->st_name);
+ switch( ELF32_R_TYPE(r_info) )
+ {
+ // Standard 32 Bit Relocation (S+A)
+ case R_386_32:
+ TRACE("R_386_32 *0x%x = %p + 0x%x", ptr, symval, addend);
+ *ptr = (intptr_t)symval + addend;
+ break;
+
+ // 32 Bit Relocation wrt. Offset (S+A-P)
+ case R_386_PC32:
+ TRACE("R_386_PC32 *0x%x = 0x%x + 0x%p - 0x%x", ptr, *ptr, symval, (intptr_t)ptr );
+ *ptr = (intptr_t)symval + addend - (intptr_t)ptr;
+ //*ptr = val + addend - ((Uint)ptr - iBaseDiff);
+ break;
+
+ // Absolute Value of a symbol (S)
+ case R_386_GLOB_DAT:
+ TRACE("R_386_GLOB_DAT *0x%x = %p", ptr, symval); if(0)
+ case R_386_JMP_SLOT:
+ TRACE("R_386_JMP_SLOT *0x%x = %p", ptr, symval);
+ *ptr = (intptr_t)symval;
+ break;
+
+ // Base Address (B+A)
+ case R_386_RELATIVE:
+ TRACE("R_386_RELATIVE *0x%x = 0x%x + 0x%x", ptr, Info->iBaseDiff, addend);
+ *ptr = Info->iBaseDiff + addend;
+ break;
+
+ case R_386_COPY: {
+ void *old_symval = symval;
+ GetSymbol(Info->strtab + sym->st_name, &symval, &size, Info->Base);
+ if( symval == old_symval )
+ {
+ if( ELF32_ST_BIND(sym->st_info) != STB_WEAK )
+ {
+ WARNING("sym={val:%p,size:0x%x,info:0x%x,other:0x%x,shndx:%i}",
+ sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx);
+ WARNING("Can't find required external symbol '%s' for R_386_COPY", Info->strtab + sym->st_name);
+ return 1;
+ }
+ // Don't bother doing the memcpy
+ TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
+ }
+ else
+ {
+ TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
+ memcpy(ptr, symval, size);
+ }
+ break; }
+
+ default:
+ WARNING("Unknown relocation %i", ELF32_ST_TYPE(r_info));
+ return 2;
+ }
+ return 0;
+}
+
+int elf_doRelocate_arm(const Elf32_RelocInfo *Info, Elf32_Word r_info, Elf32_Word* ptr, Elf32_Addr addend, bool bRela)
+{
+ const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ];
+ void *symval = (void*)(intptr_t)sym->st_value;
+ size_t size = sym->st_size;
+ TRACE("%i '%s'", ELF32_R_TYPE(r_info), Info->strtab + sym->st_name);
+ uintptr_t val = (uintptr_t)symval;
+ switch( ELF32_R_TYPE(r_info) )
+ {
+ // (S + A) | T
+ case R_ARM_ABS32:
+ TRACE("R_ARM_ABS32 %p (%p + %x)", ptr, symval, addend);
+ *ptr = val + addend;
+ break;
+ case R_ARM_GLOB_DAT:
+ TRACE("R_ARM_GLOB_DAT %p (%p + %x)", ptr, symval, addend);
+ *ptr = val + addend;
+ break;
+ case R_ARM_JUMP_SLOT:
+ if(!bRela) addend = 0;
+ TRACE("R_ARM_JUMP_SLOT %p (%p + %x)", ptr, symval, addend);
+ *ptr = val + addend;
+ break;
+ // Copy
+ case R_ARM_COPY:
+ TRACE("R_ARM_COPY (%p, %p, %i)", ptr, symval, size);
+ memcpy(ptr, symval, size);
+ break;
+ // Delta between link and runtime locations + A
+ case R_ARM_RELATIVE:
+ TRACE("R_ARM_RELATIVE %p (0x%x + 0x%x)", ptr, Info->iBaseDiff, addend);
+ if(ELF32_R_SYM(r_info) != 0) {
+ // TODO: Get delta for a symbol
+ WARNING("TODO - Implment R_ARM_RELATIVE for symbols");
+ return 2;
+ }
+ else {
+ *ptr = Info->iBaseDiff + addend;
+ }
+ break;
+ default:
+ WARNING("Unknown Relocation, %i", ELF32_R_TYPE(r_info));
+ return 2;
+ }
+ return 0;
+}
+
+Elf32_RelocFcn* Elf32_GetRelocFcn(unsigned Machine)
+{
+ switch(Machine)
+ {
+ case EM_386: return elf_doRelocate_386;
+ case EM_ARM: return elf_doRelocate_arm;
+ default: return NULL;
+ }
+}
+
+
+// --------------------------------------------------------------------
+// Elf64 support
+// --------------------------------------------------------------------
+#ifdef SUPPORT_ELF64
+
+#define ELFTYPE Elf64
+#include "elf_impl.c"
+#undef ELFTYPE
+
+Elf64_RelocFcn elf_doRelocate_x86_64;
+
+int elf_doRelocate_x86_64(const Elf64_RelocInfo *Info, Elf64_Xword r_info, Elf64_Xword* ptr, Elf64_Addr addend, bool bRela)
+{
+ const Elf64_Sym *sym = &Info->symtab[ ELF64_R_SYM(r_info) ];
+ void *symval = (void*)(intptr_t)sym->st_value;
+ size_t size = sym->st_size;
+ TRACE("%i '%s'", ELF64_R_TYPE(r_info), Info->strtab + sym->st_name);
+ switch( ELF64_R_TYPE(r_info) )
+ {
+ case R_X86_64_NONE:
+ break;
+ case R_X86_64_64:
+ TRACE("R_X86_64_64 *0x%x = %p + 0x%x", ptr, symval, addend);
+ *ptr = (intptr_t)symval + addend;
+ break;
+ // Absolute Value of a symbol (S)
+ case R_X86_64_GLOB_DAT:
+ TRACE("R_X86_64_GLOB_DAT *0x%x = %p", ptr, symval); if(0)
+ case R_X86_64_JUMP_SLOT:
+ TRACE("R_X86_64_JUMP_SLOT *0x%x = %p", ptr, symval);
+ *ptr = (intptr_t)symval;
+ break;
+
+ // Base Address (B+A)
+ case R_X86_64_RELATIVE:
+ TRACE("R_X86_64_RELATIVE *0x%x = 0x%x + 0x%x", ptr, Info->iBaseDiff, addend);
+ *ptr = Info->iBaseDiff + addend;
+ break;
+
+ case R_X86_64_COPY: {
+ void *old_symval = symval;
+ GetSymbol(Info->strtab + sym->st_name, &symval, &size, Info->Base);
+ if( symval == old_symval )
+ {
+ if( ELF64_ST_BIND(sym->st_info) != STB_WEAK )
+ {
+ WARNING("sym={val:%p,size:0x%x,info:0x%x,other:0x%x,shndx:%i}",
+ sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx);
+ WARNING("Can't find required external symbol '%s' for R_X86_64_COPY", Info->strtab + sym->st_name);
+ return 1;
+ }
+ // Don't bother doing the memcpy
+ TRACE("R_X86_64_COPY (%p, %p, %i)", ptr, symval, size);
+ }
+ else
+ {
+ TRACE("R_X86_64_COPY (%p, %p, %i)", ptr, symval, size);
+ memcpy(ptr, symval, size);
+ }
+ break; }
+ default:
+ WARNING("Unknown Relocation, %i", ELF64_R_TYPE(r_info));
+ return 2;
+ }
+ return 0;
+}
+
+Elf64_RelocFcn* Elf64_GetRelocFcn(unsigned Machine)
+{
+ switch(Machine)
+ {
+ case EM_X86_64: return elf_doRelocate_x86_64;
+ default: return NULL;
+ }
+}
+
+#endif // SUPPORT_ELF64
+
+
+#ifdef SUPPORT_ELF64
+#if 0
+typedef int (*t_elf64_doreloc)(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend);
+
+int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend)
+{
+ int sym = ELF64_R_SYM(r_info);
+ int type = ELF64_R_TYPE(r_info);
+ const char *symname = strtab + symtab[sym].st_name;
+ void *symval;
+ //DEBUGS("_Elf64DoReloc: %s", symname);
+ switch( type )
+ {
+ case R_X86_64_NONE:
+ break;
+ case R_X86_64_64:
+ if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
+ *(uint64_t*)ptr = (uintptr_t)symval + addend;
+ break;
+ case R_X86_64_COPY: {
+ size_t size;
+ if( !GetSymbol(symname, &symval, &size, NULL) ) return 1;
+ memcpy(ptr, symval, size);
+ } break;
+ case R_X86_64_GLOB_DAT:
+ if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
+ *(uint64_t*)ptr = (uintptr_t)symval;
+ break;
+ case R_X86_64_JUMP_SLOT:
+ if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
+ *(uint64_t*)ptr = (uintptr_t)symval;
+ break;
+ case R_X86_64_RELATIVE:
+ *(uint64_t*)ptr = (uintptr_t)Base + addend;
+ break;
+ default:
+ SysDebug("ld-acess - _Elf64DoReloc: Unknown relocation type %i", type);
+ return 2;
+ }
+ //DEBUGS("_Elf64DoReloc: - Good");
+ return 0;
+}
+