; PASSIVE-NEXT: Name: __wasm_init_memory
; PASSIVE-PIC: - Type: START
-; PASSIVE-PIC-NEXT: StartFunction: 3
+; PASSIVE-PIC-NEXT: StartFunction: 2
; PASSIVE-PIC-NEXT: - Type: DATACOUNT
; PASSIVE-PIC-NEXT: Count: 1
; PASSIVE-PIC-NEXT: - Type: CODE
; PASSIVE-PIC-NEXT: Functions:
; PASSIVE-PIC-NEXT: - Index: 0
; PASSIVE-PIC-NEXT: Locals: []
-; PASSIVE-PIC-NEXT: Body: 10010B
+; PASSIVE-PIC-NEXT: Body: 10030B
; PASSIVE-PIC-NEXT: - Index: 1
; PASSIVE-PIC-NEXT: Locals: []
; PASSIVE-PIC-NEXT: Body: 0B
; 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: 1
; PASSIVE32-PIC-NEXT: Body: 230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
; PASSIVE64-PIC-NEXT: Body: 230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
+; 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: 4
; PASSIVE-PIC-NEXT: - Index: 0
; PASSIVE-PIC-NEXT: Name: __wasm_call_ctors
; PASSIVE-PIC-NEXT: - Index: 1
-; PASSIVE-PIC-NEXT: Name: __wasm_apply_relocs
-; PASSIVE-PIC-NEXT: - Index: 2
; PASSIVE-PIC-NEXT: Name: __wasm_init_tls
-; PASSIVE-PIC-NEXT: - Index: 3
+; 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
; RUN: llc -relocation-model=pic -mattr=+mutable-globals -filetype=obj %s -o %t.o
; RUN: wasm-ld --no-gc-sections --allow-undefined --experimental-pic -pie -o %t.wasm %t.o
-; RUN: obj2yaml %t.wasm | FileCheck %s
target triple = "wasm32-unknown-emscripten"
; CHECK-NEXT: GlobalType: I32
; CHECK-NEXT: GlobalMutable: false
+; CHECK: - Type: START
+; CHECK-NEXT: StartFunction: 2
+
+; CHECK: - Type: CUSTOM
+; CHECK-NEXT: Name: name
+; CHECK-NEXT: FunctionNames:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Name: __wasm_call_ctors
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: __wasm_apply_data_relocs
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: __wasm_apply_global_relocs
+
+
+; Run the same test with threading support. In this mode
+; we expect __wasm_init_memory and __wasm_apply_data_relocs
+; to be generated along with __wasm_start as the start
+; function.
+
+; RUN: llc -relocation-model=pic -mattr=+mutable-globals,+atomics,+bulk-memory -filetype=obj %s -o %t.shmem.o
+; RUN: wasm-ld --no-gc-sections --shared-memory --allow-undefined --experimental-pic -pie -o %t.shmem.wasm %t.shmem.o
+; RUN: obj2yaml %t.shmem.wasm | FileCheck %s --check-prefix=SHMEM
+
+; SHMEM: - Type: CODE
+; SHMEM: - Index: 5
+; SHMEM-NEXT: Locals: []
+; SHMEM-NEXT: Body: 100210040B
+
+; SHMEM: FunctionNames:
+; SHMEM-NEXT: - Index: 0
+; SHMEM-NEXT: Name: __wasm_call_ctors
+; SHMEM-NEXT: - Index: 1
+; SHMEM-NEXT: Name: __wasm_init_tls
+; SHMEM-NEXT: - Index: 2
+; SHMEM-NEXT: Name: __wasm_init_memory
+; SHMEM-NEXT: - Index: 3
+; SHMEM-NEXT: Name: __wasm_apply_data_relocs
+; SHMEM-NEXT: - Index: 4
+; SHMEM-NEXT: Name: __wasm_apply_global_relocs
+; SHMEM-NEXT: - Index: 5
+; SHMEM-NEXT: Name: __wasm_start
+; SHMEM-NEXT: - Index: 6
+; SHMEM-NEXT: Name: foo
+; SHMEM-NEXT: - Index: 7
+; SHMEM-NEXT: Name: get_data_address
+; SHMEM-NEXT: - Index: 8
+; SHMEM-NEXT: Name: _start
void createSyntheticInitFunctions();
void createInitMemoryFunction();
- void createApplyRelocationsFunction();
+ void createStartFunction();
+ void createApplyDataRelocationsFunction();
+ void createApplyGlobalRelocationsFunction();
void createCallCtorsFunction();
void createInitTLSFunction();
void createCommandExportWrappers();
}
// Make space for the memory initialization flag
- if (WasmSym::initMemoryFlag) {
+ if (config->sharedMemory && hasPassiveInitializedSegments()) {
memoryPtr = alignTo(memoryPtr, 4);
+ WasmSym::initMemoryFlag = symtab->addSyntheticDataSymbol(
+ "__wasm_init_memory_flag", WASM_SYMBOL_VISIBILITY_HIDDEN);
+ WasmSym::initMemoryFlag->markLive();
WasmSym::initMemoryFlag->setVirtualAddress(memoryPtr);
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}",
"__wasm_init_memory_flag", memoryPtr, 4, 4));
}
void Writer::createSyntheticInitFunctions() {
+ if (config->relocatable)
+ return;
+
+ static WasmSignature nullSignature = {{}, {}};
+
// Passive segments are used to avoid memory being reinitialized on each
// thread's instantiation. These passive segments are initialized and
// dropped in __wasm_init_memory, which is registered as the start function
-
if (config->sharedMemory && hasPassiveInitializedSegments()) {
- static WasmSignature nullSignature = {{}, {}};
WasmSym::initMemory = symtab->addSyntheticFunction(
"__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN,
make<SyntheticFunction>(nullSignature, "__wasm_init_memory"));
WasmSym::initMemory->markLive();
- WasmSym::initMemoryFlag = symtab->addSyntheticDataSymbol(
- "__wasm_init_memory_flag", WASM_SYMBOL_VISIBILITY_HIDDEN);
- WasmSym::initMemoryFlag->markLive();
+ }
+
+ if (config->isPic) {
+ // For PIC code 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<SyntheticFunction>(nullSignature, "__wasm_apply_data_relocs"));
+ WasmSym::applyDataRelocs->markLive();
+
+ if (out.globalSec->needsRelocations()) {
+ WasmSym::applyGlobalRelocs = symtab->addSyntheticFunction(
+ "__wasm_apply_global_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
+ make<SyntheticFunction>(nullSignature, "__wasm_apply_global_relocs"));
+ WasmSym::applyGlobalRelocs->markLive();
+ }
+ }
+
+ if (WasmSym::applyGlobalRelocs && WasmSym::initMemory) {
+ WasmSym::startFunction = symtab->addSyntheticFunction(
+ "__wasm_start", WASM_SYMBOL_VISIBILITY_HIDDEN,
+ make<SyntheticFunction>(nullSignature, "__wasm_start"));
+ WasmSym::startFunction->markLive();
}
}
createFunction(WasmSym::initMemory, bodyContent);
}
+void Writer::createStartFunction() {
+ if (WasmSym::startFunction) {
+ std::string bodyContent;
+ {
+ raw_string_ostream os(bodyContent);
+ writeUleb128(os, 0, "num locals");
+ writeU8(os, WASM_OPCODE_CALL, "CALL");
+ writeUleb128(os, WasmSym::initMemory->getFunctionIndex(),
+ "function index");
+ writeU8(os, WASM_OPCODE_CALL, "CALL");
+ writeUleb128(os, WasmSym::applyGlobalRelocs->getFunctionIndex(),
+ "function index");
+ writeU8(os, WASM_OPCODE_END, "END");
+ }
+ createFunction(WasmSym::startFunction, bodyContent);
+ } else if (WasmSym::initMemory) {
+ WasmSym::startFunction = WasmSym::initMemory;
+ } else if (WasmSym::applyGlobalRelocs) {
+ WasmSym::startFunction = WasmSym::applyGlobalRelocs;
+ }
+}
+
// 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_relocs and is added at the beginning of __wasm_call_ctors
// before any of the constructors run.
-void Writer::createApplyRelocationsFunction() {
- LLVM_DEBUG(dbgs() << "createApplyRelocationsFunction\n");
+void Writer::createApplyDataRelocationsFunction() {
+ LLVM_DEBUG(dbgs() << "createApplyDataRelocationsFunction\n");
// First write the body's contents to a string.
std::string bodyContent;
{
raw_string_ostream os(bodyContent);
writeUleb128(os, 0, "num locals");
-
- // First apply relocations to any internalized GOT entries. These
- // are the result of relaxation when building with -Bsymbolic.
- out.globalSec->generateRelocationCode(os);
-
- // Next apply any realocation to the data section by reading GOT entry
- // globals.
for (const OutputSegment *seg : segments)
for (const InputSegment *inSeg : seg->inputSegments)
inSeg->generateRelocationCode(os);
writeU8(os, WASM_OPCODE_END, "END");
}
- createFunction(WasmSym::applyRelocs, bodyContent);
+ createFunction(WasmSym::applyDataRelocs, bodyContent);
+}
+
+// Similar to createApplyDataRelocationsFunction but generates relocation code
+// fro WebAssembly globals. Because these globals are not shared between threads
+// these relocation need to run on every thread.
+void Writer::createApplyGlobalRelocationsFunction() {
+ // First write the body's contents to a string.
+ std::string bodyContent;
+ {
+ raw_string_ostream os(bodyContent);
+ writeUleb128(os, 0, "num locals");
+ out.globalSec->generateRelocationCode(os);
+ writeU8(os, WASM_OPCODE_END, "END");
+ }
+
+ createFunction(WasmSym::applyGlobalRelocs, bodyContent);
}
// Create synthetic "__wasm_call_ctors" function based on ctor functions
// If __wasm_call_ctors isn't referenced, there aren't any ctors, and we
// aren't calling `__wasm_apply_relocs` for Emscripten-style PIC, don't
// define the `__wasm_call_ctors` function.
- if (!WasmSym::callCtors->isLive() && initFunctions.empty() && !config->isPic)
+ if (!WasmSym::callCtors->isLive() && !WasmSym::applyDataRelocs &&
+ initFunctions.empty())
return;
// First write the body's contents to a string.
raw_string_ostream os(bodyContent);
writeUleb128(os, 0, "num locals");
- if (config->isPic) {
+ if (WasmSym::applyDataRelocs) {
writeU8(os, WASM_OPCODE_CALL, "CALL");
- writeUleb128(os, WasmSym::applyRelocs->getFunctionIndex(),
+ writeUleb128(os, WasmSym::applyDataRelocs->getFunctionIndex(),
"function index");
}
writeU8(os, WASM_OPCODE_DROP, "DROP");
}
}
+
writeU8(os, WASM_OPCODE_END, "END");
}
// If we have any ctors, or we're calling `__wasm_apply_relocs` for
// Emscripten-style PIC, call `__wasm_call_ctors` which performs those
// calls.
- if (!initFunctions.empty() || config->isPic) {
+ if (WasmSym::callCtors->isLive()) {
writeU8(os, WASM_OPCODE_CALL, "CALL");
writeUleb128(os, WasmSym::callCtors->getFunctionIndex(),
"function index");
populateProducers();
log("-- calculateImports");
calculateImports();
- log("-- createSyntheticInitFunctions");
- createSyntheticInitFunctions();
log("-- layoutMemory");
layoutMemory();
log("-- scanRelocations");
scanRelocations();
+ log("-- createSyntheticInitFunctions");
+ createSyntheticInitFunctions();
log("-- assignIndexes");
assignIndexes();
log("-- calculateInitFunctions");
calculateInitFunctions();
if (!config->relocatable) {
- if (WasmSym::applyRelocs)
- createApplyRelocationsFunction();
+ // Create linker synthesized functions
+ if (WasmSym::applyDataRelocs)
+ createApplyDataRelocationsFunction();
+ if (WasmSym::applyGlobalRelocs)
+ createApplyGlobalRelocationsFunction();
if (WasmSym::initMemory)
createInitMemoryFunction();
+ createStartFunction();
- // Create linker synthesized functions
createCallCtorsFunction();
// Create export wrappers for commands if needed.