Skip to content

Commit ab58e4c

Browse files
committed
[lld][WebAssembly] Add suppport for PIC + passive data initialization
This change improves our support for shared memory to include PIC executables (and shared libraries). To handle this case the linker-generated `__wasm_init_memory` function (that only exists in shared memory builds) must be capable of loading memory segements at non-const offsets based on the runtime value of `__memory_base`. Differential Revision: https://reviews.llvm.org/D92620
1 parent 2518433 commit ab58e4c

File tree

6 files changed

+90
-15
lines changed

6 files changed

+90
-15
lines changed

lld/test/lit.cfg.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818

1919
# testFormat: The test format to use to interpret tests.
2020
#
21-
# For now we require '&&' between commands, until they get globally killed and
22-
# the test runner updated.
21+
# For now we require '&&' between commands, until they get globally killed and the test runner updated.
2322
config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
2423

2524
# suffixes: A list of file extensions to treat as test files.

lld/test/wasm/data-segments.ll

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj %s -o %t.bulk-mem.o -mattr=+bulk-memory
33
; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj %s -o %t.atomics.bulk-mem.o -mattr=+atomics,+bulk-memory
44
; RUN: llc --mtriple=wasm64-unknown-unknown -filetype=obj %s -o %t.atomics.bulk-mem64.o -mattr=+atomics,+bulk-memory
5+
; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj %s -o %t.atomics.bulk-mem.pic.o -relocation-model=pic -mattr=+atomics,+bulk-memory,+mutable-globals
6+
; RUN: llc --mtriple=wasm64-unknown-unknown -filetype=obj %s -o %t.atomics.bulk-mem.pic-mem64.o -relocation-model=pic -mattr=+atomics,+bulk-memory,+mutable-globals
57

68
; atomics, shared memory => error
79
; RUN: not wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.o -o %t.atomics.wasm 2>&1 | FileCheck %s --check-prefix ERROR
@@ -19,8 +21,12 @@
1921
; RUN: obj2yaml %t.atomics.bulk-mem64.wasm | FileCheck %s --check-prefixes PASSIVE,PASSIVE64
2022

2123
; Also test in combination with PIC/pie
22-
; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj -relocation-model=pic %s -o %t.atomics.bulk-mem.pic.o -mattr=+atomics,+bulk-memory,+mutable-globals
2324
; RUN: wasm-ld --experimental-pic -pie -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.pic.o -o %t.pic.wasm
25+
; RUN: obj2yaml %t.pic.wasm | FileCheck %s --check-prefixes PASSIVE-PIC,PASSIVE32-PIC
26+
27+
; Also test in combination with PIC/pie + wasm64
28+
; RUN: wasm-ld -mwasm64 --experimental-pic -pie -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.pic-mem64.o -o %t.pic-mem64.wasm
29+
; RUN: obj2yaml %t.pic-mem64.wasm | FileCheck %s --check-prefixes PASSIVE-PIC,PASSIVE64-PIC
2430

