authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-30 18:49:40-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log9ccf500508923c5694904e660b7dfbd563aba68b
tree09a59c1bc329ea64c90c8d63f64d6218b1feaabd
parent5b18af85cb77d8dd7b2300bd01c00990d03abde2

implement function relocations

not all relocation types are implemented yet

2 files changed, 188 insertions(+), 14 deletions(-)

src/link/Wasm.zig+43-8
...@@ -349,6 +349,10 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -349,6 +349,10 @@ pub const OutputFunctionIndex = enum(u32) {
349 return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index));349 return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index));
350 }350 }
351351
352 pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex {
353 return fromResolution(wasm, .fromObjectFunction(wasm, index)).?;
354 }
355
352 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) OutputFunctionIndex {356 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) OutputFunctionIndex {
353 const zcu = wasm.base.comp.zcu.?;357 const zcu = wasm.base.comp.zcu.?;
354 const ip = &zcu.intern_pool;358 const ip = &zcu.intern_pool;
...@@ -401,6 +405,33 @@ pub const GlobalIndex = enum(u32) {...@@ -401,6 +405,33 @@ pub const GlobalIndex = enum(u32) {
401 const i = wasm.globals.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;405 const i = wasm.globals.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;
402 return @enumFromInt(i);406 return @enumFromInt(i);
403 }407 }
408
409 pub fn fromObjectGlobal(wasm: *const Wasm, i: ObjectGlobalIndex) GlobalIndex {
410 return @enumFromInt(wasm.globals.getIndex(.fromObjectGlobal(wasm, i)).?);
411 }
412
413 pub fn fromSymbolName(wasm: *const Wasm, name: String) GlobalIndex {
414 const import = wasm.object_global_imports.getPtr(name).?;
415 return @enumFromInt(wasm.globals.getIndex(import.resolution).?);
416 }
417};
418
419/// Index into `tables`.
420pub const TableIndex = enum(u32) {
421 _,
422
423 pub fn ptr(index: TableIndex, f: *const Flush) *Wasm.TableImport.Resolution {
424 return &f.tables.items[@intFromEnum(index)];
425 }
426
427 pub fn fromObjectTable(wasm: *const Wasm, i: ObjectTableIndex) TableIndex {
428 return @enumFromInt(wasm.tables.getIndex(.fromObjectTable(i)).?);
429 }
430
431 pub fn fromSymbolName(wasm: *const Wasm, name: String) TableIndex {
432 const import = wasm.object_table_imports.getPtr(name).?;
433 return @enumFromInt(wasm.tables.getIndex(import.resolution).?);
434 }
404};435};
405436
406/// The first N indexes correspond to input objects (`objects`) array.437/// The first N indexes correspond to input objects (`objects`) array.
...@@ -1019,7 +1050,7 @@ pub const ObjectFunction = extern struct {...@@ -1019,7 +1050,7 @@ pub const ObjectFunction = extern struct {
10191050
1020 pub const Code = DataPayload;1051 pub const Code = DataPayload;
10211052
1022 fn relocations(of: *const ObjectFunction, wasm: *const Wasm) ObjectRelocation.IterableSlice {1053 pub fn relocations(of: *const ObjectFunction, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1023 const code_section_index = of.object_index.ptr(wasm).code_section_index.?;1054 const code_section_index = of.object_index.ptr(wasm).code_section_index.?;
1024 const relocs = wasm.object_relocations_table.get(code_section_index) orelse return .empty;1055 const relocs = wasm.object_relocations_table.get(code_section_index) orelse return .empty;
1025 return .init(relocs, of.offset, of.code.len, wasm);1056 return .init(relocs, of.offset, of.code.len, wasm);
...@@ -1181,7 +1212,7 @@ pub const ObjectGlobal = extern struct {...@@ -1181,7 +1212,7 @@ pub const ObjectGlobal = extern struct {
1181 mutable: bool,1212 mutable: bool,
1182 };1213 };
11831214
1184 fn relocations(og: *const ObjectGlobal, wasm: *const Wasm) ObjectRelocation.IterableSlice {1215 pub fn relocations(og: *const ObjectGlobal, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1185 const global_section_index = og.object_index.ptr(wasm).global_section_index.?;1216 const global_section_index = og.object_index.ptr(wasm).global_section_index.?;
1186 const relocs = wasm.object_relocations_table.get(global_section_index) orelse return .empty;1217 const relocs = wasm.object_relocations_table.get(global_section_index) orelse return .empty;
1187 return .init(relocs, og.offset, og.size, wasm);1218 return .init(relocs, og.offset, og.size, wasm);
...@@ -1440,7 +1471,7 @@ pub const ObjectDataSegment = extern struct {...@@ -1440,7 +1471,7 @@ pub const ObjectDataSegment = extern struct {
1440 }1471 }
1441 };1472 };
14421473
1443 fn relocations(ods: *const ObjectDataSegment, wasm: *const Wasm) ObjectRelocation.IterableSlice {1474 pub fn relocations(ods: *const ObjectDataSegment, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1444 const data_section_index = ods.object_index.ptr(wasm).data_section_index.?;1475 const data_section_index = ods.object_index.ptr(wasm).data_section_index.?;
1445 const relocs = wasm.object_relocations_table.get(data_section_index) orelse return .empty;1476 const relocs = wasm.object_relocations_table.get(data_section_index) orelse return .empty;
1446 return .init(relocs, ods.offset, ods.payload.len, wasm);1477 return .init(relocs, ods.offset, ods.payload.len, wasm);
...@@ -1563,6 +1594,10 @@ pub const DataId = enum(u32) {...@@ -1563,6 +1594,10 @@ pub const DataId = enum(u32) {
1563 };1594 };
1564 }1595 }
15651596
1597 pub fn fromObjectDataSegment(wasm: *const Wasm, object_data_segment: ObjectDataSegment.Index) DataId {
1598 return pack(wasm, .{ .object = object_data_segment });
1599 }
1600
1566 pub fn category(id: DataId, wasm: *const Wasm) Category {1601 pub fn category(id: DataId, wasm: *const Wasm) Category {
1567 return switch (unpack(id, wasm)) {1602 return switch (unpack(id, wasm)) {
1568 .__zig_error_names, .__zig_error_name_table => .data,1603 .__zig_error_names, .__zig_error_name_table => .data,
...@@ -2258,19 +2293,19 @@ pub const ObjectRelocation = struct {...@@ -2258,19 +2293,19 @@ pub const ObjectRelocation = struct {
22582293
2259 const empty: Slice = .{ .off = 0, .len = 0 };2294 const empty: Slice = .{ .off = 0, .len = 0 };
22602295
2261 fn tags(s: Slice, wasm: *const Wasm) []const ObjectRelocation.Tag {2296 pub fn tags(s: Slice, wasm: *const Wasm) []const ObjectRelocation.Tag {
2262 return wasm.object_relocations.items(.tag)[s.off..][0..s.len];2297 return wasm.object_relocations.items(.tag)[s.off..][0..s.len];
2263 }2298 }
22642299
2265 fn offsets(s: Slice, wasm: *const Wasm) []const u32 {2300 pub fn offsets(s: Slice, wasm: *const Wasm) []const u32 {
2266 return wasm.object_relocations.items(.offset)[s.off..][0..s.len];2301 return wasm.object_relocations.items(.offset)[s.off..][0..s.len];
2267 }2302 }
22682303
2269 fn pointees(s: Slice, wasm: *const Wasm) []const Pointee {2304 pub fn pointees(s: Slice, wasm: *const Wasm) []const Pointee {
2270 return wasm.object_relocations.items(.pointee)[s.off..][0..s.len];2305 return wasm.object_relocations.items(.pointee)[s.off..][0..s.len];
2271 }2306 }
22722307
2273 fn addends(s: Slice, wasm: *const Wasm) []const i32 {2308 pub fn addends(s: Slice, wasm: *const Wasm) []const i32 {
2274 return wasm.object_relocations.items(.addend)[s.off..][0..s.len];2309 return wasm.object_relocations.items(.addend)[s.off..][0..s.len];
2275 }2310 }
2276 };2311 };
...@@ -3131,7 +3166,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.Fil...@@ -3131,7 +3166,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.Fil
3131}3166}
31323167
3133fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void {3168fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void {
3134 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| {3169 for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, pointee, offset| {
3135 if (offset >= relocs.end) break;3170 if (offset >= relocs.end) break;
3136 switch (tag) {3171 switch (tag) {
3137 .function_import_index_leb,3172 .function_import_index_leb,
src/link/Wasm/Flush.zig+145-6
...@@ -683,10 +683,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -683,10 +683,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
683 .__wasm_init_memory => @panic("TODO lower __wasm_init_memory "),683 .__wasm_init_memory => @panic("TODO lower __wasm_init_memory "),
684 .__wasm_init_tls => @panic("TODO lower __wasm_init_tls "),684 .__wasm_init_tls => @panic("TODO lower __wasm_init_tls "),
685 .object_function => |i| {685 .object_function => |i| {
686 _ = i;686 const ptr = i.ptr(wasm);
687 @panic("TODO lower object function code and apply relocations");687 const code = ptr.code.slice(wasm);
688 //try leb.writeUleb128(binary_writer, atom.code.len);688 try leb.writeUleb128(binary_writer, code.len);
689 //try binary_bytes.appendSlice(gpa, atom.code.slice(wasm));689 const code_start = binary_bytes.items.len;
690 try binary_bytes.appendSlice(gpa, code);
691 if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);
690 },692 },
691 .zcu_func => |i| {693 .zcu_func => |i| {
692 const code_start = try reserveSize(gpa, binary_bytes);694 const code_start = try reserveSize(gpa, binary_bytes);
...@@ -699,7 +701,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -699,7 +701,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
699 };701 };
700702
701 replaceVecSectionHeader(binary_bytes, header_offset, .code, @intCast(wasm.functions.entries.len));703 replaceVecSectionHeader(binary_bytes, header_offset, .code, @intCast(wasm.functions.entries.len));
702 if (is_obj) @panic("TODO apply offset to code relocs");
703 code_section_index = section_index;704 code_section_index = section_index;
704 section_index += 1;705 section_index += 1;
705 }706 }
...@@ -801,7 +802,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -801,7 +802,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
801 }802 }
802803
803 if (is_obj) {804 if (is_obj) {
804 @panic("TODO emit link section for object file and apply relocations");805 @panic("TODO emit link section for object file and emit modified relocations");
805 //var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena);806 //var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena);
806 //try wasm.emitLinkSection(binary_bytes, &symbol_table);807 //try wasm.emitLinkSection(binary_bytes, &symbol_table);
807 //if (code_section_index) |code_index| {808 //if (code_section_index) |code_index| {
...@@ -1420,3 +1421,141 @@ fn emitErrorNameTable(...@@ -1420,3 +1421,141 @@ fn emitErrorNameTable(
1420 mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little);1421 mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little);
1421 }1422 }
1422}1423}
1424
1425fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.IterableSlice, wasm: *const Wasm) void {
1426 for (
1427 relocs.slice.tags(wasm),
1428 relocs.slice.pointees(wasm),
1429 relocs.slice.offsets(wasm),
1430 relocs.slice.addends(wasm),
1431 ) |tag, pointee, offset, *addend| {
1432 if (offset >= relocs.end) break;
1433 const sliced_code = code[offset - code_offset ..];
1434 switch (tag) {
1435 .function_index_i32 => reloc_u32_function(sliced_code, .fromObjectFunction(wasm, pointee.function)),
1436 .function_index_leb => reloc_leb_function(sliced_code, .fromObjectFunction(wasm, pointee.function)),
1437 .function_offset_i32 => @panic("TODO this value is not known yet"),
1438 .function_offset_i64 => @panic("TODO this value is not known yet"),
1439 .table_index_i32 => @panic("TODO indirect function table needs to support object functions too"),
1440 .table_index_i64 => @panic("TODO indirect function table needs to support object functions too"),
1441 .table_index_rel_sleb => @panic("TODO indirect function table needs to support object functions too"),
1442 .table_index_rel_sleb64 => @panic("TODO indirect function table needs to support object functions too"),
1443 .table_index_sleb => @panic("TODO indirect function table needs to support object functions too"),
1444 .table_index_sleb64 => @panic("TODO indirect function table needs to support object functions too"),
1445
1446 .function_import_index_i32 => reloc_u32_function(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1447 .function_import_index_leb => reloc_leb_function(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1448 .function_import_offset_i32 => @panic("TODO this value is not known yet"),
1449 .function_import_offset_i64 => @panic("TODO this value is not known yet"),
1450 .table_import_index_i32 => @panic("TODO indirect function table needs to support object functions too"),
1451 .table_import_index_i64 => @panic("TODO indirect function table needs to support object functions too"),
1452 .table_import_index_rel_sleb => @panic("TODO indirect function table needs to support object functions too"),
1453 .table_import_index_rel_sleb64 => @panic("TODO indirect function table needs to support object functions too"),
1454 .table_import_index_sleb => @panic("TODO indirect function table needs to support object functions too"),
1455 .table_import_index_sleb64 => @panic("TODO indirect function table needs to support object functions too"),
1456
1457 .global_index_i32 => reloc_u32_global(sliced_code, .fromObjectGlobal(wasm, pointee.global)),
1458 .global_index_leb => reloc_leb_global(sliced_code, .fromObjectGlobal(wasm, pointee.global)),
1459
1460 .global_import_index_i32 => reloc_u32_global(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1461 .global_import_index_leb => reloc_leb_global(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1462
1463 .memory_addr_i32 => reloc_u32_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1464 .memory_addr_i64 => reloc_u64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1465 .memory_addr_leb => reloc_leb_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1466 .memory_addr_leb64 => reloc_leb64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1467 .memory_addr_locrel_i32 => @panic("TODO implement relocation memory_addr_locrel_i32"),
1468 .memory_addr_rel_sleb => @panic("TODO implement relocation memory_addr_rel_sleb"),
1469 .memory_addr_rel_sleb64 => @panic("TODO implement relocation memory_addr_rel_sleb64"),
1470 .memory_addr_sleb => reloc_sleb_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1471 .memory_addr_sleb64 => reloc_sleb64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1472 .memory_addr_tls_sleb => @panic("TODO implement relocation memory_addr_tls_sleb"),
1473 .memory_addr_tls_sleb64 => @panic("TODO implement relocation memory_addr_tls_sleb64"),
1474
1475 .memory_addr_import_i32 => reloc_u32_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1476 .memory_addr_import_i64 => reloc_u64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1477 .memory_addr_import_leb => reloc_leb_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1478 .memory_addr_import_leb64 => reloc_leb64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1479 .memory_addr_import_locrel_i32 => @panic("TODO implement relocation memory_addr_import_locrel_i32"),
1480 .memory_addr_import_rel_sleb => @panic("TODO implement relocation memory_addr_import_rel_sleb"),
1481 .memory_addr_import_rel_sleb64 => @panic("TODO implement memory_addr_import_rel_sleb64"),
1482 .memory_addr_import_sleb => reloc_sleb_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1483 .memory_addr_import_sleb64 => reloc_sleb64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1484 .memory_addr_import_tls_sleb => @panic("TODO"),
1485 .memory_addr_import_tls_sleb64 => @panic("TODO"),
1486
1487 .section_offset_i32 => @panic("TODO this value is not known yet"),
1488
1489 .table_number_leb => reloc_leb_table(sliced_code, .fromObjectTable(wasm, pointee.table)),
1490 .table_import_number_leb => reloc_leb_table(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1491
1492 .type_index_leb => reloc_leb_type(sliced_code, pointee.type_index),
1493 }
1494 }
1495}
1496
1497fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void {
1498 mem.writeInt(u32, code[0..4], @intFromEnum(function), .little);
1499}
1500
1501fn reloc_leb_function(code: []u8, function: Wasm.OutputFunctionIndex) void {
1502 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(function));
1503}
1504
1505fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void {
1506 mem.writeInt(u32, code[0..4], @intFromEnum(global), .little);
1507}
1508
1509fn reloc_leb_global(code: []u8, global: Wasm.GlobalIndex) void {
1510 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(global));
1511}
1512
1513const RelocAddr = struct {
1514 addr: u32,
1515
1516 fn fromObjectData(wasm: *const Wasm, i: Wasm.ObjectData.Index, addend: i32) RelocAddr {
1517 const ptr = i.ptr(wasm);
1518 const f = &wasm.flush_buffer;
1519 const addr = f.data_segments.get(.fromObjectDataSegment(wasm, ptr.segment)).?;
1520 return .{ .addr = @intCast(@as(i64, addr) + addend) };
1521 }
1522
1523 fn fromSymbolName(wasm: *const Wasm, name: String, addend: i32) RelocAddr {
1524 _ = wasm;
1525 _ = name;
1526 _ = addend;
1527 @panic("TODO implement data symbol resolution");
1528 }
1529};
1530
1531fn reloc_u32_addr(code: []u8, ra: RelocAddr) void {
1532 mem.writeInt(u32, code[0..4], ra.addr, .little);
1533}
1534
1535fn reloc_u64_addr(code: []u8, ra: RelocAddr) void {
1536 mem.writeInt(u64, code[0..8], ra.addr, .little);
1537}
1538
1539fn reloc_leb_addr(code: []u8, ra: RelocAddr) void {
1540 leb.writeUnsignedFixed(5, code[0..5], ra.addr);
1541}
1542
1543fn reloc_leb64_addr(code: []u8, ra: RelocAddr) void {
1544 leb.writeUnsignedFixed(11, code[0..11], ra.addr);
1545}
1546
1547fn reloc_sleb_addr(code: []u8, ra: RelocAddr) void {
1548 leb.writeSignedFixed(5, code[0..5], ra.addr);
1549}
1550
1551fn reloc_sleb64_addr(code: []u8, ra: RelocAddr) void {
1552 leb.writeSignedFixed(11, code[0..11], ra.addr);
1553}
1554
1555fn reloc_leb_table(code: []u8, table: Wasm.TableIndex) void {
1556 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(table));
1557}
1558
1559fn reloc_leb_type(code: []u8, index: Wasm.FunctionType.Index) void {
1560 leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index));
1561}