Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions lld/test/wasm/function-pointer-alignmnet.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# 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 () -> ()
.functype func3 () -> ()

.globl _start
_start:
.functype _start () -> ()
i32.const func1
drop
i32.const func2
drop
i32.const func3
drop
end_function

.globl func1
func1:
.functype func1 () -> ()
end_function

.globl func2
func2:
.functype func2 () -> ()
end_function

.globl func3
func3:
.functype func3 () -> ()
end_function

# 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, 3 ]

# 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, 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: [ 1, 0, 2, 0, 0, 3, 0, 0 ]
1 change: 1 addition & 0 deletions lld/wasm/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,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;
uint64_t pageSize;
unsigned ltoPartitions;
Expand Down
2 changes: 2 additions & 0 deletions lld/wasm/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,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.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);
Expand Down
3 changes: 3 additions & 0 deletions lld/wasm/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,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)">;
Expand Down
11 changes: 9 additions & 2 deletions lld/wasm/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,13 @@ void ElemSection::addEntry(FunctionSymbol *sym) {
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) {
while ((ctx.arg.tableBase + indirectFunctions.size()) % ctx.arg.functionPointerAlignment) {
indirectFunctions.push_back(nullptr);
}
}
}

void ElemSection::writeBody() {
Expand Down Expand Up @@ -617,9 +624,9 @@ void ElemSection::writeBody() {
writeUleb128(os, indirectFunctions.size(), "elem count");
uint32_t tableIndex = ctx.arg.tableBase;
for (const FunctionSymbol *sym : indirectFunctions) {
assert(sym->getTableIndex() == tableIndex);
assert(!sym || sym->getTableIndex() == tableIndex);
(void) tableIndex;
writeUleb128(os, sym->getFunctionIndex(), "function index");
writeUleb128(os, sym ? sym->getFunctionIndex() : 0, "function index");
++tableIndex;
}
}
Expand Down