diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-12-30 18:49:40 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-01-15 15:11:36 -0800 |
| commit | 9ccf500508923c5694904e660b7dfbd563aba68b (patch) | |
| tree | 09a59c1bc329ea64c90c8d63f64d6218b1feaabd /src | |
| parent | 5b18af85cb77d8dd7b2300bd01c00990d03abde2 (diff) | |
| download | zig-9ccf500508923c5694904e660b7dfbd563aba68b.tar.gz zig-9ccf500508923c5694904e660b7dfbd563aba68b.zip | |
implement function relocations
not all relocation types are implemented yet
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Wasm.zig | 51 | ||||
| -rw-r--r-- | src/link/Wasm/Flush.zig | 151 |
2 files changed, 188 insertions, 14 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 58c3a949d9..23fab0b865 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -349,6 +349,10 @@ pub const OutputFunctionIndex = enum(u32) { return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index)); } + pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex { + return fromResolution(wasm, .fromObjectFunction(wasm, index)).?; + } + pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) OutputFunctionIndex { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; @@ -401,6 +405,33 @@ pub const GlobalIndex = enum(u32) { const i = wasm.globals.getIndex(.fromIpNav(wasm, nav_index)) orelse return null; return @enumFromInt(i); } + + pub fn fromObjectGlobal(wasm: *const Wasm, i: ObjectGlobalIndex) GlobalIndex { + return @enumFromInt(wasm.globals.getIndex(.fromObjectGlobal(wasm, i)).?); + } + + pub fn fromSymbolName(wasm: *const Wasm, name: String) GlobalIndex { + const import = wasm.object_global_imports.getPtr(name).?; + return @enumFromInt(wasm.globals.getIndex(import.resolution).?); + } +}; + +/// Index into `tables`. +pub const TableIndex = enum(u32) { + _, + + pub fn ptr(index: TableIndex, f: *const Flush) *Wasm.TableImport.Resolution { + return &f.tables.items[@intFromEnum(index)]; + } + + pub fn fromObjectTable(wasm: *const Wasm, i: ObjectTableIndex) TableIndex { + return @enumFromInt(wasm.tables.getIndex(.fromObjectTable(i)).?); + } + + pub fn fromSymbolName(wasm: *const Wasm, name: String) TableIndex { + const import = wasm.object_table_imports.getPtr(name).?; + return @enumFromInt(wasm.tables.getIndex(import.resolution).?); + } }; /// The first N indexes correspond to input objects (`objects`) array. @@ -1019,7 +1050,7 @@ pub const ObjectFunction = extern struct { pub const Code = DataPayload; - fn relocations(of: *const ObjectFunction, wasm: *const Wasm) ObjectRelocation.IterableSlice { + pub fn relocations(of: *const ObjectFunction, wasm: *const Wasm) ObjectRelocation.IterableSlice { const code_section_index = of.object_index.ptr(wasm).code_section_index.?; const relocs = wasm.object_relocations_table.get(code_section_index) orelse return .empty; return .init(relocs, of.offset, of.code.len, wasm); @@ -1181,7 +1212,7 @@ pub const ObjectGlobal = extern struct { mutable: bool, }; - fn relocations(og: *const ObjectGlobal, wasm: *const Wasm) ObjectRelocation.IterableSlice { + pub fn relocations(og: *const ObjectGlobal, wasm: *const Wasm) ObjectRelocation.IterableSlice { const global_section_index = og.object_index.ptr(wasm).global_section_index.?; const relocs = wasm.object_relocations_table.get(global_section_index) orelse return .empty; return .init(relocs, og.offset, og.size, wasm); @@ -1440,7 +1471,7 @@ pub const ObjectDataSegment = extern struct { } }; - fn relocations(ods: *const ObjectDataSegment, wasm: *const Wasm) ObjectRelocation.IterableSlice { + pub fn relocations(ods: *const ObjectDataSegment, wasm: *const Wasm) ObjectRelocation.IterableSlice { const data_section_index = ods.object_index.ptr(wasm).data_section_index.?; const relocs = wasm.object_relocations_table.get(data_section_index) orelse return .empty; return .init(relocs, ods.offset, ods.payload.len, wasm); @@ -1563,6 +1594,10 @@ pub const DataId = enum(u32) { }; } + pub fn fromObjectDataSegment(wasm: *const Wasm, object_data_segment: ObjectDataSegment.Index) DataId { + return pack(wasm, .{ .object = object_data_segment }); + } + pub fn category(id: DataId, wasm: *const Wasm) Category { return switch (unpack(id, wasm)) { .__zig_error_names, .__zig_error_name_table => .data, @@ -2258,19 +2293,19 @@ pub const ObjectRelocation = struct { const empty: Slice = .{ .off = 0, .len = 0 }; - fn tags(s: Slice, wasm: *const Wasm) []const ObjectRelocation.Tag { + pub fn tags(s: Slice, wasm: *const Wasm) []const ObjectRelocation.Tag { return wasm.object_relocations.items(.tag)[s.off..][0..s.len]; } - fn offsets(s: Slice, wasm: *const Wasm) []const u32 { + pub fn offsets(s: Slice, wasm: *const Wasm) []const u32 { return wasm.object_relocations.items(.offset)[s.off..][0..s.len]; } - fn pointees(s: Slice, wasm: *const Wasm) []const Pointee { + pub fn pointees(s: Slice, wasm: *const Wasm) []const Pointee { return wasm.object_relocations.items(.pointee)[s.off..][0..s.len]; } - fn addends(s: Slice, wasm: *const Wasm) []const i32 { + pub fn addends(s: Slice, wasm: *const Wasm) []const i32 { return wasm.object_relocations.items(.addend)[s.off..][0..s.len]; } }; @@ -3131,7 +3166,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.Fil } fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void { - for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| { + for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, pointee, offset| { if (offset >= relocs.end) break; switch (tag) { .function_import_index_leb, diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 91ab224850..d7983d1708 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -683,10 +683,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .__wasm_init_memory => @panic("TODO lower __wasm_init_memory "), .__wasm_init_tls => @panic("TODO lower __wasm_init_tls "), .object_function => |i| { - _ = i; - @panic("TODO lower object function code and apply relocations"); - //try leb.writeUleb128(binary_writer, atom.code.len); - //try binary_bytes.appendSlice(gpa, atom.code.slice(wasm)); + const ptr = i.ptr(wasm); + const code = ptr.code.slice(wasm); + try leb.writeUleb128(binary_writer, code.len); + const code_start = binary_bytes.items.len; + try binary_bytes.appendSlice(gpa, code); + if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); }, .zcu_func => |i| { const code_start = try reserveSize(gpa, binary_bytes); @@ -699,7 +701,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { }; replaceVecSectionHeader(binary_bytes, header_offset, .code, @intCast(wasm.functions.entries.len)); - if (is_obj) @panic("TODO apply offset to code relocs"); code_section_index = section_index; section_index += 1; } @@ -801,7 +802,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } if (is_obj) { - @panic("TODO emit link section for object file and apply relocations"); + @panic("TODO emit link section for object file and emit modified relocations"); //var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena); //try wasm.emitLinkSection(binary_bytes, &symbol_table); //if (code_section_index) |code_index| { @@ -1420,3 +1421,141 @@ fn emitErrorNameTable( mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little); } } + +fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.IterableSlice, wasm: *const Wasm) void { + for ( + relocs.slice.tags(wasm), + relocs.slice.pointees(wasm), + relocs.slice.offsets(wasm), + relocs.slice.addends(wasm), + ) |tag, pointee, offset, *addend| { + if (offset >= relocs.end) break; + const sliced_code = code[offset - code_offset ..]; + switch (tag) { + .function_index_i32 => reloc_u32_function(sliced_code, .fromObjectFunction(wasm, pointee.function)), + .function_index_leb => reloc_leb_function(sliced_code, .fromObjectFunction(wasm, pointee.function)), + .function_offset_i32 => @panic("TODO this value is not known yet"), + .function_offset_i64 => @panic("TODO this value is not known yet"), + .table_index_i32 => @panic("TODO indirect function table needs to support object functions too"), + .table_index_i64 => @panic("TODO indirect function table needs to support object functions too"), + .table_index_rel_sleb => @panic("TODO indirect function table needs to support object functions too"), + .table_index_rel_sleb64 => @panic("TODO indirect function table needs to support object functions too"), + .table_index_sleb => @panic("TODO indirect function table needs to support object functions too"), + .table_index_sleb64 => @panic("TODO indirect function table needs to support object functions too"), + + .function_import_index_i32 => reloc_u32_function(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), + .function_import_index_leb => reloc_leb_function(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), + .function_import_offset_i32 => @panic("TODO this value is not known yet"), + .function_import_offset_i64 => @panic("TODO this value is not known yet"), + .table_import_index_i32 => @panic("TODO indirect function table needs to support object functions too"), + .table_import_index_i64 => @panic("TODO indirect function table needs to support object functions too"), + .table_import_index_rel_sleb => @panic("TODO indirect function table needs to support object functions too"), + .table_import_index_rel_sleb64 => @panic("TODO indirect function table needs to support object functions too"), + .table_import_index_sleb => @panic("TODO indirect function table needs to support object functions too"), + .table_import_index_sleb64 => @panic("TODO indirect function table needs to support object functions too"), + + .global_index_i32 => reloc_u32_global(sliced_code, .fromObjectGlobal(wasm, pointee.global)), + .global_index_leb => reloc_leb_global(sliced_code, .fromObjectGlobal(wasm, pointee.global)), + + .global_import_index_i32 => reloc_u32_global(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), + .global_import_index_leb => reloc_leb_global(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), + + .memory_addr_i32 => reloc_u32_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)), + .memory_addr_i64 => reloc_u64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)), + .memory_addr_leb => reloc_leb_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)), + .memory_addr_leb64 => reloc_leb64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)), + .memory_addr_locrel_i32 => @panic("TODO implement relocation memory_addr_locrel_i32"), + .memory_addr_rel_sleb => @panic("TODO implement relocation memory_addr_rel_sleb"), + .memory_addr_rel_sleb64 => @panic("TODO implement relocation memory_addr_rel_sleb64"), + .memory_addr_sleb => reloc_sleb_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)), + .memory_addr_sleb64 => reloc_sleb64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)), + .memory_addr_tls_sleb => @panic("TODO implement relocation memory_addr_tls_sleb"), + .memory_addr_tls_sleb64 => @panic("TODO implement relocation memory_addr_tls_sleb64"), + + .memory_addr_import_i32 => reloc_u32_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)), + .memory_addr_import_i64 => reloc_u64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)), + .memory_addr_import_leb => reloc_leb_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)), + .memory_addr_import_leb64 => reloc_leb64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)), + .memory_addr_import_locrel_i32 => @panic("TODO implement relocation memory_addr_import_locrel_i32"), + .memory_addr_import_rel_sleb => @panic("TODO implement relocation memory_addr_import_rel_sleb"), + .memory_addr_import_rel_sleb64 => @panic("TODO implement memory_addr_import_rel_sleb64"), + .memory_addr_import_sleb => reloc_sleb_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)), + .memory_addr_import_sleb64 => reloc_sleb64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)), + .memory_addr_import_tls_sleb => @panic("TODO"), + .memory_addr_import_tls_sleb64 => @panic("TODO"), + + .section_offset_i32 => @panic("TODO this value is not known yet"), + + .table_number_leb => reloc_leb_table(sliced_code, .fromObjectTable(wasm, pointee.table)), + .table_import_number_leb => reloc_leb_table(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), + + .type_index_leb => reloc_leb_type(sliced_code, pointee.type_index), + } + } +} + +fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void { + mem.writeInt(u32, code[0..4], @intFromEnum(function), .little); +} + +fn reloc_leb_function(code: []u8, function: Wasm.OutputFunctionIndex) void { + leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(function)); +} + +fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void { + mem.writeInt(u32, code[0..4], @intFromEnum(global), .little); +} + +fn reloc_leb_global(code: []u8, global: Wasm.GlobalIndex) void { + leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(global)); +} + +const RelocAddr = struct { + addr: u32, + + fn fromObjectData(wasm: *const Wasm, i: Wasm.ObjectData.Index, addend: i32) RelocAddr { + const ptr = i.ptr(wasm); + const f = &wasm.flush_buffer; + const addr = f.data_segments.get(.fromObjectDataSegment(wasm, ptr.segment)).?; + return .{ .addr = @intCast(@as(i64, addr) + addend) }; + } + + fn fromSymbolName(wasm: *const Wasm, name: String, addend: i32) RelocAddr { + _ = wasm; + _ = name; + _ = addend; + @panic("TODO implement data symbol resolution"); + } +}; + +fn reloc_u32_addr(code: []u8, ra: RelocAddr) void { + mem.writeInt(u32, code[0..4], ra.addr, .little); +} + +fn reloc_u64_addr(code: []u8, ra: RelocAddr) void { + mem.writeInt(u64, code[0..8], ra.addr, .little); +} + +fn reloc_leb_addr(code: []u8, ra: RelocAddr) void { + leb.writeUnsignedFixed(5, code[0..5], ra.addr); +} + +fn reloc_leb64_addr(code: []u8, ra: RelocAddr) void { + leb.writeUnsignedFixed(11, code[0..11], ra.addr); +} + +fn reloc_sleb_addr(code: []u8, ra: RelocAddr) void { + leb.writeSignedFixed(5, code[0..5], ra.addr); +} + +fn reloc_sleb64_addr(code: []u8, ra: RelocAddr) void { + leb.writeSignedFixed(11, code[0..11], ra.addr); +} + +fn reloc_leb_table(code: []u8, table: Wasm.TableIndex) void { + leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(table)); +} + +fn reloc_leb_type(code: []u8, index: Wasm.FunctionType.Index) void { + leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index)); +} |
