[lld] r346918 - [WebAssembly] Initial support for shared objects (-shared)

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 14 16:37:22 PST 2018


Author: sbc
Date: Wed Nov 14 16:37:21 2018
New Revision: 346918

URL: http://llvm.org/viewvc/llvm-project?rev=346918&view=rev
Log:
[WebAssembly] Initial support for shared objects (-shared)

Based on the initial spec proposal:
https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md

The llvm/codegen side of this is still missing but I believe this change is
still worth landing as an incremental step

Differential Revision: https://reviews.llvm.org/D54249

Added:
    lld/trunk/test/wasm/shared.ll
Modified:
    lld/trunk/docs/ReleaseNotes.rst
    lld/trunk/docs/WebAssembly.rst
    lld/trunk/wasm/Config.h
    lld/trunk/wasm/Driver.cpp
    lld/trunk/wasm/LTO.cpp
    lld/trunk/wasm/Options.td
    lld/trunk/wasm/OutputSections.cpp
    lld/trunk/wasm/Symbols.cpp
    lld/trunk/wasm/Symbols.h
    lld/trunk/wasm/Writer.cpp

Modified: lld/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/docs/ReleaseNotes.rst?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/docs/ReleaseNotes.rst (original)
+++ lld/trunk/docs/ReleaseNotes.rst Wed Nov 14 16:37:21 2018
@@ -65,3 +65,11 @@ MachO Improvements
 ------------------
 
 * Item 1.
+
+WebAssembly Improvements
+------------------------
+
+* Add initial support for creating shared libraries (-shared).
+  Note: The shared library format is still under active development and may
+  undergo significant changes in future versions.
+  See: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md

Modified: lld/trunk/docs/WebAssembly.rst
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/docs/WebAssembly.rst?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/docs/WebAssembly.rst (original)
+++ lld/trunk/docs/WebAssembly.rst Wed Nov 14 16:37:21 2018
@@ -29,6 +29,8 @@ Missing features
 There are several key features that are not yet implement in the WebAssembly
 ports:
 
+- Support for building shared libraries via ``-shared`` is still as work in
+  progress.
 - COMDAT support.  This means that support for C++ is still very limited.
 - Function stripping.  Currently there is no support for ``--gc-sections`` so
   functions and data from a given object will linked as a unit.

Added: lld/trunk/test/wasm/shared.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/shared.ll?rev=346918&view=auto
==============================================================================
--- lld/trunk/test/wasm/shared.ll (added)
+++ lld/trunk/test/wasm/shared.ll Wed Nov 14 16:37:21 2018
@@ -0,0 +1,70 @@
+; RUN: llc -O0 -filetype=obj %s -o %t.o
+; RUN: wasm-ld -shared -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+ at used_data = hidden global i32 2, align 4
+ at indirect_func = local_unnamed_addr global void ()* @foo, align 4
+
+define default void @foo() {
+entry:
+  %0 = load i32, i32* @used_data, align 4
+  %1 = load void ()*, void ()** @indirect_func, align 4
+  call void %1()
+  ret void
+}
+
+; check for dylink section at start
+
+; CHECK:      Sections:
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            dylink
+; CHECK-NEXT:     MemorySize:      4
+; CHECK-NEXT:     MemoryAlignment: 2
+; CHECK-NEXT:     TableSize:       1
+; CHECK-NEXT:     TableAlignment:  0
+
+; check for import of __table_base and __memory_base globals
+
+; CHECK:        - Type:            IMPORT
+; CHECK-NEXT:     Imports:
+; CHECK-NEXT:       - Module:          env
+; CHECK-NEXT:         Field:           __indirect_function_table
+; CHECK-NEXT:         Kind:            TABLE
+; CHECK-NEXT:         Table:
+; CHECK-NEXT:           ElemType:        ANYFUNC
+; CHECK-NEXT:           Limits:
+; CHECK-NEXT:             Flags:           [ HAS_MAX ]
+; CHECK-NEXT:             Initial:         0x00000001
+; CHECK-NEXT:             Maximum:         0x00000001
+; CHECK-NEXT:       - Module:          env
+; CHECK-NEXT:         Field:           __memory_base
+; CHECK-NEXT:         Kind:            GLOBAL
+; CHECK-NEXT:         GlobalType:      I32
+; CHECK-NEXT:         GlobalMutable:   false
+; CHECK-NEXT:       - Module:          env
+; CHECK-NEXT:         Field:           __table_base
+; CHECK-NEXT:         Kind:            GLOBAL
+; CHECK-NEXT:         GlobalType:      I32
+; CHECK-NEXT:         GlobalMutable:   false
+
+; check for elem segment initialized with __table_base global as offset
+
+; CHECK:        - Type:            ELEM
+; CHECK-NEXT:     Segments:
+; CHECK-NEXT:       - Offset:
+; CHECK-NEXT:           Opcode:          GET_GLOBAL
+; CHECK-NEXT:           Index:           1
+; CHECK-NEXT:         Functions:       [ 1 ]
+
+; check the data segment initialized with __memory_base global as offset
+
+; CHECK:        - Type:            DATA
+; CHECK-NEXT:     Segments:
+; CHECK-NEXT:       - SectionOffset:   6
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:
+; CHECK-NEXT:           Opcode:          GET_GLOBAL
+; CHECK-NEXT:           Index:           0
+; CHECK-NEXT:         Content:         '00000000'

