forked from OSchip/llvm-project
[WebAssembly] Always take into account added when applying runtime relocations
The code we generate for applying data relocations at runtime omitted the symbols with GOT entries. Also refactor the code to reduce duplication. Differential Revision: https://reviews.llvm.org/D61111 llvm-svn: 359207
This commit is contained in:
parent
a1309a3147
commit
b685ddf288
|
|
@ -9,8 +9,14 @@ target triple = "wasm32-unknown-unknown"
|
||||||
@indirect_func = local_unnamed_addr global i32 ()* @foo, align 4
|
@indirect_func = local_unnamed_addr global i32 ()* @foo, align 4
|
||||||
@indirect_func_external = local_unnamed_addr global void ()* @func_external, align 4
|
@indirect_func_external = local_unnamed_addr global void ()* @func_external, align 4
|
||||||
|
|
||||||
|
; Test data relocations
|
||||||
@data_addr = local_unnamed_addr global i32* @data, align 4
|
@data_addr = local_unnamed_addr global i32* @data, align 4
|
||||||
|
; .. against external symbols
|
||||||
@data_addr_external = local_unnamed_addr global i32* @data_external, align 4
|
@data_addr_external = local_unnamed_addr global i32* @data_external, align 4
|
||||||
|
; .. including addends
|
||||||
|
%struct.s = type { i32, i32 }
|
||||||
|
@extern_struct = external global %struct.s
|
||||||
|
@extern_struct_internal_ptr = local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @extern_struct, i32 0, i32 1), align 4
|
||||||
|
|
||||||
define hidden i32 @foo() {
|
define hidden i32 @foo() {
|
||||||
entry:
|
entry:
|
||||||
|
|
@ -46,7 +52,7 @@ declare void @func_external()
|
||||||
; CHECK: Sections:
|
; CHECK: Sections:
|
||||||
; CHECK-NEXT: - Type: CUSTOM
|
; CHECK-NEXT: - Type: CUSTOM
|
||||||
; CHECK-NEXT: Name: dylink
|
; CHECK-NEXT: Name: dylink
|
||||||
; CHECK-NEXT: MemorySize: 20
|
; CHECK-NEXT: MemorySize: 24
|
||||||
; CHECK-NEXT: MemoryAlignment: 2
|
; CHECK-NEXT: MemoryAlignment: 2
|
||||||
; CHECK-NEXT: TableSize: 3
|
; CHECK-NEXT: TableSize: 3
|
||||||
; CHECK-NEXT: TableAlignment: 0
|
; CHECK-NEXT: TableAlignment: 0
|
||||||
|
|
@ -98,6 +104,11 @@ declare void @func_external()
|
||||||
; CHECK-NEXT: Kind: GLOBAL
|
; CHECK-NEXT: Kind: GLOBAL
|
||||||
; CHECK-NEXT: GlobalType: I32
|
; CHECK-NEXT: GlobalType: I32
|
||||||
; CHECK-NEXT: GlobalMutable: true
|
; 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-NEXT: - Type: FUNCTION
|
||||||
|
|
||||||
; CHECK: - Type: EXPORT
|
; CHECK: - Type: EXPORT
|
||||||
|
|
@ -125,7 +136,7 @@ declare void @func_external()
|
||||||
; CHECK-NEXT: Body: 10020B
|
; CHECK-NEXT: Body: 10020B
|
||||||
; CHECK-NEXT: - Index: 2
|
; CHECK-NEXT: - Index: 2
|
||||||
; CHECK-NEXT: Locals: []
|
; CHECK-NEXT: Locals: []
|
||||||
; CHECK-NEXT: Body: 230141046A230241016A360200230141086A230241026A3602002301410C6A230141006A360200230141106A23033602000B
|
; CHECK-NEXT: Body: 230141046A230241016A360200230141086A23043602002301410C6A230141006A360200230141106A2303360200230141146A230541046A3602000B
|
||||||
|
|
||||||
; check the data segment initialized with __memory_base global as offset
|
; check the data segment initialized with __memory_base global as offset
|
||||||
|
|
||||||
|
|
@ -136,4 +147,4 @@ declare void @func_external()
|
||||||
; CHECK-NEXT: Offset:
|
; CHECK-NEXT: Offset:
|
||||||
; CHECK-NEXT: Opcode: GLOBAL_GET
|
; CHECK-NEXT: Opcode: GLOBAL_GET
|
||||||
; CHECK-NEXT: Index: 1
|
; CHECK-NEXT: Index: 1
|
||||||
; CHECK-NEXT: Content: '0200000001000000020000000000000000000000'
|
; CHECK-NEXT: Content: '020000000100000002000000000000000000000000000000'
|
||||||
|
|
|
||||||
|
|
@ -301,10 +301,19 @@ void InputFunction::writeTo(uint8_t *Buf) const {
|
||||||
// This is only called when generating shared libaries (PIC) where address are
|
// This is only called when generating shared libaries (PIC) where address are
|
||||||
// not known at static link time.
|
// not known at static link time.
|
||||||
void InputSegment::generateRelocationCode(raw_ostream &OS) const {
|
void InputSegment::generateRelocationCode(raw_ostream &OS) const {
|
||||||
|
LLVM_DEBUG(dbgs() << "generating runtime relocations: " << getName()
|
||||||
|
<< " count=" << Relocations.size() << "\n");
|
||||||
|
|
||||||
|
// TODO(sbc): Encode the relocations in the data section and write a loop
|
||||||
|
// here to apply them.
|
||||||
uint32_t SegmentVA = OutputSeg->StartVA + OutputSegmentOffset;
|
uint32_t SegmentVA = OutputSeg->StartVA + OutputSegmentOffset;
|
||||||
for (const WasmRelocation &Rel : Relocations) {
|
for (const WasmRelocation &Rel : Relocations) {
|
||||||
uint32_t Offset = Rel.Offset - getInputSectionOffset();
|
uint32_t Offset = Rel.Offset - getInputSectionOffset();
|
||||||
uint32_t OutputVA = SegmentVA + Offset;
|
uint32_t OutputOffset = SegmentVA + Offset;
|
||||||
|
|
||||||
|
LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(Rel.Type)
|
||||||
|
<< " addend=" << Rel.Addend << " index=" << Rel.Index
|
||||||
|
<< " output offset=" << OutputOffset << "\n");
|
||||||
|
|
||||||
// Get __memory_base
|
// Get __memory_base
|
||||||
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
|
|
@ -312,38 +321,28 @@ void InputSegment::generateRelocationCode(raw_ostream &OS) const {
|
||||||
|
|
||||||
// Add the offset of the relocation
|
// Add the offset of the relocation
|
||||||
writeU8(OS, WASM_OPCODE_I32_CONST, "I32_CONST");
|
writeU8(OS, WASM_OPCODE_I32_CONST, "I32_CONST");
|
||||||
writeSleb128(OS, OutputVA, "offset");
|
writeSleb128(OS, OutputOffset, "offset");
|
||||||
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
|
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
|
||||||
|
|
||||||
|
Symbol *Sym = File->getSymbol(Rel);
|
||||||
// Now figure out what we want to store
|
// Now figure out what we want to store
|
||||||
switch (Rel.Type) {
|
if (Sym->hasGOTIndex()) {
|
||||||
case R_WASM_TABLE_INDEX_I32:
|
|
||||||
// Add the table index to the __table_base
|
|
||||||
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
writeUleb128(OS, WasmSym::TableBase->getGlobalIndex(), "table_base");
|
writeUleb128(OS, Sym->getGOTIndex(), "global index");
|
||||||
writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
|
if (Rel.Addend) {
|
||||||
writeSleb128(OS, File->calcNewValue(Rel), "new table index");
|
|
||||||
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
|
|
||||||
break;
|
|
||||||
case R_WASM_MEMORY_ADDR_I32: {
|
|
||||||
Symbol *Sym = File->getSymbol(Rel);
|
|
||||||
if (Sym->isLocal() || Sym->isHidden()) {
|
|
||||||
// Hidden/Local data symbols are accessed via known offset from
|
|
||||||
// __memory_base
|
|
||||||
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
|
||||||
writeUleb128(OS, WasmSym::MemoryBase->getGlobalIndex(), "memory_base");
|
|
||||||
writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
|
writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
|
||||||
writeSleb128(OS, File->calcNewValue(Rel), "new memory offset");
|
writeSleb128(OS, Rel.Addend, "addend");
|
||||||
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
|
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
|
||||||
} else {
|
|
||||||
// Default data symbols are accessed via imported GOT globals
|
|
||||||
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
|
||||||
writeUleb128(OS, Sym->getGOTIndex(), "global index");
|
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
}
|
const GlobalSymbol* BaseSymbol = WasmSym::MemoryBase;
|
||||||
default:
|
if (Rel.Type == R_WASM_TABLE_INDEX_I32)
|
||||||
llvm_unreachable("unexpected relocation type in data segment");
|
BaseSymbol = WasmSym::TableBase;
|
||||||
|
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
|
||||||
|
writeUleb128(OS, BaseSymbol->getGlobalIndex(), "base");
|
||||||
|
writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
|
||||||
|
writeSleb128(OS, File->calcNewValue(Rel), "offset");
|
||||||
|
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store that value at the virtual address
|
// Store that value at the virtual address
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,9 @@ void Symbol::setOutputSymbolIndex(uint32_t Index) {
|
||||||
void Symbol::setGOTIndex(uint32_t Index) {
|
void Symbol::setGOTIndex(uint32_t Index) {
|
||||||
LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n");
|
LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n");
|
||||||
assert(GOTIndex == INVALID_INDEX);
|
assert(GOTIndex == INVALID_INDEX);
|
||||||
|
// Any symbol that is assigned a GOT entry must be exported othewise the
|
||||||
|
// dynamic linker won't be able create the entry that contains it.
|
||||||
|
ForceExport = true;
|
||||||
GOTIndex = Index;
|
GOTIndex = Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue