From 4ce4fe223091fe461384a36f476fae48e7d854d1 Mon Sep 17 00:00:00 2001 From: Ethan O'Brien Date: Wed, 21 Aug 2024 08:56:25 -0500 Subject: [PATCH 1/8] Implement wip WebAssembly function alignment --- lld/wasm/SyntheticSections.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index f02f55519a251..13333a6737868 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -563,8 +563,24 @@ void ElemSection::addEntry(FunctionSymbol *sym) { // They only exist so that the calls to missing functions can validate. if (sym->hasTableIndex() || sym->isStub) return; + + uint32_t padding = 0; + uint64_t alignment = 1; + + if (indirectFunctions.size() == 0 && padding > 0) { + for (uint32_t i=0; isetTableIndex(config->tableBase + indirectFunctions.size()); indirectFunctions.emplace_back(sym); + + if (alignment > 1) { + for (uint32_t i=0; itableBase; for (const FunctionSymbol *sym : indirectFunctions) { + if (sym == nullptr) { + (void) tableIndex; + writeUleb128(os, 0, "function index"); + ++tableIndex; + continue; + } assert(sym->getTableIndex() == tableIndex); (void) tableIndex; writeUleb128(os, sym->getFunctionIndex(), "function index"); From d8df549f879794fa206080e97426e2937e71f1cb Mon Sep 17 00:00:00 2001 From: Ethan O'Brien Date: Mon, 30 Dec 2024 10:33:15 -0800 Subject: [PATCH 2/8] [wasm] Add function-pointer-alignment function --- lld/wasm/Config.h | 1 + lld/wasm/Driver.cpp | 1 + lld/wasm/Options.td | 3 +++ lld/wasm/SyntheticSections.cpp | 13 ++----------- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h index 0c2ba3eebffc4..970e9243dad3d 100644 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -93,6 +93,7 @@ struct Config { // for shared libraries (since they always added to a dynamic offset at // runtime). uint64_t tableBase; + uint64_t functionPointerAlignment; uint64_t zStackSize; unsigned ltoPartitions; unsigned ltoo; diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 02471950fb519..225785329f8f3 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -638,6 +638,7 @@ static void readConfigs(opt::InputArgList &args) { LLVM_DEBUG(errorHandler().verbose = true); config->tableBase = args::getInteger(args, OPT_table_base, 0); + config->functionPointerAlignment = args::getInteger(args, OPT_function_pointer_alignment, 0); config->globalBase = args::getInteger(args, OPT_global_base, 0); config->initialHeap = args::getInteger(args, OPT_initial_heap, 0); config->initialMemory = args::getInteger(args, OPT_initial_memory, 0); diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index 1316dc5c70d93..b43ff513b89b6 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -251,6 +251,9 @@ def stack_first: FF<"stack-first">, def table_base: JJ<"table-base=">, HelpText<"Table offset at which to place address taken functions (Defaults to 1)">; +def function_pointer_alignment: JJ<"function-pointer-alignment=">, + HelpText<"Align function pointers at a given value (Defaults to 1)">; + defm whole_archive: B<"whole-archive", "Force load of all members in a static library", "Do not force load of all members in a static library (default)">; diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 5292915d885a6..a0c347651dbf8 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -567,20 +567,11 @@ void ElemSection::addEntry(FunctionSymbol *sym) { if (sym->hasTableIndex() || sym->isStub) return; - uint32_t padding = 0; - uint64_t alignment = 1; - - if (indirectFunctions.size() == 0 && padding > 0) { - for (uint32_t i=0; isetTableIndex(config->tableBase + indirectFunctions.size()); indirectFunctions.emplace_back(sym); - if (alignment > 1) { - for (uint32_t i=0; ifunctionPointerAlignment > 1) { + for (uint32_t i=0; ifunctionPointerAlignment-1; i++) { indirectFunctions.push_back(nullptr); } } From 983433dc9b196e8a0d42c74f04438df535401db8 Mon Sep 17 00:00:00 2001 From: Ethan O'Brien Date: Tue, 21 Jan 2025 22:10:04 -0600 Subject: [PATCH 3/8] Requested changes --- lld/wasm/Driver.cpp | 3 ++- lld/wasm/SyntheticSections.cpp | 13 +++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index d8fd2b7820d8b..4a0e923868b25 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -636,7 +636,8 @@ static void readConfigs(opt::InputArgList &args) { LLVM_DEBUG(errorHandler().verbose = true); ctx.arg.tableBase = args::getInteger(args, OPT_table_base, 0); - ctx.arg.functionPointerAlignment = args::getInteger(args, OPT_function_pointer_alignment, 0); + ctx.arg.functionPointerAlignment = + args::getInteger(args, OPT_function_pointer_alignment, 0); ctx.arg.globalBase = args::getInteger(args, OPT_global_base, 0); ctx.arg.initialHeap = args::getInteger(args, OPT_initial_heap, 0); ctx.arg.initialMemory = args::getInteger(args, OPT_initial_memory, 0); diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 3fcef7cb3db2c..96126fe47c9f2 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -569,8 +569,9 @@ void ElemSection::addEntry(FunctionSymbol *sym) { sym->setTableIndex(ctx.arg.tableBase + indirectFunctions.size()); indirectFunctions.emplace_back(sym); + // Pad with null function pointers if alignment is requesting. if (ctx.arg.functionPointerAlignment > 1) { - for (uint32_t i=0; igetTableIndex() == tableIndex); } - assert(sym->getTableIndex() == tableIndex); (void) tableIndex; - writeUleb128(os, sym->getFunctionIndex(), "function index"); + writeUleb128(os, sym ? sym->getFunctionIndex() : 0, "function index"); ++tableIndex; } } From bbaf4e41080104004809c07cc14aecfe41bef0b5 Mon Sep 17 00:00:00 2001 From: Ethan O'Brien <77750390+ethanaobrien@users.noreply.github.com> Date: Tue, 21 Jan 2025 22:14:15 -0600 Subject: [PATCH 4/8] Correct indentation --- lld/wasm/SyntheticSections.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 96126fe47c9f2..dd130cc455f7f 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -612,7 +612,7 @@ void ElemSection::writeBody() { uint32_t tableIndex = ctx.arg.tableBase; for (const FunctionSymbol *sym : indirectFunctions) { if (sym != nullptr) { - assert(sym->getTableIndex() == tableIndex); + assert(sym->getTableIndex() == tableIndex); } (void) tableIndex; writeUleb128(os, sym ? sym->getFunctionIndex() : 0, "function index"); From a10be0216f55f1f11ea6e36a5a7182d8b5c72f5b Mon Sep 17 00:00:00 2001 From: Ethan O'Brien Date: Sun, 11 May 2025 22:58:31 -0500 Subject: [PATCH 5/8] Add tests --- lld/test/wasm/function-pointer-alignmnet.s | 237 +++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 lld/test/wasm/function-pointer-alignmnet.s diff --git a/lld/test/wasm/function-pointer-alignmnet.s b/lld/test/wasm/function-pointer-alignmnet.s new file mode 100644 index 0000000000000..9a95b69399951 --- /dev/null +++ b/lld/test/wasm/function-pointer-alignmnet.s @@ -0,0 +1,237 @@ +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.o + +# RUN: wasm-ld -o %t.wasm %t.o +# RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=CHECK-DEFAULT + +# RUN: wasm-ld --function-pointer-alignment=2 -o %t.wasm %t.o +# RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=CHECK-2 + +# RUN: wasm-ld --function-pointer-alignment=3 -o %t.wasm %t.o +# RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=CHECK-3 + +.functype func1 () -> () +.functype func2 () -> () + +.globl _start +_start: + .functype _start () -> () + i32.const func1 + drop + i32.const func2 + drop + end_function + +.globl func1 +func1: + .functype func1 () -> () + end_function + +.globl func2 +func2: + .functype func2 () -> () + end_function + + +# CHECK-DEFAULT: --- !WASM +# CHECK-DEFAULT-NEXT: FileHeader: +# CHECK-DEFAULT-NEXT: Version: 0x1 +# CHECK-DEFAULT-NEXT: Sections: +# CHECK-DEFAULT-NEXT: - Type: TYPE +# CHECK-DEFAULT-NEXT: Signatures: +# CHECK-DEFAULT-NEXT: - Index: 0 +# CHECK-DEFAULT-NEXT: ParamTypes: [] +# CHECK-DEFAULT-NEXT: ReturnTypes: [] +# CHECK-DEFAULT-NEXT: - Type: FUNCTION +# CHECK-DEFAULT-NEXT: FunctionTypes: [ 0, 0, 0 ] +# CHECK-DEFAULT-NEXT: - Type: TABLE +# CHECK-DEFAULT-NEXT: Tables: +# CHECK-DEFAULT-NEXT: - Index: 0 +# CHECK-DEFAULT-NEXT: ElemType: FUNCREF +# CHECK-DEFAULT-NEXT: Limits: +# CHECK-DEFAULT-NEXT: Flags: [ HAS_MAX ] +# CHECK-DEFAULT-NEXT: Minimum: 0x3 +# CHECK-DEFAULT-NEXT: Maximum: 0x3 +# CHECK-DEFAULT-NEXT: - Type: MEMORY +# CHECK-DEFAULT-NEXT: Memories: +# CHECK-DEFAULT-NEXT: - Minimum: 0x2 +# CHECK-DEFAULT-NEXT: - Type: GLOBAL +# CHECK-DEFAULT-NEXT: Globals: +# CHECK-DEFAULT-NEXT: - Index: 0 +# CHECK-DEFAULT-NEXT: Type: I32 +# CHECK-DEFAULT-NEXT: Mutable: true +# CHECK-DEFAULT-NEXT: InitExpr: +# CHECK-DEFAULT-NEXT: Opcode: I32_CONST +# CHECK-DEFAULT-NEXT: Value: 66560 +# CHECK-DEFAULT-NEXT: - Type: EXPORT +# CHECK-DEFAULT-NEXT: Exports: +# CHECK-DEFAULT-NEXT: - Name: memory +# CHECK-DEFAULT-NEXT: Kind: MEMORY +# CHECK-DEFAULT-NEXT: Index: 0 +# CHECK-DEFAULT-NEXT: - Name: _start +# CHECK-DEFAULT-NEXT: Kind: FUNCTION +# CHECK-DEFAULT-NEXT: Index: 0 +# CHECK-DEFAULT-NEXT: - Type: ELEM +# CHECK-DEFAULT-NEXT: Segments: +# CHECK-DEFAULT-NEXT: - Offset: +# CHECK-DEFAULT-NEXT: Opcode: I32_CONST +# CHECK-DEFAULT-NEXT: Value: 1 +# CHECK-DEFAULT-NEXT: Functions: [ 1, 2 ] +# CHECK-DEFAULT-NEXT: - Type: CODE +# CHECK-DEFAULT-NEXT: Functions: +# CHECK-DEFAULT-NEXT: - Index: 0 +# CHECK-DEFAULT-NEXT: Locals: [] +# CHECK-DEFAULT-NEXT: Body: 4181808080001A4182808080001A0B +# CHECK-DEFAULT-NEXT: - Index: 1 +# CHECK-DEFAULT-NEXT: Locals: [] +# CHECK-DEFAULT-NEXT: Body: 0B +# CHECK-DEFAULT-NEXT: - Index: 2 +# CHECK-DEFAULT-NEXT: Locals: [] +# CHECK-DEFAULT-NEXT: Body: 0B +# CHECK-DEFAULT-NEXT: - Type: CUSTOM +# CHECK-DEFAULT-NEXT: Name: name +# CHECK-DEFAULT-NEXT: FunctionNames: +# CHECK-DEFAULT-NEXT: - Index: 0 +# CHECK-DEFAULT-NEXT: Name: _start +# CHECK-DEFAULT-NEXT: - Index: 1 +# CHECK-DEFAULT-NEXT: Name: func1 +# CHECK-DEFAULT-NEXT: - Index: 2 +# CHECK-DEFAULT-NEXT: Name: func2 +# CHECK-DEFAULT-NEXT: GlobalNames: +# CHECK-DEFAULT-NEXT: - Index: 0 +# CHECK-DEFAULT-NEXT: Name: __stack_pointer + +# CHECK-2: --- !WASM +# CHECK-2-NEXT: FileHeader: +# CHECK-2-NEXT: Version: 0x1 +# CHECK-2-NEXT: Sections: +# CHECK-2-NEXT: - Type: TYPE +# CHECK-2-NEXT: Signatures: +# CHECK-2-NEXT: - Index: 0 +# CHECK-2-NEXT: ParamTypes: [] +# CHECK-2-NEXT: ReturnTypes: [] +# CHECK-2-NEXT: - Type: FUNCTION +# CHECK-2-NEXT: FunctionTypes: [ 0, 0, 0 ] +# CHECK-2-NEXT: - Type: TABLE +# CHECK-2-NEXT: Tables: +# CHECK-2-NEXT: - Index: 0 +# CHECK-2-NEXT: ElemType: FUNCREF +# CHECK-2-NEXT: Limits: +# CHECK-2-NEXT: Flags: [ HAS_MAX ] +# CHECK-2-NEXT: Minimum: 0x4 +# CHECK-2-NEXT: Maximum: 0x4 +# CHECK-2-NEXT: - Type: MEMORY +# CHECK-2-NEXT: Memories: +# CHECK-2-NEXT: - Minimum: 0x2 +# CHECK-2-NEXT: - Type: GLOBAL +# CHECK-2-NEXT: Globals: +# CHECK-2-NEXT: - Index: 0 +# CHECK-2-NEXT: Type: I32 +# CHECK-2-NEXT: Mutable: true +# CHECK-2-NEXT: InitExpr: +# CHECK-2-NEXT: Opcode: I32_CONST +# CHECK-2-NEXT: Value: 66560 +# CHECK-2-NEXT: - Type: EXPORT +# CHECK-2-NEXT: Exports: +# CHECK-2-NEXT: - Name: memory +# CHECK-2-NEXT: Kind: MEMORY +# CHECK-2-NEXT: Index: 0 +# CHECK-2-NEXT: - Name: _start +# CHECK-2-NEXT: Kind: FUNCTION +# CHECK-2-NEXT: Index: 0 +# CHECK-2-NEXT: - Type: ELEM +# CHECK-2-NEXT: Segments: +# CHECK-2-NEXT: - Offset: +# CHECK-2-NEXT: Opcode: I32_CONST +# CHECK-2-NEXT: Value: 1 +# CHECK-2-NEXT: Functions: [ 1, 2, 0 ] +# CHECK-2-NEXT: - Type: CODE +# CHECK-2-NEXT: Functions: +# CHECK-2-NEXT: - Index: 0 +# CHECK-2-NEXT: Locals: [] +# CHECK-2-NEXT: Body: 4181808080001A4182808080001A0B +# CHECK-2-NEXT: - Index: 1 +# CHECK-2-NEXT: Locals: [] +# CHECK-2-NEXT: Body: 0B +# CHECK-2-NEXT: - Index: 2 +# CHECK-2-NEXT: Locals: [] +# CHECK-2-NEXT: Body: 0B +# CHECK-2-NEXT: - Type: CUSTOM +# CHECK-2-NEXT: Name: name +# CHECK-2-NEXT: FunctionNames: +# CHECK-2-NEXT: - Index: 0 +# CHECK-2-NEXT: Name: _start +# CHECK-2-NEXT: - Index: 1 +# CHECK-2-NEXT: Name: func1 +# CHECK-2-NEXT: - Index: 2 +# CHECK-2-NEXT: Name: func2 +# CHECK-2-NEXT: GlobalNames: +# CHECK-2-NEXT: - Index: 0 +# CHECK-2-NEXT: Name: __stack_pointer + +# CHECK-3: --- !WASM +# CHECK-3-NEXT: FileHeader: +# CHECK-3-NEXT: Version: 0x1 +# CHECK-3-NEXT: Sections: +# CHECK-3-NEXT: - Type: TYPE +# CHECK-3-NEXT: Signatures: +# CHECK-3-NEXT: - Index: 0 +# CHECK-3-NEXT: ParamTypes: [] +# CHECK-3-NEXT: ReturnTypes: [] +# CHECK-3-NEXT: - Type: FUNCTION +# CHECK-3-NEXT: FunctionTypes: [ 0, 0, 0 ] +# CHECK-3-NEXT: - Type: TABLE +# CHECK-3-NEXT: Tables: +# CHECK-3-NEXT: - Index: 0 +# CHECK-3-NEXT: ElemType: FUNCREF +# CHECK-3-NEXT: Limits: +# CHECK-3-NEXT: Flags: [ HAS_MAX ] +# CHECK-3-NEXT: Minimum: 0x6 +# CHECK-3-NEXT: Maximum: 0x6 +# CHECK-3-NEXT: - Type: MEMORY +# CHECK-3-NEXT: Memories: +# CHECK-3-NEXT: - Minimum: 0x2 +# CHECK-3-NEXT: - Type: GLOBAL +# CHECK-3-NEXT: Globals: +# CHECK-3-NEXT: - Index: 0 +# CHECK-3-NEXT: Type: I32 +# CHECK-3-NEXT: Mutable: true +# CHECK-3-NEXT: InitExpr: +# CHECK-3-NEXT: Opcode: I32_CONST +# CHECK-3-NEXT: Value: 66560 +# CHECK-3-NEXT: - Type: EXPORT +# CHECK-3-NEXT: Exports: +# CHECK-3-NEXT: - Name: memory +# CHECK-3-NEXT: Kind: MEMORY +# CHECK-3-NEXT: Index: 0 +# CHECK-3-NEXT: - Name: _start +# CHECK-3-NEXT: Kind: FUNCTION +# CHECK-3-NEXT: Index: 0 +# CHECK-3-NEXT: - Type: ELEM +# CHECK-3-NEXT: Segments: +# CHECK-3-NEXT: - Offset: +# CHECK-3-NEXT: Opcode: I32_CONST +# CHECK-3-NEXT: Value: 1 +# CHECK-3-NEXT: Functions: [ 1, 0, 2, 0, 0 ] +# CHECK-3-NEXT: - Type: CODE +# CHECK-3-NEXT: Functions: +# CHECK-3-NEXT: - Index: 0 +# CHECK-3-NEXT: Locals: [] +# CHECK-3-NEXT: Body: 4181808080001A4183808080001A0B +# CHECK-3-NEXT: - Index: 1 +# CHECK-3-NEXT: Locals: [] +# CHECK-3-NEXT: Body: 0B +# CHECK-3-NEXT: - Index: 2 +# CHECK-3-NEXT: Locals: [] +# CHECK-3-NEXT: Body: 0B +# CHECK-3-NEXT: - Type: CUSTOM +# CHECK-3-NEXT: Name: name +# CHECK-3-NEXT: FunctionNames: +# CHECK-3-NEXT: - Index: 0 +# CHECK-3-NEXT: Name: _start +# CHECK-3-NEXT: - Index: 1 +# CHECK-3-NEXT: Name: func1 +# CHECK-3-NEXT: - Index: 2 +# CHECK-3-NEXT: Name: func2 +# CHECK-3-NEXT: GlobalNames: +# CHECK-3-NEXT: - Index: 0 +# CHECK-3-NEXT: Name: __stack_pointer From 391f43607e296af95bb85b12c7cfebbe498bbbb4 Mon Sep 17 00:00:00 2001 From: Ethan O'Brien Date: Mon, 12 May 2025 00:39:07 -0500 Subject: [PATCH 6/8] Simplify test --- lld/test/wasm/function-pointer-alignmnet.s | 202 ++------------------- 1 file changed, 13 insertions(+), 189 deletions(-) diff --git a/lld/test/wasm/function-pointer-alignmnet.s b/lld/test/wasm/function-pointer-alignmnet.s index 9a95b69399951..97defc5d02352 100644 --- a/lld/test/wasm/function-pointer-alignmnet.s +++ b/lld/test/wasm/function-pointer-alignmnet.s @@ -11,6 +11,7 @@ .functype func1 () -> () .functype func2 () -> () +.functype func3 () -> () .globl _start _start: @@ -19,6 +20,8 @@ _start: drop i32.const func2 drop + i32.const func3 + drop end_function .globl func1 @@ -31,207 +34,28 @@ func2: .functype func2 () -> () end_function +.globl func3 +func3: + .functype func3 () -> () + end_function -# CHECK-DEFAULT: --- !WASM -# CHECK-DEFAULT-NEXT: FileHeader: -# CHECK-DEFAULT-NEXT: Version: 0x1 -# CHECK-DEFAULT-NEXT: Sections: -# CHECK-DEFAULT-NEXT: - Type: TYPE -# CHECK-DEFAULT-NEXT: Signatures: -# CHECK-DEFAULT-NEXT: - Index: 0 -# CHECK-DEFAULT-NEXT: ParamTypes: [] -# CHECK-DEFAULT-NEXT: ReturnTypes: [] -# CHECK-DEFAULT-NEXT: - Type: FUNCTION -# CHECK-DEFAULT-NEXT: FunctionTypes: [ 0, 0, 0 ] -# CHECK-DEFAULT-NEXT: - Type: TABLE -# CHECK-DEFAULT-NEXT: Tables: -# CHECK-DEFAULT-NEXT: - Index: 0 -# CHECK-DEFAULT-NEXT: ElemType: FUNCREF -# CHECK-DEFAULT-NEXT: Limits: -# CHECK-DEFAULT-NEXT: Flags: [ HAS_MAX ] -# CHECK-DEFAULT-NEXT: Minimum: 0x3 -# CHECK-DEFAULT-NEXT: Maximum: 0x3 -# CHECK-DEFAULT-NEXT: - Type: MEMORY -# CHECK-DEFAULT-NEXT: Memories: -# CHECK-DEFAULT-NEXT: - Minimum: 0x2 -# CHECK-DEFAULT-NEXT: - Type: GLOBAL -# CHECK-DEFAULT-NEXT: Globals: -# CHECK-DEFAULT-NEXT: - Index: 0 -# CHECK-DEFAULT-NEXT: Type: I32 -# CHECK-DEFAULT-NEXT: Mutable: true -# CHECK-DEFAULT-NEXT: InitExpr: -# CHECK-DEFAULT-NEXT: Opcode: I32_CONST -# CHECK-DEFAULT-NEXT: Value: 66560 -# CHECK-DEFAULT-NEXT: - Type: EXPORT -# CHECK-DEFAULT-NEXT: Exports: -# CHECK-DEFAULT-NEXT: - Name: memory -# CHECK-DEFAULT-NEXT: Kind: MEMORY -# CHECK-DEFAULT-NEXT: Index: 0 -# CHECK-DEFAULT-NEXT: - Name: _start -# CHECK-DEFAULT-NEXT: Kind: FUNCTION -# CHECK-DEFAULT-NEXT: Index: 0 -# CHECK-DEFAULT-NEXT: - Type: ELEM +# CHECK-DEFAULT: - Type: ELEM # CHECK-DEFAULT-NEXT: Segments: # CHECK-DEFAULT-NEXT: - Offset: # CHECK-DEFAULT-NEXT: Opcode: I32_CONST # CHECK-DEFAULT-NEXT: Value: 1 -# CHECK-DEFAULT-NEXT: Functions: [ 1, 2 ] -# CHECK-DEFAULT-NEXT: - Type: CODE -# CHECK-DEFAULT-NEXT: Functions: -# CHECK-DEFAULT-NEXT: - Index: 0 -# CHECK-DEFAULT-NEXT: Locals: [] -# CHECK-DEFAULT-NEXT: Body: 4181808080001A4182808080001A0B -# CHECK-DEFAULT-NEXT: - Index: 1 -# CHECK-DEFAULT-NEXT: Locals: [] -# CHECK-DEFAULT-NEXT: Body: 0B -# CHECK-DEFAULT-NEXT: - Index: 2 -# CHECK-DEFAULT-NEXT: Locals: [] -# CHECK-DEFAULT-NEXT: Body: 0B -# CHECK-DEFAULT-NEXT: - Type: CUSTOM -# CHECK-DEFAULT-NEXT: Name: name -# CHECK-DEFAULT-NEXT: FunctionNames: -# CHECK-DEFAULT-NEXT: - Index: 0 -# CHECK-DEFAULT-NEXT: Name: _start -# CHECK-DEFAULT-NEXT: - Index: 1 -# CHECK-DEFAULT-NEXT: Name: func1 -# CHECK-DEFAULT-NEXT: - Index: 2 -# CHECK-DEFAULT-NEXT: Name: func2 -# CHECK-DEFAULT-NEXT: GlobalNames: -# CHECK-DEFAULT-NEXT: - Index: 0 -# CHECK-DEFAULT-NEXT: Name: __stack_pointer +# CHECK-DEFAULT-NEXT: Functions: [ 1, 2, 3 ] -# CHECK-2: --- !WASM -# CHECK-2-NEXT: FileHeader: -# CHECK-2-NEXT: Version: 0x1 -# CHECK-2-NEXT: Sections: -# CHECK-2-NEXT: - Type: TYPE -# CHECK-2-NEXT: Signatures: -# CHECK-2-NEXT: - Index: 0 -# CHECK-2-NEXT: ParamTypes: [] -# CHECK-2-NEXT: ReturnTypes: [] -# CHECK-2-NEXT: - Type: FUNCTION -# CHECK-2-NEXT: FunctionTypes: [ 0, 0, 0 ] -# CHECK-2-NEXT: - Type: TABLE -# CHECK-2-NEXT: Tables: -# CHECK-2-NEXT: - Index: 0 -# CHECK-2-NEXT: ElemType: FUNCREF -# CHECK-2-NEXT: Limits: -# CHECK-2-NEXT: Flags: [ HAS_MAX ] -# CHECK-2-NEXT: Minimum: 0x4 -# CHECK-2-NEXT: Maximum: 0x4 -# CHECK-2-NEXT: - Type: MEMORY -# CHECK-2-NEXT: Memories: -# CHECK-2-NEXT: - Minimum: 0x2 -# CHECK-2-NEXT: - Type: GLOBAL -# CHECK-2-NEXT: Globals: -# CHECK-2-NEXT: - Index: 0 -# CHECK-2-NEXT: Type: I32 -# CHECK-2-NEXT: Mutable: true -# CHECK-2-NEXT: InitExpr: -# CHECK-2-NEXT: Opcode: I32_CONST -# CHECK-2-NEXT: Value: 66560 -# CHECK-2-NEXT: - Type: EXPORT -# CHECK-2-NEXT: Exports: -# CHECK-2-NEXT: - Name: memory -# CHECK-2-NEXT: Kind: MEMORY -# CHECK-2-NEXT: Index: 0 -# CHECK-2-NEXT: - Name: _start -# CHECK-2-NEXT: Kind: FUNCTION -# CHECK-2-NEXT: Index: 0 -# CHECK-2-NEXT: - Type: ELEM +# CHECK-2: - Type: ELEM # CHECK-2-NEXT: Segments: # CHECK-2-NEXT: - Offset: # CHECK-2-NEXT: Opcode: I32_CONST # CHECK-2-NEXT: Value: 1 -# CHECK-2-NEXT: Functions: [ 1, 2, 0 ] -# CHECK-2-NEXT: - Type: CODE -# CHECK-2-NEXT: Functions: -# CHECK-2-NEXT: - Index: 0 -# CHECK-2-NEXT: Locals: [] -# CHECK-2-NEXT: Body: 4181808080001A4182808080001A0B -# CHECK-2-NEXT: - Index: 1 -# CHECK-2-NEXT: Locals: [] -# CHECK-2-NEXT: Body: 0B -# CHECK-2-NEXT: - Index: 2 -# CHECK-2-NEXT: Locals: [] -# CHECK-2-NEXT: Body: 0B -# CHECK-2-NEXT: - Type: CUSTOM -# CHECK-2-NEXT: Name: name -# CHECK-2-NEXT: FunctionNames: -# CHECK-2-NEXT: - Index: 0 -# CHECK-2-NEXT: Name: _start -# CHECK-2-NEXT: - Index: 1 -# CHECK-2-NEXT: Name: func1 -# CHECK-2-NEXT: - Index: 2 -# CHECK-2-NEXT: Name: func2 -# CHECK-2-NEXT: GlobalNames: -# CHECK-2-NEXT: - Index: 0 -# CHECK-2-NEXT: Name: __stack_pointer +# CHECK-2-NEXT: Functions: [ 1, 2, 0, 3, 0 ] -# CHECK-3: --- !WASM -# CHECK-3-NEXT: FileHeader: -# CHECK-3-NEXT: Version: 0x1 -# CHECK-3-NEXT: Sections: -# CHECK-3-NEXT: - Type: TYPE -# CHECK-3-NEXT: Signatures: -# CHECK-3-NEXT: - Index: 0 -# CHECK-3-NEXT: ParamTypes: [] -# CHECK-3-NEXT: ReturnTypes: [] -# CHECK-3-NEXT: - Type: FUNCTION -# CHECK-3-NEXT: FunctionTypes: [ 0, 0, 0 ] -# CHECK-3-NEXT: - Type: TABLE -# CHECK-3-NEXT: Tables: -# CHECK-3-NEXT: - Index: 0 -# CHECK-3-NEXT: ElemType: FUNCREF -# CHECK-3-NEXT: Limits: -# CHECK-3-NEXT: Flags: [ HAS_MAX ] -# CHECK-3-NEXT: Minimum: 0x6 -# CHECK-3-NEXT: Maximum: 0x6 -# CHECK-3-NEXT: - Type: MEMORY -# CHECK-3-NEXT: Memories: -# CHECK-3-NEXT: - Minimum: 0x2 -# CHECK-3-NEXT: - Type: GLOBAL -# CHECK-3-NEXT: Globals: -# CHECK-3-NEXT: - Index: 0 -# CHECK-3-NEXT: Type: I32 -# CHECK-3-NEXT: Mutable: true -# CHECK-3-NEXT: InitExpr: -# CHECK-3-NEXT: Opcode: I32_CONST -# CHECK-3-NEXT: Value: 66560 -# CHECK-3-NEXT: - Type: EXPORT -# CHECK-3-NEXT: Exports: -# CHECK-3-NEXT: - Name: memory -# CHECK-3-NEXT: Kind: MEMORY -# CHECK-3-NEXT: Index: 0 -# CHECK-3-NEXT: - Name: _start -# CHECK-3-NEXT: Kind: FUNCTION -# CHECK-3-NEXT: Index: 0 -# CHECK-3-NEXT: - Type: ELEM +# CHECK-3: - Type: ELEM # CHECK-3-NEXT: Segments: # CHECK-3-NEXT: - Offset: # CHECK-3-NEXT: Opcode: I32_CONST # CHECK-3-NEXT: Value: 1 -# CHECK-3-NEXT: Functions: [ 1, 0, 2, 0, 0 ] -# CHECK-3-NEXT: - Type: CODE -# CHECK-3-NEXT: Functions: -# CHECK-3-NEXT: - Index: 0 -# CHECK-3-NEXT: Locals: [] -# CHECK-3-NEXT: Body: 4181808080001A4183808080001A0B -# CHECK-3-NEXT: - Index: 1 -# CHECK-3-NEXT: Locals: [] -# CHECK-3-NEXT: Body: 0B -# CHECK-3-NEXT: - Index: 2 -# CHECK-3-NEXT: Locals: [] -# CHECK-3-NEXT: Body: 0B -# CHECK-3-NEXT: - Type: CUSTOM -# CHECK-3-NEXT: Name: name -# CHECK-3-NEXT: FunctionNames: -# CHECK-3-NEXT: - Index: 0 -# CHECK-3-NEXT: Name: _start -# CHECK-3-NEXT: - Index: 1 -# CHECK-3-NEXT: Name: func1 -# CHECK-3-NEXT: - Index: 2 -# CHECK-3-NEXT: Name: func2 -# CHECK-3-NEXT: GlobalNames: -# CHECK-3-NEXT: - Index: 0 -# CHECK-3-NEXT: Name: __stack_pointer +# CHECK-3-NEXT: Functions: [ 1, 0, 2, 0, 0, 3, 0, 0 ] From ec254cd02b09e7410e0643b5978626f86dabe237 Mon Sep 17 00:00:00 2001 From: Ethan O'Brien Date: Mon, 12 May 2025 12:17:51 -0500 Subject: [PATCH 7/8] Requested changes --- lld/test/wasm/function-pointer-alignmnet.s | 4 ++-- lld/wasm/SyntheticSections.cpp | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lld/test/wasm/function-pointer-alignmnet.s b/lld/test/wasm/function-pointer-alignmnet.s index 97defc5d02352..a1394c4e98755 100644 --- a/lld/test/wasm/function-pointer-alignmnet.s +++ b/lld/test/wasm/function-pointer-alignmnet.s @@ -51,11 +51,11 @@ func3: # CHECK-2-NEXT: - Offset: # CHECK-2-NEXT: Opcode: I32_CONST # CHECK-2-NEXT: Value: 1 -# CHECK-2-NEXT: Functions: [ 1, 2, 0, 3, 0 ] +# CHECK-2-NEXT: Functions: [ 0, 1, 0, 2, 0, 3 ] # CHECK-3: - Type: ELEM # CHECK-3-NEXT: Segments: # CHECK-3-NEXT: - Offset: # CHECK-3-NEXT: Opcode: I32_CONST # CHECK-3-NEXT: Value: 1 -# CHECK-3-NEXT: Functions: [ 1, 0, 2, 0, 0, 3, 0, 0 ] +# CHECK-3-NEXT: Functions: [ 0, 0, 1, 0, 0, 2, 0, 0, 3 ] diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index dd130cc455f7f..99817f79e52a6 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -567,7 +567,6 @@ void ElemSection::addEntry(FunctionSymbol *sym) { if (sym->hasTableIndex() || sym->isStub) return; sym->setTableIndex(ctx.arg.tableBase + indirectFunctions.size()); - indirectFunctions.emplace_back(sym); // Pad with null function pointers if alignment is requesting. if (ctx.arg.functionPointerAlignment > 1) { @@ -575,6 +574,8 @@ void ElemSection::addEntry(FunctionSymbol *sym) { indirectFunctions.push_back(nullptr); } } + + indirectFunctions.emplace_back(sym); } void ElemSection::writeBody() { @@ -611,9 +612,7 @@ void ElemSection::writeBody() { writeUleb128(os, indirectFunctions.size(), "elem count"); uint32_t tableIndex = ctx.arg.tableBase; for (const FunctionSymbol *sym : indirectFunctions) { - if (sym != nullptr) { - assert(sym->getTableIndex() == tableIndex); - } + assert(!sym || sym->getTableIndex() == tableIndex); (void) tableIndex; writeUleb128(os, sym ? sym->getFunctionIndex() : 0, "function index"); ++tableIndex; From 5830aec170642144ab14be00ac69795e776e9830 Mon Sep 17 00:00:00 2001 From: Ethan O'Brien Date: Sun, 19 Oct 2025 18:34:02 -0500 Subject: [PATCH 8/8] Revert to alignment 0 for first function --- lld/test/wasm/function-pointer-alignmnet.s | 4 ++-- lld/wasm/SyntheticSections.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lld/test/wasm/function-pointer-alignmnet.s b/lld/test/wasm/function-pointer-alignmnet.s index a1394c4e98755..97defc5d02352 100644 --- a/lld/test/wasm/function-pointer-alignmnet.s +++ b/lld/test/wasm/function-pointer-alignmnet.s @@ -51,11 +51,11 @@ func3: # CHECK-2-NEXT: - Offset: # CHECK-2-NEXT: Opcode: I32_CONST # CHECK-2-NEXT: Value: 1 -# CHECK-2-NEXT: Functions: [ 0, 1, 0, 2, 0, 3 ] +# CHECK-2-NEXT: Functions: [ 1, 2, 0, 3, 0 ] # CHECK-3: - Type: ELEM # CHECK-3-NEXT: Segments: # CHECK-3-NEXT: - Offset: # CHECK-3-NEXT: Opcode: I32_CONST # CHECK-3-NEXT: Value: 1 -# CHECK-3-NEXT: Functions: [ 0, 0, 1, 0, 0, 2, 0, 0, 3 ] +# CHECK-3-NEXT: Functions: [ 1, 0, 2, 0, 0, 3, 0, 0 ] diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 888b04378dbdf..cfb2223503662 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -580,6 +580,7 @@ void ElemSection::addEntry(FunctionSymbol *sym) { if (sym->hasTableIndex() || sym->isStub) return; sym->setTableIndex(ctx.arg.tableBase + indirectFunctions.size()); + indirectFunctions.emplace_back(sym); // Pad with null function pointers if alignment is requesting. if (ctx.arg.functionPointerAlignment > 1) { @@ -587,8 +588,6 @@ void ElemSection::addEntry(FunctionSymbol *sym) { indirectFunctions.push_back(nullptr); } } - - indirectFunctions.emplace_back(sym); } void ElemSection::writeBody() {