From 53217ecb882c25bb69e6065512a0627828d6e870 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 24 Jun 2022 03:04:58 -0700 Subject: [PATCH] [lld][WebAssembly] Don't apply data relocations at static constructor time Instead, export `__wasm_apply_data_relocs` and `__wasm_call_ctors` separately. This is required since user code in a shared library (such as static constructors) should not be run until relocations have been applied to all loaded libraries. See: https://github.com/emscripten-core/emscripten/issues/17295 Differential Revision: https://reviews.llvm.org/D128515 --- lld/test/wasm/data-segments.ll | 25 +++++++++++++------------ lld/test/wasm/pie.ll | 16 +++++++++------- lld/test/wasm/shared-weak-symbols.s | 3 +++ lld/test/wasm/shared.s | 1 - lld/test/wasm/shared64.s | 1 - lld/test/wasm/tls-export.s | 3 +++ lld/test/wasm/tls-non-shared-memory.s | 3 +++ lld/wasm/Driver.cpp | 11 +++++++++++ lld/wasm/Writer.cpp | 27 ++++----------------------- 9 files changed, 46 insertions(+), 44 deletions(-) diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll index 11fa97fd98e82..cc97698552e9f 100644 --- a/lld/test/wasm/data-segments.ll +++ b/lld/test/wasm/data-segments.ll @@ -30,12 +30,12 @@ ; Also test in combination with PIC/pie ; 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 ; RUN: obj2yaml %t.pic.wasm | FileCheck %s --check-prefixes PASSIVE-PIC,PASSIVE32-PIC -; RUN: llvm-objdump --disassemble-symbols=__wasm_call_ctors,__wasm_init_memory --no-show-raw-insn --no-leading-addr %t.pic.wasm | FileCheck %s --check-prefixes DIS,PIC-DIS -DPTR=i32 +; RUN: llvm-objdump --disassemble-symbols=__wasm_call_ctors,__wasm_apply_data_relocs,__wasm_init_memory --no-show-raw-insn --no-leading-addr %t.pic.wasm | FileCheck %s --check-prefixes DIS,PIC-DIS -DPTR=i32 ; Also test in combination with PIC/pie + wasm64 ; 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 ; RUN: obj2yaml %t.pic-mem64.wasm | FileCheck %s --check-prefixes PASSIVE-PIC,PASSIVE64-PIC -; RUN: llvm-objdump --disassemble-symbols=__wasm_call_ctors,__wasm_init_memory --no-show-raw-insn --no-leading-addr %t.pic-mem64.wasm | FileCheck %s --check-prefixes DIS,PIC-DIS -DPTR=i64 +; RUN: llvm-objdump --disassemble-symbols=__wasm_call_ctors,__wasm_apply_data_relocs,__wasm_init_memory --no-show-raw-insn --no-leading-addr %t.pic-mem64.wasm | FileCheck %s --check-prefixes DIS,PIC-DIS -DPTR=i64 @a = hidden global [6 x i8] c"hello\00", align 1 @b = hidden global [8 x i8] c"goodbye\00", align 1 @@ -113,26 +113,26 @@ ; PASSIVE-NEXT: Name: __wasm_init_memory ; PASSIVE-PIC: - Type: START -; PASSIVE-PIC-NEXT: StartFunction: 2 +; PASSIVE-PIC-NEXT: StartFunction: 3 ; PASSIVE-PIC-NEXT: - Type: DATACOUNT ; PASSIVE-PIC-NEXT: Count: 3 ; PASSIVE-PIC-NEXT: - Type: CODE ; PASSIVE-PIC-NEXT: Functions: ; PASSIVE-PIC-NEXT: - Index: 0 ; PASSIVE-PIC-NEXT: Locals: [] -; PASSIVE-PIC-NEXT: Body: 10030B +; PASSIVE-PIC-NEXT: Body: 0B ; PASSIVE-PIC-NEXT: - Index: 1 ; PASSIVE-PIC-NEXT: Locals: [] ; PASSIVE-PIC-NEXT: Body: {{.*}} ; PASSIVE-PIC-NEXT: - Index: 2 +; PASSIVE-PIC-NEXT: Locals: [] +; PASSIVE-PIC-NEXT: Body: 0B +; PASSIVE-PIC-NEXT: - Index: 3 ; PASSIVE-PIC-NEXT: Locals: ; PASSIVE32-PIC-NEXT: - Type: I32 ; PASSIVE64-PIC-NEXT: - Type: I64 ; PASSIVE-PIC-NEXT: Count: 2 ; PASSIVE-PIC-NEXT: Body: {{.*}} -; PASSIVE-PIC-NEXT: - Index: 3 -; PASSIVE-PIC-NEXT: Locals: [] -; PASSIVE-PIC-NEXT: Body: 0B ; PASSIVE-PIC-NEXT: - Type: DATA ; PASSIVE-PIC-NEXT: Segments: ; PASSIVE-PIC-NEXT: - SectionOffset: 3 @@ -152,18 +152,19 @@ ; PASSIVE-PIC-NEXT: - Index: 1 ; PASSIVE-PIC-NEXT: Name: __wasm_init_tls ; PASSIVE-PIC-NEXT: - Index: 2 -; PASSIVE-PIC-NEXT: Name: __wasm_init_memory -; PASSIVE-PIC-NEXT: - Index: 3 ; PASSIVE-PIC-NEXT: Name: __wasm_apply_data_relocs +; PASSIVE-PIC-NEXT: - Index: 3 +; PASSIVE-PIC-NEXT: Name: __wasm_init_memory -; In PIC mode __wasm_call_ctors contains a call to __wasm_apply_data_relocs -; In non-PIC mode __wasm_call_ctors is an emtpy function since there are ; no data relocations. ; DIS-LABEL: <__wasm_call_ctors>: ; DIS-EMPTY: -; PIC-DIS-NEXT: call 3 ; DIS-NEXT: end +; In PIC mode __wasm_apply_data_relocs is export seperatly to __wasm_call_ctors +; PIC-DIS: <__wasm_apply_data_relocs>: +; PIC-DIS-EMPTY: + ; DIS-LABEL: <__wasm_init_memory>: ; PIC-DIS: .local [[PTR]] diff --git a/lld/test/wasm/pie.ll b/lld/test/wasm/pie.ll index c781611569944..467cb5d5fc2e2 100644 --- a/lld/test/wasm/pie.ll +++ b/lld/test/wasm/pie.ll @@ -1,7 +1,7 @@ ; RUN: llc -relocation-model=pic -mattr=+mutable-globals -filetype=obj %s -o %t.o ; RUN: wasm-ld --no-gc-sections --experimental-pic -pie -o %t.wasm %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s -; RUN: llvm-objdump --disassemble-symbols=__wasm_call_ctors --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --check-prefixes DISASSEM +; RUN: llvm-objdump --disassemble-symbols=__wasm_call_ctors,__wasm_apply_data_relocs --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --check-prefixes DISASSEM target triple = "wasm32-unknown-emscripten" @@ -91,11 +91,13 @@ declare void @external_func() ; CHECK-NEXT: Name: _start ; CHECK-NEXT: GlobalNames: -; DISASSEM: <__wasm_call_ctors>: +; DISASSEM-LABEL: <__wasm_call_ctors>: ; DISASSEM-EMPTY: -; DISASSEM-NEXT: call 2 ; DISASSEM-NEXT: end +; DISASSEM-LABEL: <__wasm_apply_data_relocs>: +; DISASSEM: end + ; Run the same test with extended-const support. When this is available ; we don't need __wasm_apply_global_relocs and instead rely on the add ; instruction in the InitExpr. We also, therefore, do not need these globals @@ -153,10 +155,10 @@ declare void @external_func() ; SHMEM: - Type: START ; SHMEM-NEXT: StartFunction: 6 -; DISASSEM-SHMEM: <__wasm_start>: +; DISASSEM-SHMEM-LABEL: <__wasm_start>: ; DISASSEM-SHMEM-EMPTY: ; DISASSEM-SHMEM-NEXT: call 5 -; DISASSEM-SHMEM-NEXT: call 3 +; DISASSEM-SHMEM-NEXT: call 4 ; DISASSEM-SHMEM-NEXT: end ; SHMEM: FunctionNames: @@ -167,9 +169,9 @@ declare void @external_func() ; SHMEM-NEXT: - Index: 2 ; SHMEM-NEXT: Name: __wasm_init_tls ; SHMEM-NEXT: - Index: 3 -; SHMEM-NEXT: Name: __wasm_init_memory -; SHMEM-NEXT: - Index: 4 ; SHMEM-NEXT: Name: __wasm_apply_data_relocs +; SHMEM-NEXT: - Index: 4 +; SHMEM-NEXT: Name: __wasm_init_memory ; SHMEM-NEXT: - Index: 5 ; SHMEM-NEXT: Name: __wasm_apply_global_relocs ; SHMEM-NEXT: - Index: 6 diff --git a/lld/test/wasm/shared-weak-symbols.s b/lld/test/wasm/shared-weak-symbols.s index c74d599602949..90de006353b3d 100644 --- a/lld/test/wasm/shared-weak-symbols.s +++ b/lld/test/wasm/shared-weak-symbols.s @@ -62,6 +62,9 @@ call_weak: # CHECK-NEXT: - Name: __wasm_call_ctors # CHECK-NEXT: Kind: FUNCTION # CHECK-NEXT: Index: 1 +# CHECK-NEXT: - Name: __wasm_apply_data_relocs +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT: Index: 2 # CHECK-NEXT: - Name: weak_func # CHECK-NEXT: Kind: FUNCTION # CHECK-NEXT: Index: 3 diff --git a/lld/test/wasm/shared.s b/lld/test/wasm/shared.s index 086f228308de9..e53af32ee546f 100644 --- a/lld/test/wasm/shared.s +++ b/lld/test/wasm/shared.s @@ -209,7 +209,6 @@ get_local_func_address: # DIS: <__wasm_call_ctors>: # DIS-EMPTY: -# DIS-NEXT: call 1 # DIS-NEXT: end # DIS: <__wasm_apply_data_relocs>: diff --git a/lld/test/wasm/shared64.s b/lld/test/wasm/shared64.s index c5a813ea98f34..9847aa72fe7eb 100644 --- a/lld/test/wasm/shared64.s +++ b/lld/test/wasm/shared64.s @@ -216,7 +216,6 @@ get_local_func_address: # DIS: <__wasm_call_ctors>: # DIS-EMPTY: -# DIS-NEXT: call 1 # DIS-NEXT: end # DIS: <__wasm_apply_data_relocs>: diff --git a/lld/test/wasm/tls-export.s b/lld/test/wasm/tls-export.s index 619f9d2df312a..1f64be607abb2 100644 --- a/lld/test/wasm/tls-export.s +++ b/lld/test/wasm/tls-export.s @@ -40,6 +40,9 @@ tls1: # CHECK-NEXT: - Name: __wasm_call_ctors # CHECK-NEXT: Kind: FUNCTION # CHECK-NEXT: Index: 0 +# CHECK-NEXT: - Name: __wasm_apply_data_relocs +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT: Index: 1 # CHECK-NEXT: - Name: tls1 # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: Index: 2 diff --git a/lld/test/wasm/tls-non-shared-memory.s b/lld/test/wasm/tls-non-shared-memory.s index 1754fd6254bb8..a2e2257cc9392 100644 --- a/lld/test/wasm/tls-non-shared-memory.s +++ b/lld/test/wasm/tls-non-shared-memory.s @@ -127,6 +127,9 @@ tls1: # PIE-NEXT: - Name: memory # PIE-NEXT: Kind: MEMORY # PIE-NEXT: Index: 0 +# PIE-NEXT: - Name: __wasm_apply_data_relocs +# PIE-NEXT: Kind: FUNCTION +# PIE-NEXT: Index: 1 # PIE-NEXT: - Type: # .tdata and .data are combined into single segment in PIC mode. diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 32bd1ef3344e3..0a0f0c8a05bd7 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -656,6 +656,17 @@ static void createSyntheticSymbols() { is64 ? i64ArgSignature : i32ArgSignature, "__wasm_init_tls")); } + + if (config->isPic || + config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) { + // For PIC code, or when dynamically importing addresses, we create + // synthetic functions that apply relocations. These get called from + // __wasm_call_ctors before the user-level constructors. + WasmSym::applyDataRelocs = symtab->addSyntheticFunction( + "__wasm_apply_data_relocs", + WASM_SYMBOL_VISIBILITY_DEFAULT | WASM_SYMBOL_EXPORTED, + make(nullSignature, "__wasm_apply_data_relocs")); + } } static void createOptionalSymbols() { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index fa9802d477d55..8eed209ba2172 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1018,17 +1018,6 @@ void Writer::createSyntheticInitFunctions() { WasmSym::tlsBase->markLive(); } - if (config->isPic || - config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) { - // For PIC code, or when dynamically importing addresses, we create - // synthetic functions that apply relocations. These get called from - // __wasm_call_ctors before the user-level constructors. - WasmSym::applyDataRelocs = symtab->addSyntheticFunction( - "__wasm_apply_data_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, - make(nullSignature, "__wasm_apply_data_relocs")); - WasmSym::applyDataRelocs->markLive(); - } - if (config->isPic && out.globalSec->needsRelocations()) { WasmSym::applyGlobalRelocs = symtab->addSyntheticFunction( "__wasm_apply_global_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, @@ -1298,8 +1287,8 @@ void Writer::createStartFunction() { // For -shared (PIC) output, we create create a synthetic function which will // apply any relocations to the data segments on startup. This function is -// called `__wasm_apply_data_relocs` and is added at the beginning of -// `__wasm_call_ctors` before any of the constructors run. +// called `__wasm_apply_data_relocs` and is expected to be called before +// any user code (i.e. before `__wasm_call_ctors`). void Writer::createApplyDataRelocationsFunction() { LLVM_DEBUG(dbgs() << "createApplyDataRelocationsFunction\n"); // First write the body's contents to a string. @@ -1352,11 +1341,9 @@ void Writer::createApplyGlobalTLSRelocationsFunction() { // Create synthetic "__wasm_call_ctors" function based on ctor functions // in input object. void Writer::createCallCtorsFunction() { - // If __wasm_call_ctors isn't referenced, there aren't any ctors, and we - // aren't calling `__wasm_apply_data_relocs` for Emscripten-style PIC, don't + // If __wasm_call_ctors isn't referenced, there aren't any ctors, don't // define the `__wasm_call_ctors` function. - if (!WasmSym::callCtors->isLive() && !WasmSym::applyDataRelocs && - initFunctions.empty()) + if (!WasmSym::callCtors->isLive() && initFunctions.empty()) return; // First write the body's contents to a string. @@ -1365,12 +1352,6 @@ void Writer::createCallCtorsFunction() { raw_string_ostream os(bodyContent); writeUleb128(os, 0, "num locals"); - if (WasmSym::applyDataRelocs) { - writeU8(os, WASM_OPCODE_CALL, "CALL"); - writeUleb128(os, WasmSym::applyDataRelocs->getFunctionIndex(), - "function index"); - } - // Call constructors for (const WasmInitEntry &f : initFunctions) { writeU8(os, WASM_OPCODE_CALL, "CALL");