Modified: lld/trunk/wasm/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Config.h?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/wasm/Config.h (original)
+++ lld/trunk/wasm/Config.h Wed Nov 14 16:37:21 2018
@@ -31,9 +31,11 @@ struct Configuration {
   bool SharedMemory;
   bool ImportTable;
   bool MergeDataSegments;
+  bool Pie;
   bool PrintGcSections;
   bool Relocatable;
   bool SaveTemps;
+  bool Shared;
   bool StripAll;
   bool StripDebug;
   bool StackFirst;
@@ -52,6 +54,9 @@ struct Configuration {
   llvm::StringSet<> AllowUndefinedSymbols;
   std::vector<llvm::StringRef> SearchPaths;
   llvm::CachePruningPolicy ThinLTOCachePolicy;
+
+  // True if we are creating position-independent code.
+  bool Pic;
 };
 
 // The only instance of Configuration struct.

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Wed Nov 14 16:37:21 2018
@@ -369,6 +369,7 @@ void LinkerDriver::link(ArrayRef<const c
   errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);
 
   Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
+  Config->CompressRelocations = Args.hasArg(OPT_compress_relocations);
   Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
   Config->DisableVerify = Args.hasArg(OPT_disable_verify);
   Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start");
@@ -391,13 +392,14 @@ void LinkerDriver::link(ArrayRef<const c
   Config->MergeDataSegments =
       Args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
                    !Config->Relocatable);
+  Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);
   Config->PrintGcSections =
       Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false);
   Config->SaveTemps = Args.hasArg(OPT_save_temps);
   Config->SearchPaths = args::getStrings(Args, OPT_L);
+  Config->Shared = Args.hasArg(OPT_shared);
   Config->StripAll = Args.hasArg(OPT_strip_all);
   Config->StripDebug = Args.hasArg(OPT_strip_debug);
