Index: lld/test/wasm/data-layout.s =================================================================== --- lld/test/wasm/data-layout.s +++ 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 @@ # 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 @@ # 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 Index: lld/test/wasm/shared64.s =================================================================== --- /dev/null +++ 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@MBREL + i64.add + i32.load 0 + local.set 1 + global.get indirect_func@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@GOT + end_function + +get_data_address: + .functype get_data_address () -> (i32) + global.get data_external@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@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' Index: lld/wasm/Driver.cpp =================================================================== --- lld/wasm/Driver.cpp +++ lld/wasm/Driver.cpp @@ -584,15 +584,9 @@ 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(wasmGlobal, nullptr); } @@ -635,12 +629,19 @@ // 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 @@ 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 Index: lld/wasm/InputChunks.cpp =================================================================== --- lld/wasm/InputChunks.cpp +++ lld/wasm/InputChunks.cpp @@ -105,6 +105,7 @@ encodeSLEB128(static_cast(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(value), loc, 10); Index: lld/wasm/InputElement.h =================================================================== --- lld/wasm/InputElement.h +++ lld/wasm/InputElement.h @@ -42,6 +42,18 @@ llvm::Optional 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(value); + } else { + ie.Opcode = llvm::wasm::WASM_OPCODE_I32_CONST; + ie.Value.Int32 = static_cast(value); + } + return ie; +} + class InputGlobal : public InputElement { public: InputGlobal(const WasmGlobal &g, ObjFile *f) @@ -51,13 +63,7 @@ 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: Index: lld/wasm/InputFiles.cpp =================================================================== --- lld/wasm/InputFiles.cpp +++ lld/wasm/InputFiles.cpp @@ -156,14 +156,15 @@ 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: Index: lld/wasm/OutputSections.cpp =================================================================== --- lld/wasm/OutputSections.cpp +++ 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" @@ -161,12 +162,8 @@ 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(segment->startVA); } else { - initExpr.Opcode = WASM_OPCODE_I32_CONST; - initExpr.Value.Int32 = static_cast(segment->startVA); + initExpr = intConst(segment->startVA, config->is64.getValueOr(false)); } writeInitExpr(os, initExpr); } Index: lld/wasm/Relocations.cpp =================================================================== --- lld/wasm/Relocations.cpp +++ lld/wasm/Relocations.cpp @@ -104,6 +104,7 @@ 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(sym)); Index: lld/wasm/Symbols.h =================================================================== --- lld/wasm/Symbols.h +++ lld/wasm/Symbols.h @@ -564,6 +564,11 @@ // 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 Index: lld/wasm/Symbols.cpp =================================================================== --- lld/wasm/Symbols.cpp +++ lld/wasm/Symbols.cpp @@ -87,6 +87,8 @@ GlobalSymbol *WasmSym::tlsAlign; UndefinedGlobal *WasmSym::tableBase; DefinedData *WasmSym::definedTableBase; +UndefinedGlobal *WasmSym::tableBase32; +DefinedData *WasmSym::definedTableBase32; UndefinedGlobal *WasmSym::memoryBase; DefinedData *WasmSym::definedMemoryBase; TableSymbol *WasmSym::indirectFunctionTable; Index: lld/wasm/SyntheticSections.cpp =================================================================== --- lld/wasm/SyntheticSections.cpp +++ lld/wasm/SyntheticSections.cpp @@ -362,33 +362,30 @@ 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(sym)) - initExpr.Value.Int32 = d->getVA(); + initExpr = intConst(d->getVA(), is64); else if (auto *f = dyn_cast(sym)) - initExpr.Value.Int32 = f->isStub ? 0 : f->getTableIndex(); + initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64); else { assert(isa(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 @@ 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; Index: lld/wasm/Writer.cpp =================================================================== --- lld/wasm/Writer.cpp +++ lld/wasm/Writer.cpp @@ -1403,6 +1403,8 @@ config->tableBase = 1; if (WasmSym::definedTableBase) WasmSym::definedTableBase->setVA(config->tableBase); + if (WasmSym::definedTableBase32) + WasmSym::definedTableBase32->setVA(config->tableBase); } log("-- createOutputSegments"); Index: llvm/include/llvm/BinaryFormat/WasmRelocs.def =================================================================== --- llvm/include/llvm/BinaryFormat/WasmRelocs.def +++ llvm/include/llvm/BinaryFormat/WasmRelocs.def @@ -26,3 +26,4 @@ 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) Index: llvm/lib/MC/WasmObjectWriter.cpp =================================================================== --- llvm/lib/MC/WasmObjectWriter.cpp +++ llvm/lib/MC/WasmObjectWriter.cpp @@ -528,6 +528,7 @@ } 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 @@ 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 @@ const MCSymbolWasm *Base = cast(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 @@ 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 @@ 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 = Index: llvm/lib/Object/WasmObjectFile.cpp =================================================================== --- llvm/lib/Object/WasmObjectFile.cpp +++ llvm/lib/Object/WasmObjectFile.cpp @@ -870,6 +870,7 @@ 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( "invalid relocation function index", object_error::parse_failed); Index: llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp =================================================================== --- llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -76,7 +76,8 @@ 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: Index: llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp =================================================================== --- llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -107,9 +107,8 @@ 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; } Index: llvm/test/MC/WebAssembly/reloc-pic64.s =================================================================== --- /dev/null +++ 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@GOT + i32.load 0 + end_function + +load_default_func: + .functype load_default_func () -> (i32) + global.get default_func@GOT + i32.load 0 + end_function + +load_hidden_data: + .functype load_hidden_data () -> (i64) + global.get __memory_base + i64.const .L.hidden_data@MBREL + i64.add + end_function + +load_hidden_func: + .functype load_hidden_func () -> (i64) + global.get __table_base + i64.const hidden_func@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: ...