[llvm] 3a293cb - [WebAssembly] Fix PIC/GOT codegen for wasm64
Wouter van Oortmerssen via llvm-commits
llvm-commits at lists.llvm.org
Thu May 20 10:01:52 PDT 2021
Author: Wouter van Oortmerssen
Date: 2021-05-20T09:59:31-07:00
New Revision: 3a293cbf13a2b6ddb2c1f6d27077ee922f32c404
URL: https://github.com/llvm/llvm-project/commit/3a293cbf13a2b6ddb2c1f6d27077ee922f32c404
DIFF: https://github.com/llvm/llvm-project/commit/3a293cbf13a2b6ddb2c1f6d27077ee922f32c404.diff
LOG: [WebAssembly] Fix PIC/GOT codegen for wasm64
__table_base is know 64-bit, since in LLVM it represents a function pointer offset
__table_base32 is a copy in wasm32 for use in elem init expr, since no truncation may be used there.
New reloc R_WASM_TABLE_INDEX_REL_SLEB64 added
Differential Revision: https://reviews.llvm.org/D101784
Added:
lld/test/wasm/shared64.s
llvm/test/MC/WebAssembly/reloc-pic64.s
Modified:
lld/test/wasm/data-layout.s
lld/wasm/Driver.cpp
lld/wasm/InputChunks.cpp
lld/wasm/InputElement.h
lld/wasm/InputFiles.cpp
lld/wasm/OutputSections.cpp
lld/wasm/Relocations.cpp
lld/wasm/Symbols.cpp
lld/wasm/Symbols.h
lld/wasm/SyntheticSections.cpp
lld/wasm/Writer.cpp
llvm/include/llvm/BinaryFormat/WasmRelocs.def
llvm/lib/MC/WasmObjectWriter.cpp
llvm/lib/Object/WasmObjectFile.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
Removed:
################################################################################
diff --git a/lld/test/wasm/data-layout.s b/lld/test/wasm/data-layout.s
index 8399e9f43f1a..2a447aad6221 100644
--- a/lld/test/wasm/data-layout.s
+++ b/lld/test/wasm/data-layout.s
@@ -1,12 +1,12 @@
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/hello.s -o %t.hello32.o
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t32.o
# RUN: wasm-ld -m wasm32 -no-gc-sections --export=__data_end --export=__heap_base --allow-undefined --no-entry -o %t32.wasm %t32.o %t.hello32.o
-# RUN: obj2yaml %t32.wasm | FileCheck --check-prefixes CHECK,CHK32 %s
+# RUN: obj2yaml %t32.wasm | FileCheck -DPTR=I32 %s
#
# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-unknown %p/Inputs/hello.s -o %t.hello64.o
# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-unknown %s -o %t64.o
# RUN: wasm-ld -m wasm64 -no-gc-sections --export=__data_end --export=__heap_base --allow-undefined --no-entry -o %t64.wasm %t64.o %t.hello64.o
-# RUN: obj2yaml %t64.wasm | FileCheck --check-prefixes CHECK,CHK64 %s
+# RUN: obj2yaml %t64.wasm | FileCheck --check-prefixes CHECK,CHK64 -DPTR=I64 %s
.section .data.foo,"",@
.globl foo
@@ -59,24 +59,22 @@ local_struct_internal_ptr:
# CHECK-NEXT: - Type: GLOBAL
# CHECK-NEXT: Globals:
# CHECK-NEXT: - Index: 0
-# CHK32-NEXT: Type: I32
-# CHK64-NEXT: Type: I64
+# CHECK-NEXT: Type: [[PTR]]
# CHECK-NEXT: Mutable: true
# CHECK-NEXT: InitExpr:
-# CHK32-NEXT: Opcode: I32_CONST
-# CHK64-NEXT: Opcode: I64_CONST
+# CHECK-NEXT: Opcode: [[PTR]]_CONST
# CHECK-NEXT: Value: 66624
# CHECK-NEXT: - Index: 1
-# CHECK-NEXT: Type: I32
+# CHECK-NEXT: Type: [[PTR]]
# CHECK-NEXT: Mutable: false
# CHECK-NEXT: InitExpr:
-# CHECK-NEXT: Opcode: I32_CONST
+# CHECK-NEXT: Opcode: [[PTR]]_CONST
# CHECK-NEXT: Value: 1080
# CHECK-NEXT: - Index: 2
-# CHECK-NEXT: Type: I32
+# CHECK-NEXT: Type: [[PTR]]
# CHECK-NEXT: Mutable: false
# CHECK-NEXT: InitExpr:
-# CHECK-NEXT: Opcode: I32_CONST
+# CHECK-NEXT: Opcode: [[PTR]]_CONST
# CHECK-NEXT: Value: 66624
# CHECK: - Type: DATA
@@ -84,15 +82,13 @@ local_struct_internal_ptr:
# CHECK-NEXT: - SectionOffset: 7
# CHECK-NEXT: InitFlags: 0
# CHECK-NEXT: Offset:
-# CHK32-NEXT: Opcode: I32_CONST
-# CHK64-NEXT: Opcode: I64_CONST
+# CHECK-NEXT: Opcode: [[PTR]]_CONST
# CHECK-NEXT: Value: 1024
# CHECK-NEXT: Content: 68656C6C6F0A00
# CHECK-NEXT: - SectionOffset: 20
# CHECK-NEXT: InitFlags: 0
# CHECK-NEXT: Offset:
-# CHK32-NEXT: Opcode: I32_CONST
-# CHK64-NEXT: Opcode: I64_CONST
+# CHECK-NEXT: Opcode: [[PTR]]_CONST
# CHECK-NEXT: Value: 1040
diff --git a/lld/test/wasm/shared64.s b/lld/test/wasm/shared64.s
new file mode 100644
index 000000000000..0cbe623272c9
--- /dev/null
+++ b/lld/test/wasm/shared64.s
@@ -0,0 +1,238 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-unknown -o %t.o %s
+# RUN: wasm-ld -mwasm64 --experimental-pic -shared -o %t.wasm %t.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+.section .data.data,"",@
+data:
+ .p2align 2
+ .int32 2
+ .size data, 4
+
+.section .data.indirect_func_external,"",@
+indirect_func_external:
+ .int32 func_external
+.size indirect_func_external, 4
+
+.section .data.indirect_func,"",@
+indirect_func:
+ .int32 foo
+ .size indirect_func, 4
+
+# Test data relocations
+
+.section .data.data_addr,"",@
+data_addr:
+ .int32 data
+ .size data_addr, 4
+
+# .. against external symbols
+
+.section .data.data_addr_external,"",@
+data_addr_external:
+ .int32 data_external
+ .size data_addr_external, 4
+
+# .. including addends
+
+.section .data.extern_struct_internal_ptr,"",@
+extern_struct_internal_ptr:
+ .int32 extern_struct + 4
+ .size extern_struct_internal_ptr, 4
+
+# Test use of __stack_pointer
+
+.section .text,"",@
+foo:
+ # %ptr = alloca i32
+ # %0 = load i32, i32* @data, align 4
+ # %1 = load i32 ()*, i32 ()** @indirect_func, align 4
+ # call i32 %1()
+ # ret i32 %0
+ .functype foo () -> (i32)
+ .local i64, i32
+ global.get __stack_pointer
+ i64.const 16
+ i64.sub
+ local.tee 0
+ global.set __stack_pointer
+ global.get __memory_base
+ i64.const data at MBREL
+ i64.add
+ i32.load 0
+ local.set 1
+ global.get indirect_func at GOT
+ i32.load 0
+ call_indirect () -> (i32)
+ drop
+ local.get 0
+ i64.const 16
+ i64.add
+ global.set __stack_pointer
+ local.get 1
+ end_function
+
+get_func_address:
+ .functype get_func_address () -> (i32)
+ global.get func_external at GOT
+ end_function
+
+get_data_address:
+ .functype get_data_address () -> (i32)
+ global.get data_external at GOT
+ end_function
+
+get_local_func_address:
+ # Verify that a function which is otherwise not address taken *is* added to
+ # the wasm table with referenced via R_WASM_TABLE_INDEX_REL_SLEB64
+ .functype get_local_func_address () -> (i64)
+ global.get __table_base
+ i64.const get_func_address at TBREL
+ i64.add
+ end_function
+
+.globl foo
+.globl data
+.globl indirect_func
+.globl indirect_func_external
+.globl data_addr
+.globl data_addr_external
+.globl extern_struct_internal_ptr
+.globl get_data_address
+.globl get_func_address
+.globl get_local_func_address
+
+.hidden foo
+.hidden data
+.hidden get_data_address
+.hidden get_func_address
+
+# Without this linking will fail because we import __stack_pointer (a mutable
+# global).
+# TODO(sbc): We probably want a nicer way to specify target_features section
+# in assembly.
+.section .custom_section.target_features,"",@
+.int8 1
+.int8 43
+.int8 15
+.ascii "mutable-globals"
+
+.functype func_external () -> ()
+
+# Linker-synthesized globals
+.globaltype __stack_pointer, i64
+.globaltype __table_base, i64, immutable
+.globaltype __memory_base, i64, immutable
+
+# check for dylink section at start
+
+# CHECK: Sections:
+# CHECK-NEXT: - Type: CUSTOM
+# CHECK-NEXT: Name: dylink
+# CHECK-NEXT: MemorySize: 24
+# CHECK-NEXT: MemoryAlignment: 2
+# CHECK-NEXT: TableSize: 2
+# CHECK-NEXT: TableAlignment: 0
+# CHECK-NEXT: Needed: []
+# CHECK-NEXT: - Type: TYPE
+
+# check for import of __table_base and __memory_base globals
+
+# CHECK: - Type: IMPORT
+# CHECK-NEXT: Imports:
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: memory
+# CHECK-NEXT: Kind: MEMORY
+# CHECK-NEXT: Memory:
+# CHECK-NEXT: Flags: [ IS_64 ]
+# CHECK-NEXT: Minimum: 0x1
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __indirect_function_table
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Table:
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: ElemType: FUNCREF
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Minimum: 0x2
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __stack_pointer
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I64
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __memory_base
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I64
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __table_base
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I64
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __table_base32
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: func_external
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: SigIndex: 1
+# CHECK-NEXT: - Module: GOT.mem
+# CHECK-NEXT: Field: indirect_func
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Module: GOT.func
+# CHECK-NEXT: Field: func_external
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Module: GOT.mem
+# CHECK-NEXT: Field: data_external
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Module: GOT.mem
+# CHECK-NEXT: Field: extern_struct
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Type: FUNCTION
+
+# CHECK: - Type: EXPORT
+# CHECK-NEXT: Exports:
+# CHECK-NEXT: - Name: __wasm_call_ctors
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 1
+
+# check for elem segment initialized with __table_base global as offset
+
+# CHECK: - Type: ELEM
+# CHECK-NEXT: Segments:
+# CHECK-NEXT: - Offset:
+# CHECK-NEXT: Opcode: GLOBAL_GET
+# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Functions: [ 4, 3 ]
+
+# check the generated code in __wasm_call_ctors and __wasm_apply_data_relocs functions
+# TODO(sbc): Disassemble and verify instructions.
+
+# CHECK: - Type: CODE
+# CHECK-NEXT: Functions:
+# CHECK-NEXT: - Index: 1
+# CHECK-NEXT: Locals: []
+# CHECK-NEXT: Body: 10020B
+# CHECK-NEXT: - Index: 2
+# CHECK-NEXT: Locals: []
+# CHECK-NEXT: Body: 230142047C2305360200230142087C230241016A3602002301420C7C230141006A360200230142107C2306360200230142147C230741046A3602000B
+
+# check the data segment initialized with __memory_base global as offset
+
+# CHECK: - Type: DATA
+# CHECK-NEXT: Segments:
+# CHECK-NEXT: - SectionOffset: 6
+# CHECK-NEXT: InitFlags: 0
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Opcode: GLOBAL_GET
+# CHECK-NEXT: Index: 1
+# CHECK-NEXT: Content: '020000000000000001000000000000000000000000000000'
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 9b01a84f7812..61eeb0bd2522 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -584,15 +584,9 @@ createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {
static InputGlobal *createGlobal(StringRef name, bool isMutable) {
llvm::wasm::WasmGlobal wasmGlobal;
- if (config->is64.getValueOr(false)) {
- wasmGlobal.Type = {WASM_TYPE_I64, isMutable};
- wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I64_CONST;
- wasmGlobal.InitExpr.Value.Int64 = 0;
- } else {
- wasmGlobal.Type = {WASM_TYPE_I32, isMutable};
- wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- wasmGlobal.InitExpr.Value.Int32 = 0;
- }
+ bool is64 = config->is64.getValueOr(false);
+ wasmGlobal.Type = {uint8_t(is64 ? WASM_TYPE_I64 : WASM_TYPE_I32), isMutable};
+ wasmGlobal.InitExpr = intConst(0, is64);
wasmGlobal.SymbolName = name;
return make<InputGlobal>(wasmGlobal, nullptr);
}
@@ -635,12 +629,19 @@ static void createSyntheticSymbols() {
// which to load our static data and function table.
// See:
// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
- WasmSym::memoryBase = createUndefinedGlobal(
- "__memory_base",
- config->is64.getValueOr(false) ? &globalTypeI64 : &globalTypeI32);
- WasmSym::tableBase = createUndefinedGlobal("__table_base", &globalTypeI32);
+ bool is64 = config->is64.getValueOr(false);
+ auto *globalType = is64 ? &globalTypeI64 : &globalTypeI32;
+ WasmSym::memoryBase = createUndefinedGlobal("__memory_base", globalType);
+ WasmSym::tableBase = createUndefinedGlobal("__table_base", globalType);
WasmSym::memoryBase->markLive();
WasmSym::tableBase->markLive();
+ if (is64) {
+ WasmSym::tableBase32 =
+ createUndefinedGlobal("__table_base32", &globalTypeI32);
+ WasmSym::tableBase32->markLive();
+ } else {
+ WasmSym::tableBase32 = nullptr;
+ }
} else {
// For non-PIC code
WasmSym::stackPointer = createGlobalVariable("__stack_pointer", true);
@@ -673,6 +674,9 @@ static void createOptionalSymbols() {
WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base");
WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base");
WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base");
+ if (config->is64.getValueOr(false))
+ WasmSym::definedTableBase32 =
+ symtab->addOptionalDataSymbol("__table_base32");
}
// For non-shared memory programs we still need to define __tls_base since we
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index 279cd41d1ff2..99819713c281 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -134,6 +134,7 @@ void InputChunk::relocate(uint8_t *buf) const {
encodeSLEB128(static_cast<int32_t>(value), loc, 5);
break;
case R_WASM_TABLE_INDEX_SLEB64:
+ case R_WASM_TABLE_INDEX_REL_SLEB64:
case R_WASM_MEMORY_ADDR_SLEB64:
case R_WASM_MEMORY_ADDR_REL_SLEB64:
encodeSLEB128(static_cast<int64_t>(value), loc, 10);
diff --git a/lld/wasm/InputElement.h b/lld/wasm/InputElement.h
index 97ef5ca7feab..f39a1727047f 100644
--- a/lld/wasm/InputElement.h
+++ b/lld/wasm/InputElement.h
@@ -42,6 +42,18 @@ class InputElement {
llvm::Optional<uint32_t> assignedIndex;
};
+inline WasmInitExpr intConst(uint64_t value, bool is64) {
+ WasmInitExpr ie;
+ if (is64) {
+ ie.Opcode = llvm::wasm::WASM_OPCODE_I64_CONST;
+ ie.Value.Int64 = static_cast<int64_t>(value);
+ } else {
+ ie.Opcode = llvm::wasm::WASM_OPCODE_I32_CONST;
+ ie.Value.Int32 = static_cast<int32_t>(value);
+ }
+ return ie;
+}
+
class InputGlobal : public InputElement {
public:
InputGlobal(const WasmGlobal &g, ObjFile *f)
@@ -51,13 +63,7 @@ class InputGlobal : public InputElement {
const WasmInitExpr &getInitExpr() const { return initExpr; }
void setPointerValue(uint64_t value) {
- if (config->is64.getValueOr(false)) {
- assert(initExpr.Opcode == llvm::wasm::WASM_OPCODE_I64_CONST);
- initExpr.Value.Int64 = value;
- } else {
- assert(initExpr.Opcode == llvm::wasm::WASM_OPCODE_I32_CONST);
- initExpr.Value.Int32 = value;
- }
+ initExpr = intConst(value, config->is64.getValueOr(false));
}
private:
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 7fd9215f1171..faf7bbcfa926 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -156,14 +156,15 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
case R_WASM_TABLE_INDEX_I64:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_SLEB64:
- case R_WASM_TABLE_INDEX_REL_SLEB: {
+ case R_WASM_TABLE_INDEX_REL_SLEB:
+ case R_WASM_TABLE_INDEX_REL_SLEB64: {
if (!getFunctionSymbol(reloc.Index)->hasTableIndex())
return 0;
uint32_t index = getFunctionSymbol(reloc.Index)->getTableIndex();
- if (reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB)
+ if (reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB ||
+ reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB64)
index -= config->tableBase;
return index;
-
}
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_LEB64:
diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp
index 28f611712536..829fd97b2cf2 100644
--- a/lld/wasm/OutputSections.cpp
+++ b/lld/wasm/OutputSections.cpp
@@ -8,6 +8,7 @@
#include "OutputSections.h"
#include "InputChunks.h"
+#include "InputElement.h"
#include "InputFiles.h"
#include "OutputSegment.h"
#include "WriterUtils.h"
@@ -162,12 +163,8 @@ void DataSection::finalizeContents() {
if (config->isPic) {
initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
initExpr.Value.Global = WasmSym::memoryBase->getGlobalIndex();
- } else if (config->is64.getValueOr(false)) {
- initExpr.Opcode = WASM_OPCODE_I64_CONST;
- initExpr.Value.Int64 = static_cast<int64_t>(segment->startVA);
} else {
- initExpr.Opcode = WASM_OPCODE_I32_CONST;
- initExpr.Value.Int32 = static_cast<int32_t>(segment->startVA);
+ initExpr = intConst(segment->startVA, config->is64.getValueOr(false));
}
writeInitExpr(os, initExpr);
}
diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp
index f909c377b9a5..ea0f6a063506 100644
--- a/lld/wasm/Relocations.cpp
+++ b/lld/wasm/Relocations.cpp
@@ -104,6 +104,7 @@ void scanRelocations(InputChunk *chunk) {
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_TABLE_INDEX_REL_SLEB:
+ case R_WASM_TABLE_INDEX_REL_SLEB64:
if (requiresGOTAccess(sym))
break;
out.elemSec->addEntry(cast<FunctionSymbol>(sym));
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 6d960b4cf7e6..c18510ca5fce 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -87,6 +87,8 @@ GlobalSymbol *WasmSym::tlsSize;
GlobalSymbol *WasmSym::tlsAlign;
UndefinedGlobal *WasmSym::tableBase;
DefinedData *WasmSym::definedTableBase;
+UndefinedGlobal *WasmSym::tableBase32;
+DefinedData *WasmSym::definedTableBase32;
UndefinedGlobal *WasmSym::memoryBase;
DefinedData *WasmSym::definedMemoryBase;
TableSymbol *WasmSym::indirectFunctionTable;
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 0c557530236d..95c7dd12b894 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -564,6 +564,11 @@ struct WasmSym {
// Used in PIC code for offset of indirect function table
static UndefinedGlobal *tableBase;
static DefinedData *definedTableBase;
+ // 32-bit copy in wasm64 to work around init expr limitations.
+ // These can potentially be removed again once we have
+ // https://github.com/WebAssembly/extended-const
+ static UndefinedGlobal *tableBase32;
+ static DefinedData *definedTableBase32;
// __memory_base
// Used in PIC code for offset of global data
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index b10ecc04b4b2..b8cf1cbfddca 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -362,33 +362,30 @@ void GlobalSection::writeBody() {
writeGlobalType(os, g->getType());
writeInitExpr(os, g->getInitExpr());
}
- // TODO(wvo): when do these need I64_CONST?
+ bool is64 = config->is64.getValueOr(false);
+ uint8_t itype = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32;
for (const Symbol *sym : internalGotSymbols) {
// In the case of dynamic linking, internal GOT entries
// need to be mutable since they get updated to the correct
// runtime value during `__wasm_apply_global_relocs`.
bool mutable_ = config->isPic & !sym->isStub;
- WasmGlobalType type{WASM_TYPE_I32, mutable_};
+ WasmGlobalType type{itype, mutable_};
WasmInitExpr initExpr;
- initExpr.Opcode = WASM_OPCODE_I32_CONST;
if (auto *d = dyn_cast<DefinedData>(sym))
- initExpr.Value.Int32 = d->getVA();
+ initExpr = intConst(d->getVA(), is64);
else if (auto *f = dyn_cast<FunctionSymbol>(sym))
- initExpr.Value.Int32 = f->isStub ? 0 : f->getTableIndex();
+ initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64);
else {
assert(isa<UndefinedData>(sym));
- initExpr.Value.Int32 = 0;
+ initExpr = intConst(0, is64);
}
writeGlobalType(os, type);
writeInitExpr(os, initExpr);
}
for (const DefinedData *sym : dataAddressGlobals) {
- WasmGlobalType type{WASM_TYPE_I32, false};
- WasmInitExpr initExpr;
- initExpr.Opcode = WASM_OPCODE_I32_CONST;
- initExpr.Value.Int32 = sym->getVA();
+ WasmGlobalType type{itype, false};
writeGlobalType(os, type);
- writeInitExpr(os, initExpr);
+ writeInitExpr(os, intConst(sym->getVA(), is64));
}
}
@@ -443,7 +440,10 @@ void ElemSection::writeBody() {
WasmInitExpr initExpr;
if (config->isPic) {
initExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
- initExpr.Value.Global = WasmSym::tableBase->getGlobalIndex();
+ initExpr.Value.Global =
+ (config->is64.getValueOr(false) ? WasmSym::tableBase32
+ : WasmSym::tableBase)
+ ->getGlobalIndex();
} else {
initExpr.Opcode = WASM_OPCODE_I32_CONST;
initExpr.Value.Int32 = config->tableBase;
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 1705c205eca4..90970ef326b9 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -1403,6 +1403,8 @@ void Writer::run() {
config->tableBase = 1;
if (WasmSym::definedTableBase)
WasmSym::definedTableBase->setVA(config->tableBase);
+ if (WasmSym::definedTableBase32)
+ WasmSym::definedTableBase32->setVA(config->tableBase);
}
log("-- createOutputSegments");
diff --git a/llvm/include/llvm/BinaryFormat/WasmRelocs.def b/llvm/include/llvm/BinaryFormat/WasmRelocs.def
index b83efc26e58d..80c9ebcb1fa2 100644
--- a/llvm/include/llvm/BinaryFormat/WasmRelocs.def
+++ b/llvm/include/llvm/BinaryFormat/WasmRelocs.def
@@ -26,3 +26,4 @@ WASM_RELOC(R_WASM_TABLE_NUMBER_LEB, 20)
WASM_RELOC(R_WASM_MEMORY_ADDR_TLS_SLEB, 21)
WASM_RELOC(R_WASM_FUNCTION_OFFSET_I64, 22)
WASM_RELOC(R_WASM_MEMORY_ADDR_LOCREL_I32, 23)
+WASM_RELOC(R_WASM_TABLE_INDEX_REL_SLEB64, 24)
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 541b464d3f30..23208183121e 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -528,6 +528,7 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
}
if (Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB ||
+ Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB64 ||
Type == wasm::R_WASM_TABLE_INDEX_SLEB ||
Type == wasm::R_WASM_TABLE_INDEX_SLEB64 ||
Type == wasm::R_WASM_TABLE_INDEX_I32 ||
@@ -590,6 +591,7 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
switch (RelEntry.Type) {
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
+ case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
case wasm::R_WASM_TABLE_INDEX_SLEB:
case wasm::R_WASM_TABLE_INDEX_SLEB64:
case wasm::R_WASM_TABLE_INDEX_I32:
@@ -598,7 +600,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
const MCSymbolWasm *Base =
cast<MCSymbolWasm>(Layout.getBaseSymbol(*RelEntry.Symbol));
assert(Base->isFunction());
- if (RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB)
+ if (RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB ||
+ RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB64)
return TableIndices[Base] - InitialTableOffset;
else
return TableIndices[Base];
@@ -742,6 +745,7 @@ void WasmObjectWriter::applyRelocations(
writePatchableSLEB<5>(Stream, Value, Offset);
break;
case wasm::R_WASM_TABLE_INDEX_SLEB64:
+ case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
writePatchableSLEB<10>(Stream, Value, Offset);
@@ -1757,7 +1761,8 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
Rel.Type != wasm::R_WASM_TABLE_INDEX_I64 &&
Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB &&
Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB64 &&
- Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB)
+ Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB &&
+ Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB64)
return;
assert(Rel.Symbol->isFunction());
const MCSymbolWasm *Base =
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 8004c5eb25a9..38895e46d0e2 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -870,6 +870,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
case wasm::R_WASM_TABLE_INDEX_I32:
case wasm::R_WASM_TABLE_INDEX_I64:
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
+ case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
if (!isValidFunctionSymbol(Reloc.Index))
return make_error<GenericBinaryError>(
"invalid relocation function index", object_error::parse_failed);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
index 1a79a2d597bb..9a2bd39a54a5 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
@@ -76,7 +76,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
return wasm::R_WASM_GLOBAL_INDEX_LEB;
case MCSymbolRefExpr::VK_WASM_TBREL:
assert(SymA.isFunction());
- return wasm::R_WASM_TABLE_INDEX_REL_SLEB;
+ return is64Bit() ? wasm::R_WASM_TABLE_INDEX_REL_SLEB64
+ : wasm::R_WASM_TABLE_INDEX_REL_SLEB;
case MCSymbolRefExpr::VK_WASM_TLSREL:
return wasm::R_WASM_MEMORY_ADDR_TLS_SLEB;
case MCSymbolRefExpr::VK_WASM_MBREL:
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 2383416d8a92..2468df9ab400 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -107,9 +107,8 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
strcmp(Name, "__stack_pointer") == 0 || strcmp(Name, "__tls_base") == 0;
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
WasmSym->setGlobalType(wasm::WasmGlobalType{
- uint8_t(Subtarget.hasAddr64() && strcmp(Name, "__table_base") != 0
- ? wasm::WASM_TYPE_I64
- : wasm::WASM_TYPE_I32),
+ uint8_t(Subtarget.hasAddr64() ? wasm::WASM_TYPE_I64
+ : wasm::WASM_TYPE_I32),
Mutable});
return WasmSym;
}
diff --git a/llvm/test/MC/WebAssembly/reloc-pic64.s b/llvm/test/MC/WebAssembly/reloc-pic64.s
new file mode 100644
index 000000000000..9a382a15a0a2
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/reloc-pic64.s
@@ -0,0 +1,209 @@
+# RUN: llvm-mc -triple=wasm64-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck %s
+# RUN: llvm-mc -triple=wasm64-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck --check-prefix=REF %s
+
+# Verify that @GOT relocation entries result in R_WASM_GLOBAL_INDEX_LEB against
+# against the corrsponding function or data symbol and that the corresponding
+# data symbols are imported as a wasm globals.
+
+load_default_data:
+ .functype load_default_data () -> (i32)
+ global.get default_data at GOT
+ i32.load 0
+ end_function
+
+load_default_func:
+ .functype load_default_func () -> (i32)
+ global.get default_func at GOT
+ i32.load 0
+ end_function
+
+load_hidden_data:
+ .functype load_hidden_data () -> (i64)
+ global.get __memory_base
+ i64.const .L.hidden_data at MBREL
+ i64.add
+ end_function
+
+load_hidden_func:
+ .functype load_hidden_func () -> (i64)
+ global.get __table_base
+ i64.const hidden_func at TBREL
+ i64.add
+ end_function
+
+hidden_func:
+ .functype hidden_func () -> (i32)
+ i32.const 0
+ end_function
+
+.section .rodata.hidden_data,"",@
+.L.hidden_data:
+ .int8 100
+ .size .L.hidden_data, 1
+
+#.hidden hidden_func
+#.hidden hidden_data
+.size default_data, 4
+.functype default_func () -> (i32)
+
+# CHECK: --- !WASM
+# CHECK-NEXT: FileHeader:
+# CHECK-NEXT: Version: 0x1
+# CHECK-NEXT: Sections:
+# CHECK-NEXT: - Type: TYPE
+# CHECK-NEXT: Signatures:
+# CHECK-NEXT: - Index: 0
+# CHECK-NEXT: ParamTypes: []
+# CHECK-NEXT: ReturnTypes:
+# CHECK-NEXT: - I32
+# CHECK-NEXT: - Index: 1
+# CHECK-NEXT: ParamTypes: []
+# CHECK-NEXT: ReturnTypes:
+# CHECK-NEXT: - I64
+# CHECK-NEXT: - Type: IMPORT
+# CHECK-NEXT: Imports:
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __linear_memory
+# CHECK-NEXT: Kind: MEMORY
+# CHECK-NEXT: Memory:
+# CHECK-NEXT: Flags: [ IS_64 ]
+# CHECK-NEXT: Minimum: 0x1
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: default_func
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: SigIndex: 0
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __indirect_function_table
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Table:
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: ElemType: FUNCREF
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Minimum: 0x1
+# CHECK-NEXT: - Module: GOT.mem
+# CHECK-NEXT: Field: default_data
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Module: GOT.func
+# CHECK-NEXT: Field: default_func
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Type: FUNCTION
+# CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 0 ]
+# CHECK-NEXT: - Type: ELEM
+# CHECK-NEXT: Segments:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Opcode: I32_CONST
+# CHECK-NEXT: Value: 1
+# CHECK-NEXT: Functions: [ 5 ]
+# CHECK-NEXT: - Type: DATACOUNT
+# CHECK-NEXT: Count: 1
+# CHECK-NEXT: - Type: CODE
+# CHECK-NEXT: Relocations:
+# CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB
+# CHECK-NEXT: Index: 1
+# CHECK-NEXT: Offset: 0x4
+# CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB
+# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Offset: 0x10
+# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB
+# CHECK-NEXT: Index: 5
+# CHECK-NEXT: Offset: 0x1C
+# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_REL_SLEB
+# CHECK-NEXT: Index: 6
+# CHECK-NEXT: Offset: 0x22
+# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB
+# CHECK-NEXT: Index: 8
+# CHECK-NEXT: Offset: 0x31
+# CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_REL_SLEB
+# CHECK-NEXT: Index: 9
+# CHECK-NEXT: Offset: 0x37
+# CHECK-NEXT: Functions:
+# CHECK-NEXT: - Index: 1
+# CHECK-NEXT: Locals: []
+# CHECK-NEXT: Body: 2380808080002802000B
+# CHECK-NEXT: - Index: 2
+# CHECK-NEXT: Locals: []
+# CHECK-NEXT: Body: 2381808080002802000B
+# CHECK-NEXT: - Index: 3
+# CHECK-NEXT: Locals: []
+# CHECK-NEXT: Body: 23808080800042808080808080808080007C0B
+# CHECK-NEXT: - Index: 4
+# CHECK-NEXT: Locals: []
+# CHECK-NEXT: Body: 23808080800042808080808080808080007C0B
+# CHECK-NEXT: - Index: 5
+# CHECK-NEXT: Locals: []
+# CHECK-NEXT: Body: 41000B
+# CHECK-NEXT: - Type: DATA
+# CHECK-NEXT: Segments:
+# CHECK-NEXT: - SectionOffset: 6
+# CHECK-NEXT: InitFlags: 0
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Opcode: I64_CONST
+# CHECK-NEXT: Value: 0
+# CHECK-NEXT: Content: '64'
+# CHECK-NEXT: - Type: CUSTOM
+# CHECK-NEXT: Name: linking
+# CHECK-NEXT: Version: 2
+# CHECK-NEXT: SymbolTable:
+# CHECK-NEXT: - Index: 0
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Name: load_default_data
+# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+# CHECK-NEXT: Function: 1
+# CHECK-NEXT: - Index: 1
+# CHECK-NEXT: Kind: DATA
+# CHECK-NEXT: Name: default_data
+# CHECK-NEXT: Flags: [ UNDEFINED ]
+# CHECK-NEXT: - Index: 2
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Name: load_default_func
+# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+# CHECK-NEXT: Function: 2
+# CHECK-NEXT: - Index: 3
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Name: default_func
+# CHECK-NEXT: Flags: [ UNDEFINED ]
+# CHECK-NEXT: Function: 0
+# CHECK-NEXT: - Index: 4
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Name: load_hidden_data
+# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+# CHECK-NEXT: Function: 3
+# CHECK-NEXT: - Index: 5
+# CHECK-NEXT: Kind: DATA
+# CHECK-NEXT: Name: __memory_base
+# CHECK-NEXT: Flags: [ UNDEFINED ]
+# CHECK-NEXT: - Index: 6
+# CHECK-NEXT: Kind: DATA
+# CHECK-NEXT: Name: .L.hidden_data
+# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+# CHECK-NEXT: Segment: 0
+# CHECK-NEXT: Size: 1
+# CHECK-NEXT: - Index: 7
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Name: load_hidden_func
+# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+# CHECK-NEXT: Function: 4
+# CHECK-NEXT: - Index: 8
+# CHECK-NEXT: Kind: DATA
+# CHECK-NEXT: Name: __table_base
+# CHECK-NEXT: Flags: [ UNDEFINED ]
+# CHECK-NEXT: - Index: 9
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Name: hidden_func
+# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
+# CHECK-NEXT: Function: 5
+# REF: - Index: 10
+# REF-NEXT: Kind: TABLE
+# REF-NEXT: Name: __indirect_function_table
+# REF-NEXT: Flags: [ UNDEFINED, NO_STRIP ]
+# REF-NEXT: Table: 0
+# CHECK-NEXT: SegmentInfo:
+# CHECK-NEXT: - Index: 0
+# CHECK-NEXT: Name: .rodata.hidden_data
+# CHECK-NEXT: Alignment: 0
+# CHECK-NEXT: Flags: [ ]
+# CHECK-NEXT: ...
More information about the llvm-commits
mailing list