authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-07 22:27:08+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-13 10:56:03+02:00
logdb44a7803fac38096526e9b8baba60d966d77ab6
tree5bb8d077642a1d871f9e08503265d896f56b9a66
parentb667fe2c62044ec56e05edd74f8ab3f080f813b1

zld: resolve target addresses for relocs


3 files changed, 209 insertions(+), 215 deletions(-)

src/link/MachO/Object.zig+3-1
......@@ -191,11 +191,13 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
191191}
192192
193193pub fn parseSections(self: *Object) !void {
194 log.warn("parsing sections in {s}", .{self.name.?});
194195 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
195196
196197 try self.sections.ensureCapacity(self.allocator, seg.sections.items.len);
197198
198199 for (seg.sections.items) |sect| {
200 log.warn("parsing section '{s},{s}'", .{ parseName(&sect.segname), parseName(&sect.sectname) });
199201 // Read sections' code
200202 var code = try self.allocator.alloc(u8, sect.size);
201203 _ = try self.file.?.preadAll(code, sect.offset);
......@@ -215,7 +217,7 @@ pub fn parseSections(self: *Object) !void {
215217
216218 break :relocs try reloc.parse(
217219 self.allocator,
218 &section.code,
220 section.code,
219221 mem.bytesAsSlice(macho.relocation_info, raw_relocs),
220222 );
221223 } else null;
src/link/MachO/Zld.zig+125-146
......@@ -16,6 +16,7 @@ const Allocator = mem.Allocator;
1616const Archive = @import("Archive.zig");
1717const CodeSignature = @import("CodeSignature.zig");
1818const Object = @import("Object.zig");
19const Relocation = @import("reloc.zig").Relocation;
1920const Symbol = @import("Symbol.zig");
2021const Trie = @import("Trie.zig");
2122
......@@ -77,7 +78,7 @@ symtab: std.StringArrayHashMapUnmanaged(Symbol) = .{},
7778strtab: std.ArrayListUnmanaged(u8) = .{},
7879
7980threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
80rebases: std.ArrayListUnmanaged(Pointer) = .{},
81local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
8182stubs: std.StringArrayHashMapUnmanaged(u32) = .{},
8283got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
8384
......@@ -186,7 +187,7 @@ pub fn init(allocator: *Allocator) Zld {
186187
187188pub fn deinit(self: *Zld) void {
188189 self.threadlocal_offsets.deinit(self.allocator);
189 self.rebases.deinit(self.allocator);
190 self.local_rebases.deinit(self.allocator);
190191
191192 for (self.stubs.items()) |entry| {
192193 self.allocator.free(entry.key);
......@@ -280,9 +281,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
280281 self.allocateLinkeditSegment();
281282 try self.allocateSymbols();
282283 try self.allocateStubsAndGotEntries();
283 self.printDebug();
284 // try self.writeStubHelperCommon();
285 // try self.resolveRelocsAndWriteSections();
284 try self.writeStubHelperCommon();
285 try self.resolveRelocsAndWriteSections();
286286 // try self.flush();
287287}
288288
......@@ -1051,7 +1051,7 @@ fn writeStubHelperCommon(self: *Zld) !void {
10511051 code[9] = 0xff;
10521052 code[10] = 0x25;
10531053 {
1054 const dyld_stub_binder = self.nonlazy_imports.get("dyld_stub_binder").?;
1054 const dyld_stub_binder = self.got_entries.get("dyld_stub_binder").?;
10551055 const addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64));
10561056 const displacement = try math.cast(u32, addr - stub_helper.addr - code_size);
10571057 mem.writeIntLittle(u32, code[11..], displacement);
......@@ -1095,7 +1095,7 @@ fn writeStubHelperCommon(self: *Zld) !void {
10951095 code[10] = 0xbf;
10961096 code[11] = 0xa9;
10971097 binder_blk_outer: {
1098 const dyld_stub_binder = self.nonlazy_imports.get("dyld_stub_binder").?;
1098 const dyld_stub_binder = self.got_entries.get("dyld_stub_binder").?;
10991099 const this_addr = stub_helper.addr + 3 * @sizeOf(u32);
11001100 const target_addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64));
11011101 binder_blk: {
......@@ -1113,7 +1113,6 @@ fn writeStubHelperCommon(self: *Zld) !void {
11131113 const new_this_addr = this_addr + @sizeOf(u32);
11141114 const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :binder_blk;
11151115 const literal = math.cast(u18, displacement) catch |_| break :binder_blk;
1116 log.debug("2: disp=0x{x}, literal=0x{x}", .{ displacement, literal });
11171116 // Pad with nop to please division.
11181117 // nop
11191118 mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32());
......@@ -1149,8 +1148,8 @@ fn writeStubHelperCommon(self: *Zld) !void {
11491148 }
11501149 };
11511150
1152 for (self.lazy_imports.items()) |_, i| {
1153 const index = @intCast(u32, i);
1151 for (self.stubs.items()) |entry| {
1152 const index = entry.value;
11541153 try self.writeLazySymbolPointer(index);
11551154 try self.writeStub(index);
11561155 try self.writeStubInStubHelper(index);
......@@ -1458,6 +1457,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
14581457
14591458 if (self.got_entries.contains(sym_name)) continue;
14601459
1460 // TODO clean this up
14611461 const is_import = self.symtab.get(sym_name).?.tag == .Import;
14621462 var name = try self.allocator.dupe(u8, sym_name);
14631463 const index = @intCast(u32, self.got_entries.items().len);
......@@ -1509,8 +1509,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
15091509
15101510fn resolveRelocsAndWriteSections(self: *Zld) !void {
15111511 for (self.objects.items) |object, object_id| {
1512 log.debug("\n\n", .{});
1513 log.debug("relocating object {s}", .{object.name});
1512 log.warn("relocating object {s}", .{object.name});
15141513
15151514 for (object.sections.items) |sect, source_sect_id| {
15161515 const segname = parseName(&sect.inner.segname);
......@@ -1529,78 +1528,86 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
15291528 const target_sect_addr = target_sect.addr + target_mapping.offset;
15301529 const target_sect_off = target_sect.offset + target_mapping.offset;
15311530
1532 for (sect.relocs) |reloc| {
1533 const source_addr = target_sect_addr + reloc.offset;
1531 if (sect.relocs) |relocs| {
1532 for (relocs) |rel| {
1533 const source_addr = target_sect_addr + rel.offset;
15341534
1535 var args: Relocation.ResolveArgs = .{
1536 .source_addr = source_addr,
1537 .target_addr = undefined,
1538 };
1535 var args: Relocation.ResolveArgs = .{
1536 .source_addr = source_addr,
1537 .target_addr = undefined,
1538 .subtractor = null,
1539 };
15391540
1540 if (reloc.cast(Relocation.Unsigned)) |unsigned| {
1541 // TODO resolve target addr
1541 switch (rel.@"type") {
1542 .unsigned => {
1543 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);
15421544
1543 if (unsigned.subtractor) |subtractor| {
1544 args.subtractor = undefined; // TODO resolve
1545 }
1545 const unsigned = rel.cast(Relocation.Unsigned) orelse unreachable;
1546 if (unsigned.subtractor) |subtractor| {
1547 args.subtractor = try self.relocTargetAddr(@intCast(u16, object_id), subtractor);
1548 }
15461549
1547 rebases: {
1548 var hit: bool = false;
1549 if (target_mapping.target_seg_id == self.data_segment_cmd_index.?) {
1550 if (self.data_section_index) |index| {
1551 if (index == target_mapping.target_sect_id) hit = true;
1550 rebases: {
1551 var hit: bool = false;
1552 if (target_mapping.target_seg_id == self.data_segment_cmd_index.?) {
1553 if (self.data_section_index) |index| {
1554 if (index == target_mapping.target_sect_id) hit = true;
1555 }
1556 }
1557 if (target_mapping.target_seg_id == self.data_const_segment_cmd_index.?) {
1558 if (self.data_const_section_index) |index| {
1559 if (index == target_mapping.target_sect_id) hit = true;
1560 }
1561 }
1562
1563 if (!hit) break :rebases;
1564
1565 try self.local_rebases.append(self.allocator, .{
1566 .offset = source_addr - target_seg.inner.vmaddr,
1567 .segment_id = target_mapping.target_seg_id,
1568 });
15521569 }
1553 }
1554 if (target_mapping.target_seg_id == self.data_const_segment_cmd_index.?) {
1555 if (self.data_const_section_index) |index| {
1556 if (index == target_mapping.target_sect_id) hit = true;
1570 // TLV is handled via a separate offset mechanism.
1571 // Calculate the offset to the initializer.
1572 if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
1573 const sym = object.symtab.items[rel.target.symbol];
1574 const sym_name = object.getString(sym.inner.n_strx);
1575
1576 // TODO we don't want to save offset to tlv_bootstrap
1577 if (mem.eql(u8, sym_name, "__tlv_boostrap")) break :tlv;
1578
1579 const base_addr = blk: {
1580 if (self.tlv_data_section_index) |index| {
1581 const tlv_data = target_seg.sections.items[index];
1582 break :blk tlv_data.addr;
1583 } else {
1584 const tlv_bss = target_seg.sections.items[self.tlv_bss_section_index.?];
1585 break :blk tlv_bss.addr;
1586 }
1587 };
1588 // Since we require TLV data to always preceed TLV bss section, we calculate
1589 // offsets wrt to the former if it is defined; otherwise, wrt to the latter.
1590 try self.threadlocal_offsets.append(self.allocator, args.target_addr - base_addr);
15571591 }
1558 }
1559
1560 if (!hit) break :rebases;
1561
1562 try self.local_rebases.append(self.allocator, .{
1563 .offset = source_addr - target_seg.inner.vmaddr,
1564 .segment_id = target_mapping.target_seg_id,
1565 });
1592 },
1593 .got_page, .got_page_off => {
1594 const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1595 const got = dc_seg.sections.items[self.got_section_index.?];
1596 const sym = object.symtab.items[rel.target.symbol];
1597 const sym_name = object.getString(sym.inner.n_strx);
1598 const entry = self.got_entries.get(sym_name) orelse unreachable;
1599 args.target_addr = got.addr + entry.index * @sizeOf(u64);
1600 },
1601 else => {
1602 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);
1603 },
15661604 }
1567 // TLV is handled via a separate offset mechanism.
1568 // Calculate the offset to the initializer.
1569 if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: {
1570 const sym = object.symtab.items[reloc.target.symbol];
1571 const sym_name = object.getString(sym.inner.n_strx);
1572
1573 // TODO we don't want to save offset to tlv_bootstrap
1574 if (mem.eql(u8, sym_name, "__tlv_boostrap")) break :tlv;
15751605
1576 const base_addr = blk: {
1577 if (self.tlv_data_section_index) |index| {
1578 const tlv_data = target_seg.sections.items[index];
1579 break :blk tlv_data.addr;
1580 } else {
1581 const tlv_bss = target_seg.sections.items[self.tlv_bss_section_index.?];
1582 break :blk tlv_bss.addr;
1583 }
1584 };
1585 // Since we require TLV data to always preceed TLV bss section, we calculate
1586 // offsets wrt to the former if it is defined; otherwise, wrt to the latter.
1587 try self.threadlocal_offsets.append(self.allocator, target_addr - base_addr);
1588 }
1589 } else if (reloc.cast(Relocation.GotPageOff)) |page_off| {
1590 // TODO here we need to work out the indirection to GOT.
1591 } else {
1592 // TODO resolve target addr.
1606 try rel.resolve(args);
15931607 }
1594
1595 log.debug("{s}", .{reloc.@"type"});
1596 log.debug(" | offset 0x{x}", .{reloc.offset});
1597 log.debug(" | source address 0x{x}", .{args.source_addr});
1598 log.debug(" | target address 0x{x}", .{args.target_addr});
1599
1600 try reloc.resolve(args);
16011608 }
16021609
1603 log.debug("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{
1610 log.warn("writing contents of '{s},{s}' section from '{s}' from 0x{x} to 0x{x}", .{
16041611 segname,
16051612 sectname,
16061613 object.name,
......@@ -1612,7 +1619,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16121619 target_sect.flags == macho.S_THREAD_LOCAL_ZEROFILL or
16131620 target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES)
16141621 {
1615 log.debug("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{
1622 log.warn("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{
16161623 parseName(&target_sect.segname),
16171624 parseName(&target_sect.sectname),
16181625 target_sect_off,
......@@ -1630,88 +1637,60 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16301637 }
16311638}
16321639
1633fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 {
1640fn relocTargetAddr(self: *Zld, object_id: u16, target: Relocation.Target) !u64 {
16341641 const object = self.objects.items[object_id];
1635 const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
1642 const target_addr = blk: {
1643 switch (target) {
1644 .symbol => |sym_id| {
1645 const sym = object.symtab.items[sym_id];
1646 const sym_name = object.getString(sym.inner.n_strx);
16361647
1637 const is_got: bool = is_got: {
1638 switch (self.arch.?) {
1639 .x86_64 => {
1640 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
1641 break :is_got = switch (rel_type) {
1642 .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => true,
1643 else => false,
1644 };
1645 },
1646 .aarch64 => {
1647 const rel_type = @intToEnum(macho.reloc_type_aarch64, rel.r_type);
1648 break :is_got = switch (rel_type) {
1649 .ARM64_RELOC_GOT_LOAD_PAGE21,
1650 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
1651 .ARM64_RELOC_POINTER_TO_GOT,
1652 => true,
1653 else => false,
1654 };
1648 switch (sym.tag) {
1649 .Stab => unreachable, // TODO is this even allowed to happen?
1650 .Local, .Weak, .Strong => {
1651 // Relocate using section offsets only.
1652 const target_mapping = self.mappings.get(.{
1653 .object_id = object_id,
1654 .source_sect_id = sym.inner.n_sect - 1,
1655 }) orelse unreachable;
1656 const source_sect = object.sections.items[target_mapping.source_sect_id];
1657 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
1658 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1659 const target_sect_addr = target_sect.addr + target_mapping.offset;
1660 log.warn(" | symbol local to object", .{});
1661 break :blk target_sect_addr + sym.inner.n_value - source_sect.inner.addr;
1662 },
1663 else => {
1664 if (self.stubs.get(sym_name)) |index| {
1665 log.warn(" | symbol stub {s}", .{sym_name});
1666 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1667 const stubs = segment.sections.items[self.stubs_section_index.?];
1668 break :blk stubs.addr + index * stubs.reserved2;
1669 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
1670 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1671 const tlv = segment.sections.items[self.tlv_section_index.?];
1672 break :blk tlv.addr;
1673 } else {
1674 const global = self.symtab.get(sym_name) orelse {
1675 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
1676 return error.FailedToResolveRelocationTarget;
1677 };
1678 break :blk global.inner.n_value;
1679 }
1680 },
1681 }
16551682 },
1656 }
1657 };
1658
1659 const target_addr = blk: {
1660 if (rel.r_extern == 1) {
1661 const sym = object.symtab.items[rel.r_symbolnum];
1662 if (sym.isSect()) {
1663 // Relocate using section offsets only.
1683 .section => |sect_id| {
16641684 const target_mapping = self.mappings.get(.{
16651685 .object_id = object_id,
1666 .source_sect_id = sym.n_sect - 1,
1686 .source_sect_id = sect_id,
16671687 }) orelse unreachable;
1668 const source_sect = seg.sections.items[target_mapping.source_sect_id];
16691688 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
16701689 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1671 const target_sect_addr = target_sect.addr + target_mapping.offset;
1672 log.debug(" | symbol local to object", .{});
1673 break :blk target_sect_addr + sym.n_value - source_sect.addr;
1674 } else if (sym.isUndf()) {
1675 // Relocate to either the global symbol, or an import from
1676 // shared library.
1677 const sym_name = object.getString(sym.n_strx);
1678 if (self.globals.get(sym_name)) |glob| {
1679 break :blk glob.inner.n_value;
1680 } else if (self.externs.getEntry(sym_name)) |ext| {
1681 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1682 const stubs = segment.sections.items[self.stubs_section_index.?];
1683 break :blk stubs.addr + ext.index * stubs.reserved2;
1684 } else if (self.nonlazy_imports.get(sym_name)) |ext| {
1685 const segment = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1686 const got = segment.sections.items[self.got_section_index.?];
1687 break :blk got.addr + ext.index * @sizeOf(u64);
1688 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
1689 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1690 const tlv = segment.sections.items[self.tlv_section_index.?];
1691 break :blk tlv.addr;
1692 } else {
1693 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
1694 return error.FailedToResolveRelocationTarget;
1695 }
1696 } else {
1697 log.err("unexpected symbol {}, {s}", .{ sym, object.getString(sym.n_strx) });
1698 return error.UnexpectedSymbolWhenRelocating;
1699 }
1700 } else {
1701 // TODO I think we need to reparse the relocation_info as scattered_relocation_info
1702 // here to get the actual section plus offset into that section of the relocated
1703 // symbol. Unless the fine-grained location is encoded within the cell in the code
1704 // buffer?
1705 const target_mapping = self.mappings.get(.{
1706 .object_id = object_id,
1707 .source_sect_id = @intCast(u16, rel.r_symbolnum - 1),
1708 }) orelse unreachable;
1709 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
1710 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1711 break :blk target_sect.addr + target_mapping.offset;
1690 break :blk target_sect.addr + target_mapping.offset;
1691 },
17121692 }
17131693 };
1714
17151694 return target_addr;
17161695}
17171696
src/link/MachO/reloc.zig+81-68
......@@ -3,6 +3,7 @@ const aarch64 = @import("../../codegen/aarch64.zig");
33const assert = std.debug.assert;
44const log = std.log.scoped(.reloc);
55const macho = std.macho;
6const math = std.math;
67const mem = std.mem;
78const meta = std.meta;
89
......@@ -10,7 +11,7 @@ const Allocator = mem.Allocator;
1011
1112pub const Relocation = struct {
1213 @"type": Type,
13 code: *[]u8,
14 code: []u8,
1415 offset: u32,
1516 target: Target,
1617
......@@ -24,20 +25,26 @@ pub const Relocation = struct {
2425 pub const ResolveArgs = struct {
2526 source_addr: u64,
2627 target_addr: u64,
27 subtractor: i64 = undefined,
28 subtractor: ?u64,
2829 };
2930
3031 pub fn resolve(base: *Relocation, args: ResolveArgs) !void {
31 switch (base.@"type") {
32 .branch => try base.cast(Branch).?.resolve(args.source_addr, args.target_addr),
33 .unsigned => try base.cast(Unsigned).?.resolve(args.target_addr, args.subtractor),
34 .page => try base.cast(Page).?.resolve(args.source_addr, args.target_addr),
35 .page_off => try base.cast(PageOff).?.resolve(args.target_addr),
36 .got_page => try base.cast(GotPage).?.resolve(args.source_addr, args.target_addr),
37 .got_page_off => try base.cast(GotPageOff).?.resolve(args.target_addr),
38 .tlvp_page => try base.cast(TlvpPage).?.resolve(args.source_addr, args.target_addr),
39 .tlvp_page_off => try base.cast(TlvpPageOff).?.resolve(args.target_addr),
40 }
32 log.warn("{s}", .{base.@"type"});
33 log.warn(" | offset 0x{x}", .{base.offset});
34 log.warn(" | source address 0x{x}", .{args.source_addr});
35 log.warn(" | target address 0x{x}", .{args.target_addr});
36 log.warn(" | subtractor address 0x{x}", .{args.subtractor});
37
38 return switch (base.@"type") {
39 .branch => @fieldParentPtr(Branch, "base", base).resolve(args.source_addr, args.target_addr),
40 .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args.target_addr, args.subtractor),
41 .page => @fieldParentPtr(Page, "base", base).resolve(args.source_addr, args.target_addr),
42 .page_off => @fieldParentPtr(PageOff, "base", base).resolve(args.target_addr),
43 .got_page => @fieldParentPtr(GotPage, "base", base).resolve(args.source_addr, args.target_addr),
44 .got_page_off => @fieldParentPtr(GotPageOff, "base", base).resolve(args.target_addr),
45 .tlvp_page => @fieldParentPtr(TlvpPage, "base", base).resolve(args.source_addr, args.target_addr),
46 .tlvp_page_off => @fieldParentPtr(TlvpPageOff, "base", base).resolve(args.target_addr),
47 };
4148 }
4249
4350 pub const Type = enum {
......@@ -73,9 +80,12 @@ pub const Relocation = struct {
7380
7481 pub fn resolve(branch: Branch, source_addr: u64, target_addr: u64) !void {
7582 const displacement = try math.cast(i28, @intCast(i64, target_addr) - @intCast(i64, source_addr));
83
84 log.warn(" | displacement 0x{x}", .{displacement});
85
7686 var inst = branch.inst;
77 inst.AddSubtractImmediate.imm26 = @truncate(u26, @bitCast(u28, displacement) >> 2);
78 mem.writeIntLittle(u32, branch.base.code.*[branch.base.offset..], inst.toU32());
87 inst.UnconditionalBranchImmediate.imm26 = @truncate(u26, @bitCast(u28, displacement) >> 2);
88 mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32());
7989 }
8090 };
8191
......@@ -92,22 +102,25 @@ pub const Relocation = struct {
92102
93103 pub const base_type: Relocation.Type = .unsigned;
94104
95 pub fn resolve(unsigned: Unsigned, target_addr: u64, subtractor: i64) !void {
96 const result = @intCast(i64, target_addr) - subtractor + unsigned.addend;
105 pub fn resolve(unsigned: Unsigned, target_addr: u64, subtractor: ?u64) !void {
106 const result = if (subtractor) |sub|
107 @intCast(i64, target_addr) - @intCast(i64, sub) + unsigned.addend
108 else
109 @intCast(i64, target_addr) + unsigned.addend;
97110
98 log.debug(" | calculated addend 0x{x}", .{unsigned.addend});
99 log.debug(" | calculated unsigned value 0x{x}", .{result});
111 log.warn(" | calculated addend 0x{x}", .{unsigned.addend});
112 log.warn(" | calculated unsigned value 0x{x}", .{result});
100113
101114 if (unsigned.is_64bit) {
102115 mem.writeIntLittle(
103116 u64,
104 unsigned.base.code.*[unsigned.base.offset..],
117 unsigned.base.code[0..8],
105118 @bitCast(u64, result),
106119 );
107120 } else {
108121 mem.writeIntLittle(
109122 u32,
110 unsigned.base.code.*[unsigned.base.offset..],
123 unsigned.base.code[0..4],
111124 @truncate(u32, @bitCast(u64, result)),
112125 );
113126 }
......@@ -128,13 +141,14 @@ pub const Relocation = struct {
128141 const target_page = @intCast(i32, ta >> 12);
129142 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
130143
131 log.debug(" | moving by {} pages", .{pages});
144 log.warn(" | calculated addend 0x{x}", .{page.addend});
145 log.warn(" | moving by {} pages", .{pages});
132146
133147 var inst = page.inst;
134148 inst.PCRelativeAddress.immhi = @truncate(u19, pages >> 2);
135149 inst.PCRelativeAddress.immlo = @truncate(u2, pages);
136150
137 mem.writeIntLittle(u32, page.base.code.*[page.base.offset..], inst.toU32());
151 mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
138152 }
139153 };
140154
......@@ -155,8 +169,8 @@ pub const Relocation = struct {
155169 const ta = if (page_off.addend) |a| target_addr + a else target_addr;
156170 const narrowed = @truncate(u12, ta);
157171
158 log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
159 log.debug(" | {s} opcode", .{page_off.op_kind});
172 log.warn(" | narrowed address within the page 0x{x}", .{narrowed});
173 log.warn(" | {s} opcode", .{page_off.op_kind});
160174
161175 var inst = page_off.inst;
162176 if (page_off.op_kind == .arithmetic) {
......@@ -178,7 +192,7 @@ pub const Relocation = struct {
178192 inst.LoadStoreRegister.offset = offset;
179193 }
180194
181 mem.writeIntLittle(u32, page_off.base.code.*[page_off.base.offset..], inst.toU32());
195 mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
182196 }
183197 };
184198
......@@ -194,13 +208,13 @@ pub const Relocation = struct {
194208 const target_page = @intCast(i32, target_addr >> 12);
195209 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
196210
197 log.debug(" | moving by {} pages", .{pages});
211 log.warn(" | moving by {} pages", .{pages});
198212
199213 var inst = page.inst;
200214 inst.PCRelativeAddress.immhi = @truncate(u19, pages >> 2);
201215 inst.PCRelativeAddress.immlo = @truncate(u2, pages);
202216
203 mem.writeIntLittle(u32, page.base.code.*[page.base.offset..], inst.toU32());
217 mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
204218 }
205219 };
206220
......@@ -214,13 +228,13 @@ pub const Relocation = struct {
214228 pub fn resolve(page_off: GotPageOff, target_addr: u64) !void {
215229 const narrowed = @truncate(u12, target_addr);
216230
217 log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
231 log.warn(" | narrowed address within the page 0x{x}", .{narrowed});
218232
219233 var inst = page_off.inst;
220234 const offset = try math.divExact(u12, narrowed, 8);
221235 inst.LoadStoreRegister.offset = offset;
222236
223 mem.writeIntLittle(u32, page_off.base.code.*[page_off.base.offset..], inst.toU32());
237 mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
224238 }
225239 };
226240
......@@ -236,13 +250,13 @@ pub const Relocation = struct {
236250 const target_page = @intCast(i32, target_addr >> 12);
237251 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
238252
239 log.debug(" | moving by {} pages", .{pages});
253 log.warn(" | moving by {} pages", .{pages});
240254
241255 var inst = page.inst;
242256 inst.PCRelativeAddress.immhi = @truncate(u19, pages >> 2);
243257 inst.PCRelativeAddress.immlo = @truncate(u2, pages);
244258
245 mem.writeIntLittle(u32, page.base.code.*[page.base.offset..], inst.toU32());
259 mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
246260 }
247261 };
248262
......@@ -258,17 +272,17 @@ pub const Relocation = struct {
258272 pub fn resolve(page_off: TlvpPageOff, target_addr: u64) !void {
259273 const narrowed = @truncate(u12, target_addr);
260274
261 log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
275 log.warn(" | narrowed address within the page 0x{x}", .{narrowed});
262276
263277 var inst = page_off.inst;
264278 inst.AddSubtractImmediate.imm12 = narrowed;
265279
266 mem.writeIntLittle(u32, page_off.base.code.*[page_off.base.offset..], inst.toU32());
280 mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
267281 }
268282 };
269283};
270284
271pub fn parse(allocator: *Allocator, code: *[]u8, relocs: []const macho.relocation_info) ![]*Relocation {
285pub fn parse(allocator: *Allocator, code: []u8, relocs: []const macho.relocation_info) ![]*Relocation {
272286 var it = RelocIterator{
273287 .buffer = relocs,
274288 };
......@@ -280,8 +294,9 @@ pub fn parse(allocator: *Allocator, code: *[]u8, relocs: []const macho.relocatio
280294 .parsed = std.ArrayList(*Relocation).init(allocator),
281295 };
282296 defer parser.deinit();
297 try parser.parse();
283298
284 return parser.parse();
299 return parser.parsed.toOwnedSlice();
285300}
286301
287302const RelocIterator = struct {
......@@ -292,12 +307,12 @@ const RelocIterator = struct {
292307 self.index += 1;
293308 if (self.index < self.buffer.len) {
294309 const reloc = self.buffer[@intCast(u64, self.index)];
295 log.debug("{s}", .{@intToEnum(macho.reloc_type_arm64, reloc.r_type)});
296 log.debug(" | offset = {}", .{reloc.r_address});
297 log.debug(" | PC = {}", .{reloc.r_pcrel == 1});
298 log.debug(" | length = {}", .{reloc.r_length});
299 log.debug(" | symbolnum = {}", .{reloc.r_symbolnum});
300 log.debug(" | extern = {}", .{reloc.r_extern == 1});
310 log.warn("{s}", .{@intToEnum(macho.reloc_type_arm64, reloc.r_type)});
311 log.warn(" | offset = {}", .{reloc.r_address});
312 log.warn(" | PC = {}", .{reloc.r_pcrel == 1});
313 log.warn(" | length = {}", .{reloc.r_length});
314 log.warn(" | symbolnum = {}", .{reloc.r_symbolnum});
315 log.warn(" | extern = {}", .{reloc.r_extern == 1});
301316 return reloc;
302317 }
303318 return null;
......@@ -316,7 +331,7 @@ const RelocIterator = struct {
316331const Parser = struct {
317332 allocator: *Allocator,
318333 it: *RelocIterator,
319 code: *[]u8,
334 code: []u8,
320335 parsed: std.ArrayList(*Relocation),
321336 addend: ?u32 = null,
322337 subtractor: ?Relocation.Target = null,
......@@ -325,7 +340,7 @@ const Parser = struct {
325340 parser.parsed.deinit();
326341 }
327342
328 fn parse(parser: *Parser) ![]*Relocation {
343 fn parse(parser: *Parser) !void {
329344 while (parser.it.next()) |reloc| {
330345 switch (@intToEnum(macho.reloc_type_arm64, reloc.r_type)) {
331346 .ARM64_RELOC_BRANCH26 => {
......@@ -360,8 +375,6 @@ const Parser = struct {
360375 },
361376 }
362377 }
363
364 return parser.parsed.toOwnedSlice();
365378 }
366379
367380 fn parseAddend(parser: *Parser, reloc: macho.relocation_info) !void {
......@@ -395,7 +408,7 @@ const Parser = struct {
395408 assert(reloc.r_length == 2);
396409
397410 const offset = @intCast(u32, reloc.r_address);
398 const inst = parser.code.*[offset..][0..4];
411 const inst = parser.code[offset..][0..4];
399412 const parsed_inst = aarch64.Instruction{ .UnconditionalBranchImmediate = mem.bytesToValue(
400413 meta.TagPayload(
401414 aarch64.Instruction,
......@@ -412,14 +425,14 @@ const Parser = struct {
412425 branch.* = .{
413426 .base = .{
414427 .@"type" = .branch,
415 .code = parser.code,
428 .code = inst,
416429 .offset = @intCast(u32, reloc.r_address),
417430 .target = target,
418431 },
419432 .inst = parsed_inst,
420433 };
421434
422 log.debug(" | emitting {}", .{branch});
435 log.warn(" | emitting {}", .{branch});
423436 try parser.parsed.append(&branch.base);
424437 }
425438
......@@ -431,7 +444,7 @@ const Parser = struct {
431444 const target = Relocation.Target.from_reloc(reloc);
432445
433446 const offset = @intCast(u32, reloc.r_address);
434 const inst = parser.code.*[offset..][0..4];
447 const inst = parser.code[offset..][0..4];
435448 const parsed_inst = aarch64.Instruction{ .PCRelativeAddress = mem.bytesToValue(meta.TagPayload(
436449 aarch64.Instruction,
437450 aarch64.Instruction.PCRelativeAddress,
......@@ -450,7 +463,7 @@ const Parser = struct {
450463 page.* = .{
451464 .base = .{
452465 .@"type" = .page,
453 .code = parser.code,
466 .code = inst,
454467 .offset = offset,
455468 .target = target,
456469 },
......@@ -458,7 +471,7 @@ const Parser = struct {
458471 .inst = parsed_inst,
459472 };
460473
461 log.debug(" | emitting {}", .{page});
474 log.warn(" | emitting {}", .{page});
462475
463476 break :ptr &page.base;
464477 },
......@@ -469,14 +482,14 @@ const Parser = struct {
469482 page.* = .{
470483 .base = .{
471484 .@"type" = .got_page,
472 .code = parser.code,
485 .code = inst,
473486 .offset = offset,
474487 .target = target,
475488 },
476489 .inst = parsed_inst,
477490 };
478491
479 log.debug(" | emitting {}", .{page});
492 log.warn(" | emitting {}", .{page});
480493
481494 break :ptr &page.base;
482495 },
......@@ -487,14 +500,14 @@ const Parser = struct {
487500 page.* = .{
488501 .base = .{
489502 .@"type" = .tlvp_page,
490 .code = parser.code,
503 .code = inst,
491504 .offset = offset,
492505 .target = target,
493506 },
494507 .inst = parsed_inst,
495508 };
496509
497 log.debug(" | emitting {}", .{page});
510 log.warn(" | emitting {}", .{page});
498511
499512 break :ptr &page.base;
500513 },
......@@ -517,7 +530,7 @@ const Parser = struct {
517530 assert(reloc.r_length == 2);
518531
519532 const offset = @intCast(u32, reloc.r_address);
520 const inst = parser.code.*[offset..][0..4];
533 const inst = parser.code[offset..][0..4];
521534
522535 var op_kind: Relocation.PageOff.OpKind = undefined;
523536 var parsed_inst: aarch64.Instruction = undefined;
......@@ -542,7 +555,7 @@ const Parser = struct {
542555 page_off.* = .{
543556 .base = .{
544557 .@"type" = .page_off,
545 .code = parser.code,
558 .code = inst,
546559 .offset = offset,
547560 .target = target,
548561 },
......@@ -551,7 +564,7 @@ const Parser = struct {
551564 .addend = parser.addend,
552565 };
553566
554 log.debug(" | emitting {}", .{page_off});
567 log.warn(" | emitting {}", .{page_off});
555568 try parser.parsed.append(&page_off.base);
556569 }
557570
......@@ -562,7 +575,7 @@ const Parser = struct {
562575 assert(reloc.r_length == 2);
563576
564577 const offset = @intCast(u32, reloc.r_address);
565 const inst = parser.code.*[offset..][0..4];
578 const inst = parser.code[offset..][0..4];
566579 assert(!isArithmeticOp(inst));
567580
568581 const parsed_inst = mem.bytesToValue(meta.TagPayload(
......@@ -579,7 +592,7 @@ const Parser = struct {
579592 page_off.* = .{
580593 .base = .{
581594 .@"type" = .got_page_off,
582 .code = parser.code,
595 .code = inst,
583596 .offset = offset,
584597 .target = target,
585598 },
......@@ -588,7 +601,7 @@ const Parser = struct {
588601 },
589602 };
590603
591 log.debug(" | emitting {}", .{page_off});
604 log.warn(" | emitting {}", .{page_off});
592605 try parser.parsed.append(&page_off.base);
593606 }
594607
......@@ -605,7 +618,7 @@ const Parser = struct {
605618 };
606619
607620 const offset = @intCast(u32, reloc.r_address);
608 const inst = parser.code.*[offset..][0..4];
621 const inst = parser.code[offset..][0..4];
609622 const parsed: RegInfo = parsed: {
610623 if (isArithmeticOp(inst)) {
611624 const parsed_inst = mem.bytesAsValue(meta.TagPayload(
......@@ -638,7 +651,7 @@ const Parser = struct {
638651 page_off.* = .{
639652 .base = .{
640653 .@"type" = .tlvp_page_off,
641 .code = parser.code,
654 .code = inst,
642655 .offset = @intCast(u32, reloc.r_address),
643656 .target = target,
644657 },
......@@ -655,7 +668,7 @@ const Parser = struct {
655668 },
656669 };
657670
658 log.debug(" | emitting {}", .{page_off});
671 log.warn(" | emitting {}", .{page_off});
659672 try parser.parsed.append(&page_off.base);
660673 }
661674
......@@ -700,14 +713,14 @@ const Parser = struct {
700713 };
701714 const offset = @intCast(u32, reloc.r_address);
702715 const addend: i64 = if (is_64bit)
703 mem.readIntLittle(i64, parser.code.*[offset..][0..8])
716 mem.readIntLittle(i64, parser.code[offset..][0..8])
704717 else
705 mem.readIntLittle(i32, parser.code.*[offset..][0..4]);
718 mem.readIntLittle(i32, parser.code[offset..][0..4]);
706719
707720 unsigned.* = .{
708721 .base = .{
709722 .@"type" = .unsigned,
710 .code = parser.code,
723 .code = if (is_64bit) parser.code[offset..][0..8] else parser.code[offset..][0..4],
711724 .offset = offset,
712725 .target = target,
713726 },
......@@ -716,7 +729,7 @@ const Parser = struct {
716729 .addend = addend,
717730 };
718731
719 log.debug(" | emitting {}", .{unsigned});
732 log.warn(" | emitting {}", .{unsigned});
720733 try parser.parsed.append(&unsigned.base);
721734 }
722735};