From 46ebbc27717ff876c233fd4463fa039d2829a2db Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 20 Feb 2025 17:11:20 -0800 Subject: [PATCH] [lld][WebAssembly] Allow linker-synthetic symbols to be undefine when building shared libraries Fixes: #103592 --- lld/test/wasm/shared-synthetic-symbols.s | 75 ++++++++++++++++++++++++ lld/wasm/Driver.cpp | 31 ++++++---- lld/wasm/Symbols.h | 2 +- 3 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 lld/test/wasm/shared-synthetic-symbols.s diff --git a/lld/test/wasm/shared-synthetic-symbols.s b/lld/test/wasm/shared-synthetic-symbols.s new file mode 100644 index 0000000000000..0c9c68aabc239 --- /dev/null +++ b/lld/test/wasm/shared-synthetic-symbols.s @@ -0,0 +1,75 @@ +## Check that synthetic data-layout symbols such as __heap_base and __heap_end +## can be referenced from shared libraries and pie executables without +## generating undefined symbols. + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: wasm-ld --experimental-pic -pie --import-memory -o %t.wasm %t.o +# RUN: obj2yaml %t.wasm | FileCheck %s +# RUN: wasm-ld --experimental-pic -shared -o %t.so %t.o +# RUN: obj2yaml %t.so | FileCheck %s + +.globl _start + +_start: + .functype _start () -> () + i32.const __heap_base@GOT + drop + i32.const __heap_end@GOT + drop + i32.const __stack_low@GOT + drop + i32.const __stack_high@GOT + drop + i32.const __global_base@GOT + drop + i32.const __data_end@GOT + drop + end_function + +# CHECK: - Type: IMPORT +# CHECK-NEXT: Imports: +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: memory +# CHECK-NEXT: Kind: MEMORY +# CHECK-NEXT: Memory: +# CHECK-NEXT: Minimum: 0x0 +# 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-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __heap_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __heap_end +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __stack_low +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __stack_high +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __global_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __data_end +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index c3a74dde6480e..ff047b15b6be6 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -965,6 +965,8 @@ static void createSyntheticSymbols() { } else { // For non-PIC code WasmSym::stackPointer = createGlobalVariable("__stack_pointer", true); + WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base"); + WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base"); WasmSym::stackPointer->markLive(); } @@ -986,18 +988,23 @@ static void createOptionalSymbols() { WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle"); - if (!ctx.arg.shared) - WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end"); - - if (!ctx.isPic) { - WasmSym::stackLow = symtab->addOptionalDataSymbol("__stack_low"); - WasmSym::stackHigh = symtab->addOptionalDataSymbol("__stack_high"); - WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base"); - WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base"); - WasmSym::heapEnd = symtab->addOptionalDataSymbol("__heap_end"); - WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base"); - WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base"); - } + auto addDataLayoutSymbol = [&](StringRef s) -> DefinedData * { + // Data layout symbols are either defined by the lld, or (in the case + // of PIC code) defined by the dynamic linker / embedder. + if (ctx.isPic) { + ctx.arg.allowUndefinedSymbols.insert(s); + return nullptr; + } else { + return symtab->addOptionalDataSymbol(s); + } + }; + + WasmSym::dataEnd = addDataLayoutSymbol("__data_end"); + WasmSym::stackLow = addDataLayoutSymbol("__stack_low"); + WasmSym::stackHigh = addDataLayoutSymbol("__stack_high"); + WasmSym::globalBase = addDataLayoutSymbol("__global_base"); + WasmSym::heapBase = addDataLayoutSymbol("__heap_base"); + WasmSym::heapEnd = addDataLayoutSymbol("__heap_end"); // For non-shared memory programs we still need to define __tls_base since we // allow object files built with TLS to be linked into single threaded diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index b409fffc50a6c..4ccb95aa486a1 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -560,7 +560,7 @@ struct WasmSym { // Symbol whose value is the size of the TLS block. static GlobalSymbol *tlsSize; - // __tls_size + // __tls_align // Symbol whose value is the alignment of the TLS block. static GlobalSymbol *tlsAlign;