Index: llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h =================================================================== --- llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h +++ llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h @@ -361,9 +361,17 @@ /// Describes symbol linkage. This can be used to make resolve definition /// clashes. +/// Strong -- Error when symbol is already defined outside current linkgraph. +/// Weak -- If symbol was defined before use that definition, otherwise +/// uses this definition. +/// WeakExternal -- If symbol was not defined before looks up a definition +/// outside current linkgraph. If symbol was still not +/// found, uses this definition. +/// enum class Linkage : uint8_t { Strong, Weak, + WeakExternal, }; /// For errors and debugging output. @@ -508,6 +516,13 @@ return Base->isDefined(); } + /// Returns truw if this symbol has content defined wihthin this object file + /// but as a weak external stub. + bool isWeakExternal() const { + assert(Base && "Attempt to access null symbol"); + return Base->isDefined() && getLinkage() == Linkage::WeakExternal; + } + /// Returns true if this symbol is live (i.e. should be treated as a root for /// dead stripping). bool isLive() const { @@ -518,7 +533,7 @@ /// Set this symbol's live bit. void setLive(bool IsLive) { this->IsLive = IsLive; } - /// Returns true is this symbol is callable. + /// Returns true if this symbol is callable. bool isCallable() const { return IsCallable; } /// Set this symbol's callable bit. @@ -648,8 +663,8 @@ // FIXME: A char* or SymbolStringPtr may pack better. StringRef Name; Addressable *Base = nullptr; - uint64_t Offset : 59; - uint64_t L : 1; + uint64_t Offset : 58; + uint64_t L : 2; uint64_t S : 2; uint64_t IsLive : 1; uint64_t IsCallable : 1; Index: llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp =================================================================== --- llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp +++ llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp @@ -335,8 +335,8 @@ ? Scope::Default : Scope::Local; - auto NewSymbol = - createAliasSymbol(WeakExternal.SymbolName, Linkage::Weak, S, *Target); + auto NewSymbol = createAliasSymbol(WeakExternal.SymbolName, + Linkage::WeakExternal, S, *Target); if (!NewSymbol) return NewSymbol.takeError(); setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias, @@ -357,14 +357,14 @@ } Error COFFLinkGraphBuilder::handleAlternateNames() { - // FIXME: Use proper alias for (auto &KeyValue : AlternateNames) if (DefinedSymbols.count(KeyValue.second) && ExternalSymbols.count(KeyValue.first)) { auto *Target = DefinedSymbols[KeyValue.second]; auto *Alias = ExternalSymbols[KeyValue.first]; G->makeDefined(*Alias, Target->getBlock(), Target->getOffset(), - Target->getSize(), Linkage::Weak, Scope::Local, false); + Target->getSize(), Linkage::WeakExternal, Scope::Local, + false); } return Error::success(); } Index: llvm/lib/ExecutionEngine/JITLink/JITLink.cpp =================================================================== --- llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -72,6 +72,8 @@ return "strong"; case Linkage::Weak: return "weak"; + case Linkage::WeakExternal: + return "weakexternal"; } llvm_unreachable("Unrecognized llvm.jitlink.Linkage enum"); } @@ -102,7 +104,7 @@ OS << Sym.getAddress() << " (" << (Sym.isDefined() ? "block" : "addressable") << " + " << formatv("{0:x8}", Sym.getOffset()) << "): size: " << formatv("{0:x8}", Sym.getSize()) - << ", linkage: " << formatv("{0:6}", getLinkageName(Sym.getLinkage())) + << ", linkage: " << formatv("{0:12}", getLinkageName(Sym.getLinkage())) << ", scope: " << formatv("{0:8}", getScopeName(Sym.getScope())) << ", " << (Sym.isLive() ? "live" : "dead") << " - " << (Sym.hasName() ? Sym.getName() : ""); Index: llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp =================================================================== --- llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp +++ llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp @@ -197,11 +197,20 @@ assert(Sym->getName() != StringRef() && Sym->getName() != "" && "Externals must be named"); SymbolLookupFlags LookupFlags = - Sym->getLinkage() == Linkage::Weak - ? SymbolLookupFlags::WeaklyReferencedSymbol - : SymbolLookupFlags::RequiredSymbol; + Sym->getLinkage() == Linkage::Strong + ? SymbolLookupFlags::RequiredSymbol + : SymbolLookupFlags::WeaklyReferencedSymbol; UnresolvedExternals[Sym->getName()] = LookupFlags; } + for (auto *Sym : G->defined_symbols()) { + if (Sym->getLinkage() != Linkage::WeakExternal) + continue; + assert(Sym->getAddress() && "Weak external has no stub definition"); + assert(Sym->getName() != StringRef() && Sym->getName() != "" && + "Weak external must be named"); + UnresolvedExternals[Sym->getName()] = + SymbolLookupFlags::WeaklyReferencedSymbol; + } return UnresolvedExternals; } @@ -219,12 +228,26 @@ assert(Sym->getLinkage() == Linkage::Weak && "Failed to resolve non-weak reference"); } + for (auto *Sym : G->defined_symbols()) { + if (Sym->getLinkage() != Linkage::WeakExternal) + continue; + auto ResultI = Result.find(Sym->getName()); + if (ResultI != Result.end()) + Sym->getAddressable().setAddress( + orc::ExecutorAddr(ResultI->second.getAddress())); + } LLVM_DEBUG({ dbgs() << "Externals after applying lookup result:\n"; for (auto *Sym : G->external_symbols()) dbgs() << " " << Sym->getName() << ": " << formatv("{0:x16}", Sym->getAddress().getValue()) << "\n"; + for (auto *Sym : G->defined_symbols()) { + if (Sym->getLinkage() != Linkage::WeakExternal) + continue; + dbgs() << " " << Sym->getName() << ": " + << formatv("{0:x16}", Sym->getAddress().getValue()) << "\n"; + } }); } Index: llvm/test/ExecutionEngine/JITLink/X86/COFF_weak_external.s =================================================================== --- llvm/test/ExecutionEngine/JITLink/X86/COFF_weak_external.s +++ llvm/test/ExecutionEngine/JITLink/X86/COFF_weak_external.s @@ -10,7 +10,7 @@ # CHECK-NEXT: 9: Creating defined graph symbol for COFF symbol "main" in .text (index: 1) # CHECK-NEXT: 0x10 (block + 0x00000010): size: 0x00000000, linkage: strong, scope: default, dead - main # CHECK-NEXT: 6: Creating weak external symbol for COFF symbol "func" in section 0 -# CHECK-NEXT: 0x0 (block + 0x00000000): size: 0x00000000, linkage: weak, scope: default, dead - func +# CHECK-NEXT: 0x0 (block + 0x00000000): size: 0x00000000, linkage: weakexternal, scope: default, dead - func .text Index: llvm/test/ExecutionEngine/JITLink/X86/COFF_weak_external_multiple_defs.s =================================================================== --- /dev/null +++ llvm/test/ExecutionEngine/JITLink/X86/COFF_weak_external_multiple_defs.s @@ -0,0 +1,41 @@ +# RUN: rm -rf %t && mkdir -p %t +# RUN: yaml2obj %S/Inputs/COFF_strong_def.yaml -o %t/COFF_strong.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc %s -o %t/COFF_main.o +# RUN: llvm-jitlink --debug-only=jitlink -slab-allocate 100Kb -slab-address 0xfff00000 -slab-page-size 4096 \ +# RUN: -show-graph -noexec %t/COFF_strong.o %t/COFF_main.o 2>&1 | FileCheck %s +# +# Check symbol with weakalias linkage type uses the external definition +# from COFF_strong_def.yaml. +# +# CHECK: Link graph "{{.*}}COFF_strong.o" before post-allocation passes: +# CHECK-NEXT: section strongfunc: +# CHECK-EMPTY: +# CHECK-NEXT: block 0xfff01000 size = 0x00000001, align = 16, alignment-offset = 0 +# CHECK-NEXT: symbols: +# CHECK-NEXT: 0xfff01000 (block + 0x00000000): size: 0x00000001, linkage: strong, scope: default, live - func +# CHECK: Externals after applying lookup result: +# CHECK-NEXT: func: 0x00000000fff01000 + + .text + + .def func_def; + .scl 2; + .type 32; + .endef + .globl func_def + .p2align 4, 0x90 +func_def: + retq + + .def main; + .scl 2; + .type 32; + .endef + .globl main + .p2align 4, 0x90 +main: + callq func + retq + +.section .drectve,"yn" +.ascii "/alternatename:func=func_def"