From: Saleem Abdulrasool Date: Sun, 1 Nov 2015 01:26:15 +0000 (+0000) Subject: RuntimeDyld: add COFF i386 support X-Git-Tag: android-x86-7.1-r4~42012 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=7683ca45222185cb2a09992dd32a291a03adaa32;p=android-x86%2Fexternal-llvm.git RuntimeDyld: add COFF i386 support This adds support for COFF I386. This is sufficient for code execution in a 32-bit JIT, though, imported symbols need to custom lowered for the redirection. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251761 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp index 338724dd8f4..e5fab929ea2 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "RuntimeDyldCOFF.h" +#include "Targets/RuntimeDyldCOFFI386.h" #include "Targets/RuntimeDyldCOFFX86_64.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" @@ -47,6 +48,8 @@ llvm::RuntimeDyldCOFF::create(Triple::ArchType Arch, default: llvm_unreachable("Unsupported target for RuntimeDyldCOFF."); break; + case Triple::x86: + return make_unique(MemMgr, Resolver); case Triple::x86_64: return make_unique(MemMgr, Resolver); } diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h new file mode 100644 index 00000000000..ddf59693fa1 --- /dev/null +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h @@ -0,0 +1,199 @@ +//===--- RuntimeDyldCOFFI386.h --- COFF/X86_64 specific code ---*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// COFF x86 support for MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H + +#include "llvm/Object/COFF.h" +#include "llvm/Support/COFF.h" +#include "../RuntimeDyldCOFF.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF { +public: + RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM, + RuntimeDyld::SymbolResolver &Resolver) + : RuntimeDyldCOFF(MM, Resolver) {} + + unsigned getMaxStubSize() override { + return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad + } + + unsigned getStubAlignment() override { return 1; } + + relocation_iterator processRelocationRef(unsigned SectionID, + relocation_iterator RelI, + const ObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + auto Symbol = RelI->getSymbol(); + if (Symbol == Obj.symbol_end()) + report_fatal_error("Unknown symbol in relocation"); + + ErrorOr TargetNameOrErr = Symbol->getName(); + if (auto EC = TargetNameOrErr.getError()) + report_fatal_error(EC.message()); + StringRef TargetName = *TargetNameOrErr; + + auto Section = *Symbol->getSection(); + + uint64_t RelType = RelI->getType(); + uint64_t Offset = RelI->getOffset(); + +#if !defined(NDEBUG) + SmallString<32> RelTypeName; + RelI->getTypeName(RelTypeName); +#endif + DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset + << " RelType: " << RelTypeName << " TargetName: " << TargetName + << "\n"); + + unsigned TargetSectionID = -1; + if (Section == Obj.section_end()) { + RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0); + addRelocationForSymbol(RE, TargetName); + } else { + TargetSectionID = + findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID); + + switch (RelType) { + case COFF::IMAGE_REL_I386_ABSOLUTE: + // This relocation is ignored. + break; + case COFF::IMAGE_REL_I386_DIR32: + case COFF::IMAGE_REL_I386_DIR32NB: + case COFF::IMAGE_REL_I386_REL32: { + RelocationEntry RE = + RelocationEntry(SectionID, Offset, RelType, 0, TargetSectionID, + getSymbolOffset(*Symbol), 0, 0, false, 0); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_I386_SECTION: { + RelocationEntry RE = + RelocationEntry(TargetSectionID, Offset, RelType, 0); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_I386_SECREL: { + RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType, + getSymbolOffset(*Symbol)); + addRelocationForSection(RE, TargetSectionID); + break; + } + default: + llvm_unreachable("unsupported relocation type"); + } + + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + const auto Section = Sections[RE.SectionID]; + uint8_t *Target = Section.Address + RE.Offset; + + switch (RE.RelType) { + case COFF::IMAGE_REL_I386_ABSOLUTE: + // This relocation is ignored. + break; + case COFF::IMAGE_REL_I386_DIR32: { + // The target's 32-bit VA. + uint64_t Result = + RE.Sections.SectionA == static_cast(-1) + ? Value + : Sections[RE.Sections.SectionA].LoadAddress + RE.Addend; + assert(static_cast(Result) <= INT32_MAX && + "relocation overflow"); + assert(static_cast(Result) >= INT32_MIN && + "relocation underflow"); + DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_DIR32" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) << '\n'); + writeBytesUnaligned(Result, Target, 4); + break; + } + case COFF::IMAGE_REL_I386_DIR32NB: { + // The target's 32-bit RVA. + // NOTE: use Section[0].LoadAddress as an approximation of ImageBase + uint64_t Result = Sections[RE.Sections.SectionA].LoadAddress + RE.Addend - + Sections[0].LoadAddress; + assert(static_cast(Result) <= INT32_MAX && + "relocation overflow"); + assert(static_cast(Result) >= INT32_MIN && + "relocation underflow"); + DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_DIR32NB" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) << '\n'); + writeBytesUnaligned(Result, Target, 4); + break; + } + case COFF::IMAGE_REL_I386_REL32: { + // 32-bit relative displacement to the target. + uint64_t Result = Sections[RE.Sections.SectionA].LoadAddress - + Section.LoadAddress + RE.Addend - 4 - RE.Offset; + assert(static_cast(Result) <= INT32_MAX && + "relocation overflow"); + assert(static_cast(Result) >= INT32_MIN && + "relocation underflow"); + DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_REL32" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) << '\n'); + writeBytesUnaligned(Result, Target, 4); + break; + } + case COFF::IMAGE_REL_I386_SECTION: + // 16-bit section index of the section that contains the target. + assert(static_cast(RE.SectionID) <= INT16_MAX && + "relocation overflow"); + assert(static_cast(RE.SectionID) >= INT16_MIN && + "relocation underflow"); + DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_SECTION Value: " << RE.SectionID + << '\n'); + writeBytesUnaligned(RE.SectionID, Target, 2); + break; + case COFF::IMAGE_REL_I386_SECREL: + // 32-bit offset of the target from the beginning of its section. + assert(static_cast(RE.Addend) <= INT32_MAX && + "relocation overflow"); + assert(static_cast(RE.Addend) >= INT32_MIN && + "relocation underflow"); + DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_SECREL Value: " << RE.Addend + << '\n'); + writeBytesUnaligned(RE.Addend, Target, 2); + break; + default: + llvm_unreachable("unsupported relocation type"); + } + } + + void registerEHFrames() override {} + void deregisterEHFrames() override {} + + void finalizeLoad(const ObjectFile &Obj, + ObjSectionToIDMap &SectionMap) override {} +}; + +} + +#endif + diff --git a/test/ExecutionEngine/RuntimeDyld/X86/COFF_i386.s b/test/ExecutionEngine/RuntimeDyld/X86/COFF_i386.s new file mode 100644 index 00000000000..0a96f702501 --- /dev/null +++ b/test/ExecutionEngine/RuntimeDyld/X86/COFF_i386.s @@ -0,0 +1,66 @@ +// RUN: llvm-mc -triple i686-windows -filetype obj -o %t.obj %s +// RUN: llvm-rtdyld -triple i686-windows -dummy-extern _OutputDebugStringA@4=0xfffffffe -dummy-extern _ExitProcess@4=0xffffffff -verify -check=%s %t.obj + + .text + + .def _main + .scl 2 + .type 32 + .endef + .global _main +_main: +rel1: + call _function // IMAGE_REL_I386_REL32 +# rtdyld-check: decode_operand(rel1, 0) = (_function-_main-4-1) + xorl %eax, %eax + retl + + .def _function + .scl 2 + .type 32 + .endef +_function: +rel2: + pushl string +rel3: + calll *__imp__OutputDebugStringA // IMAGE_REL_I386_DIR32 +# rtdyld-check: decode_operand(rel3, 3) = __imp__OutputDebugStringA + addl $4, %esp + pushl $0 +rel4: + calll *__imp__ExitProcess // IMAGE_REL_I386_DIR32 +# rtdyld-check: decode_operand(rel4, 3) = __imp__ExitProcess + addl $4, %esp + retl + + .data + + .global __imp__OutputDebugStringA + .align 4 +__imp__OutputDebugStringA: + .long "_OutputDebugStringA@4" // IMAGE_REL_I386_DIR32 +# rtdyld-check: *{4}__imp__OutputDebugStringA = 0xfffffffe + + .global __imp__ExitProcess + .align 4 +__imp__ExitProcess: + .long "_ExitProcess@4" // IMAGE_REL_I386_DIR32 +# rtdyld-check: *{4}__imp__ExitProcess = 0xffffffff + + .global string + .align 1 +string: + .asciz "Hello World!\n" + + .global relocations +relocations: +rel5: + .long _function@imgrel // IMAGE_REL_I386_DIR32NB +# rtdyld-check: *{4}rel5 = _function - section_addr(COFF_i386.s.tmp.obj, .text) +rel6: +# rtdyld-check: *{2}rel6 = 1 + .secidx __imp__OutputDebugStringA // IMAGE_REL_I386_SECTION +rel7: +# rtdyld-check: *{4}rel7 = relocations - section_addr(COFF_i386.s.tmp.obj, .data) + .secrel32 relocations // IMAGE_REL_I386_SECREL +