2531
@a = hidden global [6 x i8] c"hello\00", align 1
2632
@b = hidden global [8 x i8] c"goodbye\00", align 1
@@ -91,3 +97,42 @@
9197
; PASSIVE-NEXT: Name: __wasm_init_memory
9298
; PASSIVE-NEXT: - Index: 2
9399
; PASSIVE-NEXT: Name: __wasm_init_tls
100+
101+
; PASSIVE-PIC: - Type: START
102+
; PASSIVE-PIC-NEXT: StartFunction: 2
103+
; PASSIVE-PIC-NEXT: - Type: DATACOUNT
104+
; PASSIVE-PIC-NEXT: Count: 1
105+
; PASSIVE-PIC-NEXT: - Type: CODE
106+
; PASSIVE-PIC-NEXT: Functions:
107+
; PASSIVE-PIC-NEXT: - Index: 0
108+
; PASSIVE-PIC-NEXT: Locals: []
109+
; PASSIVE-PIC-NEXT: Body: 10010B
110+
; PASSIVE-PIC-NEXT: - Index: 1
111+
; PASSIVE-PIC-NEXT: Locals: []
112+
; PASSIVE-PIC-NEXT: Body: 0B
113+
; PASSIVE-PIC-NEXT: - Index: 2
114+
; PASSIVE-PIC-NEXT: Locals:
115+
; PASSIVE32-PIC-NEXT: - Type: I32
116+
; PASSIVE64-PIC-NEXT: - Type: I64
117+
; PASSIVE-PIC-NEXT: Count: 1
118+
; PASSIVE32-PIC-NEXT: Body: 230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
119+
; PASSIVE64-PIC-NEXT: Body: 230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
120+
; PASSIVE-PIC-NEXT: - Index: 3
121+
; PASSIVE-PIC-NEXT: Locals: []
122+
; PASSIVE-PIC-NEXT: Body: 0B
123+
; PASSIVE-PIC-NEXT: - Type: DATA
124+
; PASSIVE-PIC-NEXT: Segments:
125+
; PASSIVE-PIC-NEXT: - SectionOffset: 4
126+
; PASSIVE-PIC-NEXT: InitFlags: 1
127+
128+
; PASSIVE-PIC: - Type: CUSTOM
129+
; PASSIVE-PIC-NEXT: Name: name
130+
; PASSIVE-PIC-NEXT: FunctionNames:
131+
; PASSIVE-PIC-NEXT: - Index: 0
132+
; PASSIVE-PIC-NEXT: Name: __wasm_call_ctors
133+
; PASSIVE-PIC-NEXT: - Index: 1
134+
; PASSIVE-PIC-NEXT: Name: __wasm_apply_relocs
135+
; PASSIVE-PIC-NEXT: - Index: 2
136+
; PASSIVE-PIC-NEXT: Name: __wasm_init_memory
137+
; PASSIVE-PIC-NEXT: - Index: 3
138+
; PASSIVE-PIC-NEXT: Name: __wasm_init_tls

lld/wasm/Driver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ static void createSyntheticSymbols() {
645645
WasmSym::stackPointer->markLive();
646646
}
647647

648-
if (config->sharedMemory && !config->shared) {
648+
if (config->sharedMemory) {
649649
// Passive segments are used to avoid memory being reinitialized on each
650650
// thread's instantiation. These passive segments are initialized and
651651
// dropped in __wasm_init_memory, which is registered as the start function

lld/wasm/SyntheticSections.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ void ExportSection::writeBody() {
372372
}
373373

374374
bool StartSection::isNeeded() const {
375-
return !config->relocatable && hasInitializedSegments && config->sharedMemory;
375+
return WasmSym::initMemory != nullptr;
376376
}
377377

378378
void StartSection::writeBody() {

lld/wasm/Writer.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -869,10 +869,24 @@ void Writer::createInitMemoryFunction() {
869869
LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
870870
assert(WasmSym::initMemoryFlag);
871871
uint64_t flagAddress = WasmSym::initMemoryFlag->getVirtualAddress();
872+
bool is64 = config->is64.getValueOr(false);
872873
std::string bodyContent;
873874
{
874875
raw_string_ostream os(bodyContent);
875-
writeUleb128(os, 0, "num locals");
876+
// With PIC code we cache the flag address in local 0
877+
if (config->isPic) {
878+
writeUleb128(os, 1, "num local decls");
879+
writeUleb128(os, 1, "local count");
880+
writeU8(os, is64 ? WASM_TYPE_I64 : WASM_TYPE_I32, "address type");
881+
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
882+
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base");
883+
writePtrConst(os, flagAddress, is64, "flag address");
884+
writeU8(os, WASM_OPCODE_I32_ADD, "add");
885+
writeU8(os, WASM_OPCODE_LOCAL_SET, "local.set");
886+
writeUleb128(os, 0, "local 0");
887+
} else {
888+
writeUleb128(os, 0, "num locals");
889+
}
876890

877891
if (hasPassiveInitializedSegments()) {
878892
// Initialize memory in a thread-safe manner. The thread that successfully
@@ -916,11 +930,24 @@ void Writer::createInitMemoryFunction() {
916930
// )
917931
// ( ... drop data segments ... )
918932
// )
933+
//
934+
// When we are building with PIC, calculate the flag location using:
935+
//
936+
// (global.get $__memory_base)
937+
// (i32.const $__init_memory_flag)
938+
// (i32.const 1)
919939

920-
bool is64 = config->is64.getValueOr(false);
940+
auto writeGetFlagAddress = [&]() {
941+
if (config->isPic) {
942+
writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get");
943+
writeUleb128(os, 0, "local 0");
944+
} else {
945+
writePtrConst(os, flagAddress, is64, "flag address");
946+
}
947+
};
921948

922949
// Atomically check whether this is the main thread.
923-
writePtrConst(os, flagAddress, is64, "flag address");
950+
writeGetFlagAddress();
924951
writeI32Const(os, 0, "expected flag value");
925952
writeI32Const(os, 1, "flag value");
926953
writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix");
@@ -930,7 +957,7 @@ void Writer::createInitMemoryFunction() {
930957
writeU8(os, WASM_TYPE_NORESULT, "blocktype");
931958

932959
// Did not increment 0, so wait for main thread to initialize memory
933-
writePtrConst(os, flagAddress, is64, "flag address");
960+
writeGetFlagAddress();
934961
writeI32Const(os, 1, "expected flag value");
935962
writeI64Const(os, -1, "timeout");
936963

@@ -946,6 +973,12 @@ void Writer::createInitMemoryFunction() {
946973
if (needsPassiveInitialization(s)) {
947974
// destination address
948975
writePtrConst(os, s->startVA, is64, "destination address");
976+
if (config->isPic) {
977+
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
978+
writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(),
979+
"memory_base");
980+
writeU8(os, WASM_OPCODE_I32_ADD, "i32.add");
981+
}
949982
// source segment offset
950983
writeI32Const(os, 0, "segment offset");
951984
// memory region size
@@ -959,14 +992,14 @@ void Writer::createInitMemoryFunction() {
959992
}
960993

961994
// Set flag to 2 to mark end of initialization
962-
writePtrConst(os, flagAddress, is64, "flag address");
995+
writeGetFlagAddress();
963996
writeI32Const(os, 2, "flag value");
964997
writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix");
965998
writeUleb128(os, WASM_OPCODE_I32_ATOMIC_STORE, "i32.atomic.store");
966999
writeMemArg(os, 2, 0);
9671000

9681001
// Notify any waiters that memory initialization is complete
969-
writePtrConst(os, flagAddress, is64, "flag address");
1002+
writeGetFlagAddress();
9701003
writeI32Const(os, -1, "number of waiters");
9711004
writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix");
9721005
writeUleb128(os, WASM_OPCODE_ATOMIC_NOTIFY, "atomic.notify");
@@ -1095,9 +1128,6 @@ void Writer::createCommandExportWrapper(uint32_t functionIndex,
10951128
}
10961129

10971130
void Writer::createInitTLSFunction() {
1098-
if (!WasmSym::initTLS->isLive())
1099-
return;
1100-
11011131
std::string bodyContent;
11021132
{
11031133
raw_string_ostream os(bodyContent);
@@ -1244,7 +1274,7 @@ void Writer::run() {
12441274
}
12451275
}
12461276

1247-
if (!config->relocatable && config->sharedMemory && !config->shared)
1277+
if (WasmSym::initTLS && WasmSym::initTLS->isLive())
12481278
createInitTLSFunction();
12491279

12501280
if (errorCount())

llvm/include/llvm/BinaryFormat/Wasm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ enum : unsigned {
263263
WASM_OPCODE_END = 0x0b,
264264
WASM_OPCODE_CALL = 0x10,
265265
WASM_OPCODE_LOCAL_GET = 0x20,
266+
WASM_OPCODE_LOCAL_SET = 0x21,
266267
WASM_OPCODE_GLOBAL_GET = 0x23,
267268
WASM_OPCODE_GLOBAL_SET = 0x24,
268269
WASM_OPCODE_I32_STORE = 0x36,

0 commit comments

Comments
 (0)