authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-01 11:55:32+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-01 12:14:29+02:00
log7a99cd069afed01b8573274c20f685e61d0950c8
tree4410eab0ac04f55e110740777f73377b54624336
parentd0dc622638716583eb4d9de78dfc87bef7969bc0

macho: clean up allocating atom logic

Instead of checking for stage1 at every callsite, move the logic inside `allocateAtom`. This is fine since this logic will disappear anyhow once I add expanding and shifting segments and sections.

3 files changed, 94 insertions(+), 167 deletions(-)

src/link/MachO.zig+78-118
...@@ -760,27 +760,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -760,27 +760,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
760 try self.addCodeSignatureLC();760 try self.addCodeSignatureLC();
761761
762 if (use_stage1) {762 if (use_stage1) {
763 {
764 const atom = try self.createDyldPrivateAtom();
765 try self.allocateAtomStage1(atom, .{
766 .seg = self.data_segment_cmd_index.?,
767 .sect = self.data_section_index.?,
768 });
769 }
770 {
771 const atom = try self.createStubHelperPreambleAtom();
772 try self.allocateAtomStage1(atom, .{
773 .seg = self.text_segment_cmd_index.?,
774 .sect = self.stub_helper_section_index.?,
775 });
776 // TODO this is just a temp
777 // We already prealloc stub helper size in populateMissingMetadata(), but
778 // perhaps it's not needed after all?
779 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
780 const sect = &seg.sections.items[self.stub_helper_section_index.?];
781 sect.size -= atom.size;
782 }
783
784 try self.parseTextBlocks();763 try self.parseTextBlocks();
785 try self.allocateTextSegment();764 try self.allocateTextSegment();
786 try self.allocateDataConstSegment();765 try self.allocateDataConstSegment();
...@@ -1919,55 +1898,70 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment:...@@ -1919,55 +1898,70 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment:
1919pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {1898pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {
1920 const seg = &self.load_commands.items[match.seg].Segment;1899 const seg = &self.load_commands.items[match.seg].Segment;
1921 const sect = &seg.sections.items[match.sect];1900 const sect = &seg.sections.items[match.sect];
1922 const sym = &self.locals.items[atom.local_sym_index];1901 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
1923
1924 var atom_placement: ?*TextBlock = null;
1925
1926 // TODO converge with `allocateTextBlock` and handle free list
1927 const vaddr = if (self.blocks.get(match)) |last| blk: {
1928 const last_atom_sym = self.locals.items[last.local_sym_index];
1929 const ideal_capacity = padToIdeal(last.size);
1930 const ideal_capacity_end_vaddr = last_atom_sym.n_value + ideal_capacity;
1931 const last_atom_alignment = try math.powi(u32, 2, atom.alignment);
1932 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, last_atom_alignment);
1933 atom_placement = last;
1934 break :blk new_start_vaddr;
1935 } else sect.addr;
1936
1937 log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });
1938
1939 const expand_section = atom_placement == null or atom_placement.?.next == null;
1940 if (expand_section) {
1941 const needed_size = (vaddr + atom.size) - sect.addr;
1942 const end_addr = blk: {
1943 const next_ordinal = self.section_ordinals.getIndex(match).?; // Ordinals are +1 to begin with.
1944 const end_addr = if (self.section_ordinals.keys().len > next_ordinal) inner: {
1945 const next_match = self.section_ordinals.keys()[next_ordinal];
1946 const next_seg = self.load_commands.items[next_match.seg].Segment;
1947 const next_sect = next_seg.sections.items[next_match.sect];
1948 break :inner next_sect.addr;
1949 } else seg.inner.filesize;
1950 break :blk end_addr;
1951 };
1952 assert(needed_size <= end_addr); // TODO must expand the section
1953 }
1954 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1955 sym.n_value = vaddr;
1956 sym.n_sect = n_sect;
19571902
1958 // Update each alias (if any)1903 const vaddr = outer: {
1959 for (atom.aliases.items) |index| {1904 if (!use_stage1) {
1960 const alias_sym = &self.locals.items[index];1905 const sym = &self.locals.items[atom.local_sym_index];
1961 alias_sym.n_value = vaddr;1906
1962 alias_sym.n_sect = n_sect;1907 var atom_placement: ?*TextBlock = null;
1963 }1908
1909 // TODO converge with `allocateTextBlock` and handle free list
1910 const vaddr = if (self.blocks.get(match)) |last| blk: {
1911 const last_atom_sym = self.locals.items[last.local_sym_index];
1912 const ideal_capacity = padToIdeal(last.size);
1913 const ideal_capacity_end_vaddr = last_atom_sym.n_value + ideal_capacity;
1914 const last_atom_alignment = try math.powi(u32, 2, atom.alignment);
1915 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, last_atom_alignment);
1916 atom_placement = last;
1917 break :blk new_start_vaddr;
1918 } else sect.addr;
1919
1920 log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });
1921
1922 const expand_section = atom_placement == null or atom_placement.?.next == null;
1923 if (expand_section) {
1924 const needed_size = (vaddr + atom.size) - sect.addr;
1925 const end_addr = blk: {
1926 const next_ordinal = self.section_ordinals.getIndex(match).?; // Ordinals are +1 to begin with.
1927 const end_addr = if (self.section_ordinals.keys().len > next_ordinal) inner: {
1928 const next_match = self.section_ordinals.keys()[next_ordinal];
1929 const next_seg = self.load_commands.items[next_match.seg].Segment;
1930 const next_sect = next_seg.sections.items[next_match.sect];
1931 break :inner next_sect.addr;
1932 } else seg.inner.filesize;
1933 break :blk end_addr;
1934 };
1935 assert(needed_size <= end_addr); // TODO must expand the section
1936 }
1937 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1938 sym.n_value = vaddr;
1939 sym.n_sect = n_sect;
19641940
1965 // Update each symbol contained within the TextBlock1941 // Update each alias (if any)
1966 for (atom.contained.items) |sym_at_off| {1942 for (atom.aliases.items) |index| {
1967 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];1943 const alias_sym = &self.locals.items[index];
1968 contained_sym.n_value = vaddr + sym_at_off.offset;1944 alias_sym.n_value = vaddr;
1969 contained_sym.n_sect = n_sect;1945 alias_sym.n_sect = n_sect;
1970 }1946 }
1947
1948 // Update each symbol contained within the TextBlock
1949 for (atom.contained.items) |sym_at_off| {
1950 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
1951 contained_sym.n_value = vaddr + sym_at_off.offset;
1952 contained_sym.n_sect = n_sect;
1953 }
1954
1955 break :outer vaddr;
1956 } else {
1957 const new_alignment = math.max(sect.@"align", atom.alignment);
1958 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
1959 const new_size = mem.alignForwardGeneric(u64, sect.size, new_alignment_pow_2) + atom.size;
1960 sect.size = new_size;
1961 sect.@"align" = new_alignment;
1962 break :outer 0;
1963 }
1964 };
19711965
1972 if (self.blocks.getPtr(match)) |last| {1966 if (self.blocks.getPtr(match)) |last| {
1973 last.*.next = atom;1967 last.*.next = atom;
...@@ -2017,27 +2011,6 @@ fn allocateGlobalSymbols(self: *MachO) !void {...@@ -2017,27 +2011,6 @@ fn allocateGlobalSymbols(self: *MachO) !void {
2017 }2011 }
2018}2012}
20192013
2020pub fn allocateAtomStage1(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
2021 // Update target section's metadata
2022 // TODO should we update segment's size here too?
2023 // How does it tie with incremental space allocs?
2024 const tseg = &self.load_commands.items[match.seg].Segment;
2025 const tsect = &tseg.sections.items[match.sect];
2026 const new_alignment = math.max(tsect.@"align", atom.alignment);
2027 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
2028 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + atom.size;
2029 tsect.size = new_size;
2030 tsect.@"align" = new_alignment;
2031
2032 if (self.blocks.getPtr(match)) |last| {
2033 last.*.next = atom;
2034 atom.prev = last.*;
2035 last.* = atom;
2036 } else {
2037 try self.blocks.putNoClobber(self.base.allocator, match, atom);
2038 }
2039}
2040
2041fn writeAtoms(self: *MachO) !void {2014fn writeAtoms(self: *MachO) !void {
2042 var it = self.blocks.iterator();2015 var it = self.blocks.iterator();
2043 while (it.next()) |entry| {2016 while (it.next()) |entry| {
...@@ -2607,8 +2580,6 @@ fn resolveSymbolsInObject(...@@ -2607,8 +2580,6 @@ fn resolveSymbolsInObject(
2607}2580}
26082581
2609fn resolveSymbols(self: *MachO) !void {2582fn resolveSymbols(self: *MachO) !void {
2610 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
2611
2612 var tentatives = std.AutoArrayHashMap(u32, void).init(self.base.allocator);2583 var tentatives = std.AutoArrayHashMap(u32, void).init(self.base.allocator);
2613 defer tentatives.deinit();2584 defer tentatives.deinit();
26142585
...@@ -2668,27 +2639,23 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2668,27 +2639,23 @@ fn resolveSymbols(self: *MachO) !void {
2668 resolv.local_sym_index = local_sym_index;2639 resolv.local_sym_index = local_sym_index;
26692640
2670 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);2641 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);
2671 if (use_stage1) {2642 _ = try self.allocateAtom(atom, match);
2672 try self.allocateAtomStage1(atom, match);
2673 }
2674 }2643 }
26752644
2676 try self.resolveDyldStubBinder();2645 try self.resolveDyldStubBinder();
2677 if (!use_stage1) {2646 {
2678 {2647 const atom = try self.createDyldPrivateAtom();
2679 const atom = try self.createDyldPrivateAtom();2648 _ = try self.allocateAtom(atom, .{
2680 _ = try self.allocateAtom(atom, .{2649 .seg = self.data_segment_cmd_index.?,
2681 .seg = self.data_segment_cmd_index.?,2650 .sect = self.data_section_index.?,
2682 .sect = self.data_section_index.?,2651 });
2683 });2652 }
2684 }2653 {
2685 {2654 const atom = try self.createStubHelperPreambleAtom();
2686 const atom = try self.createStubHelperPreambleAtom();2655 _ = try self.allocateAtom(atom, .{
2687 _ = try self.allocateAtom(atom, .{2656 .seg = self.text_segment_cmd_index.?,
2688 .seg = self.text_segment_cmd_index.?,2657 .sect = self.stub_helper_section_index.?,
2689 .sect = self.stub_helper_section_index.?,2658 });
2690 });
2691 }
2692 }2659 }
26932660
2694 // Third pass, resolve symbols in dynamic libraries.2661 // Third pass, resolve symbols in dynamic libraries.
...@@ -2800,9 +2767,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2800,9 +2767,7 @@ fn resolveSymbols(self: *MachO) !void {
2800 // TODO perhaps we should special-case special symbols? Create a separate2767 // TODO perhaps we should special-case special symbols? Create a separate
2801 // linked list of atoms?2768 // linked list of atoms?
2802 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);2769 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);
2803 if (use_stage1) {2770 _ = try self.allocateAtom(atom, match);
2804 try self.allocateAtomStage1(atom, match);
2805 }
2806 }2771 }
28072772
2808 for (self.unresolved.keys()) |index| {2773 for (self.unresolved.keys()) |index| {
...@@ -2869,12 +2834,7 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2869,12 +2834,7 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2869 .seg = self.data_const_segment_cmd_index.?,2834 .seg = self.data_const_segment_cmd_index.?,
2870 .sect = self.got_section_index.?,2835 .sect = self.got_section_index.?,
2871 };2836 };
2872 // TODO remove once we can incrementally update in stage1 too.2837 _ = try self.allocateAtom(atom, match);
2873 if (!(build_options.is_stage1 and self.base.options.use_stage1)) {
2874 _ = try self.allocateAtom(atom, match);
2875 } else {
2876 try self.allocateAtomStage1(atom, match);
2877 }
2878 self.binding_info_dirty = true;2838 self.binding_info_dirty = true;
2879}2839}
28802840
src/link/MachO/Object.zig+3-16
...@@ -453,7 +453,6 @@ pub fn parseTextBlocks(...@@ -453,7 +453,6 @@ pub fn parseTextBlocks(
453 object_id: u16,453 object_id: u16,
454 macho_file: *MachO,454 macho_file: *MachO,
455) !void {455) !void {
456 const use_stage1 = build_options.is_stage1 and macho_file.base.options.use_stage1;
457 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;456 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
458457
459 log.debug("analysing {s}", .{self.name});458 log.debug("analysing {s}", .{self.name});
...@@ -590,11 +589,7 @@ pub fn parseTextBlocks(...@@ -590,11 +589,7 @@ pub fn parseTextBlocks(
590 }589 }
591 }590 }
592591
593 if (use_stage1) {592 _ = try macho_file.allocateAtom(block, match);
594 try macho_file.allocateAtomStage1(block, match);
595 } else {
596 _ = try macho_file.allocateAtom(block, match);
597 }
598 try self.text_blocks.append(allocator, block);593 try self.text_blocks.append(allocator, block);
599 }594 }
600595
...@@ -641,11 +636,7 @@ pub fn parseTextBlocks(...@@ -641,11 +636,7 @@ pub fn parseTextBlocks(
641 }636 }
642 }637 }
643638
644 if (use_stage1) {639 _ = try macho_file.allocateAtom(block, match);
645 try macho_file.allocateAtomStage1(block, match);
646 } else {
647 _ = try macho_file.allocateAtom(block, match);
648 }
649 try self.text_blocks.append(allocator, block);640 try self.text_blocks.append(allocator, block);
650 }641 }
651642
...@@ -734,11 +725,7 @@ pub fn parseTextBlocks(...@@ -734,11 +725,7 @@ pub fn parseTextBlocks(
734 });725 });
735 }726 }
736727
737 if (use_stage1) {728 _ = try macho_file.allocateAtom(block, match);
738 try macho_file.allocateAtomStage1(block, match);
739 } else {
740 _ = try macho_file.allocateAtom(block, match);
741 }
742 try self.text_blocks.append(allocator, block);729 try self.text_blocks.append(allocator, block);
743 }730 }
744 }731 }
src/link/MachO/TextBlock.zig+13-33
...@@ -843,11 +843,7 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R...@@ -843,11 +843,7 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
843 .seg = context.macho_file.data_const_segment_cmd_index.?,843 .seg = context.macho_file.data_const_segment_cmd_index.?,
844 .sect = context.macho_file.got_section_index.?,844 .sect = context.macho_file.got_section_index.?,
845 };845 };
846 if (!(build_options.is_stage1 and context.macho_file.base.options.use_stage1)) {846 _ = try context.macho_file.allocateAtom(atom, match);
847 _ = try context.macho_file.allocateAtom(atom, match);
848 } else {
849 try context.macho_file.allocateAtomStage1(atom, match);
850 }
851 } else if (parsed_rel.payload == .unsigned) {847 } else if (parsed_rel.payload == .unsigned) {
852 switch (parsed_rel.where) {848 switch (parsed_rel.where) {
853 .undef => {849 .undef => {
...@@ -910,34 +906,18 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R...@@ -910,34 +906,18 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
910 );906 );
911 const stub_atom = try context.macho_file.createStubAtom(laptr_atom.local_sym_index);907 const stub_atom = try context.macho_file.createStubAtom(laptr_atom.local_sym_index);
912 try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stub_atom);908 try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stub_atom);
913909 _ = try context.macho_file.allocateAtom(stub_helper_atom, .{
914 if (build_options.is_stage1 and context.macho_file.base.options.use_stage1) {910 .seg = context.macho_file.text_segment_cmd_index.?,
915 try context.macho_file.allocateAtomStage1(stub_helper_atom, .{911 .sect = context.macho_file.stub_helper_section_index.?,
916 .seg = context.macho_file.text_segment_cmd_index.?,912 });
917 .sect = context.macho_file.stub_helper_section_index.?,913 _ = try context.macho_file.allocateAtom(laptr_atom, .{
918 });914 .seg = context.macho_file.data_segment_cmd_index.?,
919 try context.macho_file.allocateAtomStage1(laptr_atom, .{915 .sect = context.macho_file.la_symbol_ptr_section_index.?,
920 .seg = context.macho_file.data_segment_cmd_index.?,916 });
921 .sect = context.macho_file.la_symbol_ptr_section_index.?,917 _ = try context.macho_file.allocateAtom(stub_atom, .{
922 });918 .seg = context.macho_file.text_segment_cmd_index.?,
923 try context.macho_file.allocateAtomStage1(stub_atom, .{919 .sect = context.macho_file.stubs_section_index.?,
924 .seg = context.macho_file.text_segment_cmd_index.?,920 });
925 .sect = context.macho_file.stubs_section_index.?,
926 });
927 } else {
928 _ = try context.macho_file.allocateAtom(stub_helper_atom, .{
929 .seg = context.macho_file.text_segment_cmd_index.?,
930 .sect = context.macho_file.stub_helper_section_index.?,
931 });
932 _ = try context.macho_file.allocateAtom(laptr_atom, .{
933 .seg = context.macho_file.data_segment_cmd_index.?,
934 .sect = context.macho_file.la_symbol_ptr_section_index.?,
935 });
936 _ = try context.macho_file.allocateAtom(stub_atom, .{
937 .seg = context.macho_file.text_segment_cmd_index.?,
938 .sect = context.macho_file.stubs_section_index.?,
939 });
940 }
941 }921 }
942 }922 }
943}923}