Implement support for ELF relocations. Bug swiftshader:17 Change-Id: I3ba076bdfd733797f627c50c37dea83326ddee35 Reviewed-on: https://swiftshader-review.googlesource.com/7714 Reviewed-by: Nicolas Capens <capn@google.com> Tested-by: Nicolas Capens <capn@google.com> Reviewed-on: https://swiftshader-review.googlesource.com/7670
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp index df16d79..4cdb9be 100644 --- a/src/Reactor/SubzeroReactor.cpp +++ b/src/Reactor/SubzeroReactor.cpp
@@ -98,9 +98,136 @@ Optimization optimization[10] = {InstructionCombining, Disabled}; + using ElfHeader = std::conditional<sizeof(void*) == 8, Elf64_Ehdr, Elf32_Ehdr>::type; + using SectionHeader = std::conditional<sizeof(void*) == 8, Elf64_Shdr, Elf32_Shdr>::type; + + inline const SectionHeader *sectionHeader(const ElfHeader *elfHeader) + { + return reinterpret_cast<const SectionHeader*>((intptr_t)elfHeader + elfHeader->e_shoff); + } + + inline const SectionHeader *elfSection(const ElfHeader *elfHeader, int index) + { + return §ionHeader(elfHeader)[index]; + } + + static void *relocateSymbol(const ElfHeader *elfHeader, const Elf32_Rel &relocation, const SectionHeader &relocationTable) + { + const SectionHeader *target = elfSection(elfHeader, relocationTable.sh_info); + + intptr_t address = (intptr_t)elfHeader + target->sh_offset; + int32_t *patchSite = (int*)(address + relocation.r_offset); + uint32_t index = relocation.getSymbol(); + int table = relocationTable.sh_link; + void *symbolValue = nullptr; + + if(index != SHN_UNDEF) + { + if(table == SHN_UNDEF) return nullptr; + const SectionHeader *symbolTable = elfSection(elfHeader, table); + + uint32_t symtab_entries = symbolTable->sh_size / symbolTable->sh_entsize; + if(index >= symtab_entries) + { + assert(index < symtab_entries && "Symbol Index out of range"); + return nullptr; + } + + intptr_t symbolAddress = (intptr_t)elfHeader + symbolTable->sh_offset; + Elf32_Sym &symbol = ((Elf32_Sym*)symbolAddress)[index]; + uint16_t section = symbol.st_shndx; + + if(section != SHN_UNDEF && section < SHN_LORESERVE) + { + const SectionHeader *target = elfSection(elfHeader, symbol.st_shndx); + symbolValue = reinterpret_cast<void*>((intptr_t)elfHeader + symbol.st_value + target->sh_offset); + } + else + { + return nullptr; + } + } + + switch(relocation.getType()) + { + case R_386_NONE: + // No relocation + break; + case R_386_32: + *patchSite = (int32_t)((intptr_t)symbolValue + *patchSite); + break; + // case R_386_PC32: + // *patchSite = (int32_t)((intptr_t)symbolValue + *patchSite - (intptr_t)patchSite); + // break; + default: + assert(false && "Unsupported relocation type"); + return nullptr; + } + + return symbolValue; + } + + static void *relocateSymbol(const ElfHeader *elfHeader, const Elf64_Rela &relocation, const SectionHeader &relocationTable) + { + const SectionHeader *target = elfSection(elfHeader, relocationTable.sh_info); + + intptr_t address = (intptr_t)elfHeader + target->sh_offset; + int32_t *patchSite = (int*)(address + relocation.r_offset); + uint32_t index = relocation.getSymbol(); + int table = relocationTable.sh_link; + void *symbolValue = nullptr; + + if(index != SHN_UNDEF) + { + if(table == SHN_UNDEF) return nullptr; + const SectionHeader *symbolTable = elfSection(elfHeader, table); + + uint32_t symtab_entries = symbolTable->sh_size / symbolTable->sh_entsize; + if(index >= symtab_entries) + { + assert(index < symtab_entries && "Symbol Index out of range"); + return nullptr; + } + + intptr_t symbolAddress = (intptr_t)elfHeader + symbolTable->sh_offset; + Elf64_Sym &symbol = ((Elf64_Sym*)symbolAddress)[index]; + uint16_t section = symbol.st_shndx; + + if(section != SHN_UNDEF && section < SHN_LORESERVE) + { + const SectionHeader *target = elfSection(elfHeader, symbol.st_shndx); + symbolValue = reinterpret_cast<void*>((intptr_t)elfHeader + symbol.st_value + target->sh_offset); + } + else + { + return nullptr; + } + } + + switch(relocation.getType()) + { + case R_X86_64_NONE: + // No relocation + break; + // case R_X86_64_64: + // *patchSite = (int32_t)((intptr_t)symbolValue + *patchSite) + relocation->r_addend; + // break; + case R_X86_64_PC32: + *patchSite = (int32_t)((intptr_t)symbolValue + *patchSite - (intptr_t)patchSite) + relocation.r_addend; + break; + // case R_X86_64_32S: + // *patchSite = (int32_t)((intptr_t)symbolValue + *patchSite) + relocation.r_addend; + // break; + default: + assert(false && "Unsupported relocation type"); + return nullptr; + } + + return symbolValue; + } + void *loadImage(uint8_t *const elfImage) { - using ElfHeader = std::conditional<sizeof(void*) == 8, Elf64_Ehdr, Elf32_Ehdr>::type; ElfHeader *elfHeader = (ElfHeader*)elfImage; if(!elfHeader->checkMagic()) @@ -108,15 +235,40 @@ return nullptr; } - using SectionHeader = std::conditional<sizeof(void*) == 8, Elf64_Shdr, Elf32_Shdr>::type; + // Expect ELF bitness to match platform + assert(sizeof(void*) == 8 ? elfHeader->e_machine == EM_X86_64 : elfHeader->e_machine == EM_386); + SectionHeader *sectionHeader = (SectionHeader*)(elfImage + elfHeader->e_shoff); void *entry = nullptr; for(int i = 0; i < elfHeader->e_shnum; i++) { - if(sectionHeader[i].sh_type == SHT_PROGBITS && sectionHeader[i].sh_flags & SHF_EXECINSTR) + if(sectionHeader[i].sh_type == SHT_PROGBITS) { - entry = elfImage + sectionHeader[i].sh_offset; + if(sectionHeader[i].sh_flags & SHF_EXECINSTR) + { + entry = elfImage + sectionHeader[i].sh_offset; + } + } + else if(sectionHeader[i].sh_type == SHT_REL) + { + assert(sizeof(void*) == 4 && "UNIMPLEMENTED"); // Only expected/implemented for 32-bit code + + for(int index = 0; index < sectionHeader[i].sh_size / sectionHeader[i].sh_entsize; index++) + { + const Elf32_Rel &relocation = ((const Elf32_Rel*)(elfImage + sectionHeader[i].sh_offset))[index]; + void *symbol = relocateSymbol(elfHeader, relocation, sectionHeader[i]); + } + } + else if(sectionHeader[i].sh_type == SHT_RELA) + { + assert(sizeof(void*) == 8 && "UNIMPLEMENTED"); // Only expected/implemented for 64-bit code + + for(int index = 0; index < sectionHeader[i].sh_size / sectionHeader[i].sh_entsize; index++) + { + const Elf64_Rela &relocation = ((const Elf64_Rela*)(elfImage + sectionHeader[i].sh_offset))[index]; + void *symbol = relocateSymbol(elfHeader, relocation, sectionHeader[i]); + } } } @@ -193,8 +345,8 @@ const void *getEntry() override { - VirtualProtect(&buffer[0], buffer.size(), PAGE_EXECUTE_READ, &oldProtection); - position = std::numeric_limits<std::size_t>::max(); // Can't write more data after this + VirtualProtect(&buffer[0], buffer.size(), PAGE_EXECUTE_READWRITE, &oldProtection); + position = std::numeric_limits<std::size_t>::max(); // Can't stream more data after this return loadImage(&buffer[0]); } @@ -209,10 +361,13 @@ { ::codegenMutex.lock(); // Reactor is currently not thread safe - Ice::ClFlags::Flags.setTargetArch(sizeof(void*) == 8 ? Ice::Target_X8664 : Ice::Target_X8632); - Ice::ClFlags::Flags.setOutFileType(Ice::FT_Elf); - Ice::ClFlags::Flags.setOptLevel(Ice::Opt_2); - Ice::ClFlags::Flags.setApplicationBinaryInterface(Ice::ABI_Platform); + Ice::ClFlags &Flags = Ice::ClFlags::Flags; + Ice::ClFlags::getParsedClFlags(Flags); + + Flags.setTargetArch(sizeof(void*) == 8 ? Ice::Target_X8664 : Ice::Target_X8632); + Flags.setOutFileType(Ice::FT_Elf); + Flags.setOptLevel(Ice::Opt_2); + Flags.setApplicationBinaryInterface(Ice::ABI_Platform); std::unique_ptr<Ice::Ostream> cout(new llvm::raw_os_ostream(std::cout)); @@ -255,12 +410,22 @@ ::function->setFunctionName(Ice::GlobalString::createWithString(::context, asciiName)); ::function->translate(); + auto *globals = ::function->getGlobalInits().release(); + + if(globals && !globals->empty()) + { + ::context->getGlobals()->merge(globals); + } ::context->emitFileHeader(); ::function->emitIAS(); auto assembler = ::function->releaseAssembler(); - ::context->getObjectWriter()->writeFunctionCode(::function->getFunctionName(), false, assembler.get()); - ::context->getObjectWriter()->writeNonUserSections(); + auto objectWriter = ::context->getObjectWriter(); + assembler->alignFunction(); + objectWriter->writeFunctionCode(::function->getFunctionName(), false, assembler.get()); + ::context->lowerGlobals("last"); + objectWriter->setUndefinedSyms(::context->getConstantExternSyms()); + objectWriter->writeNonUserSections(); return ::routine; }