Skip to content

Commit cc1b9b6

Browse files
committed
[WebAssembly] 64-bit (function) pointer fixes.
Accounting for the fact that Wasm function indices are 32-bit, but in wasm64 we want uniform 64-bit pointers. Includes reloc types for 64-bit table indices. Differential Revision: https://reviews.llvm.org/D83729
1 parent b636e7d commit cc1b9b6

File tree

12 files changed

+123
-11
lines changed

12 files changed

+123
-11
lines changed

lld/wasm/InputChunks.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ void InputChunk::verifyRelocTargets() const {
7272
existingValue = decodeULEB128(loc, &bytesRead);
7373
break;
7474
case R_WASM_TABLE_INDEX_SLEB:
75+
case R_WASM_TABLE_INDEX_SLEB64:
7576
case R_WASM_TABLE_INDEX_REL_SLEB:
7677
case R_WASM_MEMORY_ADDR_SLEB:
7778
case R_WASM_MEMORY_ADDR_SLEB64:
@@ -86,6 +87,7 @@ void InputChunk::verifyRelocTargets() const {
8687
case R_WASM_GLOBAL_INDEX_I32:
8788
existingValue = read32le(loc);
8889
break;
90+
case R_WASM_TABLE_INDEX_I64:
8991
case R_WASM_MEMORY_ADDR_I64:
9092
existingValue = read64le(loc);
9193
break;
@@ -151,6 +153,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
151153
case R_WASM_MEMORY_ADDR_REL_SLEB:
152154
encodeSLEB128(static_cast<int32_t>(value), loc, 5);
153155
break;
156+
case R_WASM_TABLE_INDEX_SLEB64:
154157
case R_WASM_MEMORY_ADDR_SLEB64:
155158
case R_WASM_MEMORY_ADDR_REL_SLEB64:
156159
encodeSLEB128(static_cast<int64_t>(value), loc, 10);
@@ -162,6 +165,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
162165
case R_WASM_GLOBAL_INDEX_I32:
163166
write32le(loc, value);
164167
break;
168+
case R_WASM_TABLE_INDEX_I64:
165169
case R_WASM_MEMORY_ADDR_I64:
166170
write64le(loc, value);
167171
break;
@@ -219,6 +223,7 @@ static unsigned writeCompressedReloc(uint8_t *buf, const WasmRelocation &rel,
219223
case R_WASM_MEMORY_ADDR_LEB64:
220224
return encodeULEB128(value, buf);
221225
case R_WASM_TABLE_INDEX_SLEB:
226+
case R_WASM_TABLE_INDEX_SLEB64:
222227
case R_WASM_MEMORY_ADDR_SLEB:
223228
case R_WASM_MEMORY_ADDR_SLEB64:
224229
return encodeSLEB128(static_cast<int64_t>(value), buf);
@@ -237,6 +242,7 @@ static unsigned getRelocWidthPadded(const WasmRelocation &rel) {
237242
case R_WASM_TABLE_INDEX_SLEB:
238243
case R_WASM_MEMORY_ADDR_SLEB:
239244
return 5;
245+
case R_WASM_TABLE_INDEX_SLEB64:
240246
case R_WASM_MEMORY_ADDR_LEB64:
241247
case R_WASM_MEMORY_ADDR_SLEB64:
242248
return 10;
@@ -382,7 +388,8 @@ void InputSegment::generateRelocationCode(raw_ostream &os) const {
382388
}
383389
} else {
384390
const GlobalSymbol* baseSymbol = WasmSym::memoryBase;
385-
if (rel.Type == R_WASM_TABLE_INDEX_I32)
391+
if (rel.Type == R_WASM_TABLE_INDEX_I32 ||
392+
rel.Type == R_WASM_TABLE_INDEX_I64)
386393
baseSymbol = WasmSym::tableBase;
387394
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
388395
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");

lld/wasm/InputFiles.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ uint64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {
126126
uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
127127
switch (reloc.Type) {
128128
case R_WASM_TABLE_INDEX_I32:
129-
case R_WASM_TABLE_INDEX_SLEB: {
129+
case R_WASM_TABLE_INDEX_I64:
130+
case R_WASM_TABLE_INDEX_SLEB:
131+
case R_WASM_TABLE_INDEX_SLEB64: {
130132
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
131133
return tableEntries[sym.Info.ElementIndex];
132134
}
@@ -195,7 +197,9 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc) const {
195197

196198
switch (reloc.Type) {
197199
case R_WASM_TABLE_INDEX_I32:
200+
case R_WASM_TABLE_INDEX_I64:
198201
case R_WASM_TABLE_INDEX_SLEB:
202+
case R_WASM_TABLE_INDEX_SLEB64:
199203
case R_WASM_TABLE_INDEX_REL_SLEB: {
200204
if (!getFunctionSymbol(reloc.Index)->hasTableIndex())
201205
return 0;

lld/wasm/MarkLive.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ void MarkLive::mark() {
122122
// functions used for weak-undefined symbols have this behaviour (compare
123123
// equal to null pointer, only reachable via direct call).
124124
if (reloc.Type == R_WASM_TABLE_INDEX_SLEB ||
125-
reloc.Type == R_WASM_TABLE_INDEX_I32) {
125+
reloc.Type == R_WASM_TABLE_INDEX_SLEB64 ||
126+
reloc.Type == R_WASM_TABLE_INDEX_I32 ||
127+
reloc.Type == R_WASM_TABLE_INDEX_I64) {
126128
auto *funcSym = cast<FunctionSymbol>(sym);
127129
if (funcSym->hasTableIndex() && funcSym->getTableIndex() == 0)
128130
continue;

lld/wasm/Relocations.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ void scanRelocations(InputChunk *chunk) {
7070

7171
switch (reloc.Type) {
7272
case R_WASM_TABLE_INDEX_I32:
73+
case R_WASM_TABLE_INDEX_I64:
7374
case R_WASM_TABLE_INDEX_SLEB:
75+
case R_WASM_TABLE_INDEX_SLEB64:
7476
case R_WASM_TABLE_INDEX_REL_SLEB:
7577
if (requiresGOTAccess(sym))
7678
break;
@@ -86,6 +88,7 @@ void scanRelocations(InputChunk *chunk) {
8688
if (config->isPic) {
8789
switch (reloc.Type) {
8890
case R_WASM_TABLE_INDEX_SLEB:
91+
case R_WASM_TABLE_INDEX_SLEB64:
8992
case R_WASM_MEMORY_ADDR_SLEB:
9093
case R_WASM_MEMORY_ADDR_LEB:
9194
case R_WASM_MEMORY_ADDR_SLEB64:
@@ -97,6 +100,7 @@ void scanRelocations(InputChunk *chunk) {
97100
"; recompile with -fPIC");
98101
break;
99102
case R_WASM_TABLE_INDEX_I32:
103+
case R_WASM_TABLE_INDEX_I64:
100104
case R_WASM_MEMORY_ADDR_I32:
101105
case R_WASM_MEMORY_ADDR_I64:
102106
// These relocation types are only present in the data section and

llvm/include/llvm/BinaryFormat/WasmRelocs.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ WASM_RELOC(R_WASM_MEMORY_ADDR_LEB64, 14)
2020
WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB64, 15)
2121
WASM_RELOC(R_WASM_MEMORY_ADDR_I64, 16)
2222
WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB64, 17)
23+
WASM_RELOC(R_WASM_TABLE_INDEX_SLEB64, 18)
24+
WASM_RELOC(R_WASM_TABLE_INDEX_I64, 19)

llvm/lib/MC/WasmObjectWriter.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,9 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
556556
switch (RelEntry.Type) {
557557
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
558558
case wasm::R_WASM_TABLE_INDEX_SLEB:
559-
case wasm::R_WASM_TABLE_INDEX_I32: {
559+
case wasm::R_WASM_TABLE_INDEX_SLEB64:
560+
case wasm::R_WASM_TABLE_INDEX_I32:
561+
case wasm::R_WASM_TABLE_INDEX_I64: {
560562
// Provisional value is table address of the resolved symbol itself
561563
const MCSymbolWasm *Base =
562564
cast<MCSymbolWasm>(Layout.getBaseSymbol(*RelEntry.Symbol));
@@ -688,6 +690,7 @@ void WasmObjectWriter::applyRelocations(
688690
case wasm::R_WASM_GLOBAL_INDEX_I32:
689691
patchI32(Stream, Value, Offset);
690692
break;
693+
case wasm::R_WASM_TABLE_INDEX_I64:
691694
case wasm::R_WASM_MEMORY_ADDR_I64:
692695
patchI64(Stream, Value, Offset);
693696
break;
@@ -697,6 +700,7 @@ void WasmObjectWriter::applyRelocations(
697700
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
698701
writePatchableSLEB<5>(Stream, Value, Offset);
699702
break;
703+
case wasm::R_WASM_TABLE_INDEX_SLEB64:
700704
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
701705
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
702706
writePatchableSLEB<10>(Stream, Value, Offset);
@@ -1599,7 +1603,9 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
15991603
// purely to make the object file's provisional values readable, and is
16001604
// ignored by the linker, which re-calculates the relocations itself.
16011605
if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 &&
1606+
Rel.Type != wasm::R_WASM_TABLE_INDEX_I64 &&
16021607
Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB &&
1608+
Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB64 &&
16031609
Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB)
16041610
return;
16051611
assert(Rel.Symbol->isFunction());

llvm/lib/Object/RelocationResolver.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@ static bool supportsWasm64(uint64_t Type) {
531531
case wasm::R_WASM_MEMORY_ADDR_LEB64:
532532
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
533533
case wasm::R_WASM_MEMORY_ADDR_I64:
534+
case wasm::R_WASM_TABLE_INDEX_SLEB64:
535+
case wasm::R_WASM_TABLE_INDEX_I64:
534536
return true;
535537
default:
536538
return supportsWasm32(Type);
@@ -563,6 +565,8 @@ static uint64_t resolveWasm64(RelocationRef R, uint64_t S, uint64_t A) {
563565
case wasm::R_WASM_MEMORY_ADDR_LEB64:
564566
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
565567
case wasm::R_WASM_MEMORY_ADDR_I64:
568+
case wasm::R_WASM_TABLE_INDEX_SLEB64:
569+
case wasm::R_WASM_TABLE_INDEX_I64:
566570
// For wasm section, its offset at 0 -- ignoring Value
567571
return A;
568572
default:

llvm/lib/Object/WasmObjectFile.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,9 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
791791
switch (Reloc.Type) {
792792
case wasm::R_WASM_FUNCTION_INDEX_LEB:
793793
case wasm::R_WASM_TABLE_INDEX_SLEB:
794+
case wasm::R_WASM_TABLE_INDEX_SLEB64:
794795
case wasm::R_WASM_TABLE_INDEX_I32:
796+
case wasm::R_WASM_TABLE_INDEX_I64:
795797
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
796798
if (!isValidFunctionSymbol(Reloc.Index))
797799
return make_error<GenericBinaryError>("Bad relocation function index",
@@ -871,7 +873,8 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
871873
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
872874
Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
873875
Size = 4;
874-
if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64)
876+
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
877+
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64)
875878
Size = 8;
876879
if (Reloc.Offset + Size > EndOffset)
877880
return make_error<GenericBinaryError>("Bad relocation offset",

llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
9292
return wasm::R_WASM_TABLE_INDEX_SLEB;
9393
return wasm::R_WASM_MEMORY_ADDR_SLEB;
9494
case WebAssembly::fixup_sleb128_i64:
95-
assert(SymA.isData());
95+
if (SymA.isFunction())
96+
return wasm::R_WASM_TABLE_INDEX_SLEB64;
9697
return wasm::R_WASM_MEMORY_ADDR_SLEB64;
9798
case WebAssembly::fixup_uleb128_i32:
9899
if (SymA.isGlobal())
@@ -119,6 +120,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
119120
}
120121
return wasm::R_WASM_MEMORY_ADDR_I32;
121122
case FK_Data_8:
123+
if (SymA.isFunction())
124+
return wasm::R_WASM_TABLE_INDEX_I64;
122125
assert(SymA.isData());
123126
return wasm::R_WASM_MEMORY_ADDR_I64;
124127
default:

llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,19 @@ static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults,
441441
const MCInstrDesc &MCID = TII.get(CallOp);
442442
MachineInstrBuilder MIB(MF, MF.CreateMachineInstr(MCID, DL));
443443

444+
// See if we must truncate the function pointer.
445+
// CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers
446+
// as 64-bit for uniformity with other pointer types.
447+
if (IsIndirect && MF.getSubtarget<WebAssemblySubtarget>().hasAddr64()) {
448+
Register Reg32 =
449+
MF.getRegInfo().createVirtualRegister(&WebAssembly::I32RegClass);
450+
auto &FnPtr = CallParams.getOperand(0);
451+
BuildMI(*BB, CallResults.getIterator(), DL,
452+
TII.get(WebAssembly::I32_WRAP_I64), Reg32)
453+
.addReg(FnPtr.getReg());
454+
FnPtr.setReg(Reg32);
455+
}
456+
444457
// Move the function pointer to the end of the arguments for indirect calls
445458
if (IsIndirect) {
446459
auto FnPtr = CallParams.getOperand(0);

llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -328,19 +328,25 @@ defm CONST_F64 : I<(outs F64:$res), (ins f64imm_op:$imm),
328328
} // isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1
329329

330330
def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
331-
(CONST_I32 tglobaladdr:$addr)>, Requires<[IsNotPIC]>;
331+
(CONST_I32 tglobaladdr:$addr)>, Requires<[IsNotPIC, HasAddr32]>;
332+
def : Pat<(i64 (WebAssemblywrapper tglobaladdr:$addr)),
333+
(CONST_I64 tglobaladdr:$addr)>, Requires<[IsNotPIC, HasAddr64]>;
332334

333335
def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
334-
(GLOBAL_GET_I32 tglobaladdr:$addr)>, Requires<[IsPIC]>;
336+
(GLOBAL_GET_I32 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr32]>;
335337

336338
def : Pat<(i32 (WebAssemblywrapperPIC tglobaladdr:$addr)),
337-
(CONST_I32 tglobaladdr:$addr)>, Requires<[IsPIC]>;
339+
(CONST_I32 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr32]>;
340+
def : Pat<(i64 (WebAssemblywrapperPIC tglobaladdr:$addr)),
341+
(CONST_I64 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr64]>;
338342

339343
def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
340-
(GLOBAL_GET_I32 texternalsym:$addr)>, Requires<[IsPIC]>;
344+
(GLOBAL_GET_I32 texternalsym:$addr)>, Requires<[IsPIC, HasAddr32]>;
341345

342346
def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
343-
(CONST_I32 texternalsym:$addr)>, Requires<[IsNotPIC]>;
347+
(CONST_I32 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr32]>;
348+
def : Pat<(i64 (WebAssemblywrapper texternalsym:$addr)),
349+
(CONST_I64 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr64]>;
344350

345351
def : Pat<(i32 (WebAssemblywrapper mcsym:$sym)), (CONST_I32 mcsym:$sym)>;
346352
def : Pat<(i64 (WebAssemblywrapper mcsym:$sym)), (CONST_I64 mcsym:$sym)>;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
; RUN: llc < %s -asm-verbose=false -O2 | FileCheck %s
2+
; RUN: llc < %s -asm-verbose=false -O2 --filetype=obj | obj2yaml | FileCheck --check-prefix=YAML %s
3+
4+
; This tests pointer features that may codegen differently in wasm64.
5+
6+
target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
7+
target triple = "wasm64-unknown-unknown"
8+
9+
define void @bar(i32 %n) {
10+
entry:
11+
ret void
12+
}
13+
14+
define void @foo(void (i32)* %fp) {
15+
entry:
16+
call void %fp(i32 1)
17+
ret void
18+
}
19+
20+
define void @test() {
21+
entry:
22+
call void @foo(void (i32)* @bar)
23+
store void (i32)* @bar, void (i32)** @fptr
24+
ret void
25+
}
26+
27+
@fptr = global void (i32)* @bar
28+
29+
; For simplicity (and compatibility with UB C/C++ code) we keep all types
30+
; of pointers the same size, so function pointers (which are 32-bit indices
31+
; in Wasm) are represented as 64-bit until called.
32+
33+
; CHECK: .functype foo (i64) -> ()
34+
; CHECK-NEXT: i32.const 1
35+
; CHECK-NEXT: local.get 0
36+
; CHECK-NEXT: i32.wrap_i64
37+
; CHECK-NEXT: call_indirect (i32) -> ()
38+
39+
; CHECK: .functype test () -> ()
40+
; CHECK-NEXT: i64.const bar
41+
; CHECK-NEXT: call foo
42+
43+
44+
; Check we're emitting a 64-bit reloc for `i64.const bar` and the global.
45+
46+
; YAML: Memory:
47+
; YAML-NEXT: Flags: [ IS_64 ]
48+
; YAML-NEXT: Initial: 0x00000001
49+
50+
; YAML: - Type: CODE
51+
; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64
52+
; YAML-NEXT: Index: 0
53+
; YAML-NEXT: Offset: 0x00000016
54+
55+
; YAML: - Type: DATA
56+
; YAML: - Type: R_WASM_TABLE_INDEX_I64
57+
; YAML-NEXT: Index: 0
58+
; YAML-NEXT: Offset: 0x00000006

0 commit comments

Comments
 (0)