From: Ayke van Laethem Date: Wed, 21 Jul 2021 21:35:10 +0000 (+0200) Subject: [lld][WebAssembly] Align __heap_base X-Git-Tag: llvmorg-14-init~382 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=13ca0c87edd026813ef7cbf3fbeb0efdb9c8bd3c;p=platform%2Fupstream%2Fllvm.git [lld][WebAssembly] Align __heap_base __heap_base was not aligned. In practice, it will often be aligned simply because it follows the stack, but when the stack is placed at the beginning (with the --stack-first option), the __heap_base might be unaligned. It could even be byte-aligned. At least wasi-libc appears to expect that __heap_base is aligned: https://github.com/WebAssembly/wasi-libc/blob/659ff414560721b1660a19685110e484a081c3d4/dlmalloc/src/malloc.c#L5224 While WebAssembly itself does not appear to require any alignment for memory accesses, it is sometimes required when sharing a pointer externally. For example, WASI might expect alignment up to 8: https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-timestamp-u64 This issue got introduced with the addition of the --stack-first flag: https://reviews.llvm.org/D46141 I suspect the lack of alignment wasn't intentional here. Differential Revision: https://reviews.llvm.org/D106499 --- diff --git a/lld/test/wasm/Inputs/stack-first.s b/lld/test/wasm/Inputs/stack-first.s new file mode 100644 index 0000000..a2a356b --- /dev/null +++ b/lld/test/wasm/Inputs/stack-first.s @@ -0,0 +1,11 @@ + .globl _start +_start: + .functype _start () -> () + end_function + + .globl someByte + .type someByte,@object + .section .data.someByte,"",@ +someByte: + .int8 42 + .size someByte, 1 diff --git a/lld/test/wasm/stack-first.test b/lld/test/wasm/stack-first.test index 9d7f077..72e1a00 100644 --- a/lld/test/wasm/stack-first.test +++ b/lld/test/wasm/stack-first.test @@ -2,9 +2,10 @@ ; memory. In this case the --stack-first option is being passed along with a ; stack size of 512. This means (since the stack grows down) the stack pointer ; global should be initialized to 512. +; Also test that __heap_base is still aligned with the --stack-first option. -RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/start.s -o %t.o -RUN: wasm-ld -z stack-size=512 --stack-first --export=__data_end --export=__heap_base -o %t.wasm %t.o +RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/stack-first.s -o %t.o +RUN: wasm-ld -z stack-size=512 --stack-first --export=__data_end --export=__heap_base --export=someByte -o %t.wasm %t.o RUN: obj2yaml %t.wasm | FileCheck %s CHECK: - Type: GLOBAL @@ -26,7 +27,13 @@ CHECK-NEXT: Type: I32 CHECK-NEXT: Mutable: false CHECK-NEXT: InitExpr: CHECK-NEXT: Opcode: I32_CONST -CHECK-NEXT: Value: 512 +CHECK-NEXT: Value: 513 +CHECK-NEXT: - Index: 3 +CHECK-NEXT: Type: I32 +CHECK-NEXT: Mutable: false +CHECK-NEXT: InitExpr: +CHECK-NEXT: Opcode: I32_CONST +CHECK-NEXT: Value: 528 CHECK-NEXT: - Type: EXPORT CHECK-NEXT: Exports: CHECK-NEXT: - Name: memory @@ -35,9 +42,12 @@ CHECK-NEXT: Index: 0 CHECK-NEXT: - Name: _start CHECK-NEXT: Kind: FUNCTION CHECK-NEXT: Index: 0 -CHECK-NEXT: - Name: __data_end +CHECK-NEXT: - Name: someByte CHECK-NEXT: Kind: GLOBAL CHECK-NEXT: Index: 1 -CHECK-NEXT: - Name: __heap_base +CHECK-NEXT: - Name: __data_end CHECK-NEXT: Kind: GLOBAL CHECK-NEXT: Index: 2 +CHECK-NEXT: - Name: __heap_base +CHECK-NEXT: Kind: GLOBAL +CHECK-NEXT: Index: 3 diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index e94ea17..cf9356b 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -43,6 +43,7 @@ using namespace llvm::wasm; namespace lld { namespace wasm { static constexpr int stackAlignment = 16; +static constexpr int heapAlignment = 16; namespace { @@ -310,9 +311,12 @@ void Writer::layoutMemory() { placeStack(); if (WasmSym::heapBase) { - // Set `__heap_base` to directly follow the end of the stack or global data. - // The fact that this comes last means that a malloc/brk implementation - // can grow the heap at runtime. + // Set `__heap_base` to follow the end of the stack or global data. The + // fact that this comes last means that a malloc/brk implementation can + // grow the heap at runtime. + // We'll align the heap base here because memory allocators might expect + // __heap_base to be aligned already. + memoryPtr = alignTo(memoryPtr, heapAlignment); log("mem: heap base = " + Twine(memoryPtr)); WasmSym::heapBase->setVA(memoryPtr); }