mirror of
https://github.com/intel/llvm.git
synced 2026-01-20 10:58:11 +08:00
[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: https://github.com/WebAssembly/tool-conventions/issues/162 Differential Revision: https://reviews.llvm.org/D96659
This commit is contained in:
89
lld/test/wasm/reloc-relative.s
Normal file
89
lld/test/wasm/reloc-relative.s
Normal file
@@ -0,0 +1,89 @@
|
||||
# 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 %t.o
|
||||
# RUN: wasm-ld --no-entry --no-gc-sections --allow-undefined -fatal-warnings -o %t.wasm %t.o %t.hello32.o
|
||||
# RUN: obj2yaml %t.wasm | FileCheck %s
|
||||
|
||||
.section .x_sec,"",@
|
||||
internal_x_seg_pad:
|
||||
# padding for provisioning value assertion
|
||||
.int32 0
|
||||
.size internal_x_seg_pad, 4
|
||||
internal_x_seg:
|
||||
.int32 42
|
||||
.size internal_x_seg, 4
|
||||
|
||||
# internal cross segment subtraction
|
||||
.section .foo,"",@
|
||||
.globl foo
|
||||
foo:
|
||||
.int32 internal_x_seg - foo
|
||||
.size foo, 4
|
||||
foo_addend:
|
||||
.int32 internal_x_seg - foo
|
||||
.size foo_addend, 4
|
||||
|
||||
# external cross segment subtraction
|
||||
.section .bar,"",@
|
||||
.globl bar
|
||||
bar:
|
||||
.int32 hello_str - bar
|
||||
.size bar, 4
|
||||
bar_addend:
|
||||
.int32 hello_str - bar
|
||||
.size bar_addend, 4
|
||||
|
||||
# positive calc result
|
||||
.section .fizz,"",@
|
||||
.globl fizz
|
||||
fizz:
|
||||
.int32 far - fizz
|
||||
.size fizz, 4
|
||||
fizz_addend:
|
||||
.int32 far - fizz
|
||||
.size fizz_addend, 4
|
||||
|
||||
.section .far,"",@
|
||||
.globl far
|
||||
far:
|
||||
.int32 21
|
||||
.size far, 4
|
||||
|
||||
# CHECK: - Type: DATA
|
||||
# CHECK-NEXT: Segments:
|
||||
# CHECK-NEXT: - SectionOffset: 7
|
||||
# CHECK-NEXT: InitFlags: 0
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 1024
|
||||
# CHECK-NEXT: Content: 68656C6C6F0A00
|
||||
# CHECK-NEXT: - SectionOffset: 20
|
||||
# CHECK-NEXT: InitFlags: 0
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 1031
|
||||
# CHECK-NEXT: Content: 000000002A000000
|
||||
# CHECK-NEXT: - SectionOffset: 34
|
||||
# CHECK-NEXT: InitFlags: 0
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 1039
|
||||
# CHECK-NEXT: Content: FCFFFFFFFCFFFFFF
|
||||
# CHECK-NEXT: - SectionOffset: 48
|
||||
# CHECK-NEXT: InitFlags: 0
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 1047
|
||||
# CHECK-NEXT: Content: E9FFFFFFE9FFFFFF
|
||||
# CHECK-NEXT: - SectionOffset: 62
|
||||
# CHECK-NEXT: InitFlags: 0
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 1055
|
||||
# CHECK-NEXT: Content: '0800000008000000'
|
||||
# CHECK-NEXT: - SectionOffset: 76
|
||||
# CHECK-NEXT: InitFlags: 0
|
||||
# CHECK-NEXT: Offset:
|
||||
# CHECK-NEXT: Opcode: I32_CONST
|
||||
# CHECK-NEXT: Value: 1063
|
||||
# CHECK-NEXT: Content: '15000000'
|
||||
|
||||
@@ -94,6 +94,7 @@ void InputChunk::verifyRelocTargets() const {
|
||||
case R_WASM_FUNCTION_OFFSET_I32:
|
||||
case R_WASM_SECTION_OFFSET_I32:
|
||||
case R_WASM_GLOBAL_INDEX_I32:
|
||||
case R_WASM_MEMORY_ADDR_LOCREL_I32:
|
||||
existingValue = read32le(loc);
|
||||
break;
|
||||
case R_WASM_TABLE_INDEX_I64:
|
||||
@@ -139,7 +140,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
|
||||
|
||||
for (const WasmRelocation &rel : relocations) {
|
||||
uint8_t *loc = buf + rel.Offset + off;
|
||||
auto value = file->calcNewValue(rel, tombstone);
|
||||
auto value = file->calcNewValue(rel, tombstone, this);
|
||||
LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(rel.Type));
|
||||
if (rel.Type != R_WASM_TYPE_INDEX_LEB)
|
||||
LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName());
|
||||
@@ -176,6 +177,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
|
||||
case R_WASM_FUNCTION_OFFSET_I32:
|
||||
case R_WASM_SECTION_OFFSET_I32:
|
||||
case R_WASM_GLOBAL_INDEX_I32:
|
||||
case R_WASM_MEMORY_ADDR_LOCREL_I32:
|
||||
write32le(loc, value);
|
||||
break;
|
||||
case R_WASM_TABLE_INDEX_I64:
|
||||
@@ -302,7 +304,8 @@ void InputFunction::calculateSize() {
|
||||
for (const WasmRelocation &rel : relocations) {
|
||||
LLVM_DEBUG(dbgs() << " region: " << (rel.Offset - lastRelocEnd) << "\n");
|
||||
compressedFuncSize += rel.Offset - lastRelocEnd;
|
||||
compressedFuncSize += getRelocWidth(rel, file->calcNewValue(rel, tombstone));
|
||||
compressedFuncSize +=
|
||||
getRelocWidth(rel, file->calcNewValue(rel, tombstone, this));
|
||||
lastRelocEnd = rel.Offset + getRelocWidthPadded(rel);
|
||||
}
|
||||
LLVM_DEBUG(dbgs() << " final region: " << (end - lastRelocEnd) << "\n");
|
||||
@@ -343,7 +346,8 @@ void InputFunction::writeTo(uint8_t *buf) const {
|
||||
LLVM_DEBUG(dbgs() << " write chunk: " << chunkSize << "\n");
|
||||
memcpy(buf, lastRelocEnd, chunkSize);
|
||||
buf += chunkSize;
|
||||
buf += writeCompressedReloc(buf, rel, file->calcNewValue(rel, tombstone));
|
||||
buf += writeCompressedReloc(buf, rel,
|
||||
file->calcNewValue(rel, tombstone, this));
|
||||
lastRelocEnd = secStart + rel.Offset + getRelocWidthPadded(rel);
|
||||
}
|
||||
|
||||
@@ -416,7 +420,7 @@ void InputSegment::generateRelocationCode(raw_ostream &os) const {
|
||||
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
|
||||
writeU8(os, opcode_reloc_const, "CONST");
|
||||
writeSleb128(os, file->calcNewValue(rel, tombstone), "offset");
|
||||
writeSleb128(os, file->calcNewValue(rel, tombstone, this), "offset");
|
||||
writeU8(os, opcode_reloc_add, "ADD");
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,7 @@ uint64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {
|
||||
case R_WASM_MEMORY_ADDR_TLS_SLEB:
|
||||
case R_WASM_FUNCTION_OFFSET_I32:
|
||||
case R_WASM_FUNCTION_OFFSET_I64:
|
||||
case R_WASM_MEMORY_ADDR_LOCREL_I32:
|
||||
return reloc.Addend;
|
||||
case R_WASM_SECTION_OFFSET_I32:
|
||||
return getSectionSymbol(reloc.Index)->section->getOffset(reloc.Addend);
|
||||
@@ -158,7 +159,8 @@ uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
|
||||
case R_WASM_MEMORY_ADDR_REL_SLEB64:
|
||||
case R_WASM_MEMORY_ADDR_I32:
|
||||
case R_WASM_MEMORY_ADDR_I64:
|
||||
case R_WASM_MEMORY_ADDR_TLS_SLEB: {
|
||||
case R_WASM_MEMORY_ADDR_TLS_SLEB:
|
||||
case R_WASM_MEMORY_ADDR_LOCREL_I32: {
|
||||
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
|
||||
if (sym.isUndefined())
|
||||
return 0;
|
||||
@@ -199,7 +201,8 @@ uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
|
||||
}
|
||||
|
||||
// Translate from the relocation's index into the final linked output value.
|
||||
uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone) const {
|
||||
uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
|
||||
const InputChunk *chunk) const {
|
||||
const Symbol* sym = nullptr;
|
||||
if (reloc.Type != R_WASM_TYPE_INDEX_LEB) {
|
||||
sym = symbols[reloc.Index];
|
||||
@@ -234,7 +237,8 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone)
|
||||
case R_WASM_MEMORY_ADDR_REL_SLEB:
|
||||
case R_WASM_MEMORY_ADDR_REL_SLEB64:
|
||||
case R_WASM_MEMORY_ADDR_I32:
|
||||
case R_WASM_MEMORY_ADDR_I64: {
|
||||
case R_WASM_MEMORY_ADDR_I64:
|
||||
case R_WASM_MEMORY_ADDR_LOCREL_I32: {
|
||||
if (isa<UndefinedData>(sym) || sym->isUndefWeak())
|
||||
return 0;
|
||||
auto D = cast<DefinedData>(sym);
|
||||
@@ -245,7 +249,15 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone)
|
||||
// backward compat with old object files built with `-fPIC`.
|
||||
if (D->segment && D->segment->outputSeg->name == ".tdata")
|
||||
return D->getOutputSegmentOffset() + reloc.Addend;
|
||||
return D->getVA(reloc.Addend);
|
||||
|
||||
uint64_t value = D->getVA(reloc.Addend);
|
||||
if (reloc.Type == R_WASM_MEMORY_ADDR_LOCREL_I32) {
|
||||
const auto *segment = cast<InputSegment>(chunk);
|
||||
uint64_t p = segment->outputSeg->startVA + segment->outputSegmentOffset +
|
||||
reloc.Offset - segment->getInputSectionOffset();
|
||||
value -= p;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
case R_WASM_MEMORY_ADDR_TLS_SLEB:
|
||||
if (isa<UndefinedData>(sym) || sym->isUndefWeak())
|
||||
|
||||
@@ -119,7 +119,8 @@ public:
|
||||
void dumpInfo() const;
|
||||
|
||||
uint32_t calcNewIndex(const WasmRelocation &reloc) const;
|
||||
uint64_t calcNewValue(const WasmRelocation &reloc, uint64_t tombstone) const;
|
||||
uint64_t calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
|
||||
const InputChunk *chunk) const;
|
||||
uint64_t calcNewAddend(const WasmRelocation &reloc) const;
|
||||
uint64_t calcExpectedValue(const WasmRelocation &reloc) const;
|
||||
Symbol *getSymbol(const WasmRelocation &reloc) const {
|
||||
|
||||
@@ -25,3 +25,4 @@ WASM_RELOC(R_WASM_TABLE_INDEX_I64, 19)
|
||||
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)
|
||||
|
||||
@@ -33,8 +33,8 @@ public:
|
||||
return W->getFormat() == Triple::Wasm;
|
||||
}
|
||||
|
||||
virtual unsigned getRelocType(const MCValue &Target,
|
||||
const MCFixup &Fixup) const = 0;
|
||||
virtual unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
|
||||
bool IsLocRel) const = 0;
|
||||
|
||||
/// \name Accessors
|
||||
/// @{
|
||||
|
||||
@@ -52,6 +52,7 @@ bool llvm::wasm::relocTypeHasAddend(uint32_t Type) {
|
||||
case R_WASM_FUNCTION_OFFSET_I32:
|
||||
case R_WASM_FUNCTION_OFFSET_I64:
|
||||
case R_WASM_SECTION_OFFSET_I32:
|
||||
case R_WASM_MEMORY_ADDR_LOCREL_I32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -445,17 +445,35 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
|
||||
uint64_t C = Target.getConstant();
|
||||
uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
|
||||
MCContext &Ctx = Asm.getContext();
|
||||
bool IsLocRel = false;
|
||||
|
||||
if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
|
||||
// To get here the A - B expression must have failed evaluateAsRelocatable.
|
||||
// This means either A or B must be undefined and in WebAssembly we can't
|
||||
// support either of those cases.
|
||||
|
||||
const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
|
||||
Ctx.reportError(
|
||||
Fixup.getLoc(),
|
||||
Twine("symbol '") + SymB.getName() +
|
||||
"': unsupported subtraction expression used in relocation.");
|
||||
return;
|
||||
|
||||
if (FixupSection.getKind().isText()) {
|
||||
Ctx.reportError(Fixup.getLoc(),
|
||||
Twine("symbol '") + SymB.getName() +
|
||||
"' unsupported subtraction expression used in "
|
||||
"relocation in code section.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SymB.isUndefined()) {
|
||||
Ctx.reportError(Fixup.getLoc(),
|
||||
Twine("symbol '") + SymB.getName() +
|
||||
"' can not be undefined in a subtraction expression");
|
||||
return;
|
||||
}
|
||||
const MCSection &SecB = SymB.getSection();
|
||||
if (&SecB != &FixupSection) {
|
||||
Ctx.reportError(Fixup.getLoc(),
|
||||
Twine("symbol '") + SymB.getName() +
|
||||
"' can not be placed in a different section");
|
||||
return;
|
||||
}
|
||||
IsLocRel = true;
|
||||
C += FixupOffset - Layout.getSymbolOffset(SymB);
|
||||
}
|
||||
|
||||
// We either rejected the fixup or folded B into C at this point.
|
||||
@@ -480,7 +498,7 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
|
||||
// be negative and don't wrap.
|
||||
FixedValue = 0;
|
||||
|
||||
unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup);
|
||||
unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup, IsLocRel);
|
||||
|
||||
// Absolute offset within a section or a function.
|
||||
// Currently only supported for for metadata sections.
|
||||
@@ -611,7 +629,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
|
||||
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
|
||||
case wasm::R_WASM_MEMORY_ADDR_I32:
|
||||
case wasm::R_WASM_MEMORY_ADDR_I64:
|
||||
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB: {
|
||||
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
|
||||
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: {
|
||||
// Provisional value is address of the global plus the offset
|
||||
// For undefined symbols, use zero
|
||||
if (!RelEntry.Symbol->isDefined())
|
||||
@@ -707,6 +726,7 @@ void WasmObjectWriter::applyRelocations(
|
||||
case wasm::R_WASM_FUNCTION_OFFSET_I32:
|
||||
case wasm::R_WASM_SECTION_OFFSET_I32:
|
||||
case wasm::R_WASM_GLOBAL_INDEX_I32:
|
||||
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
|
||||
patchI32(Stream, Value, Offset);
|
||||
break;
|
||||
case wasm::R_WASM_TABLE_INDEX_I64:
|
||||
|
||||
@@ -575,6 +575,7 @@ static bool supportsWasm32(uint64_t Type) {
|
||||
case wasm::R_WASM_EVENT_INDEX_LEB:
|
||||
case wasm::R_WASM_GLOBAL_INDEX_I32:
|
||||
case wasm::R_WASM_TABLE_NUMBER_LEB:
|
||||
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -611,6 +612,7 @@ static uint64_t resolveWasm32(uint64_t Type, uint64_t Offset, uint64_t S,
|
||||
case wasm::R_WASM_EVENT_INDEX_LEB:
|
||||
case wasm::R_WASM_GLOBAL_INDEX_I32:
|
||||
case wasm::R_WASM_TABLE_NUMBER_LEB:
|
||||
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
|
||||
// For wasm section, its offset at 0 -- ignoring Value
|
||||
return LocData;
|
||||
default:
|
||||
|
||||
@@ -905,6 +905,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
|
||||
case wasm::R_WASM_MEMORY_ADDR_I32:
|
||||
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
|
||||
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
|
||||
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
|
||||
if (!isValidDataSymbol(Reloc.Index))
|
||||
return make_error<GenericBinaryError>("invalid relocation data index",
|
||||
object_error::parse_failed);
|
||||
@@ -953,6 +954,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
|
||||
Size = 10;
|
||||
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
|
||||
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
|
||||
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
|
||||
Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
|
||||
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
|
||||
Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
|
||||
|
||||
@@ -34,8 +34,8 @@ public:
|
||||
explicit WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten);
|
||||
|
||||
private:
|
||||
unsigned getRelocType(const MCValue &Target,
|
||||
const MCFixup &Fixup) const override;
|
||||
unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
|
||||
bool IsLocRel) const override;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
@@ -63,7 +63,8 @@ static const MCSection *getFixupSection(const MCExpr *Expr) {
|
||||
}
|
||||
|
||||
unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
|
||||
const MCFixup &Fixup) const {
|
||||
const MCFixup &Fixup,
|
||||
bool IsLocRel) const {
|
||||
const MCSymbolRefExpr *RefA = Target.getSymA();
|
||||
assert(RefA);
|
||||
auto& SymA = cast<MCSymbolWasm>(RefA->getSymbol());
|
||||
@@ -122,7 +123,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
|
||||
else if (!Section->isWasmData())
|
||||
return wasm::R_WASM_SECTION_OFFSET_I32;
|
||||
}
|
||||
return wasm::R_WASM_MEMORY_ADDR_I32;
|
||||
return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
|
||||
: wasm::R_WASM_MEMORY_ADDR_I32;
|
||||
case FK_Data_8:
|
||||
if (SymA.isFunction())
|
||||
return wasm::R_WASM_TABLE_INDEX_I64;
|
||||
|
||||
@@ -13,6 +13,22 @@ bar:
|
||||
.int8 1
|
||||
.size bar, 1
|
||||
|
||||
.section .data.fizz,"",@
|
||||
fizz:
|
||||
.int8 1
|
||||
.size fizz, 1
|
||||
|
||||
.section .data.segment1,"",@
|
||||
segment1:
|
||||
// CHECK: 'bar' can not be placed in a different section
|
||||
.int32 fizz-bar
|
||||
// CHECK: 'undef_baz' can not be undefined in a subtraction expression
|
||||
.int32 fizz-undef_baz
|
||||
// CHECK: 'fizz' can not be placed in a different section
|
||||
.int32 undef_baz-fizz
|
||||
.size segment1, 12
|
||||
|
||||
|
||||
.text
|
||||
.section .text.main,"",@
|
||||
main:
|
||||
@@ -23,10 +39,10 @@ main:
|
||||
i32.const foo-foo_other+2
|
||||
i32.const foo_other-foo-10
|
||||
|
||||
// CHECK: 'bar': unsupported subtraction expression used in relocation
|
||||
// CHECK: 'bar' unsupported subtraction expression used in relocation in code section.
|
||||
i32.const foo-bar
|
||||
// CHECK: 'undef_baz': unsupported subtraction expression used in relocation
|
||||
// CHECK: 'undef_baz' unsupported subtraction expression used in relocation in code section.
|
||||
i32.const foo-undef_baz
|
||||
// CHECK: 'foo': unsupported subtraction expression used in relocation
|
||||
// CHECK: 'foo' unsupported subtraction expression used in relocation in code section.
|
||||
i32.const undef_baz-foo
|
||||
end_function
|
||||
|
||||
48
llvm/test/MC/WebAssembly/reloc-relative.ll
Normal file
48
llvm/test/MC/WebAssembly/reloc-relative.ll
Normal file
@@ -0,0 +1,48 @@
|
||||
; RUN: llc -O0 -filetype=obj %s -o - | llvm-readobj -r --expand-relocs - | FileCheck %s
|
||||
|
||||
; CHECK: Format: WASM
|
||||
; CHECK: Relocations [
|
||||
; CHECK-NEXT: Section (3) DATA {
|
||||
; CHECK-NEXT: Relocation {
|
||||
; CHECK-NEXT: Type: R_WASM_MEMORY_ADDR_LOCREL_I32 (23)
|
||||
; CHECK-NEXT: Offset: 0x6
|
||||
; CHECK-NEXT: Symbol: foo
|
||||
; CHECK-NEXT: Addend: 0
|
||||
; CHECK-NEXT: }
|
||||
; CHECK-NEXT: Relocation {
|
||||
; CHECK-NEXT: Type: R_WASM_MEMORY_ADDR_LOCREL_I32 (23)
|
||||
; CHECK-NEXT: Offset: 0xA
|
||||
; CHECK-NEXT: Symbol: fizz
|
||||
; CHECK-NEXT: Addend: 0
|
||||
; CHECK-NEXT: }
|
||||
; CHECK-NEXT: Relocation {
|
||||
; CHECK-NEXT: Type: R_WASM_MEMORY_ADDR_LOCREL_I32 (23)
|
||||
; CHECK-NEXT: Offset: 0x17
|
||||
; CHECK-NEXT: Symbol: foo
|
||||
; CHECK-NEXT: Addend: 4
|
||||
; CHECK-NEXT: }
|
||||
; CHECK-NEXT: }
|
||||
; CHECK-NEXT: ]
|
||||
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
||||
|
||||
; @foo - @bar
|
||||
@foo = external global i32, align 4
|
||||
@bar = constant i32 sub (
|
||||
i32 ptrtoint (i32* @foo to i32),
|
||||
i32 ptrtoint (i32* @bar to i32)
|
||||
), section ".sec1"
|
||||
|
||||
|
||||
; @foo - @addend + 4
|
||||
@fizz = constant i32 42, align 4, section ".sec2"
|
||||
@addend = constant i32 sub (
|
||||
i32 ptrtoint (i32* @foo to i32),
|
||||
i32 ptrtoint (i32* @fizz to i32)
|
||||
), section ".sec2"
|
||||
|
||||
@x_sec = constant i32 sub (
|
||||
i32 ptrtoint (i32* @fizz to i32),
|
||||
i32 ptrtoint (i32* @x_sec to i32)
|
||||
), section ".sec1"
|
||||
Reference in New Issue
Block a user