Index: llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h =================================================================== --- llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h +++ llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h @@ -45,6 +45,7 @@ const object::COFFObjectFile &getObject() const { return Obj; } virtual Error addRelocations() = 0; + virtual Symbol &createDLLImportEntry(StringRef StubName, Symbol &Target) = 0; Error graphifySections(); Error graphifySymbols(); @@ -152,6 +153,7 @@ static bool isComdatSection(const object::coff_section *Section); static unsigned getPointerSize(const object::COFFObjectFile &Obj); static support::endianness getEndianness(const object::COFFObjectFile &Obj); + static StringRef getDLLImportStubPrefix() { return "__imp_"; } StringRef getCOFFSectionName(COFFSectionIndex SectionIndex, const object::coff_section *Sec, object::COFFSymbolRef Sym); Index: llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp =================================================================== --- llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp +++ llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp @@ -142,7 +142,7 @@ }); // Get the section's memory protection flags. - MemProt Prot = MemProt::None; + MemProt Prot = MemProt::Read; if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE) Prot |= MemProt::Exec; if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ) @@ -222,17 +222,30 @@ << " (index: " << SectionIndex << ") \n"; }); else if (Sym->isUndefined()) { - LLVM_DEBUG({ - dbgs() << " " << SymIndex - << ": Creating external graph symbol for COFF symbol \"" - << SymbolName << "\" in " - << getCOFFSectionName(SectionIndex, Sec, *Sym) - << " (index: " << SectionIndex << ") \n"; - }); - if (!ExternalSymbols.count(SymbolName)) - ExternalSymbols[SymbolName] = - &G->addExternalSymbol(SymbolName, Sym->getValue(), Linkage::Strong); - GSym = ExternalSymbols[SymbolName]; + auto CreateExternalSymbol = [&](StringRef SymbolName) { + if (!ExternalSymbols.count(SymbolName)) + ExternalSymbols[SymbolName] = &G->addExternalSymbol( + SymbolName, Sym->getValue(), Linkage::Strong); + + LLVM_DEBUG({ + dbgs() << " " << SymIndex + << ": Creating external graph symbol for COFF symbol \"" + << SymbolName << "\" in " + << getCOFFSectionName(SectionIndex, Sec, *Sym) + << " (index: " << SectionIndex << ") \n"; + }); + return ExternalSymbols[SymbolName]; + }; + if (SymbolName.startswith(getDLLImportStubPrefix())) { + if (Sym->getValue() != 0) + return make_error( + "DLL import symbol has non-zero offset"); + + auto ExternalSym = CreateExternalSymbol( + SymbolName.drop_front(getDLLImportStubPrefix().size())); + GSym = &createDLLImportEntry(SymbolName, *ExternalSym); + } else + GSym = CreateExternalSymbol(SymbolName); } else if (Sym->isWeakExternal()) { auto *WeakExternal = Sym->getAux(); COFFSymbolIndex TagIndex = WeakExternal->TagIndex; Index: llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp =================================================================== --- llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp +++ llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp @@ -80,6 +80,12 @@ return Error::success(); } + Symbol &createDLLImportEntry(StringRef StubName, Symbol &Target) override { + auto &Sym = DLLImportTable.getEntryForTarget(getGraph(), Target); + Sym.setName(StubName); + return Sym; + } + Error addSingleRelocation(const object::RelocationRef &Rel, const object::SectionRef &FixupSect, Block &BlockToFix) { @@ -148,6 +154,8 @@ return Error::success(); } + x86_64::GOTTableManager DLLImportTable; + public: COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T) : COFFLinkGraphBuilder(Obj, std::move(T), getCOFFX86RelocationKindName) {} Index: llvm/test/ExecutionEngine/JITLink/X86/COFF_x86-64_small_pic_relocations.s =================================================================== --- llvm/test/ExecutionEngine/JITLink/X86/COFF_x86-64_small_pic_relocations.s +++ llvm/test/ExecutionEngine/JITLink/X86/COFF_x86-64_small_pic_relocations.s @@ -40,6 +40,21 @@ test_rel32_data: leaq named_data(%rip), %rax +# Check a dllimport stub for target out of reach is created as a GOT entry. +# jitlink-check: decode_operand(test_call_dllimport, 3) = \ +# jitlink-check: got_addr(coff_sm_reloc.o, extern_out_of_range32) - \ +# jitlink-check: next_pc(test_call_dllimport) +# jitlink-check: *{8}(got_addr(coff_sm_reloc.o, extern_out_of_range32)) = \ +# jitlink-check: extern_out_of_range32 + .def test_call_dllimport; + .scl 2; + .type 32; + .endef + .globl test_call_dllimport + .p2align 4, 0x90 +test_call_dllimport: + callq *__imp_extern_out_of_range32(%rip) + # Local named data/func that is used in conjunction with other test cases .text .def named_func;