authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-16 17:18:53+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-16 17:18:53+02:00
log54a403d4ff9e20daf1843725012ae44ec828a833
tree1c1679ee843c9caeb1986062a400cc42a645d560
parent5a2bea29315158bc05fb4b09842bbb9ae0ddfada

zld: replace parsed reloc with a simple wrapper around macho.relocation_info


6 files changed, 340 insertions(+), 617 deletions(-)

CMakeLists.txt-1
......@@ -581,7 +581,6 @@ set(ZIG_STAGE2_SOURCES
581581 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
582582 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
583583 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
584 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
585584 "${CMAKE_SOURCE_DIR}/src/link/MachO/TextBlock.zig"
586585 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
587586 "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig"
src/link/MachO/Dylib.zig+2-2
......@@ -12,8 +12,8 @@ const fat = @import("fat.zig");
1212
1313const Allocator = mem.Allocator;
1414const Arch = std.Target.Cpu.Arch;
15const Symbol = @import("Symbol.zig");
1615const LibStub = @import("../tapi.zig").LibStub;
16const Zld = @import("Zld.zig");
1717
1818usingnamespace @import("commands.zig");
1919
......@@ -324,7 +324,7 @@ fn parseSymbols(self: *Dylib) !void {
324324 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff + self.library_offset);
325325
326326 for (slice) |sym| {
327 const add_to_symtab = Symbol.isExt(sym) and (Symbol.isSect(sym) or Symbol.isIndr(sym));
327 const add_to_symtab = Zld.symbolIsExt(sym) and (Zld.symbolIsSect(sym) or Zld.symbolIsIndr(sym));
328328
329329 if (!add_to_symtab) continue;
330330
src/link/MachO/Object.zig+277-252
......@@ -9,13 +9,10 @@ const log = std.log.scoped(.object);
99const macho = std.macho;
1010const math = std.math;
1111const mem = std.mem;
12const reloc = @import("reloc.zig");
1312const sort = std.sort;
1413
1514const Allocator = mem.Allocator;
1615const Arch = std.Target.Cpu.Arch;
17const Relocation = reloc.Relocation;
18const Symbol = @import("Symbol.zig");
1916const TextBlock = @import("TextBlock.zig");
2017const Zld = @import("Zld.zig");
2118
......@@ -57,6 +54,8 @@ tu_comp_dir: ?[]const u8 = null,
5754mtime: ?u64 = null,
5855
5956text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
57sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{},
58symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},
6059
6160const DebugInfo = struct {
6261 inner: dwarf.DwarfInfo,
......@@ -163,6 +162,8 @@ pub fn deinit(self: *Object) void {
163162 self.symtab.deinit(self.allocator);
164163 self.strtab.deinit(self.allocator);
165164 self.text_blocks.deinit(self.allocator);
165 self.sections_as_symbols.deinit(self.allocator);
166 self.symbol_mapping.deinit(self.allocator);
166167
167168 if (self.debug_info) |*db| {
168169 db.deinit(self.allocator);
......@@ -372,20 +373,17 @@ const TextBlockParser = struct {
372373 }
373374
374375 const SeniorityContext = struct {
375 zld: *Zld,
376 object: *Object,
376377 };
377378
378379 fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
379 const lsym = context.zld.locals.items[lhs.index];
380 const rsym = context.zld.locals.items[rhs.index];
381 const lreg = lsym.payload.regular;
382 const rreg = rsym.payload.regular;
383
384 return switch (rreg.linkage) {
385 .global => true,
386 .linkage_unit => lreg.linkage == .translation_unit,
387 else => lsym.isTemp(context.zld),
388 };
380 if (!Zld.symbolIsExt(rhs.nlist)) {
381 return Zld.symbolIsTemp(lhs.nlist, context.object.getString(lhs.nlist.n_strx));
382 } else if (Zld.symbolIsPext(rhs.nlist) or Zld.symbolIsWeakDef(rhs.nlist)) {
383 return !Zld.symbolIsExt(lhs.nlist);
384 } else {
385 return true;
386 }
389387 }
390388
391389 pub fn next(self: *TextBlockParser) !?*TextBlock {
......@@ -409,6 +407,7 @@ const TextBlockParser = struct {
409407 } else null;
410408
411409 for (aliases.items) |*nlist_with_index| {
410 nlist_with_index.index = self.symbol_mapping.get(nlist_with_index.index);
412411 const sym = self.object.symbols.items[nlist_with_index.index];
413412 if (sym.payload != .regular) {
414413 log.err("expected a regular symbol, found {s}", .{sym.payload});
......@@ -424,7 +423,7 @@ const TextBlockParser = struct {
424423 sort.sort(
425424 NlistWithIndex,
426425 aliases.items,
427 SeniorityContext{ .zld = self.zld },
426 SeniorityContext{ .object = self.object },
428427 @This().lessThanBySeniority,
429428 );
430429 }
......@@ -515,7 +514,7 @@ const TextBlockParser = struct {
515514pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
516515 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
517516
518 log.debug("analysing {s}", .{self.name.?});
517 log.warn("analysing {s}", .{self.name.?});
519518
520519 const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
521520 // We only care about defined symbols, so filter every other out.
......@@ -536,14 +535,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
536535
537536 for (seg.sections.items) |sect, id| {
538537 const sect_id = @intCast(u8, id);
539 log.debug("putting section '{s},{s}' as a TextBlock", .{
538 log.warn("putting section '{s},{s}' as a TextBlock", .{
540539 segmentName(sect),
541540 sectionName(sect),
542541 });
543542
544543 // Get matching segment/section in the final artifact.
545544 const match = (try zld.getMatchingSection(sect)) orelse {
546 log.debug("unhandled section", .{});
545 log.warn("unhandled section", .{});
547546 continue;
548547 };
549548
......@@ -577,200 +576,249 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
577576 };
578577 zld.has_stabs = zld.has_stabs or self.debug_info != null;
579578
580 next: {
581 if (is_splittable) blocks: {
582 if (filtered_nlists.len == 0) break :blocks;
583
584 // If the first nlist does not match the start of the section,
585 // then we need encapsulate the memory range [section start, first symbol)
586 // as a temporary symbol and insert the matching TextBlock.
587 const first_nlist = filtered_nlists[0].nlist;
588 if (first_nlist.n_value > sect.addr) {
589 const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
590 const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
591 self.name.?,
592 segmentName(sect),
593 sectionName(sect),
594 });
595 defer self.allocator.free(name);
596 const symbol = try zld.allocator.create(Symbol);
597 symbol.* = .{
598 .strx = try zld.makeString(name),
599 .payload = .{ .undef = .{} },
600 };
601 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
602 break :symbol symbol;
603 };
604
605 const local_sym_index = @intCast(u32, zld.locals.items.len);
606 symbol.payload = .{
607 .regular = .{
608 .linkage = .translation_unit,
609 .address = sect.addr,
610 .segment_id = match.seg,
611 .section_id = match.sect,
612 .file = self,
613 .local_sym_index = local_sym_index,
614 },
615 };
616 try zld.locals.append(zld.allocator, symbol);
617
618 const block_code = code[0 .. first_nlist.n_value - sect.addr];
619 const block_size = block_code.len;
620
621 const block = try self.allocator.create(TextBlock);
622 errdefer self.allocator.destroy(block);
623
624 block.* = TextBlock.init(self.allocator);
625 block.local_sym_index = local_sym_index;
626 block.code = try self.allocator.dupe(u8, block_code);
627 block.size = block_size;
628 block.alignment = sect.@"align";
629
630 const block_relocs = filterRelocs(relocs, 0, block_size);
631 if (block_relocs.len > 0) {
632 try self.parseRelocs(zld, block_relocs, block, 0);
633 }
634
635 if (zld.has_dices) {
636 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
637 try block.dices.ensureTotalCapacity(dices.len);
638
639 for (dices) |dice| {
640 block.dices.appendAssumeCapacity(.{
641 .offset = dice.offset - try math.cast(u32, sect.addr),
642 .length = dice.length,
643 .kind = dice.kind,
644 });
645 }
646 }
647
648 // Update target section's metadata
649 // TODO should we update segment's size here too?
650 // How does it tie with incremental space allocs?
651 const tseg = &zld.load_commands.items[match.seg].Segment;
652 const tsect = &tseg.sections.items[match.sect];
653 const new_alignment = math.max(tsect.@"align", block.alignment);
654 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
655 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
656 tsect.size = new_size;
657 tsect.@"align" = new_alignment;
658
659 if (zld.blocks.getPtr(match)) |last| {
660 last.*.next = block;
661 block.prev = last.*;
662 last.* = block;
663 } else {
664 try zld.blocks.putNoClobber(zld.allocator, match, block);
665 }
666
667 try self.text_blocks.append(self.allocator, block);
668 }
669
670 var parser = TextBlockParser{
671 .allocator = self.allocator,
672 .section = sect,
673 .code = code,
674 .relocs = relocs,
675 .object = self,
676 .zld = zld,
677 .nlists = filtered_nlists,
678 .match = match,
679 };
680
681 while (try parser.next()) |block| {
682 const sym = zld.locals.items[block.local_sym_index];
683 const reg = &sym.payload.regular;
684 if (reg.file) |file| {
685 if (file != self) {
686 log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? });
687 block.deinit();
688 self.allocator.destroy(block);
689 continue;
690 }
691 }
692
693 if (reg.address == sect.addr) {
694 if (self.sections_as_symbols.get(sect_id)) |alias| {
695 // Add alias.
696 const local_sym_index = @intCast(u32, zld.locals.items.len);
697 const reg_alias = &alias.payload.regular;
698 reg_alias.segment_id = match.seg;
699 reg_alias.section_id = match.sect;
700 reg_alias.local_sym_index = local_sym_index;
701 try block.aliases.append(local_sym_index);
702 try zld.locals.append(zld.allocator, alias);
703 }
704 }
705
706 // Update target section's metadata
707 // TODO should we update segment's size here too?
708 // How does it tie with incremental space allocs?
709 const tseg = &zld.load_commands.items[match.seg].Segment;
710 const tsect = &tseg.sections.items[match.sect];
711 const new_alignment = math.max(tsect.@"align", block.alignment);
712 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
713 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
714 tsect.size = new_size;
715 tsect.@"align" = new_alignment;
716
717 if (zld.blocks.getPtr(match)) |last| {
718 last.*.next = block;
719 block.prev = last.*;
720 last.* = block;
721 } else {
722 try zld.blocks.putNoClobber(zld.allocator, match, block);
723 }
724
725 try self.text_blocks.append(self.allocator, block);
726 }
727
728 break :next;
729 }
579 {
580 // next: {
581 // if (is_splittable) blocks: {
582 // if (filtered_nlists.len == 0) break :blocks;
583
584 // // If the first nlist does not match the start of the section,
585 // // then we need encapsulate the memory range [section start, first symbol)
586 // // as a temporary symbol and insert the matching TextBlock.
587 // const first_nlist = filtered_nlists[0].nlist;
588 // if (first_nlist.n_value > sect.addr) {
589 // const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
590 // const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
591 // self.name.?,
592 // segmentName(sect),
593 // sectionName(sect),
594 // });
595 // defer self.allocator.free(name);
596 // const symbol = try zld.allocator.create(Symbol);
597 // symbol.* = .{
598 // .strx = try zld.makeString(name),
599 // .payload = .{ .undef = .{} },
600 // };
601 // try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
602 // break :symbol symbol;
603 // };
604
605 // const local_sym_index = @intCast(u32, zld.locals.items.len);
606 // symbol.payload = .{
607 // .regular = .{
608 // .linkage = .translation_unit,
609 // .address = sect.addr,
610 // .segment_id = match.seg,
611 // .section_id = match.sect,
612 // .file = self,
613 // .local_sym_index = local_sym_index,
614 // },
615 // };
616 // try zld.locals.append(zld.allocator, symbol);
617
618 // const block_code = code[0 .. first_nlist.n_value - sect.addr];
619 // const block_size = block_code.len;
620
621 // const block = try self.allocator.create(TextBlock);
622 // errdefer self.allocator.destroy(block);
623
624 // block.* = TextBlock.init(self.allocator);
625 // block.local_sym_index = local_sym_index;
626 // block.code = try self.allocator.dupe(u8, block_code);
627 // block.size = block_size;
628 // block.alignment = sect.@"align";
629
630 // const block_relocs = filterRelocs(relocs, 0, block_size);
631 // if (block_relocs.len > 0) {
632 // try self.parseRelocs(zld, block_relocs, block, 0);
633 // }
634
635 // if (zld.has_dices) {
636 // const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
637 // try block.dices.ensureTotalCapacity(dices.len);
638
639 // for (dices) |dice| {
640 // block.dices.appendAssumeCapacity(.{
641 // .offset = dice.offset - try math.cast(u32, sect.addr),
642 // .length = dice.length,
643 // .kind = dice.kind,
644 // });
645 // }
646 // }
647
648 // // Update target section's metadata
649 // // TODO should we update segment's size here too?
650 // // How does it tie with incremental space allocs?
651 // const tseg = &zld.load_commands.items[match.seg].Segment;
652 // const tsect = &tseg.sections.items[match.sect];
653 // const new_alignment = math.max(tsect.@"align", block.alignment);
654 // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
655 // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
656 // tsect.size = new_size;
657 // tsect.@"align" = new_alignment;
658
659 // if (zld.blocks.getPtr(match)) |last| {
660 // last.*.next = block;
661 // block.prev = last.*;
662 // last.* = block;
663 // } else {
664 // try zld.blocks.putNoClobber(zld.allocator, match, block);
665 // }
666
667 // try self.text_blocks.append(self.allocator, block);
668 // }
669
670 // var parser = TextBlockParser{
671 // .allocator = self.allocator,
672 // .section = sect,
673 // .code = code,
674 // .relocs = relocs,
675 // .object = self,
676 // .zld = zld,
677 // .nlists = filtered_nlists,
678 // .match = match,
679 // };
680
681 // while (try parser.next()) |block| {
682 // const sym = zld.locals.items[block.local_sym_index];
683 // const reg = &sym.payload.regular;
684 // if (reg.file) |file| {
685 // if (file != self) {
686 // log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? });
687 // block.deinit();
688 // self.allocator.destroy(block);
689 // continue;
690 // }
691 // }
692
693 // if (reg.address == sect.addr) {
694 // if (self.sections_as_symbols.get(sect_id)) |alias| {
695 // // Add alias.
696 // const local_sym_index = @intCast(u32, zld.locals.items.len);
697 // const reg_alias = &alias.payload.regular;
698 // reg_alias.segment_id = match.seg;
699 // reg_alias.section_id = match.sect;
700 // reg_alias.local_sym_index = local_sym_index;
701 // try block.aliases.append(local_sym_index);
702 // try zld.locals.append(zld.allocator, alias);
703 // }
704 // }
705
706 // // Update target section's metadata
707 // // TODO should we update segment's size here too?
708 // // How does it tie with incremental space allocs?
709 // const tseg = &zld.load_commands.items[match.seg].Segment;
710 // const tsect = &tseg.sections.items[match.sect];
711 // const new_alignment = math.max(tsect.@"align", block.alignment);
712 // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
713 // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
714 // tsect.size = new_size;
715 // tsect.@"align" = new_alignment;
716
717 // if (zld.blocks.getPtr(match)) |last| {
718 // last.*.next = block;
719 // block.prev = last.*;
720 // last.* = block;
721 // } else {
722 // try zld.blocks.putNoClobber(zld.allocator, match, block);
723 // }
724
725 // try self.text_blocks.append(self.allocator, block);
726 // }
727
728 // break :next;
729 // }
730730
731731 // Since there is no symbol to refer to this block, we create
732732 // a temp one, unless we already did that when working out the relocations
733733 // of other text blocks.
734 const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
735 const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
736 self.name.?,
737 segmentName(sect),
738 sectionName(sect),
739 });
740 defer self.allocator.free(name);
741 const symbol = try zld.allocator.create(Symbol);
742 symbol.* = .{
743 .strx = try zld.makeString(name),
744 .payload = .{ .undef = .{} },
745 };
746 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
747 break :symbol symbol;
748 };
749
750 const local_sym_index = @intCast(u32, zld.locals.items.len);
751 symbol.payload = .{
752 .regular = .{
753 .linkage = .translation_unit,
754 .address = sect.addr,
755 .segment_id = match.seg,
756 .section_id = match.sect,
757 .file = self,
758 .local_sym_index = local_sym_index,
759 },
760 };
761 try zld.locals.append(zld.allocator, symbol);
734 const block_local_sym_index = @intCast(u32, zld.locals.items.len);
735 const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
736 self.name.?,
737 segmentName(sect),
738 sectionName(sect),
739 });
740 defer self.allocator.free(sym_name);
741 try zld.locals.append(zld.allocator, .{
742 .n_strx = try zld.makeString(sym_name),
743 .n_type = macho.N_SECT,
744 .n_sect = zld.sectionId(match),
745 .n_desc = 0,
746 .n_value = sect.addr,
747 });
748 const block_local = &zld.locals.items[block_local_sym_index];
749 block_local.n_sect = zld.sectionId(match);
762750
763751 const block = try self.allocator.create(TextBlock);
764752 errdefer self.allocator.destroy(block);
765753
766754 block.* = TextBlock.init(self.allocator);
767 block.local_sym_index = local_sym_index;
755 block.local_sym_index = block_local_sym_index;
768756 block.code = try self.allocator.dupe(u8, code);
769757 block.size = sect.size;
770758 block.alignment = sect.@"align";
771759
772 if (relocs.len > 0) {
773 try self.parseRelocs(zld, relocs, block, 0);
760 try block.relocs.ensureTotalCapacity(relocs.len);
761 for (relocs) |rel| {
762 const out_rel: TextBlock.Relocation = outer: {
763 if (rel.r_extern == 0) {
764 const rel_sect_id = @intCast(u16, rel.r_symbolnum - 1);
765 const sect_sym_index = self.sections_as_symbols.get(rel_sect_id) orelse blk: {
766 const sect_sym_index = @intCast(u32, zld.locals.items.len);
767 const sect_sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
768 self.name.?,
769 segmentName(sect),
770 sectionName(sect),
771 });
772 defer self.allocator.free(sect_sym_name);
773 try zld.locals.append(zld.allocator, .{
774 .n_strx = try zld.makeString(sect_sym_name),
775 .n_type = macho.N_SECT,
776 .n_sect = 0,
777 .n_desc = 0,
778 .n_value = 0,
779 });
780 try self.sections_as_symbols.putNoClobber(self.allocator, rel_sect_id, sect_sym_index);
781 break :blk sect_sym_index;
782 };
783 break :outer .{
784 .inner = rel,
785 .where = .local,
786 .where_index = sect_sym_index,
787 };
788 }
789
790 const rel_sym = self.symtab.items[rel.r_symbolnum];
791 const rel_sym_name = self.getString(rel_sym.n_strx);
792
793 if (Zld.symbolIsSect(rel_sym) and !Zld.symbolIsExt(rel_sym)) {
794 const where_index = self.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;
795 break :outer .{
796 .inner = rel,
797 .where = .local,
798 .where_index = where_index,
799 };
800 }
801
802 const resolv = zld.symbol_resolver.get(rel_sym_name) orelse unreachable;
803 switch (resolv.where) {
804 .global => {
805 break :outer .{
806 .inner = rel,
807 .where = .local,
808 .where_index = resolv.local_sym_index,
809 };
810 },
811 .import => {
812 break :outer .{
813 .inner = rel,
814 .where = .import,
815 .where_index = resolv.where_index,
816 };
817 },
818 else => unreachable,
819 }
820 };
821 block.relocs.appendAssumeCapacity(out_rel);
774822 }
775823
776824 if (zld.has_dices) {
......@@ -791,44 +839,41 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
791839 // the filtered symbols and note which symbol is contained within so that
792840 // we can properly allocate addresses down the line.
793841 // While we're at it, we need to update segment,section mapping of each symbol too.
794 if (filtered_nlists.len > 0) {
795 var contained = std.ArrayList(TextBlock.SymbolAtOffset).init(self.allocator);
796 defer contained.deinit();
797 try contained.ensureTotalCapacity(filtered_nlists.len);
798
799 for (filtered_nlists) |nlist_with_index| {
800 const sym = self.symbols.items[nlist_with_index.index];
801 assert(sym.payload == .regular);
802 const reg = &sym.payload.regular;
803
804 reg.segment_id = match.seg;
805 reg.section_id = match.sect;
806
807 const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: {
808 // TODO there has to be a better to handle this.
809 for (di.inner.func_list.items) |func| {
810 if (func.pc_range) |range| {
811 if (reg.address >= range.start and reg.address < range.end) {
812 break :blk TextBlock.Stab{
813 .function = range.end - range.start,
814 };
815 }
842 var contained = std.ArrayList(TextBlock.SymbolAtOffset).init(self.allocator);
843 defer contained.deinit();
844 try contained.ensureTotalCapacity(filtered_nlists.len);
845
846 for (filtered_nlists) |nlist_with_index| {
847 const nlist = nlist_with_index.nlist;
848 const local_sym_index = self.symbol_mapping.get(nlist_with_index.index) orelse unreachable;
849 const local = &zld.locals.items[local_sym_index];
850 local.n_sect = zld.sectionId(match);
851
852 const stab: ?TextBlock.Stab = if (self.debug_info) |di| blk: {
853 // TODO there has to be a better to handle this.
854 for (di.inner.func_list.items) |func| {
855 if (func.pc_range) |range| {
856 if (nlist.n_value >= range.start and nlist.n_value < range.end) {
857 break :blk TextBlock.Stab{
858 .function = range.end - range.start,
859 };
816860 }
817861 }
818 if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global;
819 break :blk .static;
820 } else null;
821
822 contained.appendAssumeCapacity(.{
823 .local_sym_index = reg.local_sym_index,
824 .offset = nlist_with_index.nlist.n_value - sect.addr,
825 .stab = stab,
826 });
827 }
862 }
863 // TODO
864 // if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global;
865 break :blk .static;
866 } else null;
828867
829 block.contained = contained.toOwnedSlice();
868 contained.appendAssumeCapacity(.{
869 .local_sym_index = local_sym_index,
870 .offset = nlist.n_value - sect.addr,
871 .stab = stab,
872 });
830873 }
831874
875 block.contained = contained.toOwnedSlice();
876
832877 // Update target section's metadata
833878 // TODO should we update segment's size here too?
834879 // How does it tie with incremental space allocs?
......@@ -853,26 +898,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
853898 }
854899}
855900
856fn parseRelocs(
857 self: *Object,
858 zld: *Zld,
859 relocs: []const macho.relocation_info,
860 block: *TextBlock,
861 base_addr: u64,
862) !void {
863 var it = reloc.RelocIterator{
864 .buffer = relocs,
865 };
866 var parser = reloc.Parser{
867 .object = self,
868 .zld = zld,
869 .it = &it,
870 .block = block,
871 .base_addr = base_addr,
872 };
873 try parser.parse();
874}
875
876901pub fn symbolFromReloc(self: *Object, zld: *Zld, rel: macho.relocation_info) !*Symbol {
877902 const symbol = blk: {
878903 if (rel.r_extern == 1) {
src/link/MachO/Symbol.zig deleted-285
......@@ -1,285 +0,0 @@
1const Symbol = @This();
2
3const std = @import("std");
4const assert = std.debug.assert;
5const commands = @import("commands.zig");
6const macho = std.macho;
7const mem = std.mem;
8
9const Allocator = mem.Allocator;
10const Dylib = @import("Dylib.zig");
11const Object = @import("Object.zig");
12const Zld = @import("Zld.zig");
13
14/// Offset into the string table.
15strx: u32,
16
17/// Index in GOT table for indirection.
18got_index: ?u32 = null,
19
20/// Index in stubs table for late binding.
21stubs_index: ?u32 = null,
22
23payload: union(enum) {
24 regular: Regular,
25 tentative: Tentative,
26 proxy: Proxy,
27 undef: Undefined,
28
29 pub fn format(self: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
30 return switch (self) {
31 .regular => |p| p.format(fmt, options, writer),
32 .tentative => |p| p.format(fmt, options, writer),
33 .proxy => |p| p.format(fmt, options, writer),
34 .undef => |p| p.format(fmt, options, writer),
35 };
36 }
37},
38
39pub const Regular = struct {
40 /// Linkage type.
41 linkage: Linkage,
42
43 /// Symbol address.
44 address: u64 = 0,
45
46 /// Segment ID
47 segment_id: u16 = 0,
48
49 /// Section ID
50 section_id: u16 = 0,
51
52 /// Whether the symbol is a weak ref.
53 weak_ref: bool = false,
54
55 /// Object file where to locate this symbol.
56 /// null means self-reference.
57 file: ?*Object = null,
58
59 local_sym_index: u32 = 0,
60
61 pub const Linkage = enum {
62 translation_unit,
63 linkage_unit,
64 global,
65 };
66
67 pub fn format(self: Regular, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
68 _ = fmt;
69 _ = options;
70 try std.fmt.format(writer, "Regular {{ ", .{});
71 try std.fmt.format(writer, ".linkage = {s}, ", .{self.linkage});
72 try std.fmt.format(writer, ".address = 0x{x}, ", .{self.address});
73 try std.fmt.format(writer, ".segment_id = {}, ", .{self.segment_id});
74 try std.fmt.format(writer, ".section_id = {}, ", .{self.section_id});
75 if (self.weak_ref) {
76 try std.fmt.format(writer, ".weak_ref, ", .{});
77 }
78 if (self.file) |file| {
79 try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
80 }
81 try std.fmt.format(writer, ".local_sym_index = {}, ", .{self.local_sym_index});
82 try std.fmt.format(writer, "}}", .{});
83 }
84
85 pub fn sectionId(self: Regular, zld: *Zld) u8 {
86 // TODO there might be a more generic way of doing this.
87 var section: u8 = 0;
88 for (zld.load_commands.items) |cmd, cmd_id| {
89 if (cmd != .Segment) break;
90 if (cmd_id == self.segment_id) {
91 section += @intCast(u8, self.section_id) + 1;
92 break;
93 }
94 section += @intCast(u8, cmd.Segment.sections.items.len);
95 }
96 return section;
97 }
98};
99
100pub const Tentative = struct {
101 /// Symbol size.
102 size: u64,
103
104 /// Symbol alignment as power of two.
105 alignment: u16,
106
107 /// File where this symbol was referenced.
108 file: ?*Object = null,
109
110 pub fn format(self: Tentative, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
111 _ = fmt;
112 _ = options;
113 try std.fmt.format(writer, "Tentative {{ ", .{});
114 try std.fmt.format(writer, ".size = 0x{x}, ", .{self.size});
115 try std.fmt.format(writer, ".alignment = 0x{x}, ", .{self.alignment});
116 if (self.file) |file| {
117 try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
118 }
119 try std.fmt.format(writer, "}}", .{});
120 }
121};
122
123pub const Proxy = struct {
124 /// Dylib where to locate this symbol.
125 /// null means self-reference.
126 file: ?*Dylib = null,
127
128 local_sym_index: u32 = 0,
129
130 pub fn dylibOrdinal(proxy: Proxy) u16 {
131 const dylib = proxy.file orelse return 0;
132 return dylib.ordinal.?;
133 }
134
135 pub fn format(self: Proxy, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
136 _ = fmt;
137 _ = options;
138 try std.fmt.format(writer, "Proxy {{ ", .{});
139 if (self.file) |file| {
140 try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
141 }
142 try std.fmt.format(writer, ".local_sym_index = {d}, ", .{self.local_sym_index});
143 try std.fmt.format(writer, "}}", .{});
144 }
145};
146
147pub const Undefined = struct {
148 /// File where this symbol was referenced.
149 /// null means synthetic, e.g., dyld_stub_binder.
150 file: ?*Object = null,
151
152 pub fn format(self: Undefined, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
153 _ = fmt;
154 _ = options;
155 try std.fmt.format(writer, "Undefined {{ ", .{});
156 if (self.file) |file| {
157 try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
158 }
159 try std.fmt.format(writer, "}}", .{});
160 }
161};
162
163pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
164 _ = fmt;
165 _ = options;
166 try std.fmt.format(writer, "Symbol {{", .{});
167 try std.fmt.format(writer, ".strx = {d}, ", .{self.strx});
168 if (self.got_index) |got_index| {
169 try std.fmt.format(writer, ".got_index = {}, ", .{got_index});
170 }
171 if (self.stubs_index) |stubs_index| {
172 try std.fmt.format(writer, ".stubs_index = {}, ", .{stubs_index});
173 }
174 try std.fmt.format(writer, "{}, ", .{self.payload});
175 try std.fmt.format(writer, "}}", .{});
176}
177
178pub fn isTemp(symbol: Symbol, zld: *Zld) bool {
179 const sym_name = zld.getString(symbol.strx);
180 switch (symbol.payload) {
181 .regular => |regular| {
182 if (regular.linkage == .translation_unit) {
183 return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");
184 }
185 },
186 else => {},
187 }
188 return false;
189}
190
191pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
192 const nlist = nlist: {
193 switch (symbol.payload) {
194 .regular => |regular| {
195 var nlist = macho.nlist_64{
196 .n_strx = symbol.strx,
197 .n_type = macho.N_SECT,
198 .n_sect = regular.sectionId(zld),
199 .n_desc = 0,
200 .n_value = regular.address,
201 };
202
203 if (regular.linkage != .translation_unit) {
204 nlist.n_type |= macho.N_EXT;
205 }
206 if (regular.linkage == .linkage_unit) {
207 nlist.n_type |= macho.N_PEXT;
208 nlist.n_desc |= macho.N_WEAK_DEF;
209 }
210
211 break :nlist nlist;
212 },
213 .tentative => {
214 // TODO
215 break :nlist macho.nlist_64{
216 .n_strx = symbol.strx,
217 .n_type = macho.N_UNDF,
218 .n_sect = 0,
219 .n_desc = 0,
220 .n_value = 0,
221 };
222 },
223 .proxy => |proxy| {
224 break :nlist macho.nlist_64{
225 .n_strx = symbol.strx,
226 .n_type = macho.N_UNDF | macho.N_EXT,
227 .n_sect = 0,
228 .n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
229 .n_value = 0,
230 };
231 },
232 .undef => {
233 // TODO
234 break :nlist macho.nlist_64{
235 .n_strx = symbol.strx,
236 .n_type = macho.N_UNDF,
237 .n_sect = 0,
238 .n_desc = 0,
239 .n_value = 0,
240 };
241 },
242 }
243 };
244 return nlist;
245}
246
247pub fn isStab(sym: macho.nlist_64) bool {
248 return (macho.N_STAB & sym.n_type) != 0;
249}
250
251pub fn isPext(sym: macho.nlist_64) bool {
252 return (macho.N_PEXT & sym.n_type) != 0;
253}
254
255pub fn isExt(sym: macho.nlist_64) bool {
256 return (macho.N_EXT & sym.n_type) != 0;
257}
258
259pub fn isSect(sym: macho.nlist_64) bool {
260 const type_ = macho.N_TYPE & sym.n_type;
261 return type_ == macho.N_SECT;
262}
263
264pub fn isUndf(sym: macho.nlist_64) bool {
265 const type_ = macho.N_TYPE & sym.n_type;
266 return type_ == macho.N_UNDF;
267}
268
269pub fn isIndr(sym: macho.nlist_64) bool {
270 const type_ = macho.N_TYPE & sym.n_type;
271 return type_ == macho.N_INDR;
272}
273
274pub fn isAbs(sym: macho.nlist_64) bool {
275 const type_ = macho.N_TYPE & sym.n_type;
276 return type_ == macho.N_ABS;
277}
278
279pub fn isWeakDef(sym: macho.nlist_64) bool {
280 return (sym.n_desc & macho.N_WEAK_DEF) != 0;
281}
282
283pub fn isWeakRef(sym: macho.nlist_64) bool {
284 return (sym.n_desc & macho.N_WEAK_REF) != 0;
285}
src/link/MachO/TextBlock.zig+35-29
......@@ -5,10 +5,9 @@ const commands = @import("commands.zig");
55const log = std.log.scoped(.text_block);
66const macho = std.macho;
77const mem = std.mem;
8const reloc = @import("reloc.zig");
98
109const Allocator = mem.Allocator;
11const Relocation = reloc.Relocation;
10const Arch = std.Target.Cpu.Arch;
1211const Zld = @import("Zld.zig");
1312
1413allocator: *Allocator,
......@@ -102,6 +101,15 @@ pub const Stab = union(enum) {
102101 }
103102};
104103
104pub const Relocation = struct {
105 inner: macho.relocation_info,
106 where: enum {
107 local,
108 import,
109 },
110 where_index: u32,
111};
112
105113pub fn init(allocator: *Allocator) TextBlock {
106114 return .{
107115 .allocator = allocator,
......@@ -137,18 +145,10 @@ pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
137145
138146 const source_addr = blk: {
139147 const sym = zld.locals.items[self.local_sym_index];
140 break :blk sym.payload.regular.address + rel.offset;
148 break :blk sym.n_value + rel.offset;
141149 };
142150 const target_addr = blk: {
143 const is_via_got = switch (rel.payload) {
144 .pointer_to_got => true,
145 .page => |page| page.kind == .got,
146 .page_off => |page_off| page_off.kind == .got,
147 .load => |load| load.kind == .got,
148 else => false,
149 };
150
151 if (is_via_got) {
151 if (isGotIndirection(rel, zld.target.?.cpu.arch)) {
152152 const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;
153153 const got = dc_seg.sections.items[zld.got_section_index.?];
154154 const got_index = rel.target.got_index orelse {
......@@ -228,31 +228,18 @@ pub fn print_this(self: *const TextBlock, zld: *Zld) void {
228228 log.warn(" stab: {}", .{stab});
229229 }
230230 if (self.aliases.items.len > 0) {
231 log.warn(" aliases:", .{});
232 for (self.aliases.items) |index| {
233 log.warn(" {}: {}", .{ index, zld.locals.items[index] });
234 }
231 log.warn(" aliases: {any}", .{self.aliases.items});
235232 }
236233 if (self.references.count() > 0) {
237 log.warn(" references:", .{});
238 for (self.references.keys()) |index| {
239 log.warn(" {}: {}", .{ index, zld.locals.items[index] });
240 }
234 log.warn(" references: {any}", .{self.references.keys()});
241235 }
242236 if (self.contained) |contained| {
243237 log.warn(" contained symbols:", .{});
244238 for (contained) |sym_at_off| {
245239 if (sym_at_off.stab) |stab| {
246 log.warn(" {}: {}, stab: {}\n", .{
247 sym_at_off.offset,
248 zld.locals.items[sym_at_off.local_sym_index],
249 stab,
250 });
240 log.warn(" {}: {}, stab: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index, stab });
251241 } else {
252 log.warn(" {}: {}\n", .{
253 sym_at_off.offset,
254 zld.locals.items[sym_at_off.local_sym_index],
255 });
242 log.warn(" {}: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index });
256243 }
257244 }
258245 }
......@@ -282,3 +269,22 @@ pub fn print(self: *const TextBlock, zld: *Zld) void {
282269 }
283270 self.print_this(zld);
284271}
272
273fn isGotIndirection(rel: macho.relocation_info, arch: Arch) bool {
274 return switch (arch) {
275 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
276 .ARM64_RELOC_POINTER_TO_GOT,
277 .ARM64_RELOC_GOT_LOAD_PAGE21,
278 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
279 => true,
280 else => false,
281 },
282 .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {
283 .X86_64_RELOC_GOT,
284 .X86_64_RELOC_GOT_LOAD,
285 => true,
286 else => false,
287 },
288 else => unreachable,
289 };
290}
src/link/MachO/Zld.zig+26-48
......@@ -105,7 +105,6 @@ imports: std.ArrayListUnmanaged(macho.nlist_64) = .{},
105105undefs: std.ArrayListUnmanaged(macho.nlist_64) = .{},
106106tentatives: std.ArrayListUnmanaged(macho.nlist_64) = .{},
107107symbol_resolver: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
108object_mapping: std.AutoHashMapUnmanaged(u16, []u32) = .{},
109108
110109strtab: std.ArrayListUnmanaged(u8) = .{},
111110
......@@ -199,14 +198,6 @@ pub fn deinit(self: *Zld) void {
199198 }
200199 self.symbol_resolver.deinit(self.allocator);
201200
202 {
203 var it = self.object_mapping.valueIterator();
204 while (it.next()) |value_ptr| {
205 self.allocator.free(value_ptr.*);
206 }
207 }
208 self.object_mapping.deinit(self.allocator);
209
210201 self.strtab.deinit(self.allocator);
211202
212203 // TODO dealloc all blocks
......@@ -251,33 +242,33 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
251242 try self.resolveSymbols();
252243
253244 log.warn("locals", .{});
254 for (self.locals.items) |sym| {
255 log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
245 for (self.locals.items) |sym, id| {
246 log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
256247 }
257248
258249 log.warn("globals", .{});
259 for (self.globals.items) |sym| {
260 log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
250 for (self.globals.items) |sym, id| {
251 log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
261252 }
262253
263254 log.warn("tentatives", .{});
264 for (self.tentatives.items) |sym| {
265 log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
255 for (self.tentatives.items) |sym, id| {
256 log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
266257 }
267258
268259 log.warn("undefines", .{});
269 for (self.undefs.items) |sym| {
270 log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
260 for (self.undefs.items) |sym, id| {
261 log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
271262 }
272263
273264 log.warn("imports", .{});
274 for (self.imports.items) |sym| {
275 log.warn(" | {s}: {}", .{ self.getString(sym.n_strx), sym });
265 for (self.imports.items) |sym, id| {
266 log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
276267 }
277268
278269 log.warn("symbol resolver", .{});
279270 for (self.symbol_resolver.keys()) |key| {
280 log.warn(" | {s} => {}", .{ key, self.symbol_resolver.get(key).? });
271 log.warn(" {s} => {}", .{ key, self.symbol_resolver.get(key).? });
281272 }
282273
283274 log.warn("mappings", .{});
......@@ -285,7 +276,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
285276 const object_id = @intCast(u16, id);
286277 log.warn(" in object {s}", .{object.name.?});
287278 for (object.symtab.items) |sym, sym_id| {
288 if (self.localSymIndex(object_id, @intCast(u32, sym_id))) |local_id| {
279 if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| {
289280 log.warn(" | {d} => {d}", .{ sym_id, local_id });
290281 } else {
291282 log.warn(" | {d} no local mapping for {s}", .{ sym_id, object.getString(sym.n_strx) });
......@@ -293,8 +284,19 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
293284 }
294285 }
295286
287 try self.parseTextBlocks();
288
289 var it = self.blocks.iterator();
290 while (it.next()) |entry| {
291 const seg = self.load_commands.items[entry.key_ptr.seg].Segment;
292 const sect = seg.sections.items[entry.key_ptr.sect];
293
294 log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
295 log.warn(" {}", .{sect});
296 entry.value_ptr.*.print(self);
297 }
298
296299 return error.TODO;
297 // try self.parseTextBlocks();
298300 // try self.sortSections();
299301 // try self.addRpaths(args.rpaths);
300302 // try self.addDataInCodeLC();
......@@ -305,16 +307,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
305307 // self.allocateLinkeditSegment();
306308 // try self.allocateTextBlocks();
307309
308 // // var it = self.blocks.iterator();
309 // // while (it.next()) |entry| {
310 // // const seg = self.load_commands.items[entry.key_ptr.seg].Segment;
311 // // const sect = seg.sections.items[entry.key_ptr.sect];
312
313 // // log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
314 // // log.warn(" {}", .{sect});
315 // // entry.value_ptr.*.print(self);
316 // // }
317
318310 // try self.flush();
319311}
320312
......@@ -1414,10 +1406,6 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
14141406
14151407 log.warn("resolving symbols in '{s}'", .{object.name});
14161408
1417 const mapping = try self.allocator.alloc(u32, object.symtab.items.len);
1418 mem.set(u32, mapping, 0);
1419 try self.object_mapping.putNoClobber(self.allocator, object_id, mapping);
1420
14211409 for (object.symtab.items) |sym, id| {
14221410 const sym_id = @intCast(u32, id);
14231411 const sym_name = object.getString(sym.n_strx);
......@@ -1464,7 +1452,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
14641452 .n_desc = 0,
14651453 .n_value = sym.n_value,
14661454 });
1467 mapping[sym_id] = local_sym_index;
1455 try object.symbol_mapping.putNoClobber(self.allocator, sym_id, local_sym_index);
14681456
14691457 // If the symbol's scope is not local aka translation unit, then we need work out
14701458 // if we should save the symbol as a global, or potentially flag the error.
......@@ -2987,15 +2975,6 @@ pub fn getString(self: *Zld, off: u32) []const u8 {
29872975 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off));
29882976}
29892977
2990fn localSymIndex(self: Zld, object_id: u16, orig_id: u32) ?u32 {
2991 const mapping = self.object_mapping.get(object_id) orelse return null;
2992 const local_sym_index = mapping[orig_id];
2993 if (local_sym_index == 0) {
2994 return null;
2995 }
2996 return local_sym_index;
2997}
2998
29992978pub fn symbolIsStab(sym: macho.nlist_64) bool {
30002979 return (macho.N_STAB & sym.n_type) != 0;
30012980}
......@@ -3045,10 +3024,9 @@ pub fn symbolIsNull(sym: macho.nlist_64) bool {
30453024 return sym.n_value == 0 and sym.n_desc == 0 and sym.n_type == 0 and sym.n_strx == 0 and sym.n_sect == 0;
30463025}
30473026
3048pub fn symbolIsTemp(self: Zld, sym: macho.nlist_64) bool {
3027pub fn symbolIsTemp(sym: macho.nlist_64, sym_name: []const u8) bool {
30493028 if (!symbolIsSect(sym)) return false;
30503029 if (symbolIsExt(sym)) return false;
3051 const sym_name = self.getString(sym.n_strx);
30523030 return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");
30533031}
30543032