[ExecutionEngine] Add weak symbol support to RuntimeDyld
authorKeno Fischer <kfischer@college.harvard.edu>
Tue, 27 Jan 2015 20:02:31 +0000 (20:02 +0000)
committerKeno Fischer <kfischer@college.harvard.edu>
Tue, 27 Jan 2015 20:02:31 +0000 (20:02 +0000)
Support weak symbols by first looking up if there is an externally visible symbol we can find,
and only if that fails using the one in the object file we're loading.

Reviewed By: lhames
Subscribers: llvm-commits
Differential Revision: http://reviews.llvm.org/D6950

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@227228 91177308-0d34-0410-b5e6-96231b3b80d8

lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
unittests/ExecutionEngine/MCJIT/CMakeLists.txt
unittests/ExecutionEngine/MCJIT/MCJITTest.cpp
unittests/ExecutionEngine/MCJIT/MCJITTestBase.h
unittests/ExecutionEngine/MCJIT/Makefile

index fb53ba96055cdc1d7757a36f792e094aab5b7935..81b8eb2238f44d411bfe30c5b15015fe9fbd6b0c 100644 (file)
@@ -168,6 +168,7 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
     uint32_t Flags = I->getFlags();
 
     bool IsCommon = Flags & SymbolRef::SF_Common;
+    bool IsWeak = Flags & SymbolRef::SF_Weak;
     if (IsCommon)
       CommonSymbols.push_back(*I);
     else {
@@ -188,6 +189,11 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
           continue;
         StringRef SectionData;
         Check(SI->getContents(SectionData));
+        // TODO: It make make sense to delay emitting the section for weak
+        // symbols until they are actually required, but that's not possible
+        // currently, because we only know whether we will need the symbol
+        // in resolveRelocations, which happens after we have already finalized
+        // the Load.
         bool IsCode = SI->isText();
         unsigned SectionID =
             findOrEmitSection(Obj, *SI, IsCode, LocalSections);
@@ -198,7 +204,11 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
         SymbolInfo::Visibility Vis =
           (Flags & SymbolRef::SF_Exported) ?
             SymbolInfo::Default : SymbolInfo::Hidden;
-        GlobalSymbolTable[Name] = SymbolInfo(SectionID, SectOffset, Vis);
+        if (!IsWeak) {
+          GlobalSymbolTable[Name] = SymbolInfo(SectionID, SectOffset, Vis);
+        } else {
+          WeakSymbolTable[Name] = SymbolInfo(SectionID, SectOffset, Vis);
+        }
       }
     }
   }
@@ -768,6 +778,21 @@ void RuntimeDyldImpl::resolveExternalSymbols() {
                SymInfo.getOffset();
       }
 
+      // If we didn't find the symbol yet, and it is present in the weak symbol
+      // table, the definition from this object file needs to be used, so emit
+      // it now
+      if (!Addr) {
+        RTDyldSymbolTable::const_iterator Loc = WeakSymbolTable.find(Name);
+        if (Loc != WeakSymbolTable.end()) {
+          SymbolInfo SymInfo = Loc->second;
+          Addr = getSectionLoadAddress(SymInfo.getSectionID()) + SymInfo.getOffset();
+          // Since the weak symbol is now, materialized, add it to the
+          // GlobalSymbolTable. If somebody later asks the ExecutionEngine
+          // for the address of this symbol that's where it'll look
+          GlobalSymbolTable[Name] = SymInfo;
+        }
+      }
+
       // FIXME: Implement error handling that doesn't kill the host program!
       if (!Addr)
         report_fatal_error("Program used external function '" + Name +
@@ -784,6 +809,7 @@ void RuntimeDyldImpl::resolveExternalSymbols() {
 
     ExternalSymbolRelocations.erase(i);
   }
+  WeakSymbolTable.clear();
 }
 
 //===----------------------------------------------------------------------===//
index 0f3ca0f2f3921551bbe4a019c313e4623cafca36..a01b063831a9682021a8587aa674ebb1dfd00b70 100644 (file)
@@ -947,6 +947,7 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
       break;
     }
     case SymbolRef::ST_Data:
