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) = .{},...@@ -53,6 +53,7 @@ initializers: std.ArrayListUnmanaged(u32) = .{},
53data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},53data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
5454
55symbols: std.ArrayListUnmanaged(*Symbol) = .{},55symbols: std.ArrayListUnmanaged(*Symbol) = .{},
56sections_as_symbols: std.AutoHashMapUnmanaged(u8, *Symbol) = .{},
5657
57const DebugInfo = struct {58const DebugInfo = struct {
58 inner: dwarf.DwarfInfo,59 inner: dwarf.DwarfInfo,
...@@ -160,6 +161,7 @@ pub fn deinit(self: *Object) void {...@@ -160,6 +161,7 @@ pub fn deinit(self: *Object) void {
160 self.symtab.deinit(self.allocator);161 self.symtab.deinit(self.allocator);
161 self.strtab.deinit(self.allocator);162 self.strtab.deinit(self.allocator);
162 self.symbols.deinit(self.allocator);163 self.symbols.deinit(self.allocator);
164 self.sections_as_symbols.deinit(self.allocator);
163165
164 if (self.name) |n| {166 if (self.name) |n| {
165 self.allocator.free(n);167 self.allocator.free(n);
...@@ -312,7 +314,7 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r...@@ -312,7 +314,7 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r
312314
313 while (true) {315 while (true) {
314 var change = false;316 var change = false;
315 if (relocs[start_id].r_address > end) {317 if (relocs[start_id].r_address >= end) {
316 start_id += 1;318 start_id += 1;
317 change = true;319 change = true;
318 }320 }
...@@ -332,6 +334,7 @@ const TextBlockParser = struct {...@@ -332,6 +334,7 @@ const TextBlockParser = struct {
332 allocator: *Allocator,334 allocator: *Allocator,
333 section: macho.section_64,335 section: macho.section_64,
334 code: []u8,336 code: []u8,
337 relocs: []macho.relocation_info,
335 object: *Object,338 object: *Object,
336 zld: *Zld,339 zld: *Zld,
337 nlists: []NlistWithIndex,340 nlists: []NlistWithIndex,
...@@ -405,6 +408,7 @@ const TextBlockParser = struct {...@@ -405,6 +408,7 @@ const TextBlockParser = struct {
405408
406 const start_addr = senior_nlist.nlist.n_value - self.section.addr;409 const start_addr = senior_nlist.nlist.n_value - self.section.addr;
407 const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;410 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
409 const code = self.code[start_addr..end_addr];413 const code = self.code[start_addr..end_addr];
410 const size = code.len;414 const size = code.len;
...@@ -424,11 +428,18 @@ const TextBlockParser = struct {...@@ -424,11 +428,18 @@ const TextBlockParser = struct {
424 block.* = .{428 block.* = .{
425 .local_sym_index = senior_nlist.index,429 .local_sym_index = senior_nlist.index,
426 .aliases = alias_only_indices,430 .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),
428 .size = size,434 .size = size,
429 .alignment = self.section.@"align",435 .alignment = self.section.@"align",
430 };436 };
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
432 self.index += 1;443 self.index += 1;
433444
434 return block;445 return block;
...@@ -457,7 +468,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -457,7 +468,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
457468
458 sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan);469 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);
461 log.warn("putting section '{s},{s}' as a TextBlock", .{473 log.warn("putting section '{s},{s}' as a TextBlock", .{
462 segmentName(sect),474 segmentName(sect),
463 sectionName(sect),475 sectionName(sect),
...@@ -474,6 +486,12 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -474,6 +486,12 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
474 defer self.allocator.free(code);486 defer self.allocator.free(code);
475 _ = try self.file.?.preadAll(code, sect.offset);487 _ = 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
477 // Is there any padding between symbols within the section?495 // Is there any padding between symbols within the section?
478 const is_padded = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;496 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 {...@@ -481,7 +499,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
481 if (is_padded) blocks: {499 if (is_padded) blocks: {
482 const filtered_nlists = NlistWithIndex.filterInSection(500 const filtered_nlists = NlistWithIndex.filterInSection(
483 sorted_nlists.items,501 sorted_nlists.items,
484 @intCast(u8, sect_id + 1),502 sect_id + 1,
485 );503 );
486504
487 if (filtered_nlists.len == 0) break :blocks;505 if (filtered_nlists.len == 0) break :blocks;
...@@ -490,6 +508,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -490,6 +508,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
490 .allocator = self.allocator,508 .allocator = self.allocator,
491 .section = sect,509 .section = sect,
492 .code = code,510 .code = code,
511 .relocs = relocs,
493 .object = self,512 .object = self,
494 .zld = zld,513 .zld = zld,
495 .nlists = filtered_nlists,514 .nlists = filtered_nlists,
...@@ -518,8 +537,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -518,8 +537,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
518 }537 }
519 }538 }
520539
521 // TODO parse relocs
522
523 if (zld.last_text_block) |last| {540 if (zld.last_text_block) |last| {
524 last.next = block;541 last.next = block;
525 block.prev = last;542 block.prev = last;
...@@ -531,14 +548,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -531,14 +548,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
531 }548 }
532549
533 // Since there is no symbol to refer to this block, we create550 // Since there is no symbol to refer to this block, we create
534 // a temp one.551 // a temp one, unless we already did that when working out the relocations
535 const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{552 // of other text blocks.
536 self.name.?,553 const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
537 segmentName(sect),554 const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
538 sectionName(sect),555 self.name.?,
539 });556 segmentName(sect),
540 defer self.allocator.free(name);557 sectionName(sect),
541 const symbol = try Symbol.new(self.allocator, name);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 };
542 symbol.payload = .{564 symbol.payload = .{
543 .regular = .{565 .regular = .{
544 .linkage = .translation_unit,566 .linkage = .translation_unit,
...@@ -555,12 +577,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -555,12 +577,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
555577
556 block.* = .{578 block.* = .{
557 .local_sym_index = local_sym_index,579 .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),
559 .size = sect.size,583 .size = sect.size,
560 .alignment = sect.@"align",584 .alignment = sect.@"align",
561 };585 };
562586
563 // TODO parse relocs587 if (relocs.len > 0) {
588 try self.parseRelocs(zld, relocs, block, 0);
589 }
564590
565 if (zld.last_text_block) |last| {591 if (zld.last_text_block) |last| {
566 last.next = block;592 last.next = block;
...@@ -571,6 +597,70 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -571,6 +597,70 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
571 }597 }
572}598}
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
574pub fn parseInitializers(self: *Object) !void {664pub fn parseInitializers(self: *Object) !void {
575 const index = self.mod_init_func_section_index orelse return;665 const index = self.mod_init_func_section_index orelse return;
576 const section = self.sections.items[index];666 const section = self.sections.items[index];
src/link/MachO/Zld.zig+18-62
...@@ -135,9 +135,9 @@ const TlvOffset = struct {...@@ -135,9 +135,9 @@ const TlvOffset = struct {
135pub const TextBlock = struct {135pub const TextBlock = struct {
136 local_sym_index: u32,136 local_sym_index: u32,
137 aliases: ?[]u32 = null,137 aliases: ?[]u32 = null,
138 references: ?[]u32 = null,138 references: std.AutoArrayHashMap(u32, void),
139 code: []u8,139 code: []u8,
140 relocs: ?[]*Relocation = null,140 relocs: std.ArrayList(*Relocation),
141 size: u64,141 size: u64,
142 alignment: u32,142 alignment: u32,
143 next: ?*TextBlock = null,143 next: ?*TextBlock = null,
...@@ -147,15 +147,8 @@ pub const TextBlock = struct {...@@ -147,15 +147,8 @@ pub const TextBlock = struct {
147 if (block.aliases) |aliases| {147 if (block.aliases) |aliases| {
148 allocator.free(aliases);148 allocator.free(aliases);
149 }149 }
150 if (block.references) |references| {150 block.relocs.deinit();
151 allocator.free(references);151 block.references.deinit();
152 }
153 for (block.relocs.items) |reloc| {
154 allocator.destroy(reloc);
155 }
156 if (block.relocs) |relocs| {
157 allocator.free(relocs);
158 }
159 allocator.free(code);152 allocator.free(code);
160 }153 }
161154
...@@ -168,12 +161,19 @@ pub const TextBlock = struct {...@@ -168,12 +161,19 @@ pub const TextBlock = struct {
168 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });161 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
169 }162 }
170 }163 }
171 if (self.references) |references| {164 if (self.references.count() > 0) {
172 log.warn(" | References:", .{});165 log.warn(" | References:", .{});
173 for (references) |index| {166 for (self.references.keys()) |index| {
174 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });167 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
175 }168 }
176 }169 }
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 }
177 log.warn(" | size = {}", .{self.size});177 log.warn(" | size = {}", .{self.size});
178 log.warn(" | align = {}", .{self.alignment});178 log.warn(" | align = {}", .{self.alignment});
179 }179 }
...@@ -280,7 +280,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg...@@ -280,7 +280,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
280 try self.resolveSymbols();280 try self.resolveSymbols();
281 try self.parseTextBlocks();281 try self.parseTextBlocks();
282 return error.TODO;282 return error.TODO;
283 // try self.resolveStubsAndGotEntries();
284 // try self.updateMetadata();283 // try self.updateMetadata();
285 // try self.sortSections();284 // try self.sortSections();
286 // try self.addRpaths(args.rpaths);285 // try self.addRpaths(args.rpaths);
...@@ -1603,7 +1602,9 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1603,7 +1602,9 @@ fn resolveSymbols(self: *Zld) !void {
16031602
1604 block.* = .{1603 block.* = .{
1605 .local_sym_index = local_sym_index,1604 .local_sym_index = local_sym_index,
1605 .references = std.AutoArrayHashMap(u32, void).init(self.allocator),
1606 .code = code,1606 .code = code,
1607 .relocs = std.ArrayList(*Relocation).init(self.allocator),
1607 .size = size,1608 .size = size,
1608 .alignment = alignment,1609 .alignment = alignment,
1609 };1610 };
...@@ -1624,6 +1625,9 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1624,6 +1625,9 @@ fn resolveSymbols(self: *Zld) !void {
1624 {1625 {
1625 // Put dyld_stub_binder as an undefined special symbol.1626 // Put dyld_stub_binder as an undefined special symbol.
1626 const symbol = try Symbol.new(self.allocator, "dyld_stub_binder");1627 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);
1627 try self.globals.putNoClobber(self.allocator, symbol.name, symbol);1631 try self.globals.putNoClobber(self.allocator, symbol.name, symbol);
1628 }1632 }
16291633
...@@ -1699,54 +1703,6 @@ fn parseTextBlocks(self: *Zld) !void {...@@ -1699,54 +1703,6 @@ fn parseTextBlocks(self: *Zld) !void {
1699 }1703 }
1700}1704}
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
1750fn resolveRelocsAndWriteSections(self: *Zld) !void {1706fn resolveRelocsAndWriteSections(self: *Zld) !void {
1751 for (self.objects.items) |object| {1707 for (self.objects.items) |object| {
1752 log.debug("relocating object {s}", .{object.name});1708 log.debug("relocating object {s}", .{object.name});
src/link/MachO/reloc.zig+88-127
...@@ -6,16 +6,18 @@ const math = std.math;...@@ -6,16 +6,18 @@ const math = std.math;
6const mem = std.mem;6const mem = std.mem;
7const meta = std.meta;7const meta = std.meta;
88
9const aarch64 = @import("reloc/aarch64.zig");9pub const aarch64 = @import("reloc/aarch64.zig");
10const x86_64 = @import("reloc/x86_64.zig");10pub const x86_64 = @import("reloc/x86_64.zig");
1111
12const Allocator = mem.Allocator;12const Allocator = mem.Allocator;
13const Symbol = @import("Symbol.zig");
14const TextBlock = @import("Zld.zig").TextBlock;
1315
14pub const Relocation = struct {16pub const Relocation = struct {
15 @"type": Type,17 @"type": Type,
16 code: []u8,
17 offset: u32,18 offset: u32,
18 target: Target,19 block: *TextBlock,
20 target: *Symbol,
1921
20 pub fn cast(base: *Relocation, comptime T: type) ?*T {22 pub fn cast(base: *Relocation, comptime T: type) ?*T {
21 if (base.@"type" != T.base_type)23 if (base.@"type" != T.base_type)
...@@ -24,43 +26,24 @@ pub const Relocation = struct {...@@ -24,43 +26,24 @@ pub const Relocation = struct {
24 return @fieldParentPtr(T, "base", base);26 return @fieldParentPtr(T, "base", base);
25 }27 }
2628
27 pub const ResolveArgs = struct {29 // pub fn resolve(base: *Relocation) !void {
28 source_addr: u64,30 // return switch (base.@"type") {
29 target_addr: u64,31 // .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(),
30 subtractor: ?u64 = null,32 // .branch_aarch64 => @fieldParentPtr(aarch64.Branch, "base", base).resolve(),
31 source_source_sect_addr: ?u64 = null,33 // .page => @fieldParentPtr(aarch64.Page, "base", base).resolve(),
32 source_target_sect_addr: ?u64 = null,34 // .page_off => @fieldParentPtr(aarch64.PageOff, "base", base).resolve(),
33 };35 // .got_page => @fieldParentPtr(aarch64.GotPage, "base", base).resolve(),
3436 // .got_page_off => @fieldParentPtr(aarch64.GotPageOff, "base", base).resolve(),
35 pub fn resolve(base: *Relocation, args: ResolveArgs) !void {37 // .pointer_to_got => @fieldParentPtr(aarch64.PointerToGot, "base", base).resolve(),
36 log.debug("{s}", .{base.@"type"});38 // .tlvp_page => @fieldParentPtr(aarch64.TlvpPage, "base", base).resolve(),
37 log.debug(" | offset 0x{x}", .{base.offset});39 // .tlvp_page_off => @fieldParentPtr(aarch64.TlvpPageOff, "base", base).resolve(),
38 log.debug(" | source address 0x{x}", .{args.source_addr});40 // .branch_x86_64 => @fieldParentPtr(x86_64.Branch, "base", base).resolve(),
39 log.debug(" | target address 0x{x}", .{args.target_addr});41 // .signed => @fieldParentPtr(x86_64.Signed, "base", base).resolve(),
40 if (args.subtractor) |sub|42 // .got_load => @fieldParentPtr(x86_64.GotLoad, "base", base).resolve(),
41 log.debug(" | subtractor address 0x{x}", .{sub});43 // .got => @fieldParentPtr(x86_64.Got, "base", base).resolve(),
42 if (args.source_source_sect_addr) |addr|44 // .tlv => @fieldParentPtr(x86_64.Tlv, "base", base).resolve(),
43 log.debug(" | source source section address 0x{x}", .{addr});45 // };
44 if (args.source_target_sect_addr) |addr|46 // }
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 }
6447
65 pub const Type = enum {48 pub const Type = enum {
66 branch_aarch64,49 branch_aarch64,
...@@ -79,23 +62,37 @@ pub const Relocation = struct {...@@ -79,23 +62,37 @@ pub const Relocation = struct {
79 tlv,62 tlv,
80 };63 };
8164
82 pub const Target = union(enum) {65 pub fn format(base: *const Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
83 symbol: u32,66 try std.fmt.format(writer, "Relocation {{ ", .{});
84 section: u16,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 {89 try std.fmt.format(writer, "}}", .{});
87 return if (reloc.r_extern == 1) .{90 }
88 .symbol = reloc.r_symbolnum,
89 } else .{
90 .section = @intCast(u16, reloc.r_symbolnum - 1),
91 };
92 }
93 };
94};91};
9592
96pub const Unsigned = struct {93pub const Unsigned = struct {
97 base: Relocation,94 base: Relocation,
98 subtractor: ?Relocation.Target = null,95 subtractor: ?*Symbol = null,
99 /// Addend embedded directly in the relocation slot96 /// Addend embedded directly in the relocation slot
100 addend: i64,97 addend: i64,
101 /// Extracted from r_length:98 /// Extracted from r_length:
...@@ -106,75 +103,47 @@ pub const Unsigned = struct {...@@ -106,75 +103,47 @@ pub const Unsigned = struct {
106103
107 pub const base_type: Relocation.Type = .unsigned;104 pub const base_type: Relocation.Type = .unsigned;
108105
109 pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void {106 // pub fn resolve(unsigned: Unsigned) !void {
110 const addend = if (unsigned.base.target == .section)107 // const addend = if (unsigned.base.target == .section)
111 unsigned.addend - @intCast(i64, args.source_target_sect_addr.?)108 // unsigned.addend - @intCast(i64, args.source_target_sect_addr.?)
112 else109 // else
113 unsigned.addend;110 // unsigned.addend;
114111
115 const result = if (args.subtractor) |subtractor|112 // const result = if (args.subtractor) |subtractor|
116 @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend113 // @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend
117 else114 // else
118 @intCast(i64, args.target_addr) + addend;115 // @intCast(i64, args.target_addr) + addend;
119116
120 log.debug(" | calculated addend 0x{x}", .{addend});117 // log.debug(" | calculated addend 0x{x}", .{addend});
121 log.debug(" | calculated unsigned value 0x{x}", .{result});118 // log.debug(" | calculated unsigned value 0x{x}", .{result});
122119
123 if (unsigned.is_64bit) {120 // if (unsigned.is_64bit) {
124 mem.writeIntLittle(121 // mem.writeIntLittle(
125 u64,122 // u64,
126 unsigned.base.code[0..8],123 // unsigned.base.code[0..8],
127 @bitCast(u64, result),124 // @bitCast(u64, result),
128 );125 // );
129 } else {126 // } else {
130 mem.writeIntLittle(127 // mem.writeIntLittle(
131 u32,128 // u32,
132 unsigned.base.code[0..4],129 // unsigned.base.code[0..4],
133 @truncate(u32, @bitCast(u64, result)),130 // @truncate(u32, @bitCast(u64, result)),
134 );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});
135 }140 }
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});
136 }144 }
137};145};
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
178pub const RelocIterator = struct {147pub const RelocIterator = struct {
179 buffer: []const macho.relocation_info,148 buffer: []const macho.relocation_info,
180 index: i32 = -1,149 index: i32 = -1,
...@@ -182,15 +151,7 @@ pub const RelocIterator = struct {...@@ -182,15 +151,7 @@ pub const RelocIterator = struct {
182 pub fn next(self: *RelocIterator) ?macho.relocation_info {151 pub fn next(self: *RelocIterator) ?macho.relocation_info {
183 self.index += 1;152 self.index += 1;
184 if (self.index < self.buffer.len) {153 if (self.index < self.buffer.len) {
185 const reloc = self.buffer[@intCast(u32, self.index)];154 return 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;
194 }155 }
195 return null;156 return null;
196 }157 }
src/link/MachO/reloc/aarch64.zig+278-287
...@@ -9,24 +9,34 @@ const meta = std.meta;...@@ -9,24 +9,34 @@ const meta = std.meta;
9const reloc = @import("../reloc.zig");9const reloc = @import("../reloc.zig");
1010
11const Allocator = mem.Allocator;11const Allocator = mem.Allocator;
12const Object = @import("../Object.zig");
12const Relocation = reloc.Relocation;13const Relocation = reloc.Relocation;
13const Symbol = @import("../Symbol.zig");14const Symbol = @import("../Symbol.zig");
15const TextBlock = Zld.TextBlock;
16const Zld = @import("../Zld.zig");
1417
15pub const Branch = struct {18pub const Branch = struct {
16 base: Relocation,19 base: Relocation,
17 /// Always .UnconditionalBranchImmediate20 /// Always .UnconditionalBranchImmediate
18 inst: aarch64.Instruction,21 // inst: aarch64.Instruction,
1922
20 pub const base_type: Relocation.Type = .branch_aarch64;23 pub const base_type: Relocation.Type = .branch_aarch64;
2124
22 pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void {25 // 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));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;30 // var inst = branch.inst;
28 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));31 // inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
29 mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32());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;
30 }40 }
31};41};
3242
...@@ -34,24 +44,32 @@ pub const Page = struct {...@@ -34,24 +44,32 @@ pub const Page = struct {
34 base: Relocation,44 base: Relocation,
35 addend: ?u32 = null,45 addend: ?u32 = null,
36 /// Always .PCRelativeAddress46 /// Always .PCRelativeAddress
37 inst: aarch64.Instruction,47 // inst: aarch64.Instruction,
3848
39 pub const base_type: Relocation.Type = .page;49 pub const base_type: Relocation.Type = .page;
4050
41 pub fn resolve(page: Page, args: Relocation.ResolveArgs) !void {51 // 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;52 // 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);53 // const source_page = @intCast(i32, args.source_addr >> 12);
44 const target_page = @intCast(i32, target_addr >> 12);54 // const target_page = @intCast(i32, target_addr >> 12);
45 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));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});60 // var inst = page.inst;
48 log.debug(" | moving by {} pages", .{pages});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;64 // mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32());
51 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);65 // }
52 inst.pc_relative_address.immlo = @truncate(u2, pages);
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 }
55 }73 }
56};74};
5775
...@@ -59,7 +77,7 @@ pub const PageOff = struct {...@@ -59,7 +77,7 @@ pub const PageOff = struct {
59 base: Relocation,77 base: Relocation,
60 addend: ?u32 = null,78 addend: ?u32 = null,
61 op_kind: OpKind,79 op_kind: OpKind,
62 inst: aarch64.Instruction,80 // inst: aarch64.Instruction,
6381
64 pub const base_type: Relocation.Type = .page_off;82 pub const base_type: Relocation.Type = .page_off;
6583
...@@ -68,76 +86,99 @@ pub const PageOff = struct {...@@ -68,76 +86,99 @@ pub const PageOff = struct {
68 load_store,86 load_store,
69 };87 };
7088
71 pub fn resolve(page_off: PageOff, args: Relocation.ResolveArgs) !void {89 // 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;90 // const target_addr = if (page_off.addend) |addend| args.target_addr + addend else args.target_addr;
73 const narrowed = @truncate(u12, target_addr);91 // const narrowed = @truncate(u12, target_addr);
7492
75 log.debug(" | narrowed address within the page 0x{x}", .{narrowed});93 // log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
76 log.debug(" | {s} opcode", .{page_off.op_kind});94 // log.debug(" | {s} opcode", .{page_off.op_kind});
7795
78 var inst = page_off.inst;96 // var inst = page_off.inst;
79 if (page_off.op_kind == .arithmetic) {97 // if (page_off.op_kind == .arithmetic) {
80 inst.add_subtract_immediate.imm12 = narrowed;98 // inst.add_subtract_immediate.imm12 = narrowed;
81 } else {99 // } else {
82 const offset: u12 = blk: {100 // const offset: u12 = blk: {
83 if (inst.load_store_register.size == 0) {101 // if (inst.load_store_register.size == 0) {
84 if (inst.load_store_register.v == 1) {102 // if (inst.load_store_register.v == 1) {
85 // 128-bit SIMD is scaled by 16.103 // // 128-bit SIMD is scaled by 16.
86 break :blk try math.divExact(u12, narrowed, 16);104 // break :blk try math.divExact(u12, narrowed, 16);
87 }105 // }
88 // Otherwise, 8-bit SIMD or ldrb.106 // // Otherwise, 8-bit SIMD or ldrb.
89 break :blk narrowed;107 // break :blk narrowed;
90 } else {108 // } else {
91 const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size);109 // const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size);
92 break :blk try math.divExact(u12, narrowed, denom);110 // break :blk try math.divExact(u12, narrowed, denom);
93 }111 // }
94 };112 // };
95 inst.load_store_register.offset = offset;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});
96 }124 }
97125 try std.fmt.format(writer, ".op_kind = {s}, ", .{self.op_kind});
98 mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
99 }126 }
100};127};
101128
102pub const GotPage = struct {129pub const GotPage = struct {
103 base: Relocation,130 base: Relocation,
104 /// Always .PCRelativeAddress131 /// Always .PCRelativeAddress
105 inst: aarch64.Instruction,132 // inst: aarch64.Instruction,
106133
107 pub const base_type: Relocation.Type = .got_page;134 pub const base_type: Relocation.Type = .got_page;
108135
109 pub fn resolve(page: GotPage, args: Relocation.ResolveArgs) !void {136 // pub fn resolve(page: GotPage, args: Relocation.ResolveArgs) !void {
110 const source_page = @intCast(i32, args.source_addr >> 12);137 // const source_page = @intCast(i32, args.source_addr >> 12);
111 const target_page = @intCast(i32, args.target_addr >> 12);138 // const target_page = @intCast(i32, args.target_addr >> 12);
112 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));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;143 // var inst = page.inst;
117 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);144 // inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
118 inst.pc_relative_address.immlo = @truncate(u2, pages);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;
121 }155 }
122};156};
123157
124pub const GotPageOff = struct {158pub const GotPageOff = struct {
125 base: Relocation,159 base: Relocation,
126 /// Always .LoadStoreRegister with size = 3 for GOT indirection160 /// Always .LoadStoreRegister with size = 3 for GOT indirection
127 inst: aarch64.Instruction,161 // inst: aarch64.Instruction,
128162
129 pub const base_type: Relocation.Type = .got_page_off;163 pub const base_type: Relocation.Type = .got_page_off;
130164
131 pub fn resolve(page_off: GotPageOff, args: Relocation.ResolveArgs) !void {165 // pub fn resolve(page_off: GotPageOff, args: Relocation.ResolveArgs) !void {
132 const narrowed = @truncate(u12, args.target_addr);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;174 // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
137 const offset = try math.divExact(u12, narrowed, 8);175 // }
138 inst.load_store_register.offset = offset;
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;
141 }182 }
142};183};
143184
...@@ -146,34 +187,48 @@ pub const PointerToGot = struct {...@@ -146,34 +187,48 @@ pub const PointerToGot = struct {
146187
147 pub const base_type: Relocation.Type = .pointer_to_got;188 pub const base_type: Relocation.Type = .pointer_to_got;
148189
149 pub fn resolve(ptr_to_got: PointerToGot, args: Relocation.ResolveArgs) !void {190 // 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));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;
155 }203 }
156};204};
157205
158pub const TlvpPage = struct {206pub const TlvpPage = struct {
159 base: Relocation,207 base: Relocation,
160 /// Always .PCRelativeAddress208 /// Always .PCRelativeAddress
161 inst: aarch64.Instruction,209 // inst: aarch64.Instruction,
162210
163 pub const base_type: Relocation.Type = .tlvp_page;211 pub const base_type: Relocation.Type = .tlvp_page;
164212
165 pub fn resolve(page: TlvpPage, args: Relocation.ResolveArgs) !void {213 // pub fn resolve(page: TlvpPage, args: Relocation.ResolveArgs) !void {
166 const source_page = @intCast(i32, args.source_addr >> 12);214 // const source_page = @intCast(i32, args.source_addr >> 12);
167 const target_page = @intCast(i32, args.target_addr >> 12);215 // const target_page = @intCast(i32, args.target_addr >> 12);
168 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));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;220 // var inst = page.inst;
173 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);221 // inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
174 inst.pc_relative_address.immlo = @truncate(u2, pages);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;
177 }232 }
178};233};
179234
...@@ -182,82 +237,110 @@ pub const TlvpPageOff = struct {...@@ -182,82 +237,110 @@ pub const TlvpPageOff = struct {
182 /// Always .AddSubtractImmediate regardless of the source instruction.237 /// Always .AddSubtractImmediate regardless of the source instruction.
183 /// This means, we always rewrite the instruction to add even if the238 /// This means, we always rewrite the instruction to add even if the
184 /// source instruction was an ldr.239 /// source instruction was an ldr.
185 inst: aarch64.Instruction,240 // inst: aarch64.Instruction,
186241
187 pub const base_type: Relocation.Type = .tlvp_page_off;242 pub const base_type: Relocation.Type = .tlvp_page_off;
188243
189 pub fn resolve(page_off: TlvpPageOff, args: Relocation.ResolveArgs) !void {244 // pub fn resolve(page_off: TlvpPageOff, args: Relocation.ResolveArgs) !void {
190 const narrowed = @truncate(u12, args.target_addr);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;252 // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
195 inst.add_subtract_immediate.imm12 = narrowed;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;
198 }260 }
199};261};
200262
201pub const Parser = struct {263pub const Parser = struct {
202 allocator: *Allocator,264 object: *Object,
265 zld: *Zld,
203 it: *reloc.RelocIterator,266 it: *reloc.RelocIterator,
204 code: []u8,267 block: *TextBlock,
205 parsed: std.ArrayList(*Relocation),268 base_addr: u64,
206 addend: ?u32 = null,269 addend: ?u32 = null,
207 subtractor: ?Relocation.Target = null,270 subtractor: ?*Symbol = null,
208271
209 pub fn deinit(parser: *Parser) void {272 pub fn parse(self: *Parser) !void {
210 parser.parsed.deinit();273 while (self.it.next()) |rel| {
211 }274 const out_rel = switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
212275 .ARM64_RELOC_BRANCH26 => try self.parseBranch(rel),
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 },
219 .ARM64_RELOC_SUBTRACTOR => {276 .ARM64_RELOC_SUBTRACTOR => {
220 try parser.parseSubtractor(rel);277 // Subtractor is not a relocation with effect on the TextBlock, so
221 },278 // parse it and carry on.
222 .ARM64_RELOC_UNSIGNED => {279 try self.parseSubtractor(rel);
223 try parser.parseUnsigned(rel);280 continue;
224 },281 },
282 .ARM64_RELOC_UNSIGNED => try self.parseUnsigned(rel),
225 .ARM64_RELOC_ADDEND => {283 .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;
227 },288 },
228 .ARM64_RELOC_PAGE21,289 .ARM64_RELOC_PAGE21,
229 .ARM64_RELOC_GOT_LOAD_PAGE21,290 .ARM64_RELOC_GOT_LOAD_PAGE21,
230 .ARM64_RELOC_TLVP_LOAD_PAGE21,291 .ARM64_RELOC_TLVP_LOAD_PAGE21,
231 => {292 => try self.parsePage(rel),
232 try parser.parsePage(rel);293 .ARM64_RELOC_PAGEOFF12 => try self.parsePageOff(rel),
233 },294 .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => try self.parseGotLoadPageOff(rel),
234 .ARM64_RELOC_PAGEOFF12 => {295 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => try self.parseTlvpLoadPageOff(rel),
235 try parser.parsePageOff(rel);296 .ARM64_RELOC_POINTER_TO_GOT => try self.parsePointerToGot(rel),
236 },297 };
237 .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => {298 try self.block.relocs.append(out_rel);
238 try parser.parseGotLoadPageOff(rel);299
239 },300 if (out_rel.target.payload == .regular) {
240 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {301 try self.block.references.put(out_rel.target.payload.regular.local_sym_index, {});
241 try parser.parseTlvpLoadPageOff(rel);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 });
242 },315 },
243 .ARM64_RELOC_POINTER_TO_GOT => {316 .branch_aarch64 => {
244 try parser.parsePointerToGot(rel);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 });
245 },327 },
328 else => {},
246 }329 }
247 }330 }
248 }331 }
249332
250 fn parseAddend(parser: *Parser, rel: macho.relocation_info) !void {333 fn parseAddend(self: *Parser, rel: macho.relocation_info) !void {
251 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);334 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
252 assert(rel_type == .ARM64_RELOC_ADDEND);335 assert(rel_type == .ARM64_RELOC_ADDEND);
253 assert(rel.r_pcrel == 0);336 assert(rel.r_pcrel == 0);
254 assert(rel.r_extern == 0);337 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
259 // Verify ADDEND is followed by a load.342 // 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);
261 switch (next) {344 switch (next) {
262 .ARM64_RELOC_PAGE21, .ARM64_RELOC_PAGEOFF12 => {},345 .ARM64_RELOC_PAGE21, .ARM64_RELOC_PAGEOFF12 => {},
263 else => {346 else => {
...@@ -267,127 +350,101 @@ pub const Parser = struct {...@@ -267,127 +350,101 @@ pub const Parser = struct {
267 }350 }
268 }351 }
269352
270 fn parseBranch(parser: *Parser, rel: macho.relocation_info) !void {353 fn parseBranch(self: *Parser, rel: macho.relocation_info) !*Relocation {
271 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);354 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
272 assert(rel_type == .ARM64_RELOC_BRANCH26);355 assert(rel_type == .ARM64_RELOC_BRANCH26);
273 assert(rel.r_pcrel == 1);356 assert(rel.r_pcrel == 1);
274 assert(rel.r_length == 2);357 assert(rel.r_length == 2);
275358
276 const offset = @intCast(u32, rel.r_address);359 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
277 const inst = parser.code[offset..][0..4];360 const target = try self.object.symbolFromReloc(rel);
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);
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
291 branch.* = .{365 branch.* = .{
292 .base = .{366 .base = .{
293 .@"type" = .branch_aarch64,367 .@"type" = .branch_aarch64,
294 .code = inst,
295 .offset = offset,368 .offset = offset,
296 .target = target,369 .target = target,
370 .block = self.block,
297 },371 },
298 .inst = parsed_inst,
299 };372 };
300373
301 log.debug(" | emitting {}", .{branch});374 return &branch.base;
302 try parser.parsed.append(&branch.base);
303 }375 }
304376
305 fn parsePage(parser: *Parser, rel: macho.relocation_info) !void {377 fn parsePage(self: *Parser, rel: macho.relocation_info) !*Relocation {
306 assert(rel.r_pcrel == 1);378 assert(rel.r_pcrel == 1);
307 assert(rel.r_length == 2);379 assert(rel.r_length == 2);
308380
309 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);381 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
310 const target = Relocation.Target.fromReloc(rel);382 const target = try self.object.symbolFromReloc(rel);
311383 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
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) };
318384
319 const ptr: *Relocation = ptr: {385 const ptr: *Relocation = ptr: {
320 switch (rel_type) {386 switch (rel_type) {
321 .ARM64_RELOC_PAGE21 => {387 .ARM64_RELOC_PAGE21 => {
322 defer {388 defer {
323 // Reset parser's addend state389 // Reset parser's addend state
324 parser.addend = null;390 self.addend = null;
325 }391 }
326 var page = try parser.allocator.create(Page);392 var page = try self.object.allocator.create(Page);
327 errdefer parser.allocator.destroy(page);393 errdefer self.object.allocator.destroy(page);
328394
329 page.* = .{395 page.* = .{
330 .base = .{396 .base = .{
331 .@"type" = .page,397 .@"type" = .page,
332 .code = inst,
333 .offset = offset,398 .offset = offset,
334 .target = target,399 .target = target,
400 .block = self.block,
335 },401 },
336 .addend = parser.addend,402 .addend = self.addend,
337 .inst = parsed_inst,
338 };403 };
339404
340 log.debug(" | emitting {}", .{page});
341
342 break :ptr &page.base;405 break :ptr &page.base;
343 },406 },
344 .ARM64_RELOC_GOT_LOAD_PAGE21 => {407 .ARM64_RELOC_GOT_LOAD_PAGE21 => {
345 var page = try parser.allocator.create(GotPage);408 var page = try self.object.allocator.create(GotPage);
346 errdefer parser.allocator.destroy(page);409 errdefer self.object.allocator.destroy(page);
347410
348 page.* = .{411 page.* = .{
349 .base = .{412 .base = .{
350 .@"type" = .got_page,413 .@"type" = .got_page,
351 .code = inst,
352 .offset = offset,414 .offset = offset,
353 .target = target,415 .target = target,
416 .block = self.block,
354 },417 },
355 .inst = parsed_inst,
356 };418 };
357419
358 log.debug(" | emitting {}", .{page});
359
360 break :ptr &page.base;420 break :ptr &page.base;
361 },421 },
362 .ARM64_RELOC_TLVP_LOAD_PAGE21 => {422 .ARM64_RELOC_TLVP_LOAD_PAGE21 => {
363 var page = try parser.allocator.create(TlvpPage);423 var page = try self.object.allocator.create(TlvpPage);
364 errdefer parser.allocator.destroy(page);424 errdefer self.object.allocator.destroy(page);
365425
366 page.* = .{426 page.* = .{
367 .base = .{427 .base = .{
368 .@"type" = .tlvp_page,428 .@"type" = .tlvp_page,
369 .code = inst,
370 .offset = offset,429 .offset = offset,
371 .target = target,430 .target = target,
431 .block = self.block,
372 },432 },
373 .inst = parsed_inst,
374 };433 };
375434
376 log.debug(" | emitting {}", .{page});
377
378 break :ptr &page.base;435 break :ptr &page.base;
379 },436 },
380 else => unreachable,437 else => unreachable,
381 }438 }
382 };439 };
383440
384 try parser.parsed.append(ptr);441 return ptr;
385 }442 }
386443
387 fn parsePageOff(parser: *Parser, rel: macho.relocation_info) !void {444 fn parsePageOff(self: *Parser, rel: macho.relocation_info) !*Relocation {
388 defer {445 defer {
389 // Reset parser's addend state446 // Reset parser's addend state
390 parser.addend = null;447 self.addend = null;
391 }448 }
392449
393 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);450 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
...@@ -395,83 +452,56 @@ pub const Parser = struct {...@@ -395,83 +452,56 @@ pub const Parser = struct {
395 assert(rel.r_pcrel == 0);452 assert(rel.r_pcrel == 0);
396 assert(rel.r_length == 2);453 assert(rel.r_length == 2);
397454
398 const offset = @intCast(u32, rel.r_address);455 const target = try self.object.symbolFromReloc(rel);
399 const inst = parser.code[offset..][0..4];456 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
400457 const op_kind: PageOff.OpKind = if (isArithmeticOp(self.block.code[offset..][0..4]))
401 var op_kind: PageOff.OpKind = undefined;458 .arithmetic
402 var parsed_inst: aarch64.Instruction = undefined;459 else
403 if (isArithmeticOp(inst)) {460 .load_store;
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);
417461
418 var page_off = try parser.allocator.create(PageOff);462 var page_off = try self.object.allocator.create(PageOff);
419 errdefer parser.allocator.destroy(page_off);463 errdefer self.object.allocator.destroy(page_off);
420464
421 page_off.* = .{465 page_off.* = .{
422 .base = .{466 .base = .{
423 .@"type" = .page_off,467 .@"type" = .page_off,
424 .code = inst,
425 .offset = offset,468 .offset = offset,
426 .target = target,469 .target = target,
470 .block = self.block,
427 },471 },
428 .op_kind = op_kind,472 .op_kind = op_kind,
429 .inst = parsed_inst,473 .addend = self.addend,
430 .addend = parser.addend,
431 };474 };
432475
433 log.debug(" | emitting {}", .{page_off});476 return &page_off.base;
434 try parser.parsed.append(&page_off.base);
435 }477 }
436478
437 fn parseGotLoadPageOff(parser: *Parser, rel: macho.relocation_info) !void {479 fn parseGotLoadPageOff(self: *Parser, rel: macho.relocation_info) !*Relocation {
438 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);480 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
439 assert(rel_type == .ARM64_RELOC_GOT_LOAD_PAGEOFF12);481 assert(rel_type == .ARM64_RELOC_GOT_LOAD_PAGEOFF12);
440 assert(rel.r_pcrel == 0);482 assert(rel.r_pcrel == 0);
441 assert(rel.r_length == 2);483 assert(rel.r_length == 2);
442484
443 const offset = @intCast(u32, rel.r_address);485 const target = try self.object.symbolFromReloc(rel);
444 const inst = parser.code[offset..][0..4];486 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
445 assert(!isArithmeticOp(inst));487 assert(!isArithmeticOp(self.block.code[offset..][0..4]));
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);
454488
455 var page_off = try parser.allocator.create(GotPageOff);489 var page_off = try self.object.allocator.create(GotPageOff);
456 errdefer parser.allocator.destroy(page_off);490 errdefer self.object.allocator.destroy(page_off);
457491
458 page_off.* = .{492 page_off.* = .{
459 .base = .{493 .base = .{
460 .@"type" = .got_page_off,494 .@"type" = .got_page_off,
461 .code = inst,
462 .offset = offset,495 .offset = offset,
463 .target = target,496 .target = target,
464 },497 .block = self.block,
465 .inst = .{
466 .load_store_register = parsed_inst,
467 },498 },
468 };499 };
469500
470 log.debug(" | emitting {}", .{page_off});501 return &page_off.base;
471 try parser.parsed.append(&page_off.base);
472 }502 }
473503
474 fn parseTlvpLoadPageOff(parser: *Parser, rel: macho.relocation_info) !void {504 fn parseTlvpLoadPageOff(self: *Parser, rel: macho.relocation_info) !*Relocation {
475 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);505 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
476 assert(rel_type == .ARM64_RELOC_TLVP_LOAD_PAGEOFF12);506 assert(rel_type == .ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
477 assert(rel.r_pcrel == 0);507 assert(rel.r_pcrel == 0);
...@@ -483,141 +513,102 @@ pub const Parser = struct {...@@ -483,141 +513,102 @@ pub const Parser = struct {
483 size: u1,513 size: u1,
484 };514 };
485515
486 const offset = @intCast(u32, rel.r_address);516 const target = try self.object.symbolFromReloc(rel);
487 const inst = parser.code[offset..][0..4];517 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
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 };
511518
512 const target = Relocation.Target.fromReloc(rel);519 var page_off = try self.object.allocator.create(TlvpPageOff);
513520 errdefer self.object.allocator.destroy(page_off);
514 var page_off = try parser.allocator.create(TlvpPageOff);
515 errdefer parser.allocator.destroy(page_off);
516521
517 page_off.* = .{522 page_off.* = .{
518 .base = .{523 .base = .{
519 .@"type" = .tlvp_page_off,524 .@"type" = .tlvp_page_off,
520 .code = inst,
521 .offset = offset,525 .offset = offset,
522 .target = target,526 .target = target,
523 },527 .block = self.block,
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 },
534 },528 },
535 };529 };
536530
537 log.debug(" | emitting {}", .{page_off});531 return &page_off.base;
538 try parser.parsed.append(&page_off.base);
539 }532 }
540533
541 fn parseSubtractor(parser: *Parser, rel: macho.relocation_info) !void {534 fn parseSubtractor(self: *Parser, rel: macho.relocation_info) !void {
542 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);535 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
543 assert(rel_type == .ARM64_RELOC_SUBTRACTOR);536 assert(rel_type == .ARM64_RELOC_SUBTRACTOR);
544 assert(rel.r_pcrel == 0);537 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
549 // Verify SUBTRACTOR is followed by UNSIGNED.542 // 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);
551 if (next != .ARM64_RELOC_UNSIGNED) {544 if (next != .ARM64_RELOC_UNSIGNED) {
552 log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next});545 log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next});
553 return error.UnexpectedRelocationType;546 return error.UnexpectedRelocationType;
554 }547 }
555 }548 }
556549
557 fn parseUnsigned(parser: *Parser, rel: macho.relocation_info) !void {550 fn parseUnsigned(self: *Parser, rel: macho.relocation_info) !*Relocation {
558 defer {551 defer {
559 // Reset parser's subtractor state552 // Reset parser's subtractor state
560 parser.subtractor = null;553 self.subtractor = null;
561 }554 }
562555
563 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);556 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
564 assert(rel_type == .ARM64_RELOC_UNSIGNED);557 assert(rel_type == .ARM64_RELOC_UNSIGNED);
565 assert(rel.r_pcrel == 0);558 assert(rel.r_pcrel == 0);
566559
567 var unsigned = try parser.allocator.create(reloc.Unsigned);560 const target = try self.object.symbolFromReloc(rel);
568 errdefer parser.allocator.destroy(unsigned);561 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
569
570 const target = Relocation.Target.fromReloc(rel);
571 const is_64bit: bool = switch (rel.r_length) {562 const is_64bit: bool = switch (rel.r_length) {
572 3 => true,563 3 => true,
573 2 => false,564 2 => false,
574 else => unreachable,565 else => unreachable,
575 };566 };
576 const offset = @intCast(u32, rel.r_address);
577 const addend: i64 = if (is_64bit)567 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])
579 else569 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
582 unsigned.* = .{575 unsigned.* = .{
583 .base = .{576 .base = .{
584 .@"type" = .unsigned,577 .@"type" = .unsigned,
585 .code = if (is_64bit) parser.code[offset..][0..8] else parser.code[offset..][0..4],
586 .offset = offset,578 .offset = offset,
587 .target = target,579 .target = target,
580 .block = self.block,
588 },581 },
589 .subtractor = parser.subtractor,582 .subtractor = self.subtractor,
590 .is_64bit = is_64bit,583 .is_64bit = is_64bit,
591 .addend = addend,584 .addend = addend,
592 };585 };
593586
594 log.debug(" | emitting {}", .{unsigned});587 return &unsigned.base;
595 try parser.parsed.append(&unsigned.base);
596 }588 }
597589
598 fn parsePointerToGot(parser: *Parser, rel: macho.relocation_info) !void {590 fn parsePointerToGot(self: *Parser, rel: macho.relocation_info) !*Relocation {
599 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);591 const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type);
600 assert(rel_type == .ARM64_RELOC_POINTER_TO_GOT);592 assert(rel_type == .ARM64_RELOC_POINTER_TO_GOT);
601 assert(rel.r_pcrel == 1);593 assert(rel.r_pcrel == 1);
602 assert(rel.r_length == 2);594 assert(rel.r_length == 2);
603595
604 var ptr_to_got = try parser.allocator.create(PointerToGot);596 var ptr_to_got = try self.object.allocator.create(PointerToGot);
605 errdefer parser.allocator.destroy(ptr_to_got);597 errdefer self.object.allocator.destroy(ptr_to_got);
606598
607 const target = Relocation.Target.fromReloc(rel);599 const target = try self.object.symbolFromReloc(rel);
608 const offset = @intCast(u32, rel.r_address);600 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
609601
610 ptr_to_got.* = .{602 ptr_to_got.* = .{
611 .base = .{603 .base = .{
612 .@"type" = .pointer_to_got,604 .@"type" = .pointer_to_got,
613 .code = parser.code[offset..][0..4],
614 .offset = offset,605 .offset = offset,
615 .target = target,606 .target = target,
607 .block = self.block,
616 },608 },
617 };609 };
618610
619 log.debug(" | emitting {}", .{ptr_to_got});611 return &ptr_to_got.base;
620 try parser.parsed.append(&ptr_to_got.base);
621 }612 }
622};613};
623614
src/link/MachO/reloc/x86_64.zig+182-140
...@@ -8,17 +8,28 @@ const meta = std.meta;...@@ -8,17 +8,28 @@ const meta = std.meta;
8const reloc = @import("../reloc.zig");8const reloc = @import("../reloc.zig");
99
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const Object = @import("../Object.zig");
11const Relocation = reloc.Relocation;12const Relocation = reloc.Relocation;
13const Symbol = @import("../Symbol.zig");
14const TextBlock = Zld.TextBlock;
15const Zld = @import("../Zld.zig");
1216
13pub const Branch = struct {17pub const Branch = struct {
14 base: Relocation,18 base: Relocation,
1519
16 pub const base_type: Relocation.Type = .branch_x86_64;20 pub const base_type: Relocation.Type = .branch_x86_64;
1721
18 pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void {22 // 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);23 // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
20 log.debug(" | displacement 0x{x}", .{displacement});24 // log.debug(" | displacement 0x{x}", .{displacement});
21 mem.writeIntLittle(u32, branch.base.code[0..4], @bitCast(u32, 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;
22 }33 }
23};34};
2435
...@@ -29,25 +40,32 @@ pub const Signed = struct {...@@ -29,25 +40,32 @@ pub const Signed = struct {
2940
30 pub const base_type: Relocation.Type = .signed;41 pub const base_type: Relocation.Type = .signed;
3142
32 pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void {43 // pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void {
33 const target_addr = target_addr: {44 // const target_addr = target_addr: {
34 if (signed.base.target == .section) {45 // if (signed.base.target == .section) {
35 const source_target = @intCast(i64, args.source_source_sect_addr.?) + @intCast(i64, signed.base.offset) + signed.addend + 4;46 // 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.?);47 // const source_disp = source_target - @intCast(i64, args.source_target_sect_addr.?);
37 break :target_addr @intCast(i64, args.target_addr) + source_disp;48 // break :target_addr @intCast(i64, args.target_addr) + source_disp;
38 }49 // }
39 break :target_addr @intCast(i64, args.target_addr) + signed.addend;50 // break :target_addr @intCast(i64, args.target_addr) + signed.addend;
40 };51 // };
41 const displacement = try math.cast(52 // const displacement = try math.cast(
42 i32,53 // i32,
43 target_addr - @intCast(i64, args.source_addr) - signed.correction - 4,54 // target_addr - @intCast(i64, args.source_addr) - signed.correction - 4,
44 );55 // );
4556
46 log.debug(" | addend 0x{x}", .{signed.addend});57 // log.debug(" | addend 0x{x}", .{signed.addend});
47 log.debug(" | correction 0x{x}", .{signed.correction});58 // log.debug(" | correction 0x{x}", .{signed.correction});
48 log.debug(" | displacement 0x{x}", .{displacement});59 // log.debug(" | displacement 0x{x}", .{displacement});
4960
50 mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement));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});
51 }69 }
52};70};
5371
...@@ -56,10 +74,17 @@ pub const GotLoad = struct {...@@ -56,10 +74,17 @@ pub const GotLoad = struct {
5674
57 pub const base_type: Relocation.Type = .got_load;75 pub const base_type: Relocation.Type = .got_load;
5876
59 pub fn resolve(got_load: GotLoad, args: Relocation.ResolveArgs) !void {77 // 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);78 // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
61 log.debug(" | displacement 0x{x}", .{displacement});79 // log.debug(" | displacement 0x{x}", .{displacement});
62 mem.writeIntLittle(u32, got_load.base.code[0..4], @bitCast(u32, 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;
63 }88 }
64};89};
6590
...@@ -69,113 +94,139 @@ pub const Got = struct {...@@ -69,113 +94,139 @@ pub const Got = struct {
6994
70 pub const base_type: Relocation.Type = .got;95 pub const base_type: Relocation.Type = .got;
7196
72 pub fn resolve(got: Got, args: Relocation.ResolveArgs) !void {97 // pub fn resolve(got: Got, args: Relocation.ResolveArgs) !void {
73 const displacement = try math.cast(98 // const displacement = try math.cast(
74 i32,99 // i32,
75 @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + got.addend,100 // @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + got.addend,
76 );101 // );
77 log.debug(" | displacement 0x{x}", .{displacement});102 // log.debug(" | displacement 0x{x}", .{displacement});
78 mem.writeIntLittle(u32, got.base.code[0..4], @bitCast(u32, 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});
79 }110 }
80};111};
81112
82pub const Tlv = struct {113pub const Tlv = struct {
83 base: Relocation,114 base: Relocation,
84 op: *u8,
85115
86 pub const base_type: Relocation.Type = .tlv;116 pub const base_type: Relocation.Type = .tlv;
87117
88 pub fn resolve(tlv: Tlv, args: Relocation.ResolveArgs) !void {118 // pub fn resolve(tlv: Tlv, args: Relocation.ResolveArgs) !void {
89 // We need to rewrite the opcode from movq to leaq.119 // // We need to rewrite the opcode from movq to leaq.
90 tlv.op.* = 0x8d;120 // tlv.op.* = 0x8d;
91 log.debug(" | rewriting op to leaq", .{});121 // log.debug(" | rewriting op to leaq", .{});
92122
93 const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);123 // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4);
94 log.debug(" | displacement 0x{x}", .{displacement});124 // log.debug(" | displacement 0x{x}", .{displacement});
95125
96 mem.writeIntLittle(u32, tlv.base.code[0..4], @bitCast(u32, displacement));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;
97 }133 }
98};134};
99135
100pub const Parser = struct {136pub const Parser = struct {
101 allocator: *Allocator,137 object: *Object,
138 zld: *Zld,
102 it: *reloc.RelocIterator,139 it: *reloc.RelocIterator,
103 code: []u8,140 block: *TextBlock,
104 parsed: std.ArrayList(*Relocation),141 base_addr: u64,
105 subtractor: ?Relocation.Target = null,142 subtractor: ?*Symbol = null,
106143
107 pub fn deinit(parser: *Parser) void {144 pub fn parse(self: *Parser) !void {
108 parser.parsed.deinit();145 while (self.it.next()) |rel| {
109 }146 const out_rel = switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {
110147 .X86_64_RELOC_BRANCH => try self.parseBranch(rel),
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 },
117 .X86_64_RELOC_SUBTRACTOR => {148 .X86_64_RELOC_SUBTRACTOR => {
118 try parser.parseSubtractor(rel);149 // Subtractor is not a relocation with effect on the TextBlock, so
119 },150 // parse it and carry on.
120 .X86_64_RELOC_UNSIGNED => {151 try self.parseSubtractor(rel);
121 try parser.parseUnsigned(rel);152 continue;
122 },153 },
154 .X86_64_RELOC_UNSIGNED => try self.parseUnsigned(rel),
123 .X86_64_RELOC_SIGNED,155 .X86_64_RELOC_SIGNED,
124 .X86_64_RELOC_SIGNED_1,156 .X86_64_RELOC_SIGNED_1,
125 .X86_64_RELOC_SIGNED_2,157 .X86_64_RELOC_SIGNED_2,
126 .X86_64_RELOC_SIGNED_4,158 .X86_64_RELOC_SIGNED_4,
127 => {159 => try self.parseSigned(rel),
128 try parser.parseSigned(rel);160 .X86_64_RELOC_GOT_LOAD => try self.parseGotLoad(rel),
129 },161 .X86_64_RELOC_GOT => try self.parseGot(rel),
130 .X86_64_RELOC_GOT_LOAD => {162 .X86_64_RELOC_TLV => try self.parseTlv(rel),
131 try parser.parseGotLoad(rel);163 };
132 },164 try self.block.relocs.append(out_rel);
133 .X86_64_RELOC_GOT => {165
134 try parser.parseGot(rel);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 });
135 },181 },
136 .X86_64_RELOC_TLV => {182 .branch_x86_64 => {
137 try parser.parseTlv(rel);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 });
138 },193 },
194 else => {},
139 }195 }
140 }196 }
141 }197 }
142198
143 fn parseBranch(parser: *Parser, rel: macho.relocation_info) !void {199 fn parseBranch(self: *Parser, rel: macho.relocation_info) !*Relocation {
144 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);200 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
145 assert(rel_type == .X86_64_RELOC_BRANCH);201 assert(rel_type == .X86_64_RELOC_BRANCH);
146 assert(rel.r_pcrel == 1);202 assert(rel.r_pcrel == 1);
147 assert(rel.r_length == 2);203 assert(rel.r_length == 2);
148204
149 const offset = @intCast(u32, rel.r_address);205 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
150 const inst = parser.code[offset..][0..4];206 const target = try self.object.symbolFromReloc(rel);
151
152 var branch = try parser.allocator.create(Branch);
153 errdefer parser.allocator.destroy(branch);
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
157 branch.* = .{211 branch.* = .{
158 .base = .{212 .base = .{
159 .@"type" = .branch_x86_64,213 .@"type" = .branch_x86_64,
160 .code = inst,
161 .offset = offset,214 .offset = offset,
162 .target = target,215 .target = target,
216 .block = self.block,
163 },217 },
164 };218 };
165219
166 log.debug(" | emitting {}", .{branch});220 return &branch.base;
167 try parser.parsed.append(&branch.base);
168 }221 }
169222
170 fn parseSigned(parser: *Parser, rel: macho.relocation_info) !void {223 fn parseSigned(self: *Parser, rel: macho.relocation_info) !*Relocation {
171 assert(rel.r_pcrel == 1);224 assert(rel.r_pcrel == 1);
172 assert(rel.r_length == 2);225 assert(rel.r_length == 2);
173226
174 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);227 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
175 const target = Relocation.Target.fromReloc(rel);228 const target = try self.object.symbolFromReloc(rel);
176229 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
177 const offset = @intCast(u32, rel.r_address);
178 const inst = parser.code[offset..][0..4];
179 const correction: i4 = switch (rel_type) {230 const correction: i4 = switch (rel_type) {
180 .X86_64_RELOC_SIGNED => 0,231 .X86_64_RELOC_SIGNED => 0,
181 .X86_64_RELOC_SIGNED_1 => 1,232 .X86_64_RELOC_SIGNED_1 => 1,
...@@ -183,161 +234,152 @@ pub const Parser = struct {...@@ -183,161 +234,152 @@ pub const Parser = struct {
183 .X86_64_RELOC_SIGNED_4 => 4,234 .X86_64_RELOC_SIGNED_4 => 4,
184 else => unreachable,235 else => unreachable,
185 };236 };
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);239 var signed = try self.object.allocator.create(Signed);
189 errdefer parser.allocator.destroy(signed);240 errdefer self.object.allocator.destroy(signed);
190241
191 signed.* = .{242 signed.* = .{
192 .base = .{243 .base = .{
193 .@"type" = .signed,244 .@"type" = .signed,
194 .code = inst,
195 .offset = offset,245 .offset = offset,
196 .target = target,246 .target = target,
247 .block = self.block,
197 },248 },
198 .addend = addend,249 .addend = addend,
199 .correction = correction,250 .correction = correction,
200 };251 };
201252
202 log.debug(" | emitting {}", .{signed});253 return &signed.base;
203 try parser.parsed.append(&signed.base);
204 }254 }
205255
206 fn parseGotLoad(parser: *Parser, rel: macho.relocation_info) !void {256 fn parseGotLoad(self: *Parser, rel: macho.relocation_info) !*Relocation {
207 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);257 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
208 assert(rel_type == .X86_64_RELOC_GOT_LOAD);258 assert(rel_type == .X86_64_RELOC_GOT_LOAD);
209 assert(rel.r_pcrel == 1);259 assert(rel.r_pcrel == 1);
210 assert(rel.r_length == 2);260 assert(rel.r_length == 2);
211261
212 const offset = @intCast(u32, rel.r_address);262 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
213 const inst = parser.code[offset..][0..4];263 const target = try self.object.symbolFromReloc(rel);
214 const target = Relocation.Target.fromReloc(rel);
215264
216 var got_load = try parser.allocator.create(GotLoad);265 var got_load = try self.object.allocator.create(GotLoad);
217 errdefer parser.allocator.destroy(got_load);266 errdefer self.object.allocator.destroy(got_load);
218267
219 got_load.* = .{268 got_load.* = .{
220 .base = .{269 .base = .{
221 .@"type" = .got_load,270 .@"type" = .got_load,
222 .code = inst,
223 .offset = offset,271 .offset = offset,
224 .target = target,272 .target = target,
273 .block = self.block,
225 },274 },
226 };275 };
227276
228 log.debug(" | emitting {}", .{got_load});277 return &got_load.base;
229 try parser.parsed.append(&got_load.base);
230 }278 }
231279
232 fn parseGot(parser: *Parser, rel: macho.relocation_info) !void {280 fn parseGot(self: *Parser, rel: macho.relocation_info) !*Relocation {
233 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);281 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
234 assert(rel_type == .X86_64_RELOC_GOT);282 assert(rel_type == .X86_64_RELOC_GOT);
235 assert(rel.r_pcrel == 1);283 assert(rel.r_pcrel == 1);
236 assert(rel.r_length == 2);284 assert(rel.r_length == 2);
237285
238 const offset = @intCast(u32, rel.r_address);286 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
239 const inst = parser.code[offset..][0..4];287 const target = try self.object.symbolFromReloc(rel);
240 const target = Relocation.Target.fromReloc(rel);288 const addend = mem.readIntLittle(i32, self.block.code[offset..][0..4]);
241 const addend = mem.readIntLittle(i32, inst);
242289
243 var got = try parser.allocator.create(Got);290 var got = try self.object.allocator.create(Got);
244 errdefer parser.allocator.destroy(got);291 errdefer self.object.allocator.destroy(got);
245292
246 got.* = .{293 got.* = .{
247 .base = .{294 .base = .{
248 .@"type" = .got,295 .@"type" = .got,
249 .code = inst,
250 .offset = offset,296 .offset = offset,
251 .target = target,297 .target = target,
298 .block = self.block,
252 },299 },
253 .addend = addend,300 .addend = addend,
254 };301 };
255302
256 log.debug(" | emitting {}", .{got});303 return &got.base;
257 try parser.parsed.append(&got.base);
258 }304 }
259305
260 fn parseTlv(parser: *Parser, rel: macho.relocation_info) !void {306 fn parseTlv(self: *Parser, rel: macho.relocation_info) !*Relocation {
261 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);307 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
262 assert(rel_type == .X86_64_RELOC_TLV);308 assert(rel_type == .X86_64_RELOC_TLV);
263 assert(rel.r_pcrel == 1);309 assert(rel.r_pcrel == 1);
264 assert(rel.r_length == 2);310 assert(rel.r_length == 2);
265311
266 const offset = @intCast(u32, rel.r_address);312 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
267 const inst = parser.code[offset..][0..4];313 const target = try self.object.symbolFromReloc(rel);
268 const target = Relocation.Target.fromReloc(rel);
269314
270 var tlv = try parser.allocator.create(Tlv);315 var tlv = try self.object.allocator.create(Tlv);
271 errdefer parser.allocator.destroy(tlv);316 errdefer self.object.allocator.destroy(tlv);
272317
273 tlv.* = .{318 tlv.* = .{
274 .base = .{319 .base = .{
275 .@"type" = .tlv,320 .@"type" = .tlv,
276 .code = inst,
277 .offset = offset,321 .offset = offset,
278 .target = target,322 .target = target,
323 .block = self.block,
279 },324 },
280 .op = &parser.code[offset - 2],
281 };325 };
282326
283 log.debug(" | emitting {}", .{tlv});327 return &tlv.base;
284 try parser.parsed.append(&tlv.base);
285 }328 }
286329
287 fn parseSubtractor(parser: *Parser, rel: macho.relocation_info) !void {330 fn parseSubtractor(self: *Parser, rel: macho.relocation_info) !void {
288 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);331 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
289 assert(rel_type == .X86_64_RELOC_SUBTRACTOR);332 assert(rel_type == .X86_64_RELOC_SUBTRACTOR);
290 assert(rel.r_pcrel == 0);333 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
295 // Verify SUBTRACTOR is followed by UNSIGNED.338 // 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);
297 if (next != .X86_64_RELOC_UNSIGNED) {340 if (next != .X86_64_RELOC_UNSIGNED) {
298 log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next});341 log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next});
299 return error.UnexpectedRelocationType;342 return error.UnexpectedRelocationType;
300 }343 }
301 }344 }
302345
303 fn parseUnsigned(parser: *Parser, rel: macho.relocation_info) !void {346 fn parseUnsigned(self: *Parser, rel: macho.relocation_info) !*Relocation {
304 defer {347 defer {
305 // Reset parser's subtractor state348 // Reset parser's subtractor state
306 parser.subtractor = null;349 self.subtractor = null;
307 }350 }
308351
309 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);352 const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
310 assert(rel_type == .X86_64_RELOC_UNSIGNED);353 assert(rel_type == .X86_64_RELOC_UNSIGNED);
311 assert(rel.r_pcrel == 0);354 assert(rel.r_pcrel == 0);
312355
313 var unsigned = try parser.allocator.create(reloc.Unsigned);356 const target = try self.object.symbolFromReloc(rel);
314 errdefer parser.allocator.destroy(unsigned);
315
316 const target = Relocation.Target.fromReloc(rel);
317 const is_64bit: bool = switch (rel.r_length) {357 const is_64bit: bool = switch (rel.r_length) {
318 3 => true,358 3 => true,
319 2 => false,359 2 => false,
320 else => unreachable,360 else => unreachable,
321 };361 };
322 const offset = @intCast(u32, rel.r_address);362 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
323 const addend: i64 = if (is_64bit)363 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])
325 else365 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
328 unsigned.* = .{371 unsigned.* = .{
329 .base = .{372 .base = .{
330 .@"type" = .unsigned,373 .@"type" = .unsigned,
331 .code = if (is_64bit) parser.code[offset..][0..8] else parser.code[offset..][0..4],
332 .offset = offset,374 .offset = offset,
333 .target = target,375 .target = target,
376 .block = self.block,
334 },377 },
335 .subtractor = parser.subtractor,378 .subtractor = self.subtractor,
336 .is_64bit = is_64bit,379 .is_64bit = is_64bit,
337 .addend = addend,380 .addend = addend,
338 };381 };
339382
340 log.debug(" | emitting {}", .{unsigned});383 return &unsigned.base;
341 try parser.parsed.append(&unsigned.base);
342 }384 }
343};385};