[WebAssembly] Always take into account added when applying runtime relocations The code we generate for applying data relocations at runtime omitted the symbols with GOT entries. Also refactor the code to reduce duplication. Differential Revision: https://reviews.llvm.org/D61111 llvm-svn: 359207 GitOrigin-RevId: b685ddf28882cf3b92575bc3ed7a42665324664e
diff --git a/test/wasm/shared.ll b/test/wasm/shared.ll index 678d628..50a4c8b 100644 --- a/test/wasm/shared.ll +++ b/test/wasm/shared.ll
@@ -9,8 +9,14 @@ @indirect_func = local_unnamed_addr global i32 ()* @foo, align 4 @indirect_func_external = local_unnamed_addr global void ()* @func_external, align 4 +; Test data relocations @data_addr = local_unnamed_addr global i32* @data, align 4 +; .. against external symbols @data_addr_external = local_unnamed_addr global i32* @data_external, align 4 +; .. including addends +%struct.s = type { i32, i32 } +@extern_struct = external global %struct.s +@extern_struct_internal_ptr = local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @extern_struct, i32 0, i32 1), align 4 define hidden i32 @foo() { entry: @@ -46,7 +52,7 @@ ; CHECK: Sections: ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: dylink -; CHECK-NEXT: MemorySize: 20 +; CHECK-NEXT: MemorySize: 24 ; CHECK-NEXT: MemoryAlignment: 2 ; CHECK-NEXT: TableSize: 3 ; CHECK-NEXT: TableAlignment: 0 @@ -98,6 +104,11 @@ ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: true +; CHECK-NEXT: - Module: GOT.mem +; CHECK-NEXT: Field: extern_struct +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: GlobalType: I32 +; CHECK-NEXT: GlobalMutable: true ; CHECK-NEXT: - Type: FUNCTION ; CHECK: - Type: EXPORT @@ -125,7 +136,7 @@ ; CHECK-NEXT: Body: 10020B ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Locals: [] -; CHECK-NEXT: Body: 230141046A230241016A360200230141086A230241026A3602002301410C6A230141006A360200230141106A23033602000B +; CHECK-NEXT: Body: 230141046A230241016A360200230141086A23043602002301410C6A230141006A360200230141106A2303360200230141146A230541046A3602000B ; check the data segment initialized with __memory_base global as offset @@ -136,4 +147,4 @@ ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: GLOBAL_GET ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: Content: '0200000001000000020000000000000000000000' +; CHECK-NEXT: Content: '020000000100000002000000000000000000000000000000'
diff --git a/wasm/InputChunks.cpp b/wasm/InputChunks.cpp index b609069..735eb77 100644 --- a/wasm/InputChunks.cpp +++ b/wasm/InputChunks.cpp
@@ -301,10 +301,19 @@ // This is only called when generating shared libaries (PIC) where address are // not known at static link time. void InputSegment::generateRelocationCode(raw_ostream &OS) const { + LLVM_DEBUG(dbgs() << "generating runtime relocations: " << getName() + << " count=" << Relocations.size() << "\n"); + + // TODO(sbc): Encode the relocations in the data section and write a loop + // here to apply them. uint32_t SegmentVA = OutputSeg->StartVA + OutputSegmentOffset; for (const WasmRelocation &Rel : Relocations) { uint32_t Offset = Rel.Offset - getInputSectionOffset(); - uint32_t OutputVA = SegmentVA + Offset; + uint32_t OutputOffset = SegmentVA + Offset; + + LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(Rel.Type) + << " addend=" << Rel.Addend << " index=" << Rel.Index + << " output offset=" << OutputOffset << "\n"); // Get __memory_base writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); @@ -312,38 +321,28 @@ // Add the offset of the relocation writeU8(OS, WASM_OPCODE_I32_CONST, "I32_CONST"); - writeSleb128(OS, OutputVA, "offset"); + writeSleb128(OS, OutputOffset, "offset"); writeU8(OS, WASM_OPCODE_I32_ADD, "ADD"); + Symbol *Sym = File->getSymbol(Rel); // Now figure out what we want to store - switch (Rel.Type) { - case R_WASM_TABLE_INDEX_I32: - // Add the table index to the __table_base + if (Sym->hasGOTIndex()) { writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); - writeUleb128(OS, WasmSym::TableBase->getGlobalIndex(), "table_base"); - writeU8(OS, WASM_OPCODE_I32_CONST, "CONST"); - writeSleb128(OS, File->calcNewValue(Rel), "new table index"); - writeU8(OS, WASM_OPCODE_I32_ADD, "ADD"); - break; - case R_WASM_MEMORY_ADDR_I32: { - Symbol *Sym = File->getSymbol(Rel); - if (Sym->isLocal() || Sym->isHidden()) { - // Hidden/Local data symbols are accessed via known offset from - // __memory_base - writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); - writeUleb128(OS, WasmSym::MemoryBase->getGlobalIndex(), "memory_base"); + writeUleb128(OS, Sym->getGOTIndex(), "global index"); + if (Rel.Addend) { writeU8(OS, WASM_OPCODE_I32_CONST, "CONST"); - writeSleb128(OS, File->calcNewValue(Rel), "new memory offset"); + writeSleb128(OS, Rel.Addend, "addend"); writeU8(OS, WASM_OPCODE_I32_ADD, "ADD"); - } else { - // Default data symbols are accessed via imported GOT globals - writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); - writeUleb128(OS, Sym->getGOTIndex(), "global index"); } - break; - } - default: - llvm_unreachable("unexpected relocation type in data segment"); + } else { + const GlobalSymbol* BaseSymbol = WasmSym::MemoryBase; + if (Rel.Type == R_WASM_TABLE_INDEX_I32) + BaseSymbol = WasmSym::TableBase; + writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); + writeUleb128(OS, BaseSymbol->getGlobalIndex(), "base"); + writeU8(OS, WASM_OPCODE_I32_CONST, "CONST"); + writeSleb128(OS, File->calcNewValue(Rel), "offset"); + writeU8(OS, WASM_OPCODE_I32_ADD, "ADD"); } // Store that value at the virtual address
diff --git a/wasm/Symbols.cpp b/wasm/Symbols.cpp index c2bd003..74fa723 100644 --- a/wasm/Symbols.cpp +++ b/wasm/Symbols.cpp
@@ -97,6 +97,9 @@ void Symbol::setGOTIndex(uint32_t Index) { LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n"); assert(GOTIndex == INVALID_INDEX); + // Any symbol that is assigned a GOT entry must be exported othewise the + // dynamic linker won't be able create the entry that contains it. + ForceExport = true; GOTIndex = Index; }