+    case SymbolRef::ST_Function:
     case SymbolRef::ST_Unknown: {
       Value.SymbolName = TargetName.data();
       Value.Addend = Addend;
index f37a9a768a2e5de8d71c23c8bf003ed1343393ac..69d6cf53034b754a4216650a9f5a379eaca84611 100644 (file)
@@ -203,6 +203,9 @@ protected:
   // A global symbol table for symbols from all loaded modules.
   RTDyldSymbolTable GlobalSymbolTable;
 
+  // Like the global symbol table but for weak symbols
+  RTDyldSymbolTable WeakSymbolTable;
+
   // Keep a map of common symbols to their info pairs
   typedef std::vector<SymbolRef> CommonSymbolList;
 
index b10cbb4c9ea4b94b20954a5591cd630d0c937f15..dcf8264203e28c004e9d420a4ed998d715dc69c3 100644 (file)
@@ -1,5 +1,6 @@
 set(LLVM_LINK_COMPONENTS
   Analysis
+  AsmParser
   Core
   ExecutionEngine
   IPO
index 64d8c2fca042aedcc26478d8ccc0fe52a69d1aa5..f9ca0fc87172f471da42c24356bbee742a438fe3 100644 (file)
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ExecutionEngine/MCJIT.h"
+#include "llvm/Support/DynamicLibrary.h"
 #include "MCJITTestBase.h"
 #include "gtest/gtest.h"
 
@@ -199,4 +200,45 @@ TEST_F(MCJITTest, multiple_decl_lookups) {
   EXPECT_EQ(A, B) << "Repeat calls to getPointerToFunction fail.";
 }
 
+// Test weak symbol linking when the weak symbol is present in a shared
+// library
+TEST_F(MCJITTest, weak_symbol_present) {
+  SKIP_UNSUPPORTED_PLATFORM;
+
+  int FakeWeakSymbol;
+  llvm::sys::DynamicLibrary::AddSymbol("FakeWeakSymbol", &FakeWeakSymbol);
+  createJITFromAssembly(
+  "$FakeWeakSymbol = comdat any\n"
+  "@FakeWeakSymbol = linkonce_odr global i32 42, comdat, align 4\n"
+  "define i32 @weak_test(i32* %arg) {\n"
+  "    %r = icmp eq i32* %arg, @FakeWeakSymbol\n"
+  "    %ret = zext i1 %r to i32\n"
+  "    ret i32 %ret\n"
+  "  }");
+
+  uint64_t Addr = TheJIT->getFunctionAddress("weak_test");;
+  EXPECT_TRUE(Addr != 0);
+  int32_t(*FuncPtr)(int32_t *) = (int32_t(*)(int32_t *))Addr;
+  EXPECT_EQ(FuncPtr(&FakeWeakSymbol),1);
+  EXPECT_TRUE(TheJIT->getGlobalValueAddress("FakeWeakSymbol") == 0);
+}
+
+// Test weak symbol linking when the weak symbol is not present in a
+// shared library
+TEST_F(MCJITTest, weak_symbol_absent) {
+  SKIP_UNSUPPORTED_PLATFORM;
+
+  SMDiagnostic Error;
+  createJITFromAssembly(
+  "  $FakeWeakSymbol2 = comdat any\n"
+  "  @FakeWeakSymbol2 = linkonce_odr global i32 42, comdat, align 4\n"
+  "  define i32* @get_weak() {\n"
+  "    ret i32* @FakeWeakSymbol2\n"
+  "  }\n");
+  void*(*FuncPtr)() =
+    (void*(*)(void))TheJIT->getFunctionAddress("get_weak");
+  EXPECT_EQ(FuncPtr(),(void*)TheJIT->getGlobalValueAddress("FakeWeakSymbol2"));
+}
+
+
 }
index 35af417bf14746ec913c43d920a1624e9d3609ac..b1943a763d62dac48ca051476218a707f16cebe0 100644 (file)
@@ -18,6 +18,7 @@
 #define LLVM_UNITTESTS_EXECUTIONENGINE_MCJIT_MCJITTESTBASE_H
 
 #include "MCJITTestAPICommon.h"
+#include "llvm/AsmParser/Parser.h"
 #include "llvm/Config/config.h"
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
@@ -27,6 +28,8 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/TypeBuilder.h"
 #include "llvm/Support/CodeGen.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
 
 namespace llvm {
 
@@ -338,6 +341,21 @@ protected:
     assert(TheJIT.get() != NULL && "error creating MCJIT with EngineBuilder");
   }
 
+  void createJITFromAssembly(const char *Test) {
+    SMDiagnostic Error;
+    M = parseAssemblyString(Test, Error, Context);
+
+    std::string errMsg;
+    raw_string_ostream os(errMsg);
+    Error.print("", os);
+
+    // A failure here means that the test itself is buggy.
+    if (!M)
+      report_fatal_error(os.str().c_str());
+
+    createJIT(std::move(M));
+  }
+
   CodeGenOpt::Level OptLevel;
   Reloc::Model RelocModel;
   CodeModel::Model CodeModel;
index 2822b20cdda26e2a9a4659bf624a2df6e72aad05..522ef750df776bc4d720c4c4a7c16f3a7f057d9c 100644 (file)
@@ -9,7 +9,7 @@
 
 LEVEL = ../../..
 TESTNAME = MCJIT
-LINK_COMPONENTS := core ipo mcjit native support
+LINK_COMPONENTS := core asmparser ipo mcjit native support
 
 include $(LEVEL)/Makefile.config
 include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest