| author | |
| committer | |
| log | 1efdb137d14058f3c428a001838b963de16694ea |
| tree | 5393bbbcfa325ec82684dbb542cfd4744555e7c8 |
| parent | 23be9cae346614d7d42d9c1c6426bfe2d6721c68 |
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 | } |
| 2595 | 2595 | ||
| 2596 | fn parseTextBlocks(self: *MachO) !void { | 2596 | fn 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(); |
| 2602 | 2608 | ||
| 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 | } |
| 2623 | 2657 | ||
| ... | @@ -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 | } | ||
| 2638 | 2672 | ||
| 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; |
| 2642 | 2676 | } 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); |
| 2649 | 2683 | ||
| 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, |
| 2657 | 2691 | base_vaddr + atom.size, | |
| 2658 | // var atom = self.blocks.get(match).?; | 2692 | atom.size, |
| 2659 | 2693 | atom.alignment, | |
| 2660 | // while (atom.prev) |prev| { | 2694 | }); |
| 2661 | // atom = prev; | 2695 | |
| 2662 | // } | 2696 | // Update each alias (if any) |
| 2663 | 2697 | 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 | } |
| 2668 | 2702 | ||
| 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| { |
| 2679 | 2713 | 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 | } |
| 2686 | 2726 | ||
| 2687 | fn addDataInCodeLC(self: *MachO) !void { | 2727 | fn 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 | }; |
| 321 | 322 | ||
| 322 | const TextBlockParser = struct { | 323 | const 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 | }); |
| 434 | 436 | ||
| 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 | }; |
| 457 | 459 | ||
| 460 | pub const ParsedAtoms = std.AutoHashMap(MachO.MatchingSection, *TextBlock); | ||
| 461 | |||
| 458 | pub fn parseTextBlocks( | 462 | pub 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; |
| 465 | 470 | ||
| 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 | }); |
| 593 | 599 | ||
| 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 | } |
| 606 | 612 | ||
| 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 | } |
| 610 | 622 | ||
| ... | @@ -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 | } |
| 653 | 666 | ||
| 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 | } |
| 657 | 676 | ||
| ... | @@ -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 | }); |
| 700 | 720 | ||
| 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 | } |
| 749 | 769 | ||
| 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 | } |
| 755 | 783 | ||
| 756 | fn parseSymtab(self: *Object, allocator: *Allocator) !void { | 784 | fn 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 | }; |
| 632 | 633 | ||
| 633 | fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Relocation { | 634 | fn 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 | } |