authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-06 16:31:47+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log15b85df3dd8a754bc26159ea2202781b748a613e
tree0d39fefe78b408358a1f9ac223126b7887debf4a
parent54888c6f4699b07eadd21b744d797006fb96a284

zld: parse relocs per generated TextBlock


5 files changed, 672 insertions(+), 632 deletions(-)

src/link/MachO/Object.zig+106-16
......@@ -53,6 +53,7 @@ initializers: std.ArrayListUnmanaged(u32) = .{},
5353data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
5454
5555symbols: std.ArrayListUnmanaged(*Symbol) = .{},
56sections_as_symbols: std.AutoHashMapUnmanaged(u8, *Symbol) = .{},
5657
5758const DebugInfo = struct {
5859 inner: dwarf.DwarfInfo,
......@@ -160,6 +161,7 @@ pub fn deinit(self: *Object) void {
160161 self.symtab.deinit(self.allocator);
161162 self.strtab.deinit(self.allocator);
162163 self.symbols.deinit(self.allocator);
164 self.sections_as_symbols.deinit(self.allocator);
163165
164166 if (self.name) |n| {
165167 self.allocator.free(n);
......@@ -312,7 +314,7 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r
312314
313315 while (true) {
314316 var change = false;
315 if (relocs[start_id].r_address > end) {
317 if (relocs[start_id].r_address >= end) {
316318 start_id += 1;
317319 change = true;
318320 }
......@@ -332,6 +334,7 @@ const TextBlockParser = struct {
332334 allocator: *Allocator,
333335 section: macho.section_64,
334336 code: []u8,
337 relocs: []macho.relocation_info,
335338 object: *Object,
336339 zld: *Zld,
337340 nlists: []NlistWithIndex,
......@@ -405,6 +408,7 @@ const TextBlockParser = struct {
405408
406409 const start_addr = senior_nlist.nlist.n_value - self.section.addr;
407410 const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;
411 log.warn("{} - {}", .{ start_addr, end_addr });
408412
409413 const code = self.code[start_addr..end_addr];
410414 const size = code.len;
......@@ -424,11 +428,18 @@ const TextBlockParser = struct {
424428 block.* = .{
425429 .local_sym_index = senior_nlist.index,
426430 .aliases = alias_only_indices,
427 .code = code,
431 .references = std.AutoArrayHashMap(u32, void).init(self.allocator),
432 .code = try self.allocator.dupe(u8, code),
433 .relocs = std.ArrayList(*Relocation).init(self.allocator),
428434 .size = size,
429435 .alignment = self.section.@"align",
430436 };
431437
438 const relocs = filterRelocs(self.relocs, start_addr, end_addr);
439 if (relocs.len > 0) {
440 try self.object.parseRelocs(self.zld, relocs, block, start_addr);
441 }
442
432443 self.index += 1;
433444
434445 return block;
......@@ -457,7 +468,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
457468
458469 sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan);
459470
460 for (seg.sections.items) |sect, sect_id| {
471 for (seg.sections.items) |sect, id| {
472 const sect_id = @intCast(u8, id);
461473 log.warn("putting section '{s},{s}' as a TextBlock", .{
462474 segmentName(sect),
463475 sectionName(sect),
......@@ -474,6 +486,12 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
474486 defer self.allocator.free(code);
475487 _ = try self.file.?.preadAll(code, sect.offset);
476488
489 // Read section's list of relocations
490 var raw_relocs = try self.allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
491 defer self.allocator.free(raw_relocs);
492 _ = try self.file.?.preadAll(raw_relocs, sect.reloff);
493 const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs);
494
477495 // Is there any padding between symbols within the section?
478496 const is_padded = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
479497
......@@ -481,7 +499,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
481499 if (is_padded) blocks: {
482500 const filtered_nlists = NlistWithIndex.filterInSection(
483501 sorted_nlists.items,
484 @intCast(u8, sect_id + 1),
502 sect_id + 1,
485503 );
486504
487505 if (filtered_nlists.len == 0) break :blocks;
......@@ -490,6 +508,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
490508 .allocator = self.allocator,
491509 .section = sect,
492510 .code = code,
511 .relocs = relocs,
493512 .object = self,
494513 .zld = zld,
495514 .nlists = filtered_nlists,
......@@ -518,8 +537,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
518537 }
519538 }
520539
521 // TODO parse relocs
522
523540 if (zld.last_text_block) |last| {
524541 last.next = block;
525542 block.prev = last;
......@@ -531,14 +548,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
531548 }
532549
533550 // Since there is no symbol to refer to this block, we create
534 // a temp one.
535 const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
536 self.name.?,
537 segmentName(sect),
538 sectionName(sect),
539 });
540 defer self.allocator.free(name);
541 const symbol = try Symbol.new(self.allocator, name);
551 // a temp one, unless we already did that when working out the relocations
552 // of other text blocks.
553 const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
554 const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
555 self.name.?,
556 segmentName(sect),
557 sectionName(sect),
558 });
559 defer self.allocator.free(name);
560 const symbol = try Symbol.new(self.allocator, name);
561 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
562 break :symbol symbol;
563 };
542564 symbol.payload = .{
543565 .regular = .{
544566 .linkage = .translation_unit,
......@@ -555,12 +577,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
555577
556578 block.* = .{
557579 .local_sym_index = local_sym_index,
558 .code = code,
580 .references = std.AutoArrayHashMap(u32, void).init(self.allocator),
581 .code = try self.allocator.dupe(u8, code),
582 .relocs = std.ArrayList(*Relocation).init(self.allocator),
559583 .size = sect.size,
560584 .alignment = sect.@"align",
561585 };
562586
563 // TODO parse relocs
587 if (relocs.len > 0) {
588 try self.parseRelocs(zld, relocs, block, 0);
589 }
564590
565591 if (zld.last_text_block) |last| {
566592 last.next = block;
......@@ -571,6 +597,70 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
571597 }
572598}
573599
600fn parseRelocs(
601 self: *Object,
602 zld: *Zld,
603 relocs: []const macho.relocation_info,
604 block: *TextBlock,
605 base_addr: u64,
606) !void {
607 var it = reloc.RelocIterator{
608 .buffer = relocs,
609 };
610
611 switch (self.arch.?) {
612 .aarch64 => {
613 var parser = reloc.aarch64.Parser{
614 .object = self,
615 .zld = zld,
616 .it = &it,
617 .block = block,
618 .base_addr = base_addr,
619 };
620 try parser.parse();
621 },
622 .x86_64 => {
623 var parser = reloc.x86_64.Parser{
624 .object = self,
625 .zld = zld,
626 .it = &it,
627 .block = block,
628 .base_addr = base_addr,
629 };
630 try parser.parse();
631 },
632 else => unreachable,
633 }
634}
635
636pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol {
637 const symbol = blk: {
638 if (rel.r_extern == 1) {
639 break :blk self.symbols.items[rel.r_symbolnum];
640 } else {
641 const sect_id = @intCast(u8, rel.r_symbolnum - 1);
642 const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
643 // We need a valid pointer to Symbol even if there is no symbol, so we create a
644 // dummy symbol upfront which will later be populated when created a TextBlock from
645 // the target section here.
646 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
647 const sect = seg.sections.items[sect_id];
648 const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
649 self.name.?,
650 segmentName(sect),
651 sectionName(sect),
652 });
653 defer self.allocator.free(name);
654 const symbol = try Symbol.new(self.allocator, name);
655 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
656 break :symbol symbol;
657 };
658 break :blk symbol;
659 }
660 };
661 return symbol;
662}
663
574664pub fn parseInitializers(self: *Object) !void {
575665 const index = self.mod_init_func_section_index orelse return;
576666 const section = self.sections.items[index];
src/link/MachO/Zld.zig+18-62
......@@ -135,9 +135,9 @@ const TlvOffset = struct {
135135pub const TextBlock = struct {
136136 local_sym_index: u32,
137137 aliases: ?[]u32 = null,
138 references: ?[]u32 = null,
138 references: std.AutoArrayHashMap(u32, void),
139139 code: []u8,
140 relocs: ?[]*Relocation = null,
140 relocs: std.ArrayList(*Relocation),
141141 size: u64,
142142 alignment: u32,
143143 next: ?*TextBlock = null,
......@@ -147,15 +147,8 @@ pub const TextBlock = struct {
147147 if (block.aliases) |aliases| {
148148 allocator.free(aliases);
149149 }
150 if (block.references) |references| {
151 allocator.free(references);
152 }
153 for (block.relocs.items) |reloc| {
154 allocator.destroy(reloc);
155 }
156 if (block.relocs) |relocs| {
157 allocator.free(relocs);
158 }
150 block.relocs.deinit();
151 block.references.deinit();
159152 allocator.free(code);
160153 }
161154
......@@ -168,12 +161,19 @@ pub const TextBlock = struct {
168161 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
169162 }
170163 }
171 if (self.references) |references| {
164 if (self.references.count() > 0) {
172165 log.warn(" | References:", .{});
173 for (references) |index| {
166 for (self.references.keys()) |index| {
174167 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
175168 }
176169 }
170 log.warn(" | code.len = {}", .{self.code.len});
171 if (self.relocs.items.len > 0) {
172 log.warn("Relocations:", .{});
173 for (self.relocs.items) |rel| {
174 log.warn(" | {}", .{rel});
175 }
176 }
177177 log.warn(" | size = {}", .{self.size});
178178 log.warn(" | align = {}", .{self.alignment});
179179 }
......@@ -280,7 +280,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
280280 try self.resolveSymbols();
281281 try self.parseTextBlocks();
282282 return error.TODO;
283 // try self.resolveStubsAndGotEntries();
284283 // try self.updateMetadata();
285284 // try self.sortSections();
286285 // try self.addRpaths(args.rpaths);
......@@ -1603,7 +1602,9 @@ fn resolveSymbols(self: *Zld) !void {
16031602
16041603 block.* = .{
16051604 .local_sym_index = local_sym_index,
1605 .references = std.AutoArrayHashMap(u32, void).init(self.allocator),
16061606 .code = code,
1607 .relocs = std.ArrayList(*Relocation).init(self.allocator),
16071608 .size = size,
16081609 .alignment = alignment,
16091610 };
......@@ -1624,6 +1625,9 @@ fn resolveSymbols(self: *Zld) !void {
16241625 {
16251626 // Put dyld_stub_binder as an undefined special symbol.
16261627 const symbol = try Symbol.new(self.allocator, "dyld_stub_binder");
1628 const index = @intCast(u32, self.got_entries.items.len);
1629 symbol.got_index = index;
1630 try self.got_entries.append(self.allocator, symbol);
16271631 try self.globals.putNoClobber(self.allocator, symbol.name, symbol);
16281632 }
16291633
......@@ -1699,54 +1703,6 @@ fn parseTextBlocks(self: *Zld) !void {
16991703 }
17001704}
17011705
1702fn resolveStubsAndGotEntries(self: *Zld) !void {
1703 for (self.objects.items) |object| {
1704 log.debug("resolving stubs and got entries from {s}", .{object.name});
1705
1706 for (object.sections.items) |sect| {
1707 const relocs = sect.relocs orelse continue;
1708 for (relocs) |rel| {
1709 switch (rel.@"type") {
1710 .unsigned => continue,
1711 .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {
1712 const sym = object.symbols.items[rel.target.symbol];
1713 if (sym.got_index != null) continue;
1714
1715 const index = @intCast(u32, self.got_entries.items.len);
1716 sym.got_index = index;
1717 try self.got_entries.append(self.allocator, sym);
1718
1719 log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym });
1720 },
1721 else => {
1722 if (rel.target != .symbol) continue;
1723
1724 const sym = object.symbols.items[rel.target.symbol];
1725 assert(sym.payload != .undef);
1726
1727 if (sym.stubs_index != null) continue;
1728 if (sym.payload != .proxy) continue;
1729
1730 const index = @intCast(u32, self.stubs.items.len);
1731 sym.stubs_index = index;
1732 try self.stubs.append(self.allocator, sym);
1733
1734 log.debug(" | found stub {s}: {*}", .{ sym.name, sym });
1735 },
1736 }
1737 }
1738 }
1739 }
1740
1741 // Finally, put dyld_stub_binder as the final GOT entry
1742 const sym = self.globals.get("dyld_stub_binder") orelse unreachable;
1743 const index = @intCast(u32, self.got_entries.items.len);
1744 sym.got_index = index;
1745 try self.got_entries.append(self.allocator, sym);
1746
1747 log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym });
1748}
1749
17501706fn resolveRelocsAndWriteSections(self: *Zld) !void {
17511707 for (self.objects.items) |object| {
17521708 log.debug("relocating object {s}", .{object.name});
src/link/MachO/reloc.zig+88-127
......@@ -6,16 +6,18 @@ const math = std.math;
66const mem = std.mem;
77const meta = std.meta;
88
9const aarch64 = @import("reloc/aarch64.zig");
10const x86_64 = @import("reloc/x86_64.zig");
9pub const aarch64 = @import("reloc/aarch64.zig");
10pub const x86_64 = @import("reloc/x86_64.zig");
1111
1212const Allocator = mem.Allocator;
13const Symbol = @import("Symbol.zig");
14const TextBlock = @import("Zld.zig").TextBlock;
1315
1416pub const Relocation = struct {
1517 @"type": Type,
16 code: []u8,
1718 offset: u32,
18 target: Target,
19 block: *TextBlock,
20 target: *Symbol,
1921
2022 pub fn cast(base: *Relocation, comptime T: type) ?*T {
2123 if (base.@"type" != T.base_type)
......@@ -24,43 +26,24 @@ pub const Relocation = struct {
2426 return @fieldParentPtr(T, "base", base);
2527 }
2628
27 pub const ResolveArgs = struct {
28 source_addr: u64,
29 target_addr: u64,
30 subtractor: ?u64 = null,
31 source_source_sect_addr: ?u64 = null,
32 source_target_sect_addr: ?u64 = null,
33 };
34
35 pub fn resolve(base: *Relocation, args: ResolveArgs) !void {
36 log.debug("{s}", .{base.@"type"});
37 log.debug(" | offset 0x{x}", .{base.offset});
38 log.debug(" | source address 0x{x}", .{args.source_addr});
39 log.debug(" | target address 0x{x}", .{args.target_addr});
40 if (args.subtractor) |sub|
41 log.debug(" | subtractor address 0x{x}", .{sub});
42 if (args.source_source_sect_addr) |addr|
43 log.debug(" | source source section address 0x{x}", .{addr});
44 if (args.source_target_sect_addr) |addr|
45 log.debug(" | source target section address 0x{x}", .{addr});
46
47 return switch (base.@"type") {
48 .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args),
49 .branch_aarch64 => @fieldParentPtr(aarch64.Branch, "base", base).resolve(args),
50 .page => @fieldParentPtr(aarch64.Page, "base", base).resolve(args),
51 .page_off => @fieldParentPtr(aarch64.PageOff, "base", base).resolve(args),
52 .got_page => @fieldParentPtr(aarch64.GotPage, "base", base).resolve(args),
53 .got_page_off => @fieldParentPtr(aarch64.GotPageOff, "base", base).resolve(args),
54 .pointer_to_got => @fieldParentPtr(aarch64.PointerToGot, "base", base).resolve(args),
55 .tlvp_page => @fieldParentPtr(aarch64.TlvpPage, "base", base).resolve(args),
56 .tlvp_page_off => @fieldParentPtr(aarch64.TlvpPageOff, "base", base).resolve(args),
57 .branch_x86_64 => @fieldParentPtr(x86_64.Branch, "base", base).resolve(args),
58 .signed => @fieldParentPtr(x86_64.Signed, "base", base).resolve(args),
59 .got_load => @fieldParentPtr(x86_64.GotLoad, "base", base).resolve(args),
60 .got => @fieldParentPtr(x86_64.Got, "base", base).resolve(args),
61 .tlv => @fieldParentPtr(x86_64.Tlv, "base", base).resolve(args),
62 };
63 }
29 // pub fn resolve(base: *Relocation) !void {
30 // return switch (base.@"type") {
31 // .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(),
32 // .branch_aarch64 => @fieldParentPtr(aarch64.Branch, "base", base).resolve(),
33 // .page => @fieldParentPtr(aarch64.Page, "base", base).resolve(),
34 // .page_off => @fieldParentPtr(aarch64.PageOff, "base", base).resolve(),
35 // .got_page => @fieldParentPtr(aarch64.GotPage, "base", base).resolve(),
36 // .got_page_off => @fieldParentPtr(aarch64.GotPageOff, "base", base).resolve(),
37 // .pointer_to_got => @fieldParentPtr(aarch64.PointerToGot, "base", base).resolve(),
38 // .tlvp_page => @fieldParentPtr(aarch64.TlvpPage, "base", base).resolve(),
39 // .tlvp_page_off => @fieldParentPtr(aarch64.TlvpPageOff, "base", base).resolve(),
40 // .branch_x86_64 => @fieldParentPtr(x86_64.Branch, "base", base).resolve(),
41 // .signed => @fieldParentPtr(x86_64.Signed, "base", base).resolve(),
42 // .got_load => @fieldParentPtr(x86_64.GotLoad, "base", base).resolve(),
43 // .got => @fieldParentPtr(x86_64.Got, "base", base).resolve(),
44 // .tlv => @fieldParentPtr(x86_64.Tlv, "base", base).resolve(),
45 // };
46 // }
6447
6548 pub const Type = enum {
6649 branch_aarch64,
......@@ -79,23 +62,37 @@ pub const Relocation = struct {
7962 tlv,
8063 };
8164
82 pub const Target = union(enum) {
83 symbol: u32,
84 section: u16,
65 pub fn format(base: *const Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
66 try std.fmt.format(writer, "Relocation {{ ", .{});
67 try std.fmt.format(writer, ".type = {s}, ", .{base.@"type"});
68 try std.fmt.format(writer, ".offset = {}, ", .{base.offset});
69 try std.fmt.format(writer, ".block = {}", .{base.block.local_sym_index});
70 try std.fmt.format(writer, ".target = {}, ", .{base.target});
71
72 try switch (base.@"type") {
73 .unsigned => @fieldParentPtr(Unsigned, "base", base).format(fmt, options, writer),
74 .branch_aarch64 => @fieldParentPtr(aarch64.Branch, "base", base).format(fmt, options, writer),
75 .page => @fieldParentPtr(aarch64.Page, "base", base).format(fmt, options, writer),
76 .page_off => @fieldParentPtr(aarch64.PageOff, "base", base).format(fmt, options, writer),
77 .got_page => @fieldParentPtr(aarch64.GotPage, "base", base).format(fmt, options, writer),
78 .got_page_off => @fieldParentPtr(aarch64.GotPageOff, "base", base).format(fmt, options, writer),
79 .pointer_to_got => @fieldParentPtr(aarch64.PointerToGot, "base", base).format(fmt, options, writer),
80 .tlvp_page => @fieldParentPtr(aarch64.TlvpPage, "base", base).format(fmt, options, writer),
81 .tlvp_page_off => @fieldParentPtr(aarch64.TlvpPageOff, "base", base).format(fmt, options, writer),
82 .branch_x86_64 => @fieldParentPtr(x86_64.Branch, "base", base).format(fmt, options, writer),
83 .signed => @fieldParentPtr(x86_64.Signed, "base", base).format(fmt, options, writer),
84 .got_load => @fieldParentPtr(x86_64.GotLoad, "base", base).format(fmt, options, writer),
85 .got => @fieldParentPtr(x86_64.Got, "base", base).format(fmt, options, writer),
86 .tlv => @fieldParentPtr(x86_64.Tlv, "base", base).format(fmt, options, writer),
87 };
8588
86 pub fn fromReloc(reloc: macho.relocation_info) Target {
87 return if (reloc.r_extern == 1) .{
88 .symbol = reloc.r_symbolnum,
89 } else .{
90 .section = @intCast(u16, reloc.r_symbolnum - 1),
91 };
92 }
93 };
89 try std.fmt.format(writer, "}}", .{});
90 }
9491};
9592
9693pub const Unsigned = struct {
9794 base: Relocation,
98 subtractor: ?Relocation.Target = null,
95 subtractor: ?*Symbol = null,
9996 /// Addend embedded directly in the relocation slot
10097 addend: i64,
10198 /// Extracted from r_length:
......@@ -106,75 +103,47 @@ pub const Unsigned = struct {
106103
107104 pub const base_type: Relocation.Type = .unsigned;
108105
109 pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void {
110 const addend = if (unsigned.base.target == .section)
111 unsigned.addend - @intCast(i64, args.source_target_sect_addr.?)
112 else
113 unsigned.addend;
114
115 const result = if (args.subtractor) |subtractor|
116 @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend
117 else
118 @intCast(i64, args.target_addr) + addend;
119
120 log.debug(" | calculated addend 0x{x}", .{addend});
121 log.debug(" | calculated unsigned value 0x{x}", .{result});
122
123 if (unsigned.is_64bit) {
124 mem.writeIntLittle(
125 u64,
126 unsigned.base.code[0..8],
127 @bitCast(u64, result),
128 );
129 } else {
130 mem.writeIntLittle(
131 u32,
132 unsigned.base.code[0..4],
133 @truncate(u32, @bitCast(u64, result)),
134 );
106 // pub fn resolve(unsigned: Unsigned) !void {
107 // const addend = if (unsigned.base.target == .section)
108 // unsigned.addend - @intCast(i64, args.source_target_sect_addr.?)
109 // else
110 // unsigned.addend;
111
112 // const result = if (args.subtractor) |subtractor|
113 // @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend
114 // else
115 // @intCast(i64, args.target_addr) + addend;
116
117 // log.debug(" | calculated addend 0x{x}", .{addend});
118 // log.debug(" | calculated unsigned value 0x{x}", .{result});
119
120 // if (unsigned.is_64bit) {
121 // mem.writeIntLittle(
122 // u64,
123 // unsigned.base.code[0..8],
124 // @bitCast(u64, result),
125 // );
126 // } else {
127 // mem.writeIntLittle(
128 // u32,
129 // unsigned.base.code[0..4],
130 // @truncate(u32, @bitCast(u64, result)),
131 // );
132 // }
133 // }
134
135 pub fn format(self: Unsigned, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
136 _ = fmt;
137 _ = options;
138 if (self.subtractor) |sub| {
139 try std.fmt.format(writer, ".subtractor = {}, ", .{sub});
135140 }
141 try std.fmt.format(writer, ".addend = {}, ", .{self.addend});
142 const length: usize = if (self.is_64bit) 8 else 4;
143 try std.fmt.format(writer, ".length = {}, ", .{length});
136144 }
137145};
138146
139pub fn parse(
140 allocator: *Allocator,
141 arch: std.Target.Cpu.Arch,
142 code: []u8,
143 relocs: []const macho.relocation_info,
144) ![]*Relocation {
145 var it = RelocIterator{
146 .buffer = relocs,
147 };
148
149 switch (arch) {
150 .aarch64 => {
151 var parser = aarch64.Parser{
152 .allocator = allocator,
153 .it = &it,
154 .code = code,
155 .parsed = std.ArrayList(*Relocation).init(allocator),
156 };
157 defer parser.deinit();
158 try parser.parse();
159
160 return parser.parsed.toOwnedSlice();
161 },
162 .x86_64 => {
163 var parser = x86_64.Parser{
164 .allocator = allocator,
165 .it = &it,
166 .code = code,
167 .parsed = std.ArrayList(*Relocation).init(allocator),
168 };
169 defer parser.deinit();
170 try parser.parse();
171
172 return parser.parsed.toOwnedSlice();
173 },
174 else => unreachable,
175 }
176}
177
178147pub const RelocIterator = struct {
179148 buffer: []const macho.relocation_info,
180149 index: i32 = -1,
......@@ -182,15 +151,7 @@ pub const RelocIterator = struct {
182151 pub fn next(self: *RelocIterator) ?macho.relocation_info {
183152 self.index += 1;
184153 if (self.index < self.buffer.len) {
185 const reloc = self.buffer[@intCast(u32, self.index)];
186 log.debug("relocation", .{});
187 log.debug(" | type = {}", .{reloc.r_type});
188 log.debug(" | offset = {}", .{reloc.r_address});
189 log.debug(" | PC = {}", .{reloc.r_pcrel == 1});
190 log.debug(" | length = {}", .{reloc.r_length});
191 log.debug(" | symbolnum = {}", .{reloc.r_symbolnum});
192 log.debug(" | extern = {}", .{reloc.r_extern == 1});
193 return reloc;
154 return self.buffer[@intCast(u32, self.index)];
194155 }
195156 return null;
196157 }
src/link/MachO/reloc/aarch64.zig+278-287
......@@ -9,24 +9,34 @@ const meta = std.meta;
99const reloc = @import("../reloc.zig");
1010
1111const Allocator = mem.Allocator;
12const Object = @import("../Object.zig");
1213const Relocation = reloc.Relocation;
1314const Symbol = @import("../Symbol.zig");
15const TextBlock = Zld.TextBlock;
16const Zld = @import("../Zld.zig");
1417
1518pub const Branch = struct {
1619 base: Relocation,
1720 /// Always .UnconditionalBranchImmediate
18 inst: aarch64.Instruction,
21 // inst: aarch64.Instruction,
1922
2023 pub const base_type: Relocation.Type = .branch_aarch64;
2124
22 pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void {
23 const displacement = try math.cast(i28, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr));
25 // pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void {
26 // const displacement = try math.cast(i28, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr));
2427
25 log.debug(" | displacement 0x{x}", .{displacement});
28 // log.debug(" | displacement 0x{x}", .{displacement});
2629
27 var inst = branch.inst;
28 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
29 mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32());
30 // var inst = branch.inst;
31 // inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
32 // mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32());
33 // }
34
35 pub fn format(self: Branch, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
36 _ = self;
37 _ = fmt;
38 _ = options;
39 _ = writer;
3040 }
3141};
3242
......@@ -34,24 +44,32 @@ pub const Page = struct {
3444 base: Relocation,
3545 addend: ?u32 = null,
3646 /// Always .PCRelativeAddress
37 inst: aarch64.Instruction,
47 // inst: aarch64.Instruction,
3848
3949 pub const base_type: Relocation.Type = .page;
4050
41 pub fn resolve(page: Page, args: Relocation.ResolveArgs) !void {
42 const target_addr = if (page.addend) |addend| args.target_addr + addend else args.target_addr;
43 const source_page = @intCast(i32, args.source_addr >> 12);
44 const target_page = @intCast(i32, target_addr >> 12);
45 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
51 // pub fn resolve(page: Page, args: Relocation.ResolveArgs) !void {
52 // const target_addr = if (page.addend) |addend| args.target_addr + addend else args.target_addr;
53 // const source_page = @intCast(i32, args.source_addr >> 12);
54 // const target_page = @intCast(i32, target_addr >> 12);
55 // const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
56
57 // log.debug(" | calculated addend 0x{x}", .{page.addend});
58 // log.debug(" | moving by {} pages", .{pages});
4659
47 log.debug(" | calculated addend 0x{x}", .{page.addend});
48 log.debug(" | moving by {} pages", .{pages});
60 // var inst = page.inst;
61 // inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
62 // inst.pc_relative_address.immlo = @truncate(u2, pages);
4963
50 var inst = page.inst;
51 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
52 inst.pc_relative_address.immlo = @truncate(u2, pages);
64 // mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
65 // }
5366
54 mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
67 pub fn format(self: Page, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
68 _ = fmt;
69 _ = options;
70 if (self.addend) |addend| {
71 try std.fmt.format(writer, ".addend = {}, ", .{addend});
72 }
5573 }
5674};
5775
......@@ -59,7 +77,7 @@ pub const PageOff = struct {
5977 base: Relocation,
6078 addend: ?u32 = null,
6179 op_kind: OpKind,
62 inst: aarch64.Instruction,
80 // inst: aarch64.Instruction,
6381
6482 pub const base_type: Relocation.Type = .page_off;
6583
......@@ -68,76 +86,99 @@ pub const PageOff = struct {
6886 load_store,
6987 };
7088
71 pub fn resolve(page_off: PageOff, args: Relocation.ResolveArgs) !void {
72 const target_addr = if (page_off.addend) |addend| args.target_addr + addend else args.target_addr;
73 const narrowed = @truncate(u12, target_addr);
74
75 log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
76 log.debug(" | {s} opcode", .{page_off.op_kind});
77
78 var inst = page_off.inst;
79 if (page_off.op_kind == .arithmetic) {
80 inst.add_subtract_immediate.imm12 = narrowed;
81 } else {
82 const offset: u12 = blk: {
83 if (inst.load_store_register.size == 0) {
84 if (inst.load_store_register.v == 1) {
85 // 128-bit SIMD is scaled by 16.
86 break :blk try math.divExact(u12, narrowed, 16);
87 }
88 // Otherwise, 8-bit SIMD or ldrb.
89 break :blk narrowed;
90 } else {
91 const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size);
92 break :blk try math.divExact(u12, narrowed, denom);
93 }
94 };
95 inst.load_store_register.offset = offset;
89 // pub fn resolve(page_off: PageOff, args: Relocation.ResolveArgs) !void {
90 // const target_addr = if (page_off.addend) |addend| args.target_addr + addend else args.target_addr;
91 // const narrowed = @truncate(u12, target_addr);
92
93 // log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
94 // log.debug(" | {s} opcode", .{page_off.op_kind});
95
96 // var inst = page_off.inst;
97 // if (page_off.op_kind == .arithmetic) {
98 // inst.add_subtract_immediate.imm12 = narrowed;
99 // } else {
100 // const offset: u12 = blk: {
101 // if (inst.load_store_register.size == 0) {
102 // if (inst.load_store_register.v == 1) {
103 // // 128-bit SIMD is scaled by 16.
104 // break :blk try math.divExact(u12, narrowed, 16);
105 // }
106 // // Otherwise, 8-bit SIMD or ldrb.
107 // break :blk narrowed;
108 // } else {
109 // const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size);
110 // break :blk try math.divExact(u12, narrowed, denom);
111 // }
112 // };
113 // inst.load_store_register.offset = offset;
114 // }
115
116 // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
117 // }
118
119 pub fn format(self: PageOff, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
120 _ = fmt;
121 _ = options;
122 if (self.addend) |addend| {
123 try std.fmt.format(writer, ".addend = {}, ", .{addend});
96124 }
97
98 mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
125 try std.fmt.format(writer, ".op_kind = {s}, ", .{self.op_kind});
99126 }
100127};
101128
102129pub const GotPage = struct {
103130 base: Relocation,
104131 /// Always .PCRelativeAddress
105 inst: aarch64.Instruction,
132 // inst: aarch64.Instruction,
106133
107134 pub const base_type: Relocation.Type = .got_page;
108135
109 pub fn resolve(page: GotPage, args: Relocation.ResolveArgs) !void {
110 const source_page = @intCast(i32, args.source_addr >> 12);
111 const target_page = @intCast(i32, args.target_addr >> 12);
112 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
136 // pub fn resolve(page: GotPage, args: Relocation.ResolveArgs) !void {
137 // const source_page = @intCast(i32, args.source_addr >> 12);
138 // const target_page = @intCast(i32, args.target_addr >> 12);
139 // const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
113140
114 log.debug(" | moving by {} pages", .{pages});
141 // log.debug(" | moving by {} pages", .{pages});
115142
116 var inst = page.inst;
117 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
118 inst.pc_relative_address.immlo = @truncate(u2, pages);
143 // var inst = page.inst;
144 // inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
145 // inst.pc_relative_address.immlo = @truncate(u2, pages);
119146
120 mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
147 // mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
148 // }
149
150 pub fn format(self: GotPage, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
151 _ = self;
152 _ = fmt;
153 _ = options;
154 _ = writer;
121155 }
122156};
123157
124158pub const GotPageOff = struct {
125159 base: Relocation,
126160 /// Always .LoadStoreRegister with size = 3 for GOT indirection
127 inst: aarch64.Instruction,
161 // inst: aarch64.Instruction,
128162
129163 pub const base_type: Relocation.Type = .got_page_off;
130164
131 pub fn resolve(page_off: GotPageOff, args: Relocation.ResolveArgs) !void {
132 const narrowed = @truncate(u12, args.target_addr);
165 // pub fn resolve(page_off: GotPageOff, args: Relocation.ResolveArgs) !void {
166 // const narrowed = @truncate(u12, args.target_addr);
167
168 // log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
133169
134 log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
170 // var inst = page_off.inst;
171 // const offset = try math.divExact(u12, narrowed, 8);
172 // inst.load_store_register.offset = offset;
135173
136 var inst = page_off.inst;
137 const offset = try math.divExact(u12, narrowed, 8);
138 inst.load_store_register.offset = offset;
174 // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
175 // }
139176
140 mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
177 pub fn format(self: GotPageOff, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
178 _ = self;
179 _ = fmt;
180 _ = options;
181 _ = writer;
141182 }
142183};
143184
......@@ -146,34 +187,48 @@ pub const PointerToGot = struct {
146187
147188 pub const base_type: Relocation.Type = .pointer_to_got;
148189
149 pub fn resolve(ptr_to_got: PointerToGot, args: Relocation.ResolveArgs) !void {
150 const result = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr));
190 // pub fn resolve(ptr_to_got: PointerToGot, args: Relocation.ResolveArgs) !void {
191 // const result = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr));
192
193 // log.debug(" | calculated value 0x{x}", .{result});
151194
152 log.debug(" | calculated value 0x{x}", .{result});
195 // mem.writeIntLittle(u32, ptr_to_got.base.code[0..4], @bitCast(u32, result));
196 // }
153197
154 mem.writeIntLittle(u32, ptr_to_got.base.code[0..4], @bitCast(u32, result));
198 pub fn format(self: PointerToGot, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
199 _ = self;
200 _ = fmt;
201 _ = options;
202 _ = writer;
155203 }
156204};
157205
158206pub const TlvpPage = struct {
159207 base: Relocation,
160208 /// Always .PCRelativeAddress
161 inst: aarch64.Instruction,
209 // inst: aarch64.Instruction,
162210
163211 pub const base_type: Relocation.Type = .tlvp_page;
164212
165 pub fn resolve(page: TlvpPage, args: Relocation.ResolveArgs) !void {
166 const source_page = @intCast(i32, args.source_addr >> 12);
167 const target_page = @intCast(i32, args.target_addr >> 12);
168 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
213 // pub fn resolve(page: TlvpPage, args: Relocation.ResolveArgs) !void {
214 // const source_page = @intCast(i32, args.source_addr >> 12);
215 // const target_page = @intCast(i32, args.target_addr >> 12);
216 // const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
169217
170 log.debug(" | moving by {} pages", .{pages});
218 // log.debug(" | moving by {} pages", .{pages});
171219
172 var inst = page.inst;
173 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
174 inst.pc_relative_address.immlo = @truncate(u2, pages);
220 // var inst = page.inst;
221 // inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
222 // inst.pc_relative_address.immlo = @truncate(u2, pages);
175223
176 mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
224 // mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
225 // }
226
227 pub fn format(self: TlvpPage, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
228 _ = self;
229 _ = fmt;
230 _ = options;
231 _ = writer;
177232 }
178233};
179234
......@@ -182,82 +237,110 @@ pub const TlvpPageOff = struct {
182237 /// Always .AddSubtractImmediate regardless of the source instruction.
183238 /// This means, we always rewrite the instruction to add even if the
184239 /// source instruction was an ldr.
185 inst: aarch64.Instruction,
240 // inst: aarch64.Instruction,
186241
187242 pub const base_type: Relocation.Type = .tlvp_page_off;
188243
189 pub fn resolve(page_off: TlvpPageOff, args: Relocation.ResolveArgs) !void {
190 const narrowed = @truncate(u12, args.target_addr);
244 // pub fn resolve(page_off: TlvpPageOff, args: Relocation.ResolveArgs) !void {
245 // const narrowed = @truncate(u12, args.target_addr);
246
247 // log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
191248
192 log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
249 // var inst = page_off.inst;
250 // inst.add_subtract_immediate.imm12 = narrowed;
193251
194 var inst = page_off.inst;
195 inst.add_subtract_immediate.imm12 = narrowed;
252 // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
253 // }
196254
197 mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
255 pub fn format(self: TlvpPageOff, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
256 _ = self;
257 _ = fmt;
258 _ = options;
259 _ = writer;
198260 }
199261};
200262
201263pub const Parser = struct {
202 allocator: *Allocator,
264 object: *Object,
265 zld: *Zld,
203266 it: *reloc.RelocIterator,
204 code: []u8,
205 parsed: std.ArrayList(*Relocation),
267 block: *TextBlock,
268 base_addr: u64,
206269 addend: ?u32 = null,
207 subtractor: ?Relocation.Target = null,
270 subtractor: ?*Symbol = null,
208271
209 pub fn deinit(parser: *Parser) void {
210 parser.parsed.deinit();
211 }
212
213 pub fn parse(parser: *Parser) !void {
214 while (parser.it.next()) |rel| {
215 switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
216 .ARM64_RELOC_BRANCH26 => {
217 try parser.parseBranch(rel);
218 },
272 pub fn parse(self: *Parser) !void {
273 while (self.it.next()) |rel| {
274 const out_rel = switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
275 .ARM64_RELOC_BRANCH26 => try self.parseBranch(rel),
219276 .ARM64_RELOC_SUBTRACTOR => {
220 try parser.parseSubtractor(rel);
221 },
222 .ARM64_RELOC_UNSIGNED => {
223 try parser.parseUnsigned(rel);
277 // Subtractor is not a relocation with effect on the TextBlock, so
278 // parse it and carry on.
279 try self.parseSubtractor(rel);
280 continue;
224281 },
282 .ARM64_RELOC_UNSIGNED => try self.parseUnsigned(rel),
225283 .ARM64_RELOC_ADDEND => {
226 try parser.parseAddend(rel);
284 // Addend is not a relocation with effect on the TextBlock, so
285 // parse it and carry on.
286 try self.parseAddend(rel);
287 continue;
227288 },
228289 .ARM64_RELOC_PAGE21,
229290 .ARM64_RELOC_GOT_LOAD_PAGE21,
230291 .ARM64_RELOC_TLVP_LOAD_PAGE21,
231 => {
232 try parser.parsePage(rel);
233 },
234 .ARM64_RELOC_PAGEOFF12 => {
235 try parser.parsePageOff(rel);
236 },
237 .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => {
238 try parser.parseGotLoadPageOff(rel);
239 },
240 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {
241 try parser.parseTlvpLoadPageOff(rel);
292 => try self.parsePage(rel),
293 .ARM64_RELOC_PAGEOFF12 => try self.parsePageOff(rel),
294 .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => try self.parseGotLoadPageOff(rel),
295 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => try self.parseTlvpLoadPageOff(rel),
296 .ARM64_RELOC_POINTER_TO_GOT => try self.parsePointerToGot(rel),
297 };
298 try self.block.relocs.append(out_rel);
299
300 if (out_rel.target.payload == .regular) {
301 try self.block.references.put(out_rel.target.payload.regular.local_sym_index, {});
302 }
303
304 switch (out_rel.@"type") {
305 .got_page, .got_page_off, .pointer_to_got => {
306 const sym = out_rel.target;
307
308 if (sym.got_index != null) continue;
309
310 const index = @intCast(u32, self.zld.got_entries.items.len);
311 sym.got_index = index;
312 try self.zld.got_entries.append(self.zld.allocator, sym);
313
314 log.debug("adding GOT entry for symbol {s} at index {}", .{ sym.name, index });
242315 },
243 .ARM64_RELOC_POINTER_TO_GOT => {
244 try parser.parsePointerToGot(rel);
316 .branch_aarch64 => {
317 const sym = out_rel.target;
318
319 if (sym.stubs_index != null) continue;
320 if (sym.payload != .proxy) continue;
321
322 const index = @intCast(u32, self.zld.stubs.items.len);
323 sym.stubs_index = index;
324 try self.zld.stubs.append(self.zld.allocator, sym);
325
326 log.debug("adding stub entry for symbol {s} at index {}", .{ sym.name, index });
245327 },
328 else => {},
246329 }
247330 }
248331 }
249332
250 fn parseAddend(parser: *Parser, rel: macho.relocation_info) !void {
333 fn parseAddend(self: *Parser, rel: macho.relocation_info) !void {
251334 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
252335 assert(rel_type == .ARM64_RELOC_ADDEND);
253336 assert(rel.r_pcrel == 0);
254337 assert(rel.r_extern == 0);
255 assert(parser.addend == null);
338 assert(self.addend == null);
256339
257 parser.addend = rel.r_symbolnum;
340 self.addend = rel.r_symbolnum;
258341
259342 // Verify ADDEND is followed by a load.
260 const next = @intToEnum(macho.reloc_type_arm64, parser.it.peek().r_type);
343 const next = @intToEnum(macho.reloc_type_arm64, self.it.peek().r_type);
261344 switch (next) {
262345 .ARM64_RELOC_PAGE21, .ARM64_RELOC_PAGEOFF12 => {},
263346 else => {
......@@ -267,127 +350,101 @@ pub const Parser = struct {
267350 }
268351 }
269352
270 fn parseBranch(parser: *Parser, rel: macho.relocation_info) !void {
353 fn parseBranch(self: *Parser, rel: macho.relocation_info) !*Relocation {
271354 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
272355 assert(rel_type == .ARM64_RELOC_BRANCH26);
273356 assert(rel.r_pcrel == 1);
274357 assert(rel.r_length == 2);
275358
276 const offset = @intCast(u32, rel.r_address);
277 const inst = parser.code[offset..][0..4];
278 const parsed_inst = aarch64.Instruction{ .unconditional_branch_immediate = mem.bytesToValue(
279 meta.TagPayload(
280 aarch64.Instruction,
281 aarch64.Instruction.unconditional_branch_immediate,
282 ),
283 inst,
284 ) };
285
286 var branch = try parser.allocator.create(Branch);
287 errdefer parser.allocator.destroy(branch);
359 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
360 const target = try self.object.symbolFromReloc(rel);
288361
289 const target = Relocation.Target.fromReloc(rel);
362 var branch = try self.object.allocator.create(Branch);
363 errdefer self.object.allocator.destroy(branch);
290364
291365 branch.* = .{
292366 .base = .{
293367 .@"type" = .branch_aarch64,
294 .code = inst,
295368 .offset = offset,
296369 .target = target,
370 .block = self.block,
297371 },
298 .inst = parsed_inst,
299372 };
300373
301 log.debug(" | emitting {}", .{branch});
302 try parser.parsed.append(&branch.base);
374 return &branch.base;
303375 }
304376
305 fn parsePage(parser: *Parser, rel: macho.relocation_info) !void {
377 fn parsePage(self: *Parser, rel: macho.relocation_info) !*Relocation {
306378 assert(rel.r_pcrel == 1);
307379 assert(rel.r_length == 2);
308380
309381 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
310 const target = Relocation.Target.fromReloc(rel);
311
312 const offset = @intCast(u32, rel.r_address);
313 const inst = parser.code[offset..][0..4];
314 const parsed_inst = aarch64.Instruction{ .pc_relative_address = mem.bytesToValue(meta.TagPayload(
315 aarch64.Instruction,
316 aarch64.Instruction.pc_relative_address,
317 ), inst) };
382 const target = try self.object.symbolFromReloc(rel);
383 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
318384
319385 const ptr: *Relocation = ptr: {
320386 switch (rel_type) {
321387 .ARM64_RELOC_PAGE21 => {
322388 defer {
323389 // Reset parser's addend state
324 parser.addend = null;
390 self.addend = null;
325391 }
326 var page = try parser.allocator.create(Page);
327 errdefer parser.allocator.destroy(page);
392 var page = try self.object.allocator.create(Page);
393 errdefer self.object.allocator.destroy(page);
328394
329395 page.* = .{
330396 .base = .{
331397 .@"type" = .page,
332 .code = inst,
333398 .offset = offset,
334399 .target = target,
400 .block = self.block,
335401 },
336 .addend = parser.addend,
337 .inst = parsed_inst,
402 .addend = self.addend,
338403 };
339404
340 log.debug(" | emitting {}", .{page});
341
342405 break :ptr &page.base;
343406 },
344407 .ARM64_RELOC_GOT_LOAD_PAGE21 => {
345 var page = try parser.allocator.create(GotPage);
346 errdefer parser.allocator.destroy(page);
408 var page = try self.object.allocator.create(GotPage);
409 errdefer self.object.allocator.destroy(page);
347410
348411 page.* = .{
349412 .base = .{
350413 .@"type" = .got_page,
351 .code = inst,
352414 .offset = offset,
353415 .target = target,
416 .block = self.block,
354417 },
355 .inst = parsed_inst,
356418 };
357419
358 log.debug(" | emitting {}", .{page});
359
360420 break :ptr &page.base;
361421 },
362422 .ARM64_RELOC_TLVP_LOAD_PAGE21 => {
363 var page = try parser.allocator.create(TlvpPage);
364 errdefer parser.allocator.destroy(page);
423 var page = try self.object.allocator.create(TlvpPage);
424 errdefer self.object.allocator.destroy(page);
365425
366426 page.* = .{
367427 .base = .{
368428 .@"type" = .tlvp_page,
369 .code = inst,
370429 .offset = offset,
371430 .target = target,
431 .block = self.block,
372432 },
373 .inst = parsed_inst,
374433 };
375434
376 log.debug(" | emitting {}", .{page});
377
378435 break :ptr &page.base;
379436 },
380437 else => unreachable,
381438 }
382439 };
383440
384 try parser.parsed.append(ptr);
441 return ptr;
385442 }
386443
387 fn parsePageOff(parser: *Parser, rel: macho.relocation_info) !void {
444 fn parsePageOff(self: *Parser, rel: macho.relocation_info) !*Relocation {
388445 defer {
389446 // Reset parser's addend state
390 parser.addend = null;
447 self.addend = null;
391448 }
392449
393450 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
......@@ -395,83 +452,56 @@ pub const Parser = struct {
395452 assert(rel.r_pcrel == 0);
396453 assert(rel.r_length == 2);
397454
398 const offset = @intCast(u32, rel.r_address);
399 const inst = parser.code[offset..][0..4];
400
401 var op_kind: PageOff.OpKind = undefined;
402 var parsed_inst: aarch64.Instruction = undefined;
403 if (isArithmeticOp(inst)) {
404 op_kind = .arithmetic;
405 parsed_inst = .{ .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(
406 aarch64.Instruction,
407 aarch64.Instruction.add_subtract_immediate,
408 ), inst) };
409 } else {
410 op_kind = .load_store;
411 parsed_inst = .{ .load_store_register = mem.bytesToValue(meta.TagPayload(
412 aarch64.Instruction,
413 aarch64.Instruction.load_store_register,
414 ), inst) };
415 }
416 const target = Relocation.Target.fromReloc(rel);
455 const target = try self.object.symbolFromReloc(rel);
456 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
457 const op_kind: PageOff.OpKind = if (isArithmeticOp(self.block.code[offset..][0..4]))
458 .arithmetic
459 else
460 .load_store;
417461
418 var page_off = try parser.allocator.create(PageOff);
419 errdefer parser.allocator.destroy(page_off);
462 var page_off = try self.object.allocator.create(PageOff);
463 errdefer self.object.allocator.destroy(page_off);
420464
421465 page_off.* = .{
422466 .base = .{
423467 .@"type" = .page_off,
424 .code = inst,
425468 .offset = offset,
426469 .target = target,
470 .block = self.block,
427471 },
428472 .op_kind = op_kind,
429 .inst = parsed_inst,
430 .addend = parser.addend,
473 .addend = self.addend,
431474 };
432475
433 log.debug(" | emitting {}", .{page_off});
434 try parser.parsed.append(&page_off.base);
476 return &page_off.base;
435477 }
436478
437 fn parseGotLoadPageOff(parser: *Parser, rel: macho.relocation_info) !void {
479 fn parseGotLoadPageOff(self: *Parser, rel: macho.relocation_info) !*Relocation {
438480 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
439481 assert(rel_type == .ARM64_RELOC_GOT_LOAD_PAGEOFF12);
440482 assert(rel.r_pcrel == 0);
441483 assert(rel.r_length == 2);
442484
443 const offset = @intCast(u32, rel.r_address);
444 const inst = parser.code[offset..][0..4];
445 assert(!isArithmeticOp(inst));
446
447 const parsed_inst = mem.bytesToValue(meta.TagPayload(
448 aarch64.Instruction,
449 aarch64.Instruction.load_store_register,
450 ), inst);
451 assert(parsed_inst.size == 3);
452
453 const target = Relocation.Target.fromReloc(rel);
485 const target = try self.object.symbolFromReloc(rel);
486 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
487 assert(!isArithmeticOp(self.block.code[offset..][0..4]));
454488
455 var page_off = try parser.allocator.create(GotPageOff);
456 errdefer parser.allocator.destroy(page_off);
489 var page_off = try self.object.allocator.create(GotPageOff);
490 errdefer self.object.allocator.destroy(page_off);
457491
458492 page_off.* = .{
459493 .base = .{
460494 .@"type" = .got_page_off,
461 .code = inst,
462495 .offset = offset,
463496 .target = target,
464 },
465 .inst = .{
466 .load_store_register = parsed_inst,
497 .block = self.block,
467498 },
468499 };
469500
470 log.debug(" | emitting {}", .{page_off});
471 try parser.parsed.append(&page_off.base);
501 return &page_off.base;
472502 }
473503
474 fn parseTlvpLoadPageOff(parser: *Parser, rel: macho.relocation_info) !void {
504 fn parseTlvpLoadPageOff(self: *Parser, rel: macho.relocation_info) !*Relocation {
475505 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
476506 assert(rel_type == .ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
477507 assert(rel.r_pcrel == 0);
......@@ -483,141 +513,102 @@ pub const Parser = struct {
483513 size: u1,
484514 };
485515
486 const offset = @intCast(u32, rel.r_address);
487 const inst = parser.code[offset..][0..4];
488 const parsed: RegInfo = parsed: {
489 if (isArithmeticOp(inst)) {
490 const parsed_inst = mem.bytesAsValue(meta.TagPayload(
491 aarch64.Instruction,
492 aarch64.Instruction.add_subtract_immediate,
493 ), inst);
494 break :parsed .{
495 .rd = parsed_inst.rd,
496 .rn = parsed_inst.rn,
497 .size = parsed_inst.sf,
498 };
499 } else {
500 const parsed_inst = mem.bytesAsValue(meta.TagPayload(
501 aarch64.Instruction,
502 aarch64.Instruction.load_store_register,
503 ), inst);
504 break :parsed .{
505 .rd = parsed_inst.rt,
506 .rn = parsed_inst.rn,
507 .size = @truncate(u1, parsed_inst.size),
508 };
509 }
510 };
516 const target = try self.object.symbolFromReloc(rel);
517 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
511518
512 const target = Relocation.Target.fromReloc(rel);
513
514 var page_off = try parser.allocator.create(TlvpPageOff);
515 errdefer parser.allocator.destroy(page_off);
519 var page_off = try self.object.allocator.create(TlvpPageOff);
520 errdefer self.object.allocator.destroy(page_off);
516521
517522 page_off.* = .{
518523 .base = .{
519524 .@"type" = .tlvp_page_off,
520 .code = inst,
521525 .offset = offset,
522526 .target = target,
523 },
524 .inst = .{
525 .add_subtract_immediate = .{
526 .rd = parsed.rd,
527 .rn = parsed.rn,
528 .imm12 = 0, // This will be filled when target addresses are known.
529 .sh = 0,
530 .s = 0,
531 .op = 0,
532 .sf = parsed.size,
533 },
527 .block = self.block,
534528 },
535529 };
536530
537 log.debug(" | emitting {}", .{page_off});
538 try parser.parsed.append(&page_off.base);
531 return &page_off.base;
539532 }
540533
541 fn parseSubtractor(parser: *Parser, rel: macho.relocation_info) !void {
534 fn parseSubtractor(self: *Parser, rel: macho.relocation_info) !void {
542535 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
543536 assert(rel_type == .ARM64_RELOC_SUBTRACTOR);
544537 assert(rel.r_pcrel == 0);
545 assert(parser.subtractor == null);
538 assert(self.subtractor == null);
546539
547 parser.subtractor = Relocation.Target.fromReloc(rel);
540 self.subtractor = try self.object.symbolFromReloc(rel);
548541
549542 // Verify SUBTRACTOR is followed by UNSIGNED.
550 const next = @intToEnum(macho.reloc_type_arm64, parser.it.peek().r_type);
543 const next = @intToEnum(macho.reloc_type_arm64, self.it.peek().r_type);
551544 if (next != .ARM64_RELOC_UNSIGNED) {
552545 log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next});
553546 return error.UnexpectedRelocationType;
554547 }
555548 }
556549
557 fn parseUnsigned(parser: *Parser, rel: macho.relocation_info) !void {
550 fn parseUnsigned(self: *Parser, rel: macho.relocation_info) !*Relocation {
558551 defer {
559552 // Reset parser's subtractor state
560 parser.subtractor = null;
553 self.subtractor = null;
561554 }
562555
563556 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
564557 assert(rel_type == .ARM64_RELOC_UNSIGNED);
565558 assert(rel.r_pcrel == 0);
566559
567 var unsigned = try parser.allocator.create(reloc.Unsigned);
568 errdefer parser.allocator.destroy(unsigned);
569
570 const target = Relocation.Target.fromReloc(rel);
560 const target = try self.object.symbolFromReloc(rel);
561 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
571562 const is_64bit: bool = switch (rel.r_length) {
572563 3 => true,
573564 2 => false,
574565 else => unreachable,
575566 };
576 const offset = @intCast(u32, rel.r_address);
577567 const addend: i64 = if (is_64bit)
578 mem.readIntLittle(i64, parser.code[offset..][0..8])
568 mem.readIntLittle(i64, self.block.code[offset..][0..8])
579569 else
580 mem.readIntLittle(i32, parser.code[offset..][0..4]);
570 mem.readIntLittle(i32, self.block.code[offset..][0..4]);
571
572 var unsigned = try self.object.allocator.create(reloc.Unsigned);
573 errdefer self.object.allocator.destroy(unsigned);
581574
582575 unsigned.* = .{
583576 .base = .{
584577 .@"type" = .unsigned,
585 .code = if (is_64bit) parser.code[offset..][0..8] else parser.code[offset..][0..4],
586578 .offset = offset,
587579 .target = target,
580 .block = self.block,
588581 },
589 .subtractor = parser.subtractor,
582 .subtractor = self.subtractor,
590583 .is_64bit = is_64bit,
591584 .addend = addend,
592585 };
593586
594 log.debug(" | emitting {}", .{unsigned});
595 try parser.parsed.append(&unsigned.base);
587 return &unsigned.base;
596588 }
597589
598 fn parsePointerToGot(parser: *Parser, rel: macho.relocation_info) !void {
590 fn parsePointerToGot(self: *Parser, rel: macho.relocation_info) !*Relocation {
599591 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
600592 assert(rel_type == .ARM64_RELOC_POINTER_TO_GOT);
601593 assert(rel.r_pcrel == 1);
602594 assert(rel.r_length == 2);
603595
604 var ptr_to_got = try parser.allocator.create(PointerToGot);
605 errdefer parser.allocator.destroy(ptr_to_got);
596 var ptr_to_got = try self.object.allocator.create(PointerToGot);
597 errdefer self.object.allocator.destroy(ptr_to_got);
606598
607 const target = Relocation.Target.fromReloc(rel);
608 const offset = @intCast(u32, rel.r_address);
599 const target = try self.object.symbolFromReloc(rel);
600 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
609601
610602 ptr_to_got.* = .{
611603 .base = .{
612604 .@"type" = .pointer_to_got,
613 .code = parser.code[offset..][0..4],
614605 .offset = offset,
615606 .target = target,
607 .block = self.block,
616608 },
617609 };
618610
619 log.debug(" | emitting {}", .{ptr_to_got});
620 try parser.parsed.append(&ptr_to_got.base);
611 return &ptr_to_got.base;
621612 }
622613};
623614
src/link/MachO/reloc/x86_64.zig+182-140
......@@ -8,17 +8,28 @@ const meta = std.meta;
88const reloc = @import("../reloc.zig");
99
1010const Allocator = mem.Allocator;
11const Object = @import("../Object.zig");
1112const Relocation = reloc.Relocation;
13const Symbol = @import("../Symbol.zig");
14const TextBlock = Zld.TextBlock;
15const Zld = @import("../Zld.zig");
1216
1317pub const Branch = struct {
1418 base: Relocation,
1519
1620 pub const base_type: Relocation.Type = .branch_x86_64;
1721
18 pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void {
19 const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
20 log.debug(" | displacement 0x{x}", .{displacement});
21 mem.writeIntLittle(u32, branch.base.code[0..4], @bitCast(u32, displacement));
22 // pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void {
23 // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
24 // log.debug(" | displacement 0x{x}", .{displacement});
25 // mem.writeIntLittle(u32, branch.base.code[0..4], @bitCast(u32, displacement));
26 // }
27
28 pub fn format(self: Branch, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
29 _ = self;
30 _ = fmt;
31 _ = options;
32 _ = writer;
2233 }
2334};
2435
......@@ -29,25 +40,32 @@ pub const Signed = struct {
2940
3041 pub const base_type: Relocation.Type = .signed;
3142
32 pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void {
33 const target_addr = target_addr: {
34 if (signed.base.target == .section) {
35 const source_target = @intCast(i64, args.source_source_sect_addr.?) + @intCast(i64, signed.base.offset) + signed.addend + 4;
36 const source_disp = source_target - @intCast(i64, args.source_target_sect_addr.?);
37 break :target_addr @intCast(i64, args.target_addr) + source_disp;
38 }
39 break :target_addr @intCast(i64, args.target_addr) + signed.addend;
40 };
41 const displacement = try math.cast(
42 i32,
43 target_addr - @intCast(i64, args.source_addr) - signed.correction - 4,
44 );
45
46 log.debug(" | addend 0x{x}", .{signed.addend});
47 log.debug(" | correction 0x{x}", .{signed.correction});
48 log.debug(" | displacement 0x{x}", .{displacement});
49
50 mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement));
43 // pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void {
44 // const target_addr = target_addr: {
45 // if (signed.base.target == .section) {
46 // const source_target = @intCast(i64, args.source_source_sect_addr.?) + @intCast(i64, signed.base.offset) + signed.addend + 4;
47 // const source_disp = source_target - @intCast(i64, args.source_target_sect_addr.?);
48 // break :target_addr @intCast(i64, args.target_addr) + source_disp;
49 // }
50 // break :target_addr @intCast(i64, args.target_addr) + signed.addend;
51 // };
52 // const displacement = try math.cast(
53 // i32,
54 // target_addr - @intCast(i64, args.source_addr) - signed.correction - 4,
55 // );
56
57 // log.debug(" | addend 0x{x}", .{signed.addend});
58 // log.debug(" | correction 0x{x}", .{signed.correction});
59 // log.debug(" | displacement 0x{x}", .{displacement});
60
61 // mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement));
62 // }
63
64 pub fn format(self: Signed, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
65 _ = fmt;
66 _ = options;
67 try std.fmt.format(writer, ".addend = {}, ", .{self.addend});
68 try std.fmt.format(writer, ".correction = {}, ", .{self.correction});
5169 }
5270};
5371
......@@ -56,10 +74,17 @@ pub const GotLoad = struct {
5674
5775 pub const base_type: Relocation.Type = .got_load;
5876
59 pub fn resolve(got_load: GotLoad, args: Relocation.ResolveArgs) !void {
60 const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
61 log.debug(" | displacement 0x{x}", .{displacement});
62 mem.writeIntLittle(u32, got_load.base.code[0..4], @bitCast(u32, displacement));
77 // pub fn resolve(got_load: GotLoad, args: Relocation.ResolveArgs) !void {
78 // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
79 // log.debug(" | displacement 0x{x}", .{displacement});
80 // mem.writeIntLittle(u32, got_load.base.code[0..4], @bitCast(u32, displacement));
81 // }
82
83 pub fn format(self: GotLoad, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
84 _ = self;
85 _ = fmt;
86 _ = options;
87 _ = writer;
6388 }
6489};
6590
......@@ -69,113 +94,139 @@ pub const Got = struct {
6994
7095 pub const base_type: Relocation.Type = .got;
7196
72 pub fn resolve(got: Got, args: Relocation.ResolveArgs) !void {
73 const displacement = try math.cast(
74 i32,
75 @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + got.addend,
76 );
77 log.debug(" | displacement 0x{x}", .{displacement});
78 mem.writeIntLittle(u32, got.base.code[0..4], @bitCast(u32, displacement));
97 // pub fn resolve(got: Got, args: Relocation.ResolveArgs) !void {
98 // const displacement = try math.cast(
99 // i32,
100 // @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + got.addend,
101 // );
102 // log.debug(" | displacement 0x{x}", .{displacement});
103 // mem.writeIntLittle(u32, got.base.code[0..4], @bitCast(u32, displacement));
104 // }
105
106 pub fn format(self: Got, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
107 _ = fmt;
108 _ = options;
109 try std.fmt.format(writer, ".addend = {}, ", .{self.addend});
79110 }
80111};
81112
82113pub const Tlv = struct {
83114 base: Relocation,
84 op: *u8,
85115
86116 pub const base_type: Relocation.Type = .tlv;
87117
88 pub fn resolve(tlv: Tlv, args: Relocation.ResolveArgs) !void {
89 // We need to rewrite the opcode from movq to leaq.
90 tlv.op.* = 0x8d;
91 log.debug(" | rewriting op to leaq", .{});
92
93 const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
94 log.debug(" | displacement 0x{x}", .{displacement});
95
96 mem.writeIntLittle(u32, tlv.base.code[0..4], @bitCast(u32, displacement));
118 // pub fn resolve(tlv: Tlv, args: Relocation.ResolveArgs) !void {
119 // // We need to rewrite the opcode from movq to leaq.
120 // tlv.op.* = 0x8d;
121 // log.debug(" | rewriting op to leaq", .{});
122
123 // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
124 // log.debug(" | displacement 0x{x}", .{displacement});
125
126 // mem.writeIntLittle(u32, tlv.base.code[0..4], @bitCast(u32, displacement));
127 // }
128 pub fn format(self: Tlv, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
129 _ = self;
130 _ = fmt;
131 _ = options;
132 _ = writer;
97133 }
98134};
99135
100136pub const Parser = struct {
101 allocator: *Allocator,
137 object: *Object,
138 zld: *Zld,
102139 it: *reloc.RelocIterator,
103 code: []u8,
104 parsed: std.ArrayList(*Relocation),
105 subtractor: ?Relocation.Target = null,
106
107 pub fn deinit(parser: *Parser) void {
108 parser.parsed.deinit();
109 }
110
111 pub fn parse(parser: *Parser) !void {
112 while (parser.it.next()) |rel| {
113 switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {
114 .X86_64_RELOC_BRANCH => {
115 try parser.parseBranch(rel);
116 },
140 block: *TextBlock,
141 base_addr: u64,
142 subtractor: ?*Symbol = null,
143
144 pub fn parse(self: *Parser) !void {
145 while (self.it.next()) |rel| {
146 const out_rel = switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {
147 .X86_64_RELOC_BRANCH => try self.parseBranch(rel),
117148 .X86_64_RELOC_SUBTRACTOR => {
118 try parser.parseSubtractor(rel);
119 },
120 .X86_64_RELOC_UNSIGNED => {
121 try parser.parseUnsigned(rel);
149 // Subtractor is not a relocation with effect on the TextBlock, so
150 // parse it and carry on.
151 try self.parseSubtractor(rel);
152 continue;
122153 },
154 .X86_64_RELOC_UNSIGNED => try self.parseUnsigned(rel),
123155 .X86_64_RELOC_SIGNED,
124156 .X86_64_RELOC_SIGNED_1,
125157 .X86_64_RELOC_SIGNED_2,
126158 .X86_64_RELOC_SIGNED_4,
127 => {
128 try parser.parseSigned(rel);
129 },
130 .X86_64_RELOC_GOT_LOAD => {
131 try parser.parseGotLoad(rel);
132 },
133 .X86_64_RELOC_GOT => {
134 try parser.parseGot(rel);
159 => try self.parseSigned(rel),
160 .X86_64_RELOC_GOT_LOAD => try self.parseGotLoad(rel),
161 .X86_64_RELOC_GOT => try self.parseGot(rel),
162 .X86_64_RELOC_TLV => try self.parseTlv(rel),
163 };
164 try self.block.relocs.append(out_rel);
165
166 if (out_rel.target.payload == .regular) {
167 try self.block.references.put(out_rel.target.payload.regular.local_sym_index, {});
168 }
169
170 switch (out_rel.@"type") {
171 .got_load, .got => {
172 const sym = out_rel.target;
173
174 if (sym.got_index != null) continue;
175
176 const index = @intCast(u32, self.zld.got_entries.items.len);
177 sym.got_index = index;
178 try self.zld.got_entries.append(self.zld.allocator, sym);
179
180 log.debug("adding GOT entry for symbol {s} at index {}", .{ sym.name, index });
135181 },
136 .X86_64_RELOC_TLV => {
137 try parser.parseTlv(rel);
182 .branch_x86_64 => {
183 const sym = out_rel.target;
184
185 if (sym.stubs_index != null) continue;
186 if (sym.payload != .proxy) continue;
187
188 const index = @intCast(u32, self.zld.stubs.items.len);
189 sym.stubs_index = index;
190 try self.zld.stubs.append(self.zld.allocator, sym);
191
192 log.debug("adding stub entry for symbol {s} at index {}", .{ sym.name, index });
138193 },
194 else => {},
139195 }
140196 }
141197 }
142198
143 fn parseBranch(parser: *Parser, rel: macho.relocation_info) !void {
199 fn parseBranch(self: *Parser, rel: macho.relocation_info) !*Relocation {
144200 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
145201 assert(rel_type == .X86_64_RELOC_BRANCH);
146202 assert(rel.r_pcrel == 1);
147203 assert(rel.r_length == 2);
148204
149 const offset = @intCast(u32, rel.r_address);
150 const inst = parser.code[offset..][0..4];
151
152 var branch = try parser.allocator.create(Branch);
153 errdefer parser.allocator.destroy(branch);
205 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
206 const target = try self.object.symbolFromReloc(rel);
154207
155 const target = Relocation.Target.fromReloc(rel);
208 var branch = try self.object.allocator.create(Branch);
209 errdefer self.object.allocator.destroy(branch);
156210
157211 branch.* = .{
158212 .base = .{
159213 .@"type" = .branch_x86_64,
160 .code = inst,
161214 .offset = offset,
162215 .target = target,
216 .block = self.block,
163217 },
164218 };
165219
166 log.debug(" | emitting {}", .{branch});
167 try parser.parsed.append(&branch.base);
220 return &branch.base;
168221 }
169222
170 fn parseSigned(parser: *Parser, rel: macho.relocation_info) !void {
223 fn parseSigned(self: *Parser, rel: macho.relocation_info) !*Relocation {
171224 assert(rel.r_pcrel == 1);
172225 assert(rel.r_length == 2);
173226
174227 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
175 const target = Relocation.Target.fromReloc(rel);
176
177 const offset = @intCast(u32, rel.r_address);
178 const inst = parser.code[offset..][0..4];
228 const target = try self.object.symbolFromReloc(rel);
229 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
179230 const correction: i4 = switch (rel_type) {
180231 .X86_64_RELOC_SIGNED => 0,
181232 .X86_64_RELOC_SIGNED_1 => 1,
......@@ -183,161 +234,152 @@ pub const Parser = struct {
183234 .X86_64_RELOC_SIGNED_4 => 4,
184235 else => unreachable,
185236 };
186 const addend = mem.readIntLittle(i32, inst) + correction;
237 const addend = mem.readIntLittle(i32, self.block.code[offset..][0..4]) + correction;
187238
188 var signed = try parser.allocator.create(Signed);
189 errdefer parser.allocator.destroy(signed);
239 var signed = try self.object.allocator.create(Signed);
240 errdefer self.object.allocator.destroy(signed);
190241
191242 signed.* = .{
192243 .base = .{
193244 .@"type" = .signed,
194 .code = inst,
195245 .offset = offset,
196246 .target = target,
247 .block = self.block,
197248 },
198249 .addend = addend,
199250 .correction = correction,
200251 };
201252
202 log.debug(" | emitting {}", .{signed});
203 try parser.parsed.append(&signed.base);
253 return &signed.base;
204254 }
205255
206 fn parseGotLoad(parser: *Parser, rel: macho.relocation_info) !void {
256 fn parseGotLoad(self: *Parser, rel: macho.relocation_info) !*Relocation {
207257 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
208258 assert(rel_type == .X86_64_RELOC_GOT_LOAD);
209259 assert(rel.r_pcrel == 1);
210260 assert(rel.r_length == 2);
211261
212 const offset = @intCast(u32, rel.r_address);
213 const inst = parser.code[offset..][0..4];
214 const target = Relocation.Target.fromReloc(rel);
262 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
263 const target = try self.object.symbolFromReloc(rel);
215264
216 var got_load = try parser.allocator.create(GotLoad);
217 errdefer parser.allocator.destroy(got_load);
265 var got_load = try self.object.allocator.create(GotLoad);
266 errdefer self.object.allocator.destroy(got_load);
218267
219268 got_load.* = .{
220269 .base = .{
221270 .@"type" = .got_load,
222 .code = inst,
223271 .offset = offset,
224272 .target = target,
273 .block = self.block,
225274 },
226275 };
227276
228 log.debug(" | emitting {}", .{got_load});
229 try parser.parsed.append(&got_load.base);
277 return &got_load.base;
230278 }
231279
232 fn parseGot(parser: *Parser, rel: macho.relocation_info) !void {
280 fn parseGot(self: *Parser, rel: macho.relocation_info) !*Relocation {
233281 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
234282 assert(rel_type == .X86_64_RELOC_GOT);
235283 assert(rel.r_pcrel == 1);
236284 assert(rel.r_length == 2);
237285
238 const offset = @intCast(u32, rel.r_address);
239 const inst = parser.code[offset..][0..4];
240 const target = Relocation.Target.fromReloc(rel);
241 const addend = mem.readIntLittle(i32, inst);
286 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
287 const target = try self.object.symbolFromReloc(rel);
288 const addend = mem.readIntLittle(i32, self.block.code[offset..][0..4]);
242289
243 var got = try parser.allocator.create(Got);
244 errdefer parser.allocator.destroy(got);
290 var got = try self.object.allocator.create(Got);
291 errdefer self.object.allocator.destroy(got);
245292
246293 got.* = .{
247294 .base = .{
248295 .@"type" = .got,
249 .code = inst,
250296 .offset = offset,
251297 .target = target,
298 .block = self.block,
252299 },
253300 .addend = addend,
254301 };
255302
256 log.debug(" | emitting {}", .{got});
257 try parser.parsed.append(&got.base);
303 return &got.base;
258304 }
259305
260 fn parseTlv(parser: *Parser, rel: macho.relocation_info) !void {
306 fn parseTlv(self: *Parser, rel: macho.relocation_info) !*Relocation {
261307 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
262308 assert(rel_type == .X86_64_RELOC_TLV);
263309 assert(rel.r_pcrel == 1);
264310 assert(rel.r_length == 2);
265311
266 const offset = @intCast(u32, rel.r_address);
267 const inst = parser.code[offset..][0..4];
268 const target = Relocation.Target.fromReloc(rel);
312 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
313 const target = try self.object.symbolFromReloc(rel);
269314
270 var tlv = try parser.allocator.create(Tlv);
271 errdefer parser.allocator.destroy(tlv);
315 var tlv = try self.object.allocator.create(Tlv);
316 errdefer self.object.allocator.destroy(tlv);
272317
273318 tlv.* = .{
274319 .base = .{
275320 .@"type" = .tlv,
276 .code = inst,
277321 .offset = offset,
278322 .target = target,
323 .block = self.block,
279324 },
280 .op = &parser.code[offset - 2],
281325 };
282326
283 log.debug(" | emitting {}", .{tlv});
284 try parser.parsed.append(&tlv.base);
327 return &tlv.base;
285328 }
286329
287 fn parseSubtractor(parser: *Parser, rel: macho.relocation_info) !void {
330 fn parseSubtractor(self: *Parser, rel: macho.relocation_info) !void {
288331 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
289332 assert(rel_type == .X86_64_RELOC_SUBTRACTOR);
290333 assert(rel.r_pcrel == 0);
291 assert(parser.subtractor == null);
334 assert(self.subtractor == null);
292335
293 parser.subtractor = Relocation.Target.fromReloc(rel);
336 self.subtractor = try self.object.symbolFromReloc(rel);
294337
295338 // Verify SUBTRACTOR is followed by UNSIGNED.
296 const next = @intToEnum(macho.reloc_type_x86_64, parser.it.peek().r_type);
339 const next = @intToEnum(macho.reloc_type_x86_64, self.it.peek().r_type);
297340 if (next != .X86_64_RELOC_UNSIGNED) {
298341 log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next});
299342 return error.UnexpectedRelocationType;
300343 }
301344 }
302345
303 fn parseUnsigned(parser: *Parser, rel: macho.relocation_info) !void {
346 fn parseUnsigned(self: *Parser, rel: macho.relocation_info) !*Relocation {
304347 defer {
305348 // Reset parser's subtractor state
306 parser.subtractor = null;
349 self.subtractor = null;
307350 }
308351
309352 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
310353 assert(rel_type == .X86_64_RELOC_UNSIGNED);
311354 assert(rel.r_pcrel == 0);
312355
313 var unsigned = try parser.allocator.create(reloc.Unsigned);
314 errdefer parser.allocator.destroy(unsigned);
315
316 const target = Relocation.Target.fromReloc(rel);
356 const target = try self.object.symbolFromReloc(rel);
317357 const is_64bit: bool = switch (rel.r_length) {
318358 3 => true,
319359 2 => false,
320360 else => unreachable,
321361 };
322 const offset = @intCast(u32, rel.r_address);
362 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
323363 const addend: i64 = if (is_64bit)
324 mem.readIntLittle(i64, parser.code[offset..][0..8])
364 mem.readIntLittle(i64, self.block.code[offset..][0..8])
325365 else
326 mem.readIntLittle(i32, parser.code[offset..][0..4]);
366 mem.readIntLittle(i32, self.block.code[offset..][0..4]);
367
368 var unsigned = try self.object.allocator.create(reloc.Unsigned);
369 errdefer self.object.allocator.destroy(unsigned);
327370
328371 unsigned.* = .{
329372 .base = .{
330373 .@"type" = .unsigned,
331 .code = if (is_64bit) parser.code[offset..][0..8] else parser.code[offset..][0..4],
332374 .offset = offset,
333375 .target = target,
376 .block = self.block,
334377 },
335 .subtractor = parser.subtractor,
378 .subtractor = self.subtractor,
336379 .is_64bit = is_64bit,
337380 .addend = addend,
338381 };
339382
340 log.debug(" | emitting {}", .{unsigned});
341 try parser.parsed.append(&unsigned.base);
383 return &unsigned.base;
342384 }
343385};