authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-23 11:51:48+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-23 16:55:19+02:00
log1beda818e1c10bde98b35759b3c131a864be58d9
tree6d5f04b84034a765d957fc651aba971619e790bf
parenta4feb97cdfb330207f3da05402983bf3a71de64e

macho: re-enable parsing sections into atoms

However, make it default only when building in release modes since it's a prelude to advanced dead code stripping not very useful in debug.

3 files changed, 291 insertions(+), 291 deletions(-)

src/link/MachO.zig+69-54
......@@ -965,60 +965,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
965965 try self.allocateDataSegment();
966966 self.allocateLinkeditSegment();
967967 try self.allocateTextBlocks();
968
969 // log.warn("locals", .{});
970 // for (self.locals.items) |sym, id| {
971 // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
972 // }
973
974 // log.warn("globals", .{});
975 // for (self.globals.items) |sym, id| {
976 // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
977 // }
978
979 // log.warn("tentatives", .{});
980 // for (self.tentatives.items) |sym, id| {
981 // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
982 // }
983
984 // log.warn("undefines", .{});
985 // for (self.undefs.items) |sym, id| {
986 // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
987 // }
988
989 // log.warn("imports", .{});
990 // for (self.imports.items) |sym, id| {
991 // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
992 // }
993
994 // log.warn("symbol resolver", .{});
995 // for (self.symbol_resolver.keys()) |key| {
996 // log.warn(" {s} => {}", .{ key, self.symbol_resolver.get(key).? });
997 // }
998
999 // log.warn("mappings", .{});
1000 // for (self.objects.items) |object, id| {
1001 // const object_id = @intCast(u16, id);
1002 // log.warn(" in object {s}", .{object.name.?});
1003 // for (object.symtab.items) |sym, sym_id| {
1004 // if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| {
1005 // log.warn(" | {d} => {d}", .{ sym_id, local_id });
1006 // } else {
1007 // log.warn(" | {d} no local mapping for {s}", .{ sym_id, object.getString(sym.n_strx) });
1008 // }
1009 // }
1010 // }
1011
1012 // var it = self.blocks.iterator();
1013 // while (it.next()) |entry| {
1014 // const seg = self.load_commands.items[entry.key_ptr.seg].Segment;
1015 // const sect = seg.sections.items[entry.key_ptr.sect];
1016
1017 // log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
1018 // log.warn(" {}", .{sect});
1019 // entry.value_ptr.*.print(self);
1020 // }
1021
968 self.printSymtabAndTextBlock();
1022969 try self.flushZld();
1023970 }
1024971
......@@ -2086,6 +2033,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
20862033 .n_value = sym.n_value,
20872034 });
20882035 try object.symbol_mapping.putNoClobber(self.base.allocator, sym_id, local_sym_index);
2036 try object.reverse_symbol_mapping.putNoClobber(self.base.allocator, local_sym_index, sym_id);
20892037
20902038 // If the symbol's scope is not local aka translation unit, then we need work out
20912039 // if we should save the symbol as a global, or potentially flag the error.
......@@ -5916,3 +5864,70 @@ fn createSectionOrdinal(self: *MachO, match: MatchingSection) !void {
59165864 try self.section_ordinals.append(self.base.allocator, match);
59175865 try self.section_to_ordinal.putNoClobber(self.base.allocator, match, ordinal);
59185866}
5867
5868fn printSymtabAndTextBlock(self: *MachO) void {
5869 log.debug("locals", .{});
5870 for (self.locals.items) |sym, id| {
5871 log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
5872 }
5873
5874 log.debug("globals", .{});
5875 for (self.globals.items) |sym, id| {
5876 log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
5877 }
5878
5879 log.debug("tentatives", .{});
5880 for (self.tentatives.items) |sym, id| {
5881 log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
5882 }
5883
5884 log.debug("undefines", .{});
5885 for (self.undefs.items) |sym, id| {
5886 log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
5887 }
5888
5889 log.debug("imports", .{});
5890 for (self.imports.items) |sym, id| {
5891 log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
5892 }
5893
5894 {
5895 log.debug("symbol resolver", .{});
5896 var it = self.symbol_resolver.keyIterator();
5897 while (it.next()) |key_ptr| {
5898 const sym_name = self.getString(key_ptr.*);
5899 log.debug(" {s} => {}", .{ sym_name, self.symbol_resolver.get(key_ptr.*).? });
5900 }
5901 }
5902
5903 log.debug("mappings", .{});
5904 for (self.objects.items) |object| {
5905 log.debug(" in object {s}", .{object.name.?});
5906 for (object.symtab.items) |sym, sym_id| {
5907 if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| {
5908 log.debug(" | {d} => {d}", .{ sym_id, local_id });
5909 } else {
5910 log.debug(" | {d} no local mapping for {s}", .{ sym_id, object.getString(sym.n_strx) });
5911 }
5912 }
5913 }
5914
5915 {
5916 var it = self.blocks.iterator();
5917 while (it.next()) |entry| {
5918 const seg = self.load_commands.items[entry.key_ptr.seg].Segment;
5919 const sect = seg.sections.items[entry.key_ptr.sect];
5920
5921 var block: *TextBlock = entry.value_ptr.*;
5922
5923 log.debug("\n\n{s},{s} contents:", .{ commands.segmentName(sect), commands.sectionName(sect) });
5924 log.debug("{}", .{sect});
5925 log.debug("{}", .{block});
5926
5927 while (block.prev) |prev| {
5928 block = prev;
5929 log.debug("{}", .{block});
5930 }
5931 }
5932 }
5933}
src/link/MachO/Object.zig+191-192
......@@ -55,7 +55,11 @@ mtime: ?u64 = null,
5555
5656text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
5757sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{},
58
59// TODO symbol mapping and its inverse can probably be simple arrays
60// instead of hash maps.
5861symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},
62reverse_symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},
5963
6064const DebugInfo = struct {
6165 inner: dwarf.DwarfInfo,
......@@ -164,6 +168,7 @@ pub fn deinit(self: *Object) void {
164168 self.text_blocks.deinit(self.allocator);
165169 self.sections_as_symbols.deinit(self.allocator);
166170 self.symbol_mapping.deinit(self.allocator);
171 self.reverse_symbol_mapping.deinit(self.allocator);
167172
168173 if (self.debug_info) |*db| {
169174 db.deinit(self.allocator);
......@@ -367,7 +372,7 @@ const TextBlockParser = struct {
367372 } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) {
368373 return !MachO.symbolIsExt(lhs.nlist);
369374 } else {
370 return true;
375 return false;
371376 }
372377 }
373378
......@@ -392,15 +397,7 @@ const TextBlockParser = struct {
392397 } else null;
393398
394399 for (aliases.items) |*nlist_with_index| {
395 nlist_with_index.index = self.symbol_mapping.get(nlist_with_index.index);
396 const sym = self.object.symbols.items[nlist_with_index.index];
397 if (sym.payload != .regular) {
398 log.err("expected a regular symbol, found {s}", .{sym.payload});
399 log.err(" when remapping {s}", .{self.macho_file.getString(sym.strx)});
400 return error.SymbolIsNotRegular;
401 }
402 assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.
403 nlist_with_index.index = sym.payload.regular.local_sym_index;
400 nlist_with_index.index = self.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable;
404401 }
405402
406403 if (aliases.items.len > 1) {
......@@ -409,15 +406,13 @@ const TextBlockParser = struct {
409406 NlistWithIndex,
410407 aliases.items,
411408 SeniorityContext{ .object = self.object },
412 @This().lessThanBySeniority,
409 TextBlockParser.lessThanBySeniority,
413410 );
414411 }
415412
416413 const senior_nlist = aliases.pop();
417 const senior_sym = self.macho_file.locals.items[senior_nlist.index];
418 assert(senior_sym.payload == .regular);
419 senior_sym.payload.regular.segment_id = self.match.seg;
420 senior_sym.payload.regular.section_id = self.match.sect;
414 const senior_sym = &self.macho_file.locals.items[senior_nlist.index];
415 senior_sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable;
421416
422417 const start_addr = senior_nlist.nlist.n_value - self.section.addr;
423418 const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;
......@@ -442,33 +437,29 @@ const TextBlockParser = struct {
442437 }
443438 }
444439 }
445 if (self.macho_file.globals.contains(self.macho_file.getString(senior_sym.strx))) break :blk .global;
440 // TODO
441 // if (self.macho_file.globals.contains(self.macho_file.getString(senior_sym.strx))) break :blk .global;
446442 break :blk .static;
447443 } else null;
448444
449 const block = try self.allocator.create(TextBlock);
450 errdefer self.allocator.destroy(block);
451
452 block.* = TextBlock.init(self.allocator);
445 const block = try self.macho_file.base.allocator.create(TextBlock);
446 block.* = TextBlock.empty;
453447 block.local_sym_index = senior_nlist.index;
454448 block.stab = stab;
455 block.code = try self.allocator.dupe(u8, code);
456449 block.size = size;
457450 block.alignment = actual_align;
451 try self.macho_file.managed_blocks.append(self.macho_file.base.allocator, block);
458452
459 if (aliases.items.len > 0) {
460 try block.aliases.ensureTotalCapacity(aliases.items.len);
461 for (aliases.items) |alias| {
462 block.aliases.appendAssumeCapacity(alias.index);
453 try block.code.appendSlice(self.macho_file.base.allocator, code);
463454
464 const sym = self.macho_file.locals.items[alias.index];
465 const reg = &sym.payload.regular;
466 reg.segment_id = self.match.seg;
467 reg.section_id = self.match.sect;
468 }
455 try block.aliases.ensureTotalCapacity(self.macho_file.base.allocator, aliases.items.len);
456 for (aliases.items) |alias| {
457 block.aliases.appendAssumeCapacity(alias.index);
458 const sym = &self.macho_file.locals.items[alias.index];
459 sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable;
469460 }
470461
471 try block.parseRelocsFromObject(self.allocator, relocs, object, .{
462 try block.parseRelocsFromObject(self.macho_file.base.allocator, self.relocs, self.object, .{
472463 .base_addr = start_addr,
473464 .macho_file = self.macho_file,
474465 });
......@@ -479,7 +470,7 @@ const TextBlockParser = struct {
479470 senior_nlist.nlist.n_value,
480471 senior_nlist.nlist.n_value + size,
481472 );
482 try block.dices.ensureTotalCapacity(dices.len);
473 try block.dices.ensureTotalCapacity(self.macho_file.base.allocator, dices.len);
483474
484475 for (dices) |dice| {
485476 block.dices.appendAssumeCapacity(.{
......@@ -518,10 +509,22 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
518509
519510 sort.sort(NlistWithIndex, sorted_all_nlists.items, {}, NlistWithIndex.lessThan);
520511
521 const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
512 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
513 // have to infer the start of undef section in the symtab ourselves.
514 const iundefsym = if (self.dysymtab_cmd_index) |cmd_index| blk: {
515 const dysymtab = self.load_commands.items[cmd_index].Dysymtab;
516 break :blk dysymtab.iundefsym;
517 } else blk: {
518 var iundefsym: usize = sorted_all_nlists.items.len;
519 while (iundefsym > 0) : (iundefsym -= 1) {
520 const nlist = sorted_all_nlists.items[iundefsym];
521 if (MachO.symbolIsSect(nlist.nlist)) break;
522 }
523 break :blk iundefsym;
524 };
522525
523526 // We only care about defined symbols, so filter every other out.
524 const sorted_nlists = sorted_all_nlists.items[dysymtab.ilocalsym..dysymtab.iundefsym];
527 const sorted_nlists = sorted_all_nlists.items[0..iundefsym];
525528
526529 for (seg.sections.items) |sect, id| {
527530 const sect_id = @intCast(u8, id);
......@@ -550,11 +553,12 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
550553 // Symbols within this section only.
551554 const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect);
552555
553 // Is there any padding between symbols within the section?
554 // const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
555 // TODO is it perhaps worth skip parsing subsections in Debug mode and not worry about
556 // duplicates at all? Need some benchmarks!
557 // const is_splittable = false;
556 // In release mode, if the object file was generated with dead code stripping optimisations,
557 // note it now and parse sections as atoms.
558 const is_splittable = blk: {
559 if (macho_file.base.options.optimize_mode == .Debug) break :blk false;
560 break :blk self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
561 };
558562
559563 macho_file.has_dices = blk: {
560564 if (self.text_section_index) |index| {
......@@ -566,157 +570,152 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
566570 };
567571 macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null;
568572
569 {
570 // next: {
571 // if (is_splittable) blocks: {
572 // if (filtered_nlists.len == 0) break :blocks;
573
574 // // If the first nlist does not match the start of the section,
575 // // then we need encapsulate the memory range [section start, first symbol)
576 // // as a temporary symbol and insert the matching TextBlock.
577 // const first_nlist = filtered_nlists[0].nlist;
578 // if (first_nlist.n_value > sect.addr) {
579 // const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
580 // const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
581 // self.name.?,
582 // segmentName(sect),
583 // sectionName(sect),
584 // });
585 // defer self.allocator.free(name);
586 // const symbol = try zld.allocator.create(Symbol);
587 // symbol.* = .{
588 // .strx = try zld.makeString(name),
589 // .payload = .{ .undef = .{} },
590 // };
591 // try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
592 // break :symbol symbol;
593 // };
594
595 // const local_sym_index = @intCast(u32, zld.locals.items.len);
596 // symbol.payload = .{
597 // .regular = .{
598 // .linkage = .translation_unit,
599 // .address = sect.addr,
600 // .segment_id = match.seg,
601 // .section_id = match.sect,
602 // .file = self,
603 // .local_sym_index = local_sym_index,
604 // },
605 // };
606 // try zld.locals.append(zld.allocator, symbol);
607
608 // const block_code = code[0 .. first_nlist.n_value - sect.addr];
609 // const block_size = block_code.len;
610
611 // const block = try self.allocator.create(TextBlock);
612 // errdefer self.allocator.destroy(block);
613
614 // block.* = TextBlock.init(self.allocator);
615 // block.local_sym_index = local_sym_index;
616 // block.code = try self.allocator.dupe(u8, block_code);
617 // block.size = block_size;
618 // block.alignment = sect.@"align";
619
620 // const block_relocs = filterRelocs(relocs, 0, block_size);
621 // if (block_relocs.len > 0) {
622 // try self.parseRelocs(zld, block_relocs, block, 0);
623 // }
624
625 // if (zld.has_dices) {
626 // const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
627 // try block.dices.ensureTotalCapacity(dices.len);
628
629 // for (dices) |dice| {
630 // block.dices.appendAssumeCapacity(.{
631 // .offset = dice.offset - try math.cast(u32, sect.addr),
632 // .length = dice.length,
633 // .kind = dice.kind,
634 // });
635 // }
636 // }
637
638 // // Update target section's metadata
639 // // TODO should we update segment's size here too?
640 // // How does it tie with incremental space allocs?
641 // const tseg = &zld.load_commands.items[match.seg].Segment;
642 // const tsect = &tseg.sections.items[match.sect];
643 // const new_alignment = math.max(tsect.@"align", block.alignment);
644 // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
645 // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
646 // tsect.size = new_size;
647 // tsect.@"align" = new_alignment;
648
649 // if (zld.blocks.getPtr(match)) |last| {
650 // last.*.next = block;
651 // block.prev = last.*;
652 // last.* = block;
653 // } else {
654 // try zld.blocks.putNoClobber(zld.allocator, match, block);
655 // }
656
657 // try self.text_blocks.append(self.allocator, block);
658 // }
659
660 // var parser = TextBlockParser{
661 // .allocator = self.allocator,
662 // .section = sect,
663 // .code = code,
664 // .relocs = relocs,
665 // .object = self,
666 // .zld = zld,
667 // .nlists = filtered_nlists,
668 // .match = match,
669 // };
670
671 // while (try parser.next()) |block| {
672 // const sym = zld.locals.items[block.local_sym_index];
673 // const reg = &sym.payload.regular;
674 // if (reg.file) |file| {
675 // if (file != self) {
676 // log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? });
677 // block.deinit();
678 // self.allocator.destroy(block);
679 // continue;
680 // }
681 // }
682
683 // if (reg.address == sect.addr) {
684 // if (self.sections_as_symbols.get(sect_id)) |alias| {
685 // // Add alias.
686 // const local_sym_index = @intCast(u32, zld.locals.items.len);
687 // const reg_alias = &alias.payload.regular;
688 // reg_alias.segment_id = match.seg;
689 // reg_alias.section_id = match.sect;
690 // reg_alias.local_sym_index = local_sym_index;
691 // try block.aliases.append(local_sym_index);
692 // try zld.locals.append(zld.allocator, alias);
693 // }
694 // }
695
696 // // Update target section's metadata
697 // // TODO should we update segment's size here too?
698 // // How does it tie with incremental space allocs?
699 // const tseg = &zld.load_commands.items[match.seg].Segment;
700 // const tsect = &tseg.sections.items[match.sect];
701 // const new_alignment = math.max(tsect.@"align", block.alignment);
702 // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
703 // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
704 // tsect.size = new_size;
705 // tsect.@"align" = new_alignment;
706
707 // if (zld.blocks.getPtr(match)) |last| {
708 // last.*.next = block;
709 // block.prev = last.*;
710 // last.* = block;
711 // } else {
712 // try zld.blocks.putNoClobber(zld.allocator, match, block);
713 // }
714
715 // try self.text_blocks.append(self.allocator, block);
716 // }
717
718 // break :next;
719 // }
573 next: {
574 if (is_splittable) blocks: {
575 if (filtered_nlists.len == 0) break :blocks;
576
577 // If the first nlist does not match the start of the section,
578 // then we need to encapsulate the memory range [section start, first symbol)
579 // as a temporary symbol and insert the matching TextBlock.
580 const first_nlist = filtered_nlists[0].nlist;
581 if (first_nlist.n_value > sect.addr) {
582 const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
583 self.name.?,
584 segmentName(sect),
585 sectionName(sect),
586 });
587 defer self.allocator.free(sym_name);
588
589 const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {
590 const block_local_sym_index = @intCast(u32, macho_file.locals.items.len);
591 try macho_file.locals.append(macho_file.base.allocator, .{
592 .n_strx = try macho_file.makeString(sym_name),
593 .n_type = macho.N_SECT,
594 .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable,
595 .n_desc = 0,
596 .n_value = sect.addr,
597 });
598 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, block_local_sym_index);
599 break :blk block_local_sym_index;
600 };
601
602 const block_code = code[0 .. first_nlist.n_value - sect.addr];
603 const block_size = block_code.len;
604
605 const block = try macho_file.base.allocator.create(TextBlock);
606 block.* = TextBlock.empty;
607 block.local_sym_index = block_local_sym_index;
608 block.size = block_size;
609 block.alignment = sect.@"align";
610 try macho_file.managed_blocks.append(macho_file.base.allocator, block);
611
612 try block.code.appendSlice(macho_file.base.allocator, block_code);
613
614 try block.parseRelocsFromObject(self.allocator, relocs, self, .{
615 .base_addr = 0,
616 .macho_file = macho_file,
617 });
618
619 if (macho_file.has_dices) {
620 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
621 try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len);
622
623 for (dices) |dice| {
624 block.dices.appendAssumeCapacity(.{
625 .offset = dice.offset - try math.cast(u32, sect.addr),
626 .length = dice.length,
627 .kind = dice.kind,
628 });
629 }
630 }
631
632 // Update target section's metadata
633 // TODO should we update segment's size here too?
634 // How does it tie with incremental space allocs?
635 const tseg = &macho_file.load_commands.items[match.seg].Segment;
636 const tsect = &tseg.sections.items[match.sect];
637 const new_alignment = math.max(tsect.@"align", block.alignment);
638 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
639 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
640 tsect.size = new_size;
641 tsect.@"align" = new_alignment;
642
643 if (macho_file.blocks.getPtr(match)) |last| {
644 last.*.next = block;
645 block.prev = last.*;
646 last.* = block;
647 } else {
648 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
649 }
650
651 try self.text_blocks.append(self.allocator, block);
652 }
653
654 var parser = TextBlockParser{
655 .allocator = self.allocator,
656 .section = sect,
657 .code = code,
658 .relocs = relocs,
659 .object = self,
660 .macho_file = macho_file,
661 .nlists = filtered_nlists,
662 .match = match,
663 };
664
665 while (try parser.next()) |block| {
666 const sym = macho_file.locals.items[block.local_sym_index];
667 const is_ext = blk: {
668 const orig_sym_id = self.reverse_symbol_mapping.get(block.local_sym_index) orelse unreachable;
669 break :blk MachO.symbolIsExt(self.symtab.items[orig_sym_id]);
670 };
671 if (is_ext) {
672 if (macho_file.symbol_resolver.get(sym.n_strx)) |resolv| {
673 assert(resolv.where == .global);
674 const global_object = macho_file.objects.items[resolv.file];
675 if (global_object != self) {
676 log.debug("deduping definition of {s} in {s}", .{
677 macho_file.getString(sym.n_strx),
678 self.name.?,
679 });
680 log.debug(" already defined in {s}", .{global_object.name.?});
681 continue;
682 }
683 }
684 }
685
686 if (sym.n_value == sect.addr) {
687 if (self.sections_as_symbols.get(sect_id)) |alias| {
688 // In x86_64 relocs, it can so happen that the compiler refers to the same
689 // atom by both the actual assigned symbol and the start of the section. In this
690 // case, we need to link the two together so add an alias.
691 try block.aliases.append(macho_file.base.allocator, alias);
692 }
693 }
694
695 // Update target section's metadata
696 // TODO should we update segment's size here too?
697 // How does it tie with incremental space allocs?
698 const tseg = &macho_file.load_commands.items[match.seg].Segment;
699 const tsect = &tseg.sections.items[match.sect];
700 const new_alignment = math.max(tsect.@"align", block.alignment);
701 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
702 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
703 tsect.size = new_size;
704 tsect.@"align" = new_alignment;
705
706 if (macho_file.blocks.getPtr(match)) |last| {
707 last.*.next = block;
708 block.prev = last.*;
709 last.* = block;
710 } else {
711 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
712 }
713
714 try self.text_blocks.append(self.allocator, block);
715 }
716
717 break :next;
718 }
720719
721720 // Since there is no symbol to refer to this block, we create
722721 // a temp one, unless we already did that when working out the relocations
......@@ -757,7 +756,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
757756
758757 if (macho_file.has_dices) {
759758 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size);
760 try block.dices.ensureTotalCapacity(self.allocator, dices.len);
759 try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len);
761760
762761 for (dices) |dice| {
763762 block.dices.appendAssumeCapacity(.{
......@@ -820,7 +819,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
820819 block.prev = last.*;
821820 last.* = block;
822821 } else {
823 try macho_file.blocks.putNoClobber(self.allocator, match, block);
822 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
824823 }
825824
826825 try self.text_blocks.append(self.allocator, block);
src/link/MachO/TextBlock.zig+31-45
......@@ -75,6 +75,21 @@ pub const SymbolAtOffset = struct {
7575 local_sym_index: u32,
7676 offset: u64,
7777 stab: ?Stab = null,
78
79 pub fn format(
80 self: SymbolAtOffset,
81 comptime fmt: []const u8,
82 options: std.fmt.FormatOptions,
83 writer: anytype,
84 ) !void {
85 _ = fmt;
86 _ = options;
87 try std.fmt.format(writer, "{{ {d}: .offset = {d}", .{ self.local_sym_index, self.offset });
88 if (self.stab) |stab| {
89 try std.fmt.format(writer, ", .stab = {any}", .{stab});
90 }
91 try std.fmt.format(writer, " }}", .{});
92 }
7893};
7994
8095pub const Stab = union(enum) {
......@@ -1150,53 +1165,24 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {
11501165 }
11511166}
11521167
1153pub fn print_this(self: *const TextBlock, macho_file: MachO) void {
1154 log.warn("TextBlock", .{});
1155 log.warn(" {}: {}", .{ self.local_sym_index, macho_file.locals.items[self.local_sym_index] });
1168pub fn format(self: TextBlock, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
1169 _ = fmt;
1170 _ = options;
1171 try std.fmt.format(writer, "TextBlock {{ ", .{});
1172 try std.fmt.format(writer, ".local_sym_index = {d}, ", .{self.local_sym_index});
1173 try std.fmt.format(writer, ".aliases = {any}, ", .{self.aliases.items});
1174 try std.fmt.format(writer, ".contained = {any}, ", .{self.contained.items});
1175 try std.fmt.format(writer, ".code = {*}, ", .{self.code.items});
1176 try std.fmt.format(writer, ".size = {d}, ", .{self.size});
1177 try std.fmt.format(writer, ".alignment = {d}, ", .{self.alignment});
1178 try std.fmt.format(writer, ".relocs = {any}, ", .{self.relocs.items});
1179 try std.fmt.format(writer, ".rebases = {any}, ", .{self.rebases.items});
1180 try std.fmt.format(writer, ".bindings = {any}, ", .{self.bindings.items});
1181 try std.fmt.format(writer, ".dices = {any}, ", .{self.dices.items});
11561182 if (self.stab) |stab| {
1157 log.warn(" stab: {}", .{stab});
1158 }
1159 if (self.aliases.items.len > 0) {
1160 log.warn(" aliases: {any}", .{self.aliases.items});
1161 }
1162 if (self.references.count() > 0) {
1163 log.warn(" references: {any}", .{self.references.keys()});
1164 }
1165 if (self.contained) |contained| {
1166 log.warn(" contained symbols:", .{});
1167 for (contained) |sym_at_off| {
1168 if (sym_at_off.stab) |stab| {
1169 log.warn(" {}: {}, stab: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index, stab });
1170 } else {
1171 log.warn(" {}: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index });
1172 }
1173 }
1174 }
1175 log.warn(" code.len = {}", .{self.code.items.len});
1176 if (self.relocs.items.len > 0) {
1177 log.warn(" relocations:", .{});
1178 for (self.relocs.items) |rel| {
1179 log.warn(" {}", .{rel});
1180 }
1181 }
1182 if (self.rebases.items.len > 0) {
1183 log.warn(" rebases: {any}", .{self.rebases.items});
1184 }
1185 if (self.bindings.items.len > 0) {
1186 log.warn(" bindings: {any}", .{self.bindings.items});
1187 }
1188 if (self.dices.items.len > 0) {
1189 log.warn(" dices: {any}", .{self.dices.items});
1190 }
1191 log.warn(" size = {}", .{self.size});
1192 log.warn(" align = {}", .{self.alignment});
1193}
1194
1195pub fn print(self: *const TextBlock, macho_file: MachO) void {
1196 if (self.prev) |prev| {
1197 prev.print(macho_file);
1183 try std.fmt.format(writer, ".stab = {any}, ", .{stab});
11981184 }
1199 self.print_this(macho_file);
1185 try std.fmt.format(writer, "}}", .{});
12001186}
12011187
12021188const RelocIterator = struct {