From 4b24e9be175d75c92e5adb40622fd7524abcef60 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 17 Oct 2022 13:36:19 -0700 Subject: [PATCH] [wasm-ld] Define a `__heap_end` symbol marking the end of allocated memory. Define a `__heap_end` symbol that marks the end of the memory region that starts at `__heap_base`. This will allow malloc implementations to know how much memory they can use at `__heap_base` even if someone has done a `memory.grow` before they can initialize their state. Differential Revision: https://reviews.llvm.org/D136110 --- lld/test/wasm/export-all.s | 7 +++++-- lld/test/wasm/mutable-global-exports.s | 7 +++++-- lld/wasm/Driver.cpp | 1 + lld/wasm/Symbols.cpp | 1 + lld/wasm/Symbols.h | 11 +++++++---- lld/wasm/Writer.cpp | 16 +++++++++++++--- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/lld/test/wasm/export-all.s b/lld/test/wasm/export-all.s index fa016a3..617dcc4 100644 --- a/lld/test/wasm/export-all.s +++ b/lld/test/wasm/export-all.s @@ -46,9 +46,12 @@ foo: # CHECK-NEXT: - Name: __heap_base # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: Index: 6 -# CHECK-NEXT: - Name: __memory_base +# CHECK-NEXT: - Name: __heap_end # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: Index: 7 -# CHECK-NEXT: - Name: __table_base +# CHECK-NEXT: - Name: __memory_base # CHECK-NEXT: Kind: GLOBAL # CHECK-NEXT: Index: 8 +# CHECK-NEXT: - Name: __table_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: Index: 9 diff --git a/lld/test/wasm/mutable-global-exports.s b/lld/test/wasm/mutable-global-exports.s index c85c21f..135559d 100644 --- a/lld/test/wasm/mutable-global-exports.s +++ b/lld/test/wasm/mutable-global-exports.s @@ -92,12 +92,15 @@ _start: # CHECK-ALL-NEXT: - Name: __heap_base # CHECK-ALL-NEXT: Kind: GLOBAL # CHECK-ALL-NEXT: Index: 7 -# CHECK-ALL-NEXT: - Name: __memory_base +# CHECK-ALL-NEXT: - Name: __heap_end # CHECK-ALL-NEXT: Kind: GLOBAL # CHECK-ALL-NEXT: Index: 8 -# CHECK-ALL-NEXT: - Name: __table_base +# CHECK-ALL-NEXT: - Name: __memory_base # CHECK-ALL-NEXT: Kind: GLOBAL # CHECK-ALL-NEXT: Index: 9 +# CHECK-ALL-NEXT: - Name: __table_base +# CHECK-ALL-NEXT: Kind: GLOBAL +# CHECK-ALL-NEXT: Index: 10 # CHECK-ALL-NEXT: - Type: CODE # CHECK-ALL: Name: target_features diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index cb41cf6..82d5720 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -736,6 +736,7 @@ static void createOptionalSymbols() { 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"); if (config->is64.value_or(false)) diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp index 71f0fb1..c6f6e04 100644 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -84,6 +84,7 @@ DefinedData *WasmSym::dsoHandle; DefinedData *WasmSym::dataEnd; DefinedData *WasmSym::globalBase; DefinedData *WasmSym::heapBase; +DefinedData *WasmSym::heapEnd; DefinedData *WasmSym::initMemoryFlag; GlobalSymbol *WasmSym::stackPointer; DefinedData *WasmSym::stackLow; diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index 98aae86..ee6c5db 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -541,11 +541,14 @@ struct WasmSym { // Symbol marking the end of the data and bss. static DefinedData *dataEnd; - // __heap_base - // Symbol marking the end of the data, bss and explicit stack. Any linear - // memory following this address is not used by the linked code and can - // therefore be used as a backing store for brk()/malloc() implementations. + // __heap_base/__heap_end + // Symbols marking the beginning and end of the "heap". It starts at the end + // of the data, bss and explicit stack, and extends to the end of the linear + // memory allocated by wasm-ld. This region of memory is not used by the + // linked code, so it may be used as a backing store for `sbrk` or `malloc` + // implementations. static DefinedData *heapBase; + static DefinedData *heapEnd; // __wasm_init_memory_flag // Symbol whose contents are nonzero iff memory has already been initialized. diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 47ac23f..d74ffa5 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -344,10 +344,20 @@ void Writer::layoutMemory() { Twine(maxMemorySetting)); memoryPtr = config->initialMemory; } - out.memorySec->numMemoryPages = - alignTo(memoryPtr, WasmPageSize) / WasmPageSize; + + memoryPtr = alignTo(memoryPtr, WasmPageSize); + + out.memorySec->numMemoryPages = memoryPtr / WasmPageSize; log("mem: total pages = " + Twine(out.memorySec->numMemoryPages)); + if (WasmSym::heapEnd) { + // Set `__heap_end` to follow the end of the statically allocated linear + // memory. The fact that this comes last means that a malloc/brk + // implementation can grow the heap at runtime. + log("mem: heap end = " + Twine(memoryPtr)); + WasmSym::heapEnd->setVA(memoryPtr); + } + if (config->maxMemory != 0) { if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize)) error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned"); @@ -367,7 +377,7 @@ void Writer::layoutMemory() { if (config->isPic) max = maxMemorySetting; else - max = alignTo(memoryPtr, WasmPageSize); + max = memoryPtr; } out.memorySec->maxMemoryPages = max / WasmPageSize; log("mem: max pages = " + Twine(out.memorySec->maxMemoryPages)); -- 2.7.4