Skip to content

[lld][WebAssembly] Allow linker-synthetic symbols to be undefined when building shared libraries #128223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions lld/test/wasm/shared-synthetic-symbols.s
Original file line number Diff line number Diff line change
@@ -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
31 changes: 19 additions & 12 deletions lld/wasm/Driver.cpp
Original file line number Diff line number Diff line change
@@ -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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these calls seem too early in the link process.
the symbol table is almost empty here and they are effectively no-op i guess.
createSyntheticSymbols is called even before addFile.

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Data layout symbols are either defined by the lld, or (in the case
// Data layout symbols are either defined by 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
2 changes: 1 addition & 1 deletion lld/wasm/Symbols.h
Original file line number Diff line number Diff line change
@@ -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;