@indirect_func = local_unnamed_addr global i32 ()* @foo, 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
+; .. against external symbols
@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() {
entry:
; CHECK: Sections:
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: dylink
-; CHECK-NEXT: MemorySize: 20
+; CHECK-NEXT: MemorySize: 24
; CHECK-NEXT: MemoryAlignment: 2
; CHECK-NEXT: TableSize: 3
; CHECK-NEXT: TableAlignment: 0
; 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: Body: 10020B
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Locals: []
-; CHECK-NEXT: Body: 230141046A230241016A360200230141086A230241026A3602002301410C6A230141006A360200230141106A23033602000B
+; CHECK-NEXT: Body: 230141046A230241016A360200230141086A23043602002301410C6A230141006A360200230141106A2303360200230141146A230541046A3602000B
; check the data segment initialized with __memory_base global as offset
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: GLOBAL_GET
; CHECK-NEXT: Index: 1
-; CHECK-NEXT: Content: '0200000001000000020000000000000000000000'
+; CHECK-NEXT: Content: '020000000100000002000000000000000000000000000000'
// This is only called when generating shared libaries (PIC) where address are
// not known at static link time.
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;
for (const WasmRelocation &Rel : Relocations) {
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
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
// Add the offset of the relocation
writeU8(OS, WASM_OPCODE_I32_CONST, "I32_CONST");
- writeSleb128(OS, OutputVA, "offset");
+ writeSleb128(OS, OutputOffset, "offset");
writeU8(OS, WASM_OPCODE_I32_ADD, "ADD");
+ Symbol *Sym = File->getSymbol(Rel);
// Now figure out what we want to store
- switch (Rel.Type) {
- case R_WASM_TABLE_INDEX_I32:
- // Add the table index to the __table_base
+ if (Sym->hasGOTIndex()) {
writeU8(OS, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
- writeUleb128(OS, WasmSym::TableBase->getGlobalIndex(), "table_base");
- writeU8(OS, WASM_OPCODE_I32_CONST, "CONST");
- 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");
+ writeUleb128(OS, Sym->getGOTIndex(), "global index");
+ if (Rel.Addend) {
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");
- } 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;
- }
- default:
- llvm_unreachable("unexpected relocation type in data segment");
+ } else {
+ const GlobalSymbol* BaseSymbol = WasmSym::MemoryBase;
+ if (Rel.Type == R_WASM_TABLE_INDEX_I32)
+ 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