Skip to content

Commit aa0c571

Browse files
kateinoigakukunsbc100
authored andcommitted
[WebAssembly] Add new relocation for location relative data
This `R_WASM_MEMORY_ADDR_SELFREL_I32` relocation represents an offset between its relocating address and the symbol address. It's very similar to `R_X86_64_PC32` but restricted to be used for only data segments. ``` S + A - P ``` A: Represents the addend used to compute the value of the relocatable field. P: Represents the place of the storage unit being relocated. S: Represents the value of the symbol whose index resides in the relocation entry. Proposal: WebAssembly/tool-conventions#162 Differential Revision: https://reviews.llvm.org/D96659
1 parent d9a29a6 commit aa0c571

File tree

13 files changed

+226
-28
lines changed

13 files changed

+226
-28
lines changed

lld/test/wasm/reloc-relative.s

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/hello.s -o %t.hello32.o
2+
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.o
3+
# RUN: wasm-ld --no-entry --no-gc-sections --allow-undefined -fatal-warnings -o %t.wasm %t.o %t.hello32.o
4+
# RUN: obj2yaml %t.wasm | FileCheck %s
5+
6+
.section .x_sec,"",@
7+
internal_x_seg_pad:
8+
# padding for provisioning value assertion
9+
.int32 0
10+
.size internal_x_seg_pad, 4
11+
internal_x_seg:
12+
.int32 42
13+
.size internal_x_seg, 4
14+
15+
# internal cross segment subtraction
16+
.section .foo,"",@
17+
.globl foo
18+
foo:
19+
.int32 internal_x_seg - foo
20+
.size foo, 4
21+
foo_addend:
22+
.int32 internal_x_seg - foo
23+
.size foo_addend, 4
24+
25+
# external cross segment subtraction
26+
.section .bar,"",@
27+
.globl bar
28+
bar:
29+
.int32 hello_str - bar
30+
.size bar, 4
31+
bar_addend:
32+
.int32 hello_str - bar
33+
.size bar_addend, 4
34+
35+
# positive calc result
36+
.section .fizz,"",@
37+
.globl fizz
38+
fizz:
39+
.int32 far - fizz
40+
.size fizz, 4
41+
fizz_addend:
42+
.int32 far - fizz
43+
.size fizz_addend, 4
44+
45+
.section .far,"",@
46+
.globl far
47+
far:
48+
.int32 21
49+
.size far, 4
50+
51+
# CHECK: - Type: DATA
52+
# CHECK-NEXT: Segments:
53+
# CHECK-NEXT: - SectionOffset: 7
54+
# CHECK-NEXT: InitFlags: 0
55+
# CHECK-NEXT: Offset:
56+
# CHECK-NEXT: Opcode: I32_CONST
57+
# CHECK-NEXT: Value: 1024
58+
# CHECK-NEXT: Content: 68656C6C6F0A00
59+
# CHECK-NEXT: - SectionOffset: 20
60+
# CHECK-NEXT: InitFlags: 0
61+
# CHECK-NEXT: Offset:
62+
# CHECK-NEXT: Opcode: I32_CONST
63+
# CHECK-NEXT: Value: 1031
64+
# CHECK-NEXT: Content: 000000002A000000
65+
# CHECK-NEXT: - SectionOffset: 34
66+
# CHECK-NEXT: InitFlags: 0
67+
# CHECK-NEXT: Offset:
68+
# CHECK-NEXT: Opcode: I32_CONST
69+
# CHECK-NEXT: Value: 1039
70+
# CHECK-NEXT: Content: FCFFFFFFFCFFFFFF
71+
# CHECK-NEXT: - SectionOffset: 48
72+
# CHECK-NEXT: InitFlags: 0
73+
# CHECK-NEXT: Offset:
74+
# CHECK-NEXT: Opcode: I32_CONST
75+
# CHECK-NEXT: Value: 1047
76+
# CHECK-NEXT: Content: E9FFFFFFE9FFFFFF
77+
# CHECK-NEXT: - SectionOffset: 62
78+
# CHECK-NEXT: InitFlags: 0
79+
# CHECK-NEXT: Offset:
80+
# CHECK-NEXT: Opcode: I32_CONST
81+
# CHECK-NEXT: Value: 1055
82+
# CHECK-NEXT: Content: '0800000008000000'
83+
# CHECK-NEXT: - SectionOffset: 76
84+
# CHECK-NEXT: InitFlags: 0
85+
# CHECK-NEXT: Offset:
86+
# CHECK-NEXT: Opcode: I32_CONST
87+
# CHECK-NEXT: Value: 1063
88+
# CHECK-NEXT: Content: '15000000'
89+

lld/wasm/InputChunks.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ void InputChunk::verifyRelocTargets() const {
9494
case R_WASM_FUNCTION_OFFSET_I32:
9595
case R_WASM_SECTION_OFFSET_I32:
9696
case R_WASM_GLOBAL_INDEX_I32:
97+
case R_WASM_MEMORY_ADDR_LOCREL_I32:
9798
existingValue = read32le(loc);
9899
break;
99100
case R_WASM_TABLE_INDEX_I64:
@@ -139,7 +140,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
139140

140141
for (const WasmRelocation &rel : relocations) {
141142
uint8_t *loc = buf + rel.Offset + off;
142-
auto value = file->calcNewValue(rel, tombstone);
143+
auto value = file->calcNewValue(rel, tombstone, this);
143144
LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(rel.Type));
144145
if (rel.Type != R_WASM_TYPE_INDEX_LEB)
145146
LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName());
@@ -176,6 +177,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
176177
case R_WASM_FUNCTION_OFFSET_I32:
177178
case R_WASM_SECTION_OFFSET_I32:
178179
case R_WASM_GLOBAL_INDEX_I32:
180+
case R_WASM_MEMORY_ADDR_LOCREL_I32:
179181
write32le(loc, value);
180182
break;
181183
case R_WASM_TABLE_INDEX_I64:
@@ -302,7 +304,8 @@ void InputFunction::calculateSize() {
302304
for (const WasmRelocation &rel : relocations) {
303305
LLVM_DEBUG(dbgs() << " region: " << (rel.Offset - lastRelocEnd) << "\n");
304306
compressedFuncSize += rel.Offset - lastRelocEnd;
305-
compressedFuncSize += getRelocWidth(rel, file->calcNewValue(rel, tombstone));
307+
compressedFuncSize +=
308+
getRelocWidth(rel, file->calcNewValue(rel, tombstone, this));
306309
lastRelocEnd = rel.Offset + getRelocWidthPadded(rel);
307310
}
308311
LLVM_DEBUG(dbgs() << " final region: " << (end - lastRelocEnd) << "\n");
@@ -343,7 +346,8 @@ void InputFunction::writeTo(uint8_t *buf) const {
343346
LLVM_DEBUG(dbgs() << " write chunk: " << chunkSize << "\n");
344347
memcpy(buf, lastRelocEnd, chunkSize);
345348
buf += chunkSize;
346-
buf += writeCompressedReloc(buf, rel, file->calcNewValue(rel, tombstone));
349+
buf += writeCompressedReloc(buf, rel,
350+
file->calcNewValue(rel, tombstone, this));
347351
lastRelocEnd = secStart + rel.Offset + getRelocWidthPadded(rel);
348352
}
349353

@@ -416,7 +420,7 @@ void InputSegment::generateRelocationCode(raw_ostream &os) const {
416420
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
417421
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
418422
writeU8(os, opcode_reloc_const, "CONST");
419-
writeSleb128(os, file->calcNewValue(rel, tombstone), "offset");
423+
writeSleb128(os, file->calcNewValue(rel, tombstone, this), "offset");
420424
writeU8(os, opcode_reloc_add, "ADD");
421425
}
422426

lld/wasm/InputFiles.cpp

+16-4
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ uint64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {
126126
case R_WASM_MEMORY_ADDR_TLS_SLEB:
127127
case R_WASM_FUNCTION_OFFSET_I32:
128128
case R_WASM_FUNCTION_OFFSET_I64:
129+
case R_WASM_MEMORY_ADDR_LOCREL_I32:
129130
return reloc.Addend;
130131
case R_WASM_SECTION_OFFSET_I32:
131132
return getSectionSymbol(reloc.Index)->section->getOffset(reloc.Addend);
@@ -158,7 +159,8 @@ uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
158159
case R_WASM_MEMORY_ADDR_REL_SLEB64:
159160
case R_WASM_MEMORY_ADDR_I32:
160161
case R_WASM_MEMORY_ADDR_I64:
161-
case R_WASM_MEMORY_ADDR_TLS_SLEB: {
162+
case R_WASM_MEMORY_ADDR_TLS_SLEB:
163+
case R_WASM_MEMORY_ADDR_LOCREL_I32: {
162164
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
163165
if (sym.isUndefined())
164166
return 0;
@@ -199,7 +201,8 @@ uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
199201
}
200202

201203
// Translate from the relocation's index into the final linked output value.
202-
uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone) const {
204+
uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
205+
const InputChunk *chunk) const {
203206
const Symbol* sym = nullptr;
204207
if (reloc.Type != R_WASM_TYPE_INDEX_LEB) {
205208
sym = symbols[reloc.Index];
@@ -234,7 +237,8 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone)
234237
case R_WASM_MEMORY_ADDR_REL_SLEB:
235238
case R_WASM_MEMORY_ADDR_REL_SLEB64:
236239
case R_WASM_MEMORY_ADDR_I32:
237-
case R_WASM_MEMORY_ADDR_I64: {
240+
case R_WASM_MEMORY_ADDR_I64:
241+
case R_WASM_MEMORY_ADDR_LOCREL_I32: {
238242
if (isa<UndefinedData>(sym) || sym->isUndefWeak())
239243
return 0;
240244
auto D = cast<DefinedData>(sym);
@@ -245,7 +249,15 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone)
245249
// backward compat with old object files built with `-fPIC`.
246250
if (D->segment && D->segment->outputSeg->name == ".tdata")
247251
return D->getOutputSegmentOffset() + reloc.Addend;
248-
return D->getVA(reloc.Addend);
252+
253+
uint64_t value = D->getVA(reloc.Addend);
254+
if (reloc.Type == R_WASM_MEMORY_ADDR_LOCREL_I32) {
255+
const auto *segment = cast<InputSegment>(chunk);
256+
uint64_t p = segment->outputSeg->startVA + segment->outputSegmentOffset +
257+
reloc.Offset - segment->getInputSectionOffset();
258+
value -= p;
259+
}
260+
return value;
249261
}
250262
case R_WASM_MEMORY_ADDR_TLS_SLEB:
251263
if (isa<UndefinedData>(sym) || sym->isUndefWeak())

lld/wasm/InputFiles.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ class ObjFile : public InputFile {
119119
void dumpInfo() const;
120120

121121
uint32_t calcNewIndex(const WasmRelocation &reloc) const;
122-
uint64_t calcNewValue(const WasmRelocation &reloc, uint64_t tombstone) const;
122+
uint64_t calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
123+
const InputChunk *chunk) const;
123124
uint64_t calcNewAddend(const WasmRelocation &reloc) const;
124125
uint64_t calcExpectedValue(const WasmRelocation &reloc) const;
125126
Symbol *getSymbol(const WasmRelocation &reloc) const {

llvm/include/llvm/BinaryFormat/WasmRelocs.def

+1
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ WASM_RELOC(R_WASM_TABLE_INDEX_I64, 19)
2525
WASM_RELOC(R_WASM_TABLE_NUMBER_LEB, 20)
2626
WASM_RELOC(R_WASM_MEMORY_ADDR_TLS_SLEB, 21)
2727
WASM_RELOC(R_WASM_FUNCTION_OFFSET_I64, 22)
28+
WASM_RELOC(R_WASM_MEMORY_ADDR_LOCREL_I32, 23)

llvm/include/llvm/MC/MCWasmObjectWriter.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ class MCWasmObjectTargetWriter : public MCObjectTargetWriter {
3333
return W->getFormat() == Triple::Wasm;
3434
}
3535

36-
virtual unsigned getRelocType(const MCValue &Target,
37-
const MCFixup &Fixup) const = 0;
36+
virtual unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
37+
bool IsLocRel) const = 0;
3838

3939
/// \name Accessors
4040
/// @{

llvm/lib/BinaryFormat/Wasm.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ bool llvm::wasm::relocTypeHasAddend(uint32_t Type) {
5252
case R_WASM_FUNCTION_OFFSET_I32:
5353
case R_WASM_FUNCTION_OFFSET_I64:
5454
case R_WASM_SECTION_OFFSET_I32:
55+
case R_WASM_MEMORY_ADDR_LOCREL_I32:
5556
return true;
5657
default:
5758
return false;

llvm/lib/MC/WasmObjectWriter.cpp

+30-10
Original file line numberDiff line numberDiff line change
@@ -445,17 +445,35 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
445445
uint64_t C = Target.getConstant();
446446
uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
447447
MCContext &Ctx = Asm.getContext();
448+
bool IsLocRel = false;
448449

449450
if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
450-
// To get here the A - B expression must have failed evaluateAsRelocatable.
451-
// This means either A or B must be undefined and in WebAssembly we can't
452-
// support either of those cases.
451+
453452
const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
454-
Ctx.reportError(
455-
Fixup.getLoc(),
456-
Twine("symbol '") + SymB.getName() +
457-
"': unsupported subtraction expression used in relocation.");
458-
return;
453+
454+
if (FixupSection.getKind().isText()) {
455+
Ctx.reportError(Fixup.getLoc(),
456+
Twine("symbol '") + SymB.getName() +
457+
"' unsupported subtraction expression used in "
458+
"relocation in code section.");
459+
return;
460+
}
461+
462+
if (SymB.isUndefined()) {
463+
Ctx.reportError(Fixup.getLoc(),
464+
Twine("symbol '") + SymB.getName() +
465+
"' can not be undefined in a subtraction expression");
466+
return;
467+
}
468+
const MCSection &SecB = SymB.getSection();
469+
if (&SecB != &FixupSection) {
470+
Ctx.reportError(Fixup.getLoc(),
471+
Twine("symbol '") + SymB.getName() +
472+
"' can not be placed in a different section");
473+
return;
474+
}
475+
IsLocRel = true;
476+
C += FixupOffset - Layout.getSymbolOffset(SymB);
459477
}
460478

461479
// We either rejected the fixup or folded B into C at this point.
@@ -480,7 +498,7 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
480498
// be negative and don't wrap.
481499
FixedValue = 0;
482500

483-
unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup);
501+
unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup, IsLocRel);
484502

485503
// Absolute offset within a section or a function.
486504
// Currently only supported for for metadata sections.
@@ -611,7 +629,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
611629
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
612630
case wasm::R_WASM_MEMORY_ADDR_I32:
613631
case wasm::R_WASM_MEMORY_ADDR_I64:
614-
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB: {
632+
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
633+
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: {
615634
// Provisional value is address of the global plus the offset
616635
// For undefined symbols, use zero
617636
if (!RelEntry.Symbol->isDefined())
@@ -707,6 +726,7 @@ void WasmObjectWriter::applyRelocations(
707726
case wasm::R_WASM_FUNCTION_OFFSET_I32:
708727
case wasm::R_WASM_SECTION_OFFSET_I32:
709728
case wasm::R_WASM_GLOBAL_INDEX_I32:
729+
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
710730
patchI32(Stream, Value, Offset);
711731
break;
712732
case wasm::R_WASM_TABLE_INDEX_I64:

llvm/lib/Object/RelocationResolver.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ static bool supportsWasm32(uint64_t Type) {
575575
case wasm::R_WASM_EVENT_INDEX_LEB:
576576
case wasm::R_WASM_GLOBAL_INDEX_I32:
577577
case wasm::R_WASM_TABLE_NUMBER_LEB:
578+
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
578579
return true;
579580
default:
580581
return false;
@@ -611,6 +612,7 @@ static uint64_t resolveWasm32(uint64_t Type, uint64_t Offset, uint64_t S,
611612
case wasm::R_WASM_EVENT_INDEX_LEB:
612613
case wasm::R_WASM_GLOBAL_INDEX_I32:
613614
case wasm::R_WASM_TABLE_NUMBER_LEB:
615+
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
614616
// For wasm section, its offset at 0 -- ignoring Value
615617
return LocData;
616618
default:

llvm/lib/Object/WasmObjectFile.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
905905
case wasm::R_WASM_MEMORY_ADDR_I32:
906906
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
907907
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
908+
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
908909
if (!isValidDataSymbol(Reloc.Index))
909910
return make_error<GenericBinaryError>("invalid relocation data index",
910911
object_error::parse_failed);
@@ -953,6 +954,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
953954
Size = 10;
954955
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
955956
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
957+
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
956958
Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
957959
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
958960
Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)

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

+6-4
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
3434
explicit WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten);
3535

3636
private:
37-
unsigned getRelocType(const MCValue &Target,
38-
const MCFixup &Fixup) const override;
37+
unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
38+
bool IsLocRel) const override;
3939
};
4040
} // end anonymous namespace
4141

@@ -63,7 +63,8 @@ static const MCSection *getFixupSection(const MCExpr *Expr) {
6363
}
6464

6565
unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
66-
const MCFixup &Fixup) const {
66+
const MCFixup &Fixup,
67+
bool IsLocRel) const {
6768
const MCSymbolRefExpr *RefA = Target.getSymA();
6869
assert(RefA);
6970
auto& SymA = cast<MCSymbolWasm>(RefA->getSymbol());
@@ -122,7 +123,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
122123
else if (!Section->isWasmData())
123124
return wasm::R_WASM_SECTION_OFFSET_I32;
124125
}
125-
return wasm::R_WASM_MEMORY_ADDR_I32;
126+
return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
127+
: wasm::R_WASM_MEMORY_ADDR_I32;
126128
case FK_Data_8:
127129
if (SymA.isFunction())
128130
return wasm::R_WASM_TABLE_INDEX_I64;

0 commit comments

Comments
 (0)