-  Config->CompressRelocations = Args.hasArg(OPT_compress_relocations);
   Config->StackFirst = Args.hasArg(OPT_stack_first);
   Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir);
   Config->ThinLTOCachePolicy = CHECK(
@@ -432,6 +434,9 @@ void LinkerDriver::link(ArrayRef<const c
     return;
   }
 
+  if (Config->Pie && Config->Shared)
+    error("-shared and -pie may not be used together");
+
   if (Config->OutputFile.empty())
     error("no output file specified");
 
@@ -447,8 +452,21 @@ void LinkerDriver::link(ArrayRef<const c
       error("-r -and --compress-relocations may not be used together");
     if (Args.hasArg(OPT_undefined))
       error("-r -and --undefined may not be used together");
+    if (Config->Pie)
+      error("-r and -pie may not be used together");
+  }
+
+  Config->Pic = Config->Pie || Config->Shared;
+
+  if (Config->Pic) {
+    if (Config->ExportTable)
+      error("-shared/-pie is incompatible with --export-table");
+    Config->ImportTable = true;
   }
 
+  if (Config->Shared)
+    Config->ExportDynamic = true;
+
   Symbol *EntrySym = nullptr;
   if (!Config->Relocatable) {
     llvm::wasm::WasmGlobal Global;
@@ -475,6 +493,28 @@ void LinkerDriver::link(ArrayRef<const c
         "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
     WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0);
 
+    if (Config->Pic) {
+      // For PIC code, we import two global variables (__memory_base and
+      // __table_base) from the environment and use these as the offset at
+      // which to load our static data and function table.
+      // See: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
+      static llvm::wasm::WasmGlobalType GlobalTypeI32 = {WASM_TYPE_I32, false};
+
+      WasmSym::MemoryBase = Symtab->addUndefinedGlobal(
+          "__memory_base", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr,
+          &GlobalTypeI32);
+      Config->AllowUndefinedSymbols.insert(WasmSym::MemoryBase->getName());
+      WasmSym::MemoryBase->IsUsedInRegularObj = true;
+      WasmSym::MemoryBase->markLive();
+
+      WasmSym::TableBase = Symtab->addUndefinedGlobal(
+          "__table_base", WASM_SYMBOL_VISIBILITY_HIDDEN, nullptr,
+          &GlobalTypeI32);
+      Config->AllowUndefinedSymbols.insert(WasmSym::TableBase->getName());
+      WasmSym::TableBase->IsUsedInRegularObj = true;
+      WasmSym::TableBase->markLive();
+    }
+
     // These two synthetic symbols exist purely for the embedder so we always
     // want to export them.
     WasmSym::HeapBase->ForceExport = true;
@@ -511,7 +551,7 @@ void LinkerDriver::link(ArrayRef<const c
     // Add synthetic dummies for weak undefined functions.
     handleWeakUndefines();
 
-    if (!Config->Entry.empty()) {
+    if (!Config->Shared && !Config->Entry.empty()) {
       EntrySym = handleUndefined(Config->Entry);
       if (EntrySym && EntrySym->isDefined())
         EntrySym->ForceExport = true;

Modified: lld/trunk/wasm/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/LTO.cpp?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/wasm/LTO.cpp (original)
+++ lld/trunk/wasm/LTO.cpp Wed Nov 14 16:37:21 2018
@@ -57,6 +57,13 @@ static std::unique_ptr<lto::LTO> createL
   C.OptLevel = Config->LTOO;
   C.MAttrs = GetMAttrs();
 
+  if (Config->Relocatable)
+    C.RelocModel = None;
+  else if (Config->Pic)
+    C.RelocModel = Reloc::PIC_;
+  else
+    C.RelocModel = Reloc::Static;
+
   if (Config->SaveTemps)
     checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
                               /*UseInputModulePath*/ true));

Modified: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/wasm/Options.td (original)
+++ lld/trunk/wasm/Options.td Wed Nov 14 16:37:21 2018
@@ -17,7 +17,7 @@ multiclass B<string name, string help1,
   def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
 }
 
-// The follow flags are shared with the ELF linker
+// The following flags are shared with the ELF linker
 def color_diagnostics: F<"color-diagnostics">,
   HelpText<"Use colors in diagnostics">;
 
@@ -75,12 +75,18 @@ def o: JoinedOrSeparate<["-"], "o">, Met
 
 def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
 
+defm pie: B<"pie",
+    "Create a position independent executable",
+    "Do not create a position independent executable (default)">;
+
 defm print_gc_sections: B<"print-gc-sections",
     "List removed unused sections",
     "Do not list removed unused sections">;
 
 def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
 
+def shared: F<"shared">, HelpText<"Build a shared object">;
+
 def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
 
 def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;

Modified: lld/trunk/wasm/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/OutputSections.cpp?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/wasm/OutputSections.cpp (original)
+++ lld/trunk/wasm/OutputSections.cpp Wed Nov 14 16:37:21 2018
@@ -136,9 +136,18 @@ DataSection::DataSection(ArrayRef<Output
   for (OutputSegment *Segment : Segments) {
     raw_string_ostream OS(Segment->Header);
     writeUleb128(OS, 0, "memory index");
-    writeUleb128(OS, WASM_OPCODE_I32_CONST, "opcode:i32const");
-    writeSleb128(OS, Segment->StartVA, "memory offset");
-    writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
+    WasmInitExpr InitExpr;
+    if (Config->Pic) {
+      assert(Segments.size() <= 1 &&
+             "Currenly only a single data segment is supported in PIC mode");
+      InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL;
+      InitExpr.Value.Global =
+          cast<GlobalSymbol>(WasmSym::MemoryBase)->getGlobalIndex();
+    } else {
+      InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+      InitExpr.Value.Int32 = Segment->StartVA;
+    }
+    writeInitExpr(OS, InitExpr);
     writeUleb128(OS, Segment->Size, "segment size");
     OS.flush();
 

Modified: lld/trunk/wasm/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.cpp?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.cpp (original)
+++ lld/trunk/wasm/Symbols.cpp Wed Nov 14 16:37:21 2018
@@ -28,6 +28,8 @@ DefinedData *WasmSym::DsoHandle;
 DefinedData *WasmSym::DataEnd;
 DefinedData *WasmSym::HeapBase;
 DefinedGlobal *WasmSym::StackPointer;
+Symbol *WasmSym::TableBase;
+Symbol *WasmSym::MemoryBase;
 
 WasmSymbolType Symbol::getWasmType() const {
   if (isa<FunctionSymbol>(this))

Modified: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/wasm/Symbols.h (original)
+++ lld/trunk/wasm/Symbols.h Wed Nov 14 16:37:21 2018
@@ -310,6 +310,14 @@ struct WasmSym {
   // __dso_handle
   // Symbol used in calls to __cxa_atexit to determine current DLL
   static DefinedData *DsoHandle;
+
+  // __table_base
+  // Used in PIC code for offset of indirect function table
+  static Symbol *TableBase;
+
+  // __memory_base
+  // Used in PIC code for offset of global data
+  static Symbol *MemoryBase;
 };
 
 // A buffer class that is large enough to hold any Symbol-derived

Modified: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=346918&r1=346917&r2=346918&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.cpp (original)
+++ lld/trunk/wasm/Writer.cpp Wed Nov 14 16:37:21 2018
@@ -39,7 +39,6 @@ using namespace lld;
 using namespace lld::wasm;
 
 static constexpr int kStackAlignment = 16;
-static constexpr int kInitialTableOffset = 1;
 static constexpr const char *kFunctionTableName = "__indirect_function_table";
 
 namespace {
@@ -90,6 +89,7 @@ private:
   void createCustomSections();
 
   // Custom sections
+  void createDylinkSection();
   void createRelocSections();
   void createLinkingSection();
   void createNameSection();
@@ -98,8 +98,13 @@ private:
   void writeSections();
 
   uint64_t FileSize = 0;
+  uint32_t TableBase = 0;
   uint32_t NumMemoryPages = 0;
   uint32_t MaxMemoryPages = 0;
+  // Memory size and aligment. Written to the "dylink" section
+  // when build with -shared or -pie.
+  uint32_t MemAlign = 0;
+  uint32_t MemSize = 0;
 
   std::vector<const WasmSignature *> Types;
   DenseMap<WasmSignature, int32_t> TypeIndices;
@@ -161,7 +166,7 @@ void Writer::createImportSection() {
   }
 
   if (Config->ImportTable) {
-    uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size();
+    uint32_t TableSize = TableBase + IndirectFunctions.size();
     WasmImport Import;
     Import.Module = "env";
     Import.Field = kFunctionTableName;
@@ -259,7 +264,7 @@ void Writer::createTableSection() {
   //     no address-taken function will fail at validation time since it is
   //     a validation error to include a call_indirect instruction if there
   //     is not table.
-  uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size();
+  uint32_t TableSize = TableBase + IndirectFunctions.size();
 
   SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE);
   raw_ostream &OS = Section->getStream();
@@ -325,12 +330,18 @@ void Writer::createElemSection() {
   writeUleb128(OS, 1, "segment count");
   writeUleb128(OS, 0, "table index");
   WasmInitExpr InitExpr;
-  InitExpr.Opcode = WASM_OPCODE_I32_CONST;
-  InitExpr.Value.Int32 = kInitialTableOffset;
+  if (Config->Pic) {
+    InitExpr.Opcode = WASM_OPCODE_GET_GLOBAL;
+    InitExpr.Value.Global =
+        cast<GlobalSymbol>(WasmSym::TableBase)->getGlobalIndex();
+  } else {
+    InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+    InitExpr.Value.Int32 = TableBase;
+  }
   writeInitExpr(OS, InitExpr);
   writeUleb128(OS, IndirectFunctions.size(), "elem count");
 
-  uint32_t TableIndex = kInitialTableOffset;
+  uint32_t TableIndex = TableBase;
   for (const FunctionSymbol *Sym : IndirectFunctions) {
     assert(Sym->getTableIndex() == TableIndex);
     writeUleb128(OS, Sym->getFunctionIndex(), "function index");
@@ -425,6 +436,20 @@ public:
   raw_string_ostream OS{Body};
 };
 
+// Create the custom "dylink" section containing information for the dynamic
+// linker.
+// See
+// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
+void Writer::createDylinkSection() {
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "dylink");
+  raw_ostream &OS = Section->getStream();
+
+  writeUleb128(OS, MemSize, "MemSize");
+  writeUleb128(OS, int(log2(MemAlign)), "MemAlign");
+  writeUleb128(OS, IndirectFunctions.size(), "TableSize");
+  writeUleb128(OS, 0, "TableAlign");
+}
+
 // Create the custom "linking" section containing linker metadata.
 // This is only created when relocatable output is requested.
 void Writer::createLinkingSection() {
@@ -599,7 +624,7 @@ void Writer::layoutMemory() {
   uint32_t MemoryPtr = 0;
 
   auto PlaceStack = [&]() {
-    if (Config->Relocatable)
+    if (Config->Relocatable || Config->Shared)
       return;
     MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
     if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
@@ -625,7 +650,9 @@ void Writer::layoutMemory() {
   if (WasmSym::DsoHandle)
     WasmSym::DsoHandle->setVirtualAddress(DataStart);
 
+  MemAlign = 0;
   for (OutputSegment *Seg : Segments) {
+    MemAlign = std::max(MemAlign, Seg->Alignment);
     MemoryPtr = alignTo(MemoryPtr, Seg->Alignment);
     Seg->StartVA = MemoryPtr;
     log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name,
@@ -658,8 +685,8 @@ void Writer::layoutMemory() {
     else
       MemoryPtr = Config->InitialMemory;
   }
-  uint32_t MemSize = alignTo(MemoryPtr, WasmPageSize);
-  NumMemoryPages = MemSize / WasmPageSize;
+  MemSize = MemoryPtr;
+  NumMemoryPages = alignTo(MemoryPtr, WasmPageSize) / WasmPageSize;
   log("mem: total pages = " + Twine(NumMemoryPages));
 
   if (Config->MaxMemory != 0) {
@@ -682,6 +709,8 @@ SyntheticSection *Writer::createSyntheti
 
 void Writer::createSections() {
   // Known sections
+  if (Config->Pic)
+    createDylinkSection();
   createTypeSection();
   createImportSection();
   createFunctionSection();
@@ -874,7 +903,7 @@ void Writer::assignIndexes() {
       AddDefinedFunction(Func);
   }
 
-  uint32_t TableIndex = kInitialTableOffset;
+  uint32_t TableIndex = TableBase;
   auto HandleRelocs = [&](InputChunk *Chunk) {
     if (!Chunk->Live)
       return;
@@ -926,6 +955,10 @@ void Writer::assignIndexes() {
 }
 
 static StringRef getOutputDataSegmentName(StringRef Name) {
+  // With PIC code we currently only support a single data segment since
+  // we only have a single __memory_base to use as our base address.
+  if (Config->Pic)
+    return "data";
   if (!Config->MergeDataSegments)
     return Name;
   if (Name.startswith(".text."))
@@ -1010,9 +1043,14 @@ void Writer::calculateInitFunctions() {
 }
 
 void Writer::run() {
-  if (Config->Relocatable)
+  if (Config->Relocatable || Config->Pic)
     Config->GlobalBase = 0;
 
+  // For PIC code the table base is assigned dynamically by the loader.
+  // For non-PIC, we start at 1 so that accessing table index 0 always traps.
+  if (!Config->Pic)
+    TableBase = 1;
+
   log("-- calculateImports");
   calculateImports();
   log("-- assignIndexes");




More information about the llvm-commits mailing list