diff --git a/lld/test/wasm/shared.ll b/lld/test/wasm/shared.ll --- a/lld/test/wasm/shared.ll +++ b/lld/test/wasm/shared.ll @@ -28,12 +28,12 @@ ret i32 %0 } -define default i32* @get_data_address() { +define hidden i32* @get_data_address() { entry: ret i32* @data_external } -define default i8* @get_func_address() { +define hidden i8* @get_func_address() { entry: ret i8* bitcast (void ()* @func_external to i8*) } @@ -54,7 +54,7 @@ ; CHECK-NEXT: Name: dylink ; CHECK-NEXT: MemorySize: 24 ; CHECK-NEXT: MemoryAlignment: 2 -; CHECK-NEXT: TableSize: 3 +; CHECK-NEXT: TableSize: 2 ; CHECK-NEXT: TableAlignment: 0 ; CHECK-NEXT: Needed: [] ; CHECK-NEXT: - Type: TYPE @@ -74,7 +74,7 @@ ; CHECK-NEXT: Table: ; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: -; CHECK-NEXT: Initial: 0x00000003 +; CHECK-NEXT: Initial: 0x00000002 ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: __stack_pointer ; CHECK-NEXT: Kind: GLOBAL @@ -95,7 +95,7 @@ ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 ; CHECK-NEXT: - Module: GOT.mem -; CHECK-NEXT: Field: data_external +; CHECK-NEXT: Field: indirect_func ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: true @@ -104,6 +104,12 @@ ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: true +; CHECK-NEXT: - Module: GOT.mem +; CHECK-NEXT: Field: data_external +; 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 @@ -136,7 +142,7 @@ ; CHECK-NEXT: Body: 10020B ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Locals: [] -; CHECK-NEXT: Body: 230141046A230241016A360200230141086A23043602002301410C6A230141006A360200230141106A2303360200230141146A230541046A3602000B +; CHECK-NEXT: Body: 230141046A230241016A360200230141086A23043602002301410C6A230141006A360200230141106A2305360200230141146A230641046A3602000B ; check the data segment initialized with __memory_base global as offset @@ -147,4 +153,4 @@ ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: GLOBAL_GET ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: Content: '020000000100000002000000000000000000000000000000' +; CHECK-NEXT: Content: '020000000100000000000000000000000000000000000000' diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -171,6 +171,8 @@ case R_WASM_TABLE_INDEX_I32: case R_WASM_TABLE_INDEX_SLEB: case R_WASM_TABLE_INDEX_REL_SLEB: + if (Config->Pic && !getFunctionSymbol(Reloc.Index)->hasTableIndex()) + return 0; return getFunctionSymbol(Reloc.Index)->getTableIndex(); case R_WASM_MEMORY_ADDR_SLEB: case R_WASM_MEMORY_ADDR_I32: diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1142,6 +1142,10 @@ registerType(E->Signature); } +static bool requiresGOTAccess(const Symbol* Sym) { + return Config->Pic && !Sym->isHidden() && !Sym->isLocal(); +} + void Writer::processRelocations(InputChunk *Chunk) { if (!Chunk->Live) return; @@ -1153,8 +1157,8 @@ case R_WASM_TABLE_INDEX_SLEB: case R_WASM_TABLE_INDEX_REL_SLEB: { FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index); - if (Sym->hasTableIndex() || !Sym->hasFunctionIndex()) - continue; + if (Sym->hasTableIndex() || !Sym->hasFunctionIndex() || requiresGOTAccess(Sym)) + break; Sym->setTableIndex(TableBase + IndirectFunctions.size()); IndirectFunctions.emplace_back(Sym); break; @@ -1206,7 +1210,7 @@ // will be converted into code by `generateRelocationCode`. This code // requires the symbols to have GOT entires. auto* Sym = File->getSymbols()[Reloc.Index]; - if (!Sym->isHidden() && !Sym->isLocal() && !Sym->isInGOT()) { + if (requiresGOTAccess(Sym) && !Sym->isInGOT()) { Sym->setGOTIndex(NumImportedGlobals++); GOTSymbols.push_back(Sym); } diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -167,13 +167,13 @@ if (GV && !GV->hasDefaultVisibility()) return true; - if (TT.isOSBinFormatMachO() || TT.isOSBinFormatWasm()) { + if (TT.isOSBinFormatMachO()) { if (RM == Reloc::Static) return true; return GV && GV->isStrongDefinitionForLinker(); } - assert(TT.isOSBinFormatELF()); + assert(TT.isOSBinFormatELF() || TT.isOSBinFormatWasm()); assert(RM != Reloc::DynamicNoPIC); bool IsExecutable = @@ -201,7 +201,7 @@ return true; } - // ELF supports preemption of other symbols. + // ELF & wasm support preemption of other symbols. return false; } diff --git a/llvm/test/CodeGen/WebAssembly/call-pic.ll b/llvm/test/CodeGen/WebAssembly/call-pic.ll --- a/llvm/test/CodeGen/WebAssembly/call-pic.ll +++ b/llvm/test/CodeGen/WebAssembly/call-pic.ll @@ -7,7 +7,7 @@ declare i32 @bar() declare hidden i32 @hidden_function() -@indirect_func = global i32 ()* @foo +@indirect_func = hidden global i32 ()* @foo @alias_func = hidden alias i32 (), i32 ()* @local_function define i32 @local_function() {