authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-01 12:28:58+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-03 21:19:41+02:00
logbb532584bc569edb563b757c658fd743731837ec
treeaa0c1356909f0be2431e5420b0e84ca5ae89e5ad
parentf26d5ee7ea97c8fd6e5b2655f845be7e4293930e

macho: update how we insert output sections

Instead of generating sections upfront, allow generation by scanning the object files for input -> output sections mapping. Next, always strive to keep output sections in the final container sorted as they appear in the final binary. This makes the linker less messy wrt handling of output sections sort order for dyld/macOS not to complain. There's still more work to be done for incremental context though to make this work but looks promising already.

5 files changed, 222 insertions(+), 281 deletions(-)

lib/std/macho.zig+6-1
......@@ -780,7 +780,7 @@ pub const section_64 = extern struct {
780780 return parseName(&sect.segname);
781781 }
782782
783 pub fn type_(sect: section_64) u8 {
783 pub fn @"type"(sect: section_64) u8 {
784784 return @truncate(u8, sect.flags & 0xff);
785785 }
786786
......@@ -793,6 +793,11 @@ pub const section_64 = extern struct {
793793 return attr & S_ATTR_PURE_INSTRUCTIONS != 0 or attr & S_ATTR_SOME_INSTRUCTIONS != 0;
794794 }
795795
796 pub fn isZerofill(sect: section_64) bool {
797 const tt = sect.@"type"();
798 return tt == S_ZEROFILL or tt == S_GB_ZEROFILL or tt == S_THREAD_LOCAL_ZEROFILL;
799 }
800
796801 pub fn isDebug(sect: section_64) bool {
797802 return sect.attrs() & S_ATTR_DEBUG != 0;
798803 }
src/link/MachO.zig+192-272
......@@ -559,6 +559,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
559559
560560 if (build_options.enable_logging) {
561561 self.logSymtab();
562 self.logSections();
562563 self.logAtoms();
563564 }
564565
......@@ -1140,7 +1141,6 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
11401141 try self.resolveSymbolsInArchives();
11411142 try self.resolveDyldStubBinder();
11421143 try self.createDyldPrivateAtom();
1143 try self.createStubHelperPreambleAtom();
11441144 try self.resolveSymbolsInDylibs();
11451145 try self.createMhExecuteHeaderSymbol();
11461146 try self.createDsoHandleSymbol();
......@@ -1156,6 +1156,11 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
11561156 return error.FrameworkNotFound;
11571157 }
11581158
1159 for (self.objects.items) |*object| {
1160 try object.scanInputSections(self);
1161 }
1162
1163 try self.createStubHelperPreambleAtom();
11591164 try self.createTentativeDefAtoms();
11601165
11611166 for (self.objects.items) |*object, object_id| {
......@@ -1166,14 +1171,14 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
11661171 try dead_strip.gcAtoms(self);
11671172 }
11681173
1169 try self.pruneAndSortSections();
11701174 try self.allocateSegments();
11711175 try self.allocateSymbols();
11721176
11731177 try self.allocateSpecialSymbols();
11741178
1175 if (build_options.enable_logging) {
1179 if (build_options.enable_logging or true) {
11761180 self.logSymtab();
1181 self.logSections();
11771182 self.logAtoms();
11781183 }
11791184
......@@ -1691,7 +1696,7 @@ pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
16911696 const segname = sect.segName();
16921697 const sectname = sect.sectName();
16931698 const res: ?u8 = blk: {
1694 switch (sect.type_()) {
1699 switch (sect.@"type"()) {
16951700 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
16961701 if (self.text_const_section_index == null) {
16971702 self.text_const_section_index = try self.initSection(
......@@ -2197,27 +2202,6 @@ fn allocateSymbols(self: *MachO) !void {
21972202 }
21982203}
21992204
2200fn shiftLocalsByOffset(self: *MachO, sect_id: u8, offset: i64) !void {
2201 var atom = self.sections.items(.last_atom)[sect_id] orelse return;
2202
2203 while (true) {
2204 const atom_sym = atom.getSymbolPtr(self);
2205 atom_sym.n_value = @intCast(u64, @intCast(i64, atom_sym.n_value) + offset);
2206
2207 for (atom.contained.items) |sym_at_off| {
2208 const contained_sym = self.getSymbolPtr(.{
2209 .sym_index = sym_at_off.sym_index,
2210 .file = atom.file,
2211 });
2212 contained_sym.n_value = @intCast(u64, @intCast(i64, contained_sym.n_value) + offset);
2213 }
2214
2215 if (atom.prev) |prev| {
2216 atom = prev;
2217 } else break;
2218 }
2219}
2220
22212205fn allocateSpecialSymbols(self: *MachO) !void {
22222206 for (&[_][]const u8{
22232207 "___dso_handle",
......@@ -2245,9 +2229,10 @@ fn writeAtomsOneShot(self: *MachO) !void {
22452229
22462230 for (slice.items(.last_atom)) |last_atom, sect_id| {
22472231 const header = slice.items(.header)[sect_id];
2232 if (header.size == 0) continue;
22482233 var atom = last_atom.?;
22492234
2250 if (header.flags == macho.S_ZEROFILL or header.flags == macho.S_THREAD_LOCAL_ZEROFILL) continue;
2235 if (header.isZerofill()) continue;
22512236
22522237 var buffer = std.ArrayList(u8).init(gpa);
22532238 defer buffer.deinit();
......@@ -2334,8 +2319,7 @@ fn writeAtomsIncremental(self: *MachO) !void {
23342319 const sect_i = @intCast(u8, i);
23352320 const header = slice.items(.header)[sect_i];
23362321
2337 // TODO handle zerofill in stage2
2338 // if (sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL) continue;
2322 if (header.isZerofill()) continue;
23392323
23402324 log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() });
23412325
......@@ -3904,7 +3888,12 @@ fn getOutputSectionAtom(
39043888 // TODO finish and audit this function
39053889 if (val.isUndefDeep()) {
39063890 if (mode == .ReleaseFast or mode == .ReleaseSmall) {
3907 break :blk self.bss_section_index.?;
3891 break :blk (try self.getOutputSection(.{
3892 .segname = makeStaticString("__DATA"),
3893 .sectname = makeStaticString("__bss"),
3894 .size = code.len,
3895 .@"align" = align_log_2,
3896 })).?;
39083897 } else {
39093898 break :blk self.data_section_index.?;
39103899 }
......@@ -4488,74 +4477,6 @@ fn populateMissingMetadata(self: *MachO) !void {
44884477 );
44894478 }
44904479
4491 if (self.tlv_section_index == null) {
4492 const needed_size = if (self.mode == .incremental)
4493 @sizeOf(u64) * self.base.options.symbol_count_hint
4494 else
4495 0;
4496 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4497 self.tlv_section_index = try self.initSection(
4498 self.data_segment_cmd_index.?,
4499 "__thread_vars",
4500 needed_size,
4501 alignment,
4502 .{
4503 .flags = macho.S_THREAD_LOCAL_VARIABLES,
4504 },
4505 );
4506 }
4507
4508 if (self.tlv_data_section_index == null) {
4509 const needed_size = if (self.mode == .incremental)
4510 @sizeOf(u64) * self.base.options.symbol_count_hint
4511 else
4512 0;
4513 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4514 self.tlv_data_section_index = try self.initSection(
4515 self.data_segment_cmd_index.?,
4516 "__thread_data",
4517 needed_size,
4518 alignment,
4519 .{
4520 .flags = macho.S_THREAD_LOCAL_REGULAR,
4521 },
4522 );
4523 }
4524
4525 if (self.tlv_bss_section_index == null) {
4526 const needed_size = if (self.mode == .incremental)
4527 @sizeOf(u64) * self.base.options.symbol_count_hint
4528 else
4529 0;
4530 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4531 self.tlv_bss_section_index = try self.initSection(
4532 self.data_segment_cmd_index.?,
4533 "__thread_bss",
4534 needed_size,
4535 alignment,
4536 .{
4537 .flags = macho.S_THREAD_LOCAL_ZEROFILL,
4538 },
4539 );
4540 }
4541
4542 if (self.bss_section_index == null) {
4543 const needed_size = if (self.mode == .incremental)
4544 @sizeOf(u64) * self.base.options.symbol_count_hint
4545 else
4546 0;
4547 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
4548 self.bss_section_index = try self.initSection(
4549 self.data_segment_cmd_index.?,
4550 "__bss",
4551 needed_size,
4552 alignment,
4553 .{
4554 .flags = macho.S_ZEROFILL,
4555 },
4556 );
4557 }
4558
45594480 if (self.linkedit_segment_cmd_index == null) {
45604481 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
45614482 var vmaddr: u64 = 0;
......@@ -4690,18 +4611,19 @@ fn allocateSegments(self: *MachO) !void {
46904611 }, try self.calcMinHeaderPad());
46914612
46924613 if (self.text_segment_cmd_index) |index| blk: {
4693 const seg = &self.segments.items[index];
4694 if (seg.nsects == 0) break :blk;
4614 const indexes = self.getSectionIndexes(index);
4615 if (indexes.start == indexes.end) break :blk;
4616 const seg = self.segments.items[index];
46954617
46964618 // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.
46974619 var min_alignment: u32 = 0;
4698 for (self.sections.items(.header)[0..seg.nsects]) |header| {
4620 for (self.sections.items(.header)[indexes.start..indexes.end]) |header| {
46994621 const alignment = try math.powi(u32, 2, header.@"align");
47004622 min_alignment = math.max(min_alignment, alignment);
47014623 }
47024624
47034625 assert(min_alignment > 0);
4704 const last_header = self.sections.items(.header)[seg.nsects - 1];
4626 const last_header = self.sections.items(.header)[indexes.end - 1];
47054627 const shift: u32 = shift: {
47064628 const diff = seg.filesize - last_header.offset - last_header.size;
47074629 const factor = @divTrunc(diff, min_alignment);
......@@ -4709,7 +4631,7 @@ fn allocateSegments(self: *MachO) !void {
47094631 };
47104632
47114633 if (shift > 0) {
4712 for (self.sections.items(.header)[0..seg.nsects]) |*header| {
4634 for (self.sections.items(.header)[indexes.start..indexes.end]) |*header| {
47134635 header.offset += shift;
47144636 header.addr += shift;
47154637 }
......@@ -4746,16 +4668,14 @@ fn allocateSegment(self: *MachO, maybe_index: ?u8, indices: []const ?u8, init_si
47464668 seg.vmsize = init_size;
47474669
47484670 // Allocate the sections according to their alignment at the beginning of the segment.
4671 const indexes = self.getSectionIndexes(index);
47494672 var start = init_size;
47504673 const slice = self.sections.slice();
4751 for (slice.items(.header)) |*header, sect_id| {
4752 const segment_index = slice.items(.segment_index)[sect_id];
4753 if (segment_index != index) continue;
4754 const is_zerofill = header.flags == macho.S_ZEROFILL or header.flags == macho.S_THREAD_LOCAL_ZEROFILL;
4674 for (slice.items(.header)[indexes.start..indexes.end]) |*header| {
47554675 const alignment = try math.powi(u32, 2, header.@"align");
47564676 const start_aligned = mem.alignForwardGeneric(u64, start, alignment);
47574677
4758 header.offset = if (is_zerofill)
4678 header.offset = if (header.isZerofill())
47594679 0
47604680 else
47614681 @intCast(u32, seg.fileoff + start_aligned);
......@@ -4763,7 +4683,7 @@ fn allocateSegment(self: *MachO, maybe_index: ?u8, indices: []const ?u8, init_si
47634683
47644684 start = start_aligned + header.size;
47654685
4766 if (!is_zerofill) {
4686 if (!header.isZerofill()) {
47674687 seg.filesize = start;
47684688 }
47694689 seg.vmsize = start;
......@@ -4788,7 +4708,7 @@ fn initSection(
47884708 opts: InitSectionOpts,
47894709) !u8 {
47904710 const seg = &self.segments.items[segment_id];
4791 var header = macho.section_64{
4711 const index = try self.insertSection(segment_id, .{
47924712 .sectname = makeStaticString(sectname),
47934713 .segname = seg.segname,
47944714 .size = if (self.mode == .incremental) @intCast(u32, size) else 0,
......@@ -4796,40 +4716,162 @@ fn initSection(
47964716 .flags = opts.flags,
47974717 .reserved1 = opts.reserved1,
47984718 .reserved2 = opts.reserved2,
4799 };
4719 });
4720 seg.cmdsize += @sizeOf(macho.section_64);
4721 seg.nsects += 1;
48004722
48014723 if (self.mode == .incremental) {
4724 const header = &self.sections.items(.header)[index];
4725 const prev_end_off = if (index > 0) blk: {
4726 const prev_section = self.sections.get(index - 1);
4727 if (prev_section.segment_index == segment_id) {
4728 const prev_header = prev_section.header;
4729 break :blk prev_header.offset + padToIdeal(prev_header.size);
4730 } else break :blk seg.fileoff;
4731 } else 0;
48024732 const alignment_pow_2 = try math.powi(u32, 2, alignment);
4803 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?)
4804 try self.calcMinHeaderPad()
4805 else
4806 null;
4807 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
4808 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
4809 header.segName(),
4810 header.sectName(),
4811 off,
4812 off + size,
4813 });
4733 const padding: u64 = if (index == 0) try self.calcMinHeaderPad() else 0;
4734 const off = mem.alignForwardGeneric(u64, padding + prev_end_off, alignment_pow_2);
4735 log.debug("allocating {s},{s} section at 0x{x}", .{ header.segName(), header.sectName(), off });
48144736
48154737 header.addr = seg.vmaddr + off - seg.fileoff;
48164738
4817 // TODO handle zerofill in stage2
4818 // const is_zerofill = opts.flags == macho.S_ZEROFILL or opts.flags == macho.S_THREAD_LOCAL_ZEROFILL;
4819 header.offset = @intCast(u32, off);
4739 if (!header.isZerofill()) {
4740 header.offset = @intCast(u32, off);
4741 }
4742
4743 self.updateSectionOrdinals(index + 1);
4744 }
4745
4746 return index;
4747}
48204748
4821 try self.updateSectionOrdinals();
4749fn getSectionPrecedence(header: macho.section_64) u4 {
4750 if (header.isCode()) {
4751 if (mem.eql(u8, "__text", header.sectName())) return 0x0;
4752 if (header.@"type"() == macho.S_SYMBOL_STUBS) return 0x1;
4753 return 0x2;
4754 }
4755 switch (header.@"type"()) {
4756 macho.S_NON_LAZY_SYMBOL_POINTERS,
4757 macho.S_LAZY_SYMBOL_POINTERS,
4758 => return 0x0,
4759 macho.S_MOD_INIT_FUNC_POINTERS => return 0x1,
4760 macho.S_MOD_TERM_FUNC_POINTERS => return 0x2,
4761 macho.S_ZEROFILL => return 0xf,
4762 macho.S_THREAD_LOCAL_REGULAR => return 0xd,
4763 macho.S_THREAD_LOCAL_ZEROFILL => return 0xe,
4764 else => if (mem.eql(u8, "__eh_frame", header.sectName()))
4765 return 0xf
4766 else
4767 return 0x3,
48224768 }
4769}
48234770
4824 const index = @intCast(u8, self.sections.slice().len);
4825 try self.sections.append(self.base.allocator, .{
4826 .segment_index = segment_id,
4771fn insertSection(self: *MachO, segment_index: u8, header: macho.section_64) !u8 {
4772 const precedence = getSectionPrecedence(header);
4773 const indexes = self.getSectionIndexes(segment_index);
4774 const insertion_index = for (self.sections.items(.header)[indexes.start..indexes.end]) |hdr, i| {
4775 if (getSectionPrecedence(hdr) > precedence) break @intCast(u8, i + indexes.start);
4776 } else indexes.end;
4777 log.debug("inserting section '{s},{s}' at index {d}", .{
4778 header.segName(),
4779 header.sectName(),
4780 insertion_index,
4781 });
4782 // TODO slim it down
4783 for (&[_]*?u8{
4784 // __TEXT
4785 &self.text_section_index,
4786 &self.stubs_section_index,
4787 &self.stub_helper_section_index,
4788 &self.gcc_except_tab_section_index,
4789 &self.cstring_section_index,
4790 &self.ustring_section_index,
4791 &self.text_const_section_index,
4792 &self.objc_methlist_section_index,
4793 &self.objc_methname_section_index,
4794 &self.objc_methtype_section_index,
4795 &self.objc_classname_section_index,
4796 &self.eh_frame_section_index,
4797 // __DATA_CONST
4798 &self.got_section_index,
4799 &self.mod_init_func_section_index,
4800 &self.mod_term_func_section_index,
4801 &self.data_const_section_index,
4802 &self.objc_cfstring_section_index,
4803 &self.objc_classlist_section_index,
4804 &self.objc_imageinfo_section_index,
4805 // __DATA
4806 &self.rustc_section_index,
4807 &self.la_symbol_ptr_section_index,
4808 &self.objc_const_section_index,
4809 &self.objc_selrefs_section_index,
4810 &self.objc_classrefs_section_index,
4811 &self.objc_data_section_index,
4812 &self.data_section_index,
4813 &self.tlv_section_index,
4814 &self.tlv_ptrs_section_index,
4815 &self.tlv_data_section_index,
4816 &self.tlv_bss_section_index,
4817 &self.bss_section_index,
4818 }) |maybe_index| {
4819 const index = maybe_index.* orelse continue;
4820 if (insertion_index <= index) maybe_index.* = index + 1;
4821 }
4822 try self.sections.insert(self.base.allocator, insertion_index, .{
4823 .segment_index = segment_index,
48274824 .header = header,
48284825 });
4829 seg.cmdsize += @sizeOf(macho.section_64);
4830 seg.nsects += 1;
4826 return insertion_index;
4827}
48314828
4832 return index;
4829fn updateSectionOrdinals(self: *MachO, start: u8) void {
4830 const tracy = trace(@src());
4831 defer tracy.end();
4832
4833 const slice = self.sections.slice();
4834 for (slice.items(.last_atom)[start..]) |last_atom| {
4835 var atom = last_atom.?;
4836
4837 while (true) {
4838 const sym = atom.getSymbolPtr(self);
4839 sym.n_sect = start + 1;
4840
4841 for (atom.contained.items) |sym_at_off| {
4842 const contained_sym = self.getSymbolPtr(.{
4843 .sym_index = sym_at_off.sym_index,
4844 .file = atom.file,
4845 });
4846 contained_sym.n_sect = start + 1;
4847 }
4848
4849 if (atom.prev) |prev| {
4850 atom = prev;
4851 } else break;
4852 }
4853 }
4854}
4855
4856fn shiftLocalsByOffset(self: *MachO, sect_id: u8, offset: i64) !void {
4857 var atom = self.sections.items(.last_atom)[sect_id] orelse return;
4858
4859 while (true) {
4860 const atom_sym = atom.getSymbolPtr(self);
4861 atom_sym.n_value = @intCast(u64, @intCast(i64, atom_sym.n_value) + offset);
4862
4863 for (atom.contained.items) |sym_at_off| {
4864 const contained_sym = self.getSymbolPtr(.{
4865 .sym_index = sym_at_off.sym_index,
4866 .file = atom.file,
4867 });
4868 contained_sym.n_value = @intCast(u64, @intCast(i64, contained_sym.n_value) + offset);
4869 }
4870
4871 if (atom.prev) |prev| {
4872 atom = prev;
4873 } else break;
4874 }
48334875}
48344876
48354877fn findFreeSpace(self: MachO, segment_id: u8, alignment: u64, start: ?u64) u64 {
......@@ -5181,153 +5223,18 @@ fn getSegmentAllocBase(self: MachO, indices: []const ?u8) struct { vmaddr: u64,
51815223 return .{ .vmaddr = 0, .fileoff = 0 };
51825224}
51835225
5184fn pruneAndSortSections(self: *MachO) !void {
5185 const gpa = self.base.allocator;
5186
5187 var sections = self.sections.toOwnedSlice();
5188 defer sections.deinit(gpa);
5189 try self.sections.ensureTotalCapacity(gpa, sections.len);
5190
5191 for (&[_]*?u8{
5192 // __TEXT
5193 &self.text_section_index,
5194 &self.stubs_section_index,
5195 &self.stub_helper_section_index,
5196 &self.gcc_except_tab_section_index,
5197 &self.cstring_section_index,
5198 &self.ustring_section_index,
5199 &self.text_const_section_index,
5200 &self.objc_methlist_section_index,
5201 &self.objc_methname_section_index,
5202 &self.objc_methtype_section_index,
5203 &self.objc_classname_section_index,
5204 &self.eh_frame_section_index,
5205 // __DATA_CONST
5206 &self.got_section_index,
5207 &self.mod_init_func_section_index,
5208 &self.mod_term_func_section_index,
5209 &self.data_const_section_index,
5210 &self.objc_cfstring_section_index,
5211 &self.objc_classlist_section_index,
5212 &self.objc_imageinfo_section_index,
5213 // __DATA
5214 &self.rustc_section_index,
5215 &self.la_symbol_ptr_section_index,
5216 &self.objc_const_section_index,
5217 &self.objc_selrefs_section_index,
5218 &self.objc_classrefs_section_index,
5219 &self.objc_data_section_index,
5220 &self.data_section_index,
5221 &self.tlv_section_index,
5222 &self.tlv_ptrs_section_index,
5223 &self.tlv_data_section_index,
5224 &self.tlv_bss_section_index,
5225 &self.bss_section_index,
5226 }) |maybe_index| {
5227 const old_idx = maybe_index.* orelse continue;
5228 const segment_index = sections.items(.segment_index)[old_idx];
5229 const header = sections.items(.header)[old_idx];
5230 const last_atom = sections.items(.last_atom)[old_idx];
5231 if (header.size == 0) {
5232 log.debug("pruning section {s},{s}", .{ header.segName(), header.sectName() });
5233 maybe_index.* = null;
5234 const seg = &self.segments.items[segment_index];
5235 seg.cmdsize -= @sizeOf(macho.section_64);
5236 seg.nsects -= 1;
5237 } else {
5238 maybe_index.* = @intCast(u8, self.sections.slice().len);
5239 self.sections.appendAssumeCapacity(.{
5240 .segment_index = segment_index,
5241 .header = header,
5242 .last_atom = last_atom,
5243 });
5244 }
5245 }
5246
5247 for (self.segments.items) |*seg| {
5248 const segname = seg.segName();
5249 if (seg.nsects == 0 and
5250 !mem.eql(u8, "__TEXT", segname) and
5251 !mem.eql(u8, "__PAGEZERO", segname) and
5252 !mem.eql(u8, "__LINKEDIT", segname))
5253 {
5254 // Segment has now become empty, so mark it as such
5255 log.debug("marking segment {s} as dead", .{seg.segName()});
5256 seg.cmd = @intToEnum(macho.LC, 0);
5257 }
5258 }
5259}
5260
5261fn updateSectionOrdinals(self: *MachO) !void {
5262 _ = self;
5263 const tracy = trace(@src());
5264 defer tracy.end();
5265
5266 @panic("updating section ordinals");
5267
5268 // const gpa = self.base.allocator;
5269
5270 // var ordinal_remap = std.AutoHashMap(u8, u8).init(gpa);
5271 // defer ordinal_remap.deinit();
5272 // var ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{};
5273
5274 // var new_ordinal: u8 = 0;
5275 // for (&[_]?u16{
5276 // self.text_segment_cmd_index,
5277 // self.data_const_segment_cmd_index,
5278 // self.data_segment_cmd_index,
5279 // }) |maybe_index| {
5280 // const index = maybe_index orelse continue;
5281 // const seg = self.load_commands.items[index].segment;
5282 // for (seg.sections.items) |sect, sect_id| {
5283 // const match = MatchingSection{
5284 // .seg = @intCast(u16, index),
5285 // .sect = @intCast(u16, sect_id),
5286 // };
5287 // const old_ordinal = self.getSectionOrdinal(match);
5288 // new_ordinal += 1;
5289 // log.debug("'{s},{s}': sect({d}, '_,_') => sect({d}, '_,_')", .{
5290 // sect.segName(),
5291 // sect.sectName(),
5292 // old_ordinal,
5293 // new_ordinal,
5294 // });
5295 // try ordinal_remap.putNoClobber(old_ordinal, new_ordinal);
5296 // try ordinals.putNoClobber(gpa, match, {});
5297 // }
5298 // }
5299
5300 // // FIXME Jakub
5301 // // TODO no need for duping work here; simply walk the atom graph
5302 // for (self.locals.items) |*sym| {
5303 // if (sym.undf()) continue;
5304 // if (sym.n_sect == 0) continue;
5305 // sym.n_sect = ordinal_remap.get(sym.n_sect).?;
5306 // }
5307 // for (self.objects.items) |*object| {
5308 // for (object.symtab.items) |*sym| {
5309 // if (sym.undf()) continue;
5310 // if (sym.n_sect == 0) continue;
5311 // sym.n_sect = ordinal_remap.get(sym.n_sect).?;
5312 // }
5313 // }
5314
5315 // self.section_ordinals.deinit(gpa);
5316 // self.section_ordinals = ordinals;
5317}
5318
53195226pub fn writeSegmentHeaders(self: *MachO, start: usize, end: usize, ncmds: *u32, writer: anytype) !void {
5320 var count: usize = 0;
5321 for (self.segments.items[start..end]) |seg| {
5322 if (seg.cmd == .NONE) continue;
5227 for (self.segments.items[start..end]) |seg, i| {
5228 if (seg.nsects == 0 and
5229 (mem.eql(u8, seg.segName(), "__DATA_CONST") or
5230 mem.eql(u8, seg.segName(), "__DATA"))) continue;
53235231 try writer.writeStruct(seg);
53245232
5325 // TODO
5326 for (self.sections.items(.header)[count..][0..seg.nsects]) |header| {
5233 const indexes = self.getSectionIndexes(@intCast(u8, start + i));
5234 for (self.sections.items(.header)[indexes.start..indexes.end]) |header| {
53275235 try writer.writeStruct(header);
53285236 }
53295237
5330 count += seg.nsects;
53315238 ncmds.* += 1;
53325239 }
53335240}
......@@ -6644,6 +6551,19 @@ fn generateSymbolStabsForSymbol(
66446551// try writer.writeByte(']');
66456552// }
66466553
6554fn logSections(self: *MachO) void {
6555 log.debug("sections:", .{});
6556 for (self.sections.items(.header)) |header, i| {
6557 log.debug(" sect({d}): {s},{s} @{x}, sizeof({x})", .{
6558 i + 1,
6559 header.segName(),
6560 header.sectName(),
6561 header.offset,
6562 header.size,
6563 });
6564 }
6565}
6566
66476567fn logSymAttributes(sym: macho.nlist_64, buf: *[9]u8) []const u8 {
66486568 mem.set(u8, buf[0..4], '_');
66496569 mem.set(u8, buf[4..], ' ');
src/link/MachO/Atom.zig+2-2
......@@ -466,7 +466,7 @@ fn addPtrBindingOrRebase(
466466 const section = context.macho_file.sections.get(source_sym.n_sect - 1);
467467 const header = section.header;
468468 const segment_index = section.segment_index;
469 const sect_type = header.type_();
469 const sect_type = header.@"type"();
470470
471471 const should_rebase = rebase: {
472472 if (rel.r_length != 3) break :rebase false;
......@@ -571,7 +571,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
571571 const is_tlv = is_tlv: {
572572 const source_sym = self.getSymbol(macho_file);
573573 const header = macho_file.sections.items(.header)[source_sym.n_sect - 1];
574 break :is_tlv header.type_() == macho.S_THREAD_LOCAL_VARIABLES;
574 break :is_tlv header.@"type"() == macho.S_THREAD_LOCAL_VARIABLES;
575575 };
576576 const target_addr = blk: {
577577 const target_atom = rel.getTargetAtom(macho_file) orelse {
src/link/MachO/Object.zig+18-5
......@@ -214,6 +214,23 @@ fn filterRelocs(
214214 return relocs[start..end];
215215}
216216
217pub fn scanInputSections(self: Object, macho_file: *MachO) !void {
218 for (self.sections.items) |sect| {
219 const match = (try macho_file.getOutputSection(sect)) orelse {
220 log.debug(" unhandled section", .{});
221 continue;
222 };
223 const output = macho_file.sections.items(.header)[match];
224 log.debug("mapping '{s},{s}' into output sect({d}, '{s},{s}')", .{
225 sect.segName(),
226 sect.sectName(),
227 match + 1,
228 output.segName(),
229 output.sectName(),
230 });
231 }
232}
233
217234/// Splits object into atoms assuming one-shot linking mode.
218235pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) !void {
219236 assert(macho_file.mode == .one_shot);
......@@ -280,13 +297,9 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
280297 });
281298
282299 const cpu_arch = macho_file.base.options.target.cpu.arch;
283 const is_zerofill = blk: {
284 const section_type = sect.type_();
285 break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL;
286 };
287300
288301 // Read section's code
289 const code: ?[]const u8 = if (!is_zerofill) try self.getSectionContents(sect) else null;
302 const code: ?[]const u8 = if (!sect.isZerofill()) try self.getSectionContents(sect) else null;
290303
291304 // Read section's list of relocations
292305 const relocs = @ptrCast(
src/link/MachO/dead_strip.zig+4-1
......@@ -43,6 +43,9 @@ fn removeAtomFromSection(atom: *Atom, match: u8, macho_file: *MachO) void {
4343 // The section will be GCed in the next step.
4444 section.last_atom = null;
4545 section.header.size = 0;
46 const segment = &macho_file.segments.items[section.segment_index];
47 segment.cmdsize -= @sizeOf(macho.section_64);
48 segment.nsects -= 1;
4649 }
4750 }
4851
......@@ -93,7 +96,7 @@ fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void
9396 const is_gc_root = blk: {
9497 if (source_sect.isDontDeadStrip()) break :blk true;
9598 if (mem.eql(u8, "__StaticInit", source_sect.sectName())) break :blk true;
96 switch (source_sect.type_()) {
99 switch (source_sect.@"type"()) {
97100 macho.S_MOD_INIT_FUNC_POINTERS,
98101 macho.S_MOD_TERM_FUNC_POINTERS,
99102 => break :blk true,