authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-09 14:18:28+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-09 14:18:28+02:00
log1efdb137d14058f3c428a001838b963de16694ea
tree5393bbbcfa325ec82684dbb542cfd4744555e7c8
parent23be9cae346614d7d42d9c1c6426bfe2d6721c68

macho: don't allocate atoms when parsing objects


3 files changed, 182 insertions(+), 78 deletions(-)

src/link/MachO.zig+105-65
...@@ -2594,30 +2594,64 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2594,30 +2594,64 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2594}2594}
25952595
2596fn parseTextBlocks(self: *MachO) !void {2596fn parseTextBlocks(self: *MachO) !void {
2597 var parsed_atoms = Object.ParsedAtoms.init(self.base.allocator);
2598 defer parsed_atoms.deinit();
2599
2600 var first_atoms = Object.ParsedAtoms.init(self.base.allocator);
2601 defer first_atoms.deinit();
2602
2597 var section_metadata = std.AutoHashMap(MatchingSection, struct {2603 var section_metadata = std.AutoHashMap(MatchingSection, struct {
2598 size: u64,2604 size: u64,
2599 alignment: u32,2605 alignment: u32,
2600 }).init(self.base.allocator);2606 }).init(self.base.allocator);
2601 defer section_metadata.deinit();2607 defer section_metadata.deinit();
26022608
2603 for (self.objects.items) |object| {2609 for (self.objects.items) |*object, object_id| {
2604 const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;2610 var atoms_in_objects = try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);
2605 for (seg.sections.items) |sect| {2611 defer atoms_in_objects.deinit();
2606 const match = (try self.getMatchingSection(sect)) orelse {2612
2607 log.debug("unhandled section", .{});2613 var it = atoms_in_objects.iterator();
2608 continue;2614 while (it.next()) |entry| {
2609 };2615 const match = entry.key_ptr.*;
2610 const res = try section_metadata.getOrPut(match);2616 const last_atom = entry.value_ptr.*;
2611 if (!res.found_existing) {2617 var atom = last_atom;
2612 res.value_ptr.* = .{2618
2619 const metadata = try section_metadata.getOrPut(match);
2620 if (!metadata.found_existing) {
2621 metadata.value_ptr.* = .{
2613 .size = 0,2622 .size = 0,
2614 .alignment = 0,2623 .alignment = 0,
2615 };2624 };
2616 }2625 }
2617 const size = padToIdeal(sect.size);2626
2618 const alignment = try math.powi(u32, 2, sect.@"align");2627 while (true) {
2619 res.value_ptr.size += mem.alignForwardGeneric(u64, size, alignment);2628 const alignment = try math.powi(u32, 2, atom.alignment);
2620 res.value_ptr.alignment = math.max(res.value_ptr.alignment, sect.@"align");2629 metadata.value_ptr.size += mem.alignForwardGeneric(u64, atom.size, alignment);
2630 metadata.value_ptr.alignment = math.max(metadata.value_ptr.alignment, atom.alignment);
2631
2632 const sym = self.locals.items[atom.local_sym_index];
2633 log.debug(" {s}: n_value=0x{x}, size=0x{x}, alignment=0x{x}", .{
2634 self.getString(sym.n_strx),
2635 sym.n_value,
2636 atom.size,
2637 atom.alignment,
2638 });
2639
2640 if (atom.prev) |prev| {
2641 atom = prev;
2642 } else break;
2643 }
2644
2645 if (parsed_atoms.getPtr(match)) |last| {
2646 last.*.next = atom;
2647 atom.prev = last.*;
2648 last.* = atom;
2649 }
2650 _ = try parsed_atoms.put(match, last_atom);
2651
2652 if (!first_atoms.contains(match)) {
2653 try first_atoms.putNoClobber(match, atom);
2654 }
2621 }2655 }
2622 }2656 }
26232657
...@@ -2625,63 +2659,69 @@ fn parseTextBlocks(self: *MachO) !void {...@@ -2625,63 +2659,69 @@ fn parseTextBlocks(self: *MachO) !void {
2625 while (it.next()) |entry| {2659 while (it.next()) |entry| {
2626 const match = entry.key_ptr.*;2660 const match = entry.key_ptr.*;
2627 const metadata = entry.value_ptr.*;2661 const metadata = entry.value_ptr.*;
2628 const seg = self.load_commands.items[match.seg].Segment;2662 const seg = &self.load_commands.items[match.seg].Segment;
2629 const sect = seg.sections.items[match.sect];2663 const sect = &seg.sections.items[match.sect];
2630 log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{2664 log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{
2631 commands.segmentName(sect),2665 commands.segmentName(sect.*),
2632 commands.sectionName(sect),2666 commands.sectionName(sect.*),
2633 metadata.size,2667 metadata.size,
2634 metadata.alignment,2668 metadata.alignment,
2635 });2669 });
2670 sect.@"align" = math.max(sect.@"align", metadata.alignment);
2636 try self.growSection(match, @intCast(u32, metadata.size));2671 try self.growSection(match, @intCast(u32, metadata.size));
2637 }
26382672
2639 for (self.objects.items) |*object, object_id| {2673 var base_vaddr = if (self.blocks.get(match)) |last| blk: {
2640 try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);2674 const last_atom_sym = self.locals.items[last.local_sym_index];
2641 }2675 break :blk last_atom_sym.n_value + last.size;
26422676 } else sect.addr;
2643 // it = section_metadata.iterator();2677 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2644 // while (it.next()) |entry| {2678
2645 // const match = entry.key_ptr.*;2679 var atom = first_atoms.get(match).?;
2646 // const metadata = entry.value_ptr.*;2680 while (true) {
2647 // const seg = self.load_commands.items[match.seg].Segment;2681 const alignment = try math.powi(u32, 2, atom.alignment);
2648 // const sect = seg.sections.items[match.sect];2682 base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);
26492683
2650 // var buffer = try self.base.allocator.alloc(u8, metadata.size);2684 const sym = &self.locals.items[atom.local_sym_index];
2651 // defer self.base.allocator.free(buffer);2685 sym.n_value = base_vaddr;
2652 // log.warn("{s},{s} buffer size 0x{x}", .{2686 sym.n_sect = n_sect;
2653 // commands.segmentName(sect),2687
2654 // commands.sectionName(sect),2688 log.debug(" {s}: start=0x{x}, end=0x{x}, size=0x{x}, alignment=0x{x}", .{
2655 // metadata.size,2689 self.getString(sym.n_strx),
2656 // });2690 base_vaddr,
26572691 base_vaddr + atom.size,
2658 // var atom = self.blocks.get(match).?;2692 atom.size,
26592693 atom.alignment,
2660 // while (atom.prev) |prev| {2694 });
2661 // atom = prev;2695
2662 // }2696 // Update each alias (if any)
26632697 for (atom.aliases.items) |index| {
2664 // const base = blk: {2698 const alias_sym = &self.locals.items[index];
2665 // const sym = self.locals.items[atom.local_sym_index];2699 alias_sym.n_value = base_vaddr;
2666 // break :blk sym.n_value;2700 alias_sym.n_sect = n_sect;
2667 // };2701 }
26682702
2669 // while (true) {2703 // Update each symbol contained within the TextBlock
2670 // const sym = self.locals.items[atom.local_sym_index];2704 for (atom.contained.items) |sym_at_off| {
2671 // const offset = sym.n_value - base;2705 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
2672 // try atom.resolveRelocs(self);2706 contained_sym.n_value = base_vaddr + sym_at_off.offset;
2673 // log.warn("writing atom for symbol {s} at buffer offset 0x{x}", .{2707 contained_sym.n_sect = n_sect;
2674 // self.getString(sym.n_strx),2708 }
2675 // offset,2709
2676 // });2710 base_vaddr += atom.size;
2677 // mem.copy(u8, buffer[offset..][0..atom.code.items.len], atom.code.items);2711
2678 // atom.dirty = false;2712 if (atom.next) |next| {
26792713 atom = next;
2680 // if (atom.next) |next| {2714 } else break;
2681 // atom = next;2715 }
2682 // } else break;2716
2683 // }2717 if (self.blocks.getPtr(match)) |last| {
2684 // }2718 const first_atom = first_atoms.get(match).?;
2719 last.*.next = first_atom;
2720 first_atom.prev = last.*;
2721 last.* = first_atom;
2722 }
2723 _ = try self.blocks.put(self.base.allocator, match, parsed_atoms.get(match).?);
2724 }
2685}2725}
26862726
2687fn addDataInCodeLC(self: *MachO) !void {2727fn addDataInCodeLC(self: *MachO) !void {
src/link/MachO/Object.zig+32-4
...@@ -317,6 +317,7 @@ const Context = struct {...@@ -317,6 +317,7 @@ const Context = struct {
317 object: *Object,317 object: *Object,
318 macho_file: *MachO,318 macho_file: *MachO,
319 match: MachO.MatchingSection,319 match: MachO.MatchingSection,
320 parsed_atoms: *ParsedAtoms,
320};321};
321322
322const TextBlockParser = struct {323const TextBlockParser = struct {
...@@ -430,6 +431,7 @@ const TextBlockParser = struct {...@@ -430,6 +431,7 @@ const TextBlockParser = struct {
430 .allocator = context.allocator,431 .allocator = context.allocator,
431 .object = context.object,432 .object = context.object,
432 .macho_file = context.macho_file,433 .macho_file = context.macho_file,
434 .parsed_atoms = context.parsed_atoms,
433 });435 });
434436
435 if (context.macho_file.has_dices) {437 if (context.macho_file.has_dices) {
...@@ -455,12 +457,15 @@ const TextBlockParser = struct {...@@ -455,12 +457,15 @@ const TextBlockParser = struct {
455 }457 }
456};458};
457459
460pub const ParsedAtoms = std.AutoHashMap(MachO.MatchingSection, *TextBlock);
461
458pub fn parseTextBlocks(462pub fn parseTextBlocks(
459 self: *Object,463 self: *Object,
460 allocator: *Allocator,464 allocator: *Allocator,
461 object_id: u16,465 object_id: u16,
462 macho_file: *MachO,466 macho_file: *MachO,
463) !void {467) !ParsedAtoms {
468 var parsed_atoms = ParsedAtoms.init(allocator);
464 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;469 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
465470
466 log.debug("analysing {s}", .{self.name});471 log.debug("analysing {s}", .{self.name});
...@@ -589,6 +594,7 @@ pub fn parseTextBlocks(...@@ -589,6 +594,7 @@ pub fn parseTextBlocks(
589 .allocator = allocator,594 .allocator = allocator,
590 .object = self,595 .object = self,
591 .macho_file = macho_file,596 .macho_file = macho_file,
597 .parsed_atoms = &parsed_atoms,
592 });598 });
593599
594 if (macho_file.has_dices) {600 if (macho_file.has_dices) {
...@@ -604,7 +610,13 @@ pub fn parseTextBlocks(...@@ -604,7 +610,13 @@ pub fn parseTextBlocks(
604 }610 }
605 }611 }
606612
607 _ = try macho_file.allocateAtom(block, match);613 if (parsed_atoms.getPtr(match)) |last| {
614 last.*.next = block;
615 block.prev = last.*;
616 last.* = block;
617 } else {
618 try parsed_atoms.putNoClobber(match, block);
619 }
608 try self.text_blocks.append(allocator, block);620 try self.text_blocks.append(allocator, block);
609 }621 }
610622
...@@ -620,6 +632,7 @@ pub fn parseTextBlocks(...@@ -620,6 +632,7 @@ pub fn parseTextBlocks(
620 .object = self,632 .object = self,
621 .macho_file = macho_file,633 .macho_file = macho_file,
622 .match = match,634 .match = match,
635 .parsed_atoms = &parsed_atoms,
623 })) |block| {636 })) |block| {
624 const sym = macho_file.locals.items[block.local_sym_index];637 const sym = macho_file.locals.items[block.local_sym_index];
625 const is_ext = blk: {638 const is_ext = blk: {
...@@ -651,7 +664,13 @@ pub fn parseTextBlocks(...@@ -651,7 +664,13 @@ pub fn parseTextBlocks(
651 }664 }
652 }665 }
653666
654 _ = try macho_file.allocateAtom(block, match);667 if (parsed_atoms.getPtr(match)) |last| {
668 last.*.next = block;
669 block.prev = last.*;
670 last.* = block;
671 } else {
672 try parsed_atoms.putNoClobber(match, block);
673 }
655 try self.text_blocks.append(allocator, block);674 try self.text_blocks.append(allocator, block);
656 }675 }
657676
...@@ -696,6 +715,7 @@ pub fn parseTextBlocks(...@@ -696,6 +715,7 @@ pub fn parseTextBlocks(
696 .allocator = allocator,715 .allocator = allocator,
697 .object = self,716 .object = self,
698 .macho_file = macho_file,717 .macho_file = macho_file,
718 .parsed_atoms = &parsed_atoms,
699 });719 });
700720
701 if (macho_file.has_dices) {721 if (macho_file.has_dices) {
...@@ -747,10 +767,18 @@ pub fn parseTextBlocks(...@@ -747,10 +767,18 @@ pub fn parseTextBlocks(
747 });767 });
748 }768 }
749769
750 _ = try macho_file.allocateAtom(block, match);770 if (parsed_atoms.getPtr(match)) |last| {
771 last.*.next = block;
772 block.prev = last.*;
773 last.* = block;
774 } else {
775 try parsed_atoms.putNoClobber(match, block);
776 }
751 try self.text_blocks.append(allocator, block);777 try self.text_blocks.append(allocator, block);
752 }778 }
753 }779 }
780
781 return parsed_atoms;
754}782}
755783
756fn parseSymtab(self: *Object, allocator: *Allocator) !void {784fn parseSymtab(self: *Object, allocator: *Allocator) !void {
src/link/MachO/TextBlock.zig+45-9
...@@ -628,6 +628,7 @@ const RelocContext = struct {...@@ -628,6 +628,7 @@ const RelocContext = struct {
628 allocator: *Allocator,628 allocator: *Allocator,
629 object: *Object,629 object: *Object,
630 macho_file: *MachO,630 macho_file: *MachO,
631 parsed_atoms: *Object.ParsedAtoms,
631};632};
632633
633fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Relocation {634fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Relocation {
...@@ -855,7 +856,14 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R...@@ -855,7 +856,14 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
855 .seg = context.macho_file.data_const_segment_cmd_index.?,856 .seg = context.macho_file.data_const_segment_cmd_index.?,
856 .sect = context.macho_file.got_section_index.?,857 .sect = context.macho_file.got_section_index.?,
857 };858 };
858 _ = try context.macho_file.allocateAtom(atom, match);859
860 if (context.parsed_atoms.getPtr(match)) |last| {
861 last.*.next = atom;
862 atom.prev = last.*;
863 last.* = atom;
864 } else {
865 try context.parsed_atoms.putNoClobber(match, atom);
866 }
859 } else if (parsed_rel.payload == .unsigned) {867 } else if (parsed_rel.payload == .unsigned) {
860 switch (parsed_rel.where) {868 switch (parsed_rel.where) {
861 .undef => {869 .undef => {
...@@ -918,18 +926,46 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R...@@ -918,18 +926,46 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
918 );926 );
919 const stub_atom = try context.macho_file.createStubAtom(laptr_atom.local_sym_index);927 const stub_atom = try context.macho_file.createStubAtom(laptr_atom.local_sym_index);
920 try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stub_atom);928 try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stub_atom);
921 _ = try context.macho_file.allocateAtom(stub_helper_atom, .{929 // TODO clean this up!
930 if (context.parsed_atoms.getPtr(.{
922 .seg = context.macho_file.text_segment_cmd_index.?,931 .seg = context.macho_file.text_segment_cmd_index.?,
923 .sect = context.macho_file.stub_helper_section_index.?,932 .sect = context.macho_file.stub_helper_section_index.?,
924 });933 })) |last| {
925 _ = try context.macho_file.allocateAtom(laptr_atom, .{934 last.*.next = stub_helper_atom;
926 .seg = context.macho_file.data_segment_cmd_index.?,935 stub_helper_atom.prev = last.*;
927 .sect = context.macho_file.la_symbol_ptr_section_index.?,936 last.* = stub_helper_atom;
928 });937 } else {
929 _ = try context.macho_file.allocateAtom(stub_atom, .{938 try context.parsed_atoms.putNoClobber(.{
939 .seg = context.macho_file.text_segment_cmd_index.?,
940 .sect = context.macho_file.stub_helper_section_index.?,
941 }, stub_helper_atom);
942 }
943 if (context.parsed_atoms.getPtr(.{
930 .seg = context.macho_file.text_segment_cmd_index.?,944 .seg = context.macho_file.text_segment_cmd_index.?,
931 .sect = context.macho_file.stubs_section_index.?,945 .sect = context.macho_file.stubs_section_index.?,
932 });946 })) |last| {
947 last.*.next = stub_atom;
948 stub_atom.prev = last.*;
949 last.* = stub_atom;
950 } else {
951 try context.parsed_atoms.putNoClobber(.{
952 .seg = context.macho_file.text_segment_cmd_index.?,
953 .sect = context.macho_file.stubs_section_index.?,
954 }, stub_atom);
955 }
956 if (context.parsed_atoms.getPtr(.{
957 .seg = context.macho_file.data_segment_cmd_index.?,
958 .sect = context.macho_file.la_symbol_ptr_section_index.?,
959 })) |last| {
960 last.*.next = laptr_atom;
961 laptr_atom.prev = last.*;
962 last.* = laptr_atom;
963 } else {
964 try context.parsed_atoms.putNoClobber(.{
965 .seg = context.macho_file.data_segment_cmd_index.?,
966 .sect = context.macho_file.la_symbol_ptr_section_index.?,
967 }, laptr_atom);
968 }
933 }969 }
934 }970 }
935}971}