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 {...@@ -965,60 +965,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
965 try self.allocateDataSegment();965 try self.allocateDataSegment();
966 self.allocateLinkeditSegment();966 self.allocateLinkeditSegment();
967 try self.allocateTextBlocks();967 try self.allocateTextBlocks();
968968 self.printSymtabAndTextBlock();
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
1022 try self.flushZld();969 try self.flushZld();
1023 }970 }
1024971
...@@ -2086,6 +2033,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2086,6 +2033,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2086 .n_value = sym.n_value,2033 .n_value = sym.n_value,
2087 });2034 });
2088 try object.symbol_mapping.putNoClobber(self.base.allocator, sym_id, local_sym_index);2035 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
2090 // If the symbol's scope is not local aka translation unit, then we need work out2038 // If the symbol's scope is not local aka translation unit, then we need work out
2091 // if we should save the symbol as a global, or potentially flag the error.2039 // 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 {...@@ -5916,3 +5864,70 @@ fn createSectionOrdinal(self: *MachO, match: MatchingSection) !void {
5916 try self.section_ordinals.append(self.base.allocator, match);5864 try self.section_ordinals.append(self.base.allocator, match);
5917 try self.section_to_ordinal.putNoClobber(self.base.allocator, match, ordinal);5865 try self.section_to_ordinal.putNoClobber(self.base.allocator, match, ordinal);
5918}5866}
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,...@@ -55,7 +55,11 @@ mtime: ?u64 = null,
5555
56text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},56text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
57sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{},57sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{},
58
59// TODO symbol mapping and its inverse can probably be simple arrays
60// instead of hash maps.
58symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},61symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},
62reverse_symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},
5963
60const DebugInfo = struct {64const DebugInfo = struct {
61 inner: dwarf.DwarfInfo,65 inner: dwarf.DwarfInfo,
...@@ -164,6 +168,7 @@ pub fn deinit(self: *Object) void {...@@ -164,6 +168,7 @@ pub fn deinit(self: *Object) void {
164 self.text_blocks.deinit(self.allocator);168 self.text_blocks.deinit(self.allocator);
165 self.sections_as_symbols.deinit(self.allocator);169 self.sections_as_symbols.deinit(self.allocator);
166 self.symbol_mapping.deinit(self.allocator);170 self.symbol_mapping.deinit(self.allocator);
171 self.reverse_symbol_mapping.deinit(self.allocator);
167172
168 if (self.debug_info) |*db| {173 if (self.debug_info) |*db| {
169 db.deinit(self.allocator);174 db.deinit(self.allocator);
...@@ -367,7 +372,7 @@ const TextBlockParser = struct {...@@ -367,7 +372,7 @@ const TextBlockParser = struct {
367 } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) {372 } else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) {
368 return !MachO.symbolIsExt(lhs.nlist);373 return !MachO.symbolIsExt(lhs.nlist);
369 } else {374 } else {
370 return true;375 return false;
371 }376 }
372 }377 }
373378
...@@ -392,15 +397,7 @@ const TextBlockParser = struct {...@@ -392,15 +397,7 @@ const TextBlockParser = struct {
392 } else null;397 } else null;
393398
394 for (aliases.items) |*nlist_with_index| {399 for (aliases.items) |*nlist_with_index| {
395 nlist_with_index.index = self.symbol_mapping.get(nlist_with_index.index);400 nlist_with_index.index = self.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable;
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;
404 }401 }
405402
406 if (aliases.items.len > 1) {403 if (aliases.items.len > 1) {
...@@ -409,15 +406,13 @@ const TextBlockParser = struct {...@@ -409,15 +406,13 @@ const TextBlockParser = struct {
409 NlistWithIndex,406 NlistWithIndex,
410 aliases.items,407 aliases.items,
411 SeniorityContext{ .object = self.object },408 SeniorityContext{ .object = self.object },
412 @This().lessThanBySeniority,409 TextBlockParser.lessThanBySeniority,
413 );410 );
414 }411 }
415412
416 const senior_nlist = aliases.pop();413 const senior_nlist = aliases.pop();
417 const senior_sym = self.macho_file.locals.items[senior_nlist.index];414 const senior_sym = &self.macho_file.locals.items[senior_nlist.index];
418 assert(senior_sym.payload == .regular);415 senior_sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable;
419 senior_sym.payload.regular.segment_id = self.match.seg;
420 senior_sym.payload.regular.section_id = self.match.sect;
421416
422 const start_addr = senior_nlist.nlist.n_value - self.section.addr;417 const start_addr = senior_nlist.nlist.n_value - self.section.addr;
423 const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size;418 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 {...@@ -442,33 +437,29 @@ const TextBlockParser = struct {
442 }437 }
443 }438 }
444 }439 }
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;
446 break :blk .static;442 break :blk .static;
447 } else null;443 } else null;
448444
449 const block = try self.allocator.create(TextBlock);445 const block = try self.macho_file.base.allocator.create(TextBlock);
450 errdefer self.allocator.destroy(block);446 block.* = TextBlock.empty;
451
452 block.* = TextBlock.init(self.allocator);
453 block.local_sym_index = senior_nlist.index;447 block.local_sym_index = senior_nlist.index;
454 block.stab = stab;448 block.stab = stab;
455 block.code = try self.allocator.dupe(u8, code);
456 block.size = size;449 block.size = size;
457 block.alignment = actual_align;450 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) {453 try block.code.appendSlice(self.macho_file.base.allocator, code);
460 try block.aliases.ensureTotalCapacity(aliases.items.len);
461 for (aliases.items) |alias| {
462 block.aliases.appendAssumeCapacity(alias.index);
463454
464 const sym = self.macho_file.locals.items[alias.index];455 try block.aliases.ensureTotalCapacity(self.macho_file.base.allocator, aliases.items.len);
465 const reg = &sym.payload.regular;456 for (aliases.items) |alias| {
466 reg.segment_id = self.match.seg;457 block.aliases.appendAssumeCapacity(alias.index);
467 reg.section_id = self.match.sect;458 const sym = &self.macho_file.locals.items[alias.index];
468 }459 sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable;
469 }460 }
470461
471 try block.parseRelocsFromObject(self.allocator, relocs, object, .{462 try block.parseRelocsFromObject(self.macho_file.base.allocator, self.relocs, self.object, .{
472 .base_addr = start_addr,463 .base_addr = start_addr,
473 .macho_file = self.macho_file,464 .macho_file = self.macho_file,
474 });465 });
...@@ -479,7 +470,7 @@ const TextBlockParser = struct {...@@ -479,7 +470,7 @@ const TextBlockParser = struct {
479 senior_nlist.nlist.n_value,470 senior_nlist.nlist.n_value,
480 senior_nlist.nlist.n_value + size,471 senior_nlist.nlist.n_value + size,
481 );472 );
482 try block.dices.ensureTotalCapacity(dices.len);473 try block.dices.ensureTotalCapacity(self.macho_file.base.allocator, dices.len);
483474
484 for (dices) |dice| {475 for (dices) |dice| {
485 block.dices.appendAssumeCapacity(.{476 block.dices.appendAssumeCapacity(.{
...@@ -518,10 +509,22 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -518,10 +509,22 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
518509
519 sort.sort(NlistWithIndex, sorted_all_nlists.items, {}, NlistWithIndex.lessThan);510 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
523 // We only care about defined symbols, so filter every other out.526 // 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
526 for (seg.sections.items) |sect, id| {529 for (seg.sections.items) |sect, id| {
527 const sect_id = @intCast(u8, id);530 const sect_id = @intCast(u8, id);
...@@ -550,11 +553,12 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -550,11 +553,12 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
550 // Symbols within this section only.553 // Symbols within this section only.
551 const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect);554 const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect);
552555
553 // Is there any padding between symbols within the section?556 // In release mode, if the object file was generated with dead code stripping optimisations,
554 // const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;557 // note it now and parse sections as atoms.
555 // TODO is it perhaps worth skip parsing subsections in Debug mode and not worry about558 const is_splittable = blk: {
556 // duplicates at all? Need some benchmarks!559 if (macho_file.base.options.optimize_mode == .Debug) break :blk false;
557 // const is_splittable = false;560 break :blk self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
561 };
558562
559 macho_file.has_dices = blk: {563 macho_file.has_dices = blk: {
560 if (self.text_section_index) |index| {564 if (self.text_section_index) |index| {
...@@ -566,157 +570,152 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -566,157 +570,152 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
566 };570 };
567 macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null;571 macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null;
568572
569 {573 next: {
570 // next: {574 if (is_splittable) blocks: {
571 // if (is_splittable) blocks: {575 if (filtered_nlists.len == 0) break :blocks;
572 // if (filtered_nlists.len == 0) break :blocks;576
573577 // If the first nlist does not match the start of the section,
574 // // 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)
575 // // then we need encapsulate the memory range [section start, first symbol)579 // as a temporary symbol and insert the matching TextBlock.
576 // // as a temporary symbol and insert the matching TextBlock.580 const first_nlist = filtered_nlists[0].nlist;
577 // const first_nlist = filtered_nlists[0].nlist;581 if (first_nlist.n_value > sect.addr) {
578 // if (first_nlist.n_value > sect.addr) {582 const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
579 // const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {583 self.name.?,
580 // const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{584 segmentName(sect),
581 // self.name.?,585 sectionName(sect),
582 // segmentName(sect),586 });
583 // sectionName(sect),587 defer self.allocator.free(sym_name);
584 // });588
585 // defer self.allocator.free(name);589 const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {
586 // const symbol = try zld.allocator.create(Symbol);590 const block_local_sym_index = @intCast(u32, macho_file.locals.items.len);
587 // symbol.* = .{591 try macho_file.locals.append(macho_file.base.allocator, .{
588 // .strx = try zld.makeString(name),592 .n_strx = try macho_file.makeString(sym_name),
589 // .payload = .{ .undef = .{} },593 .n_type = macho.N_SECT,
590 // };594 .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable,
591 // try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);595 .n_desc = 0,
592 // break :symbol symbol;596 .n_value = sect.addr,
593 // };597 });
594598 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, block_local_sym_index);
595 // const local_sym_index = @intCast(u32, zld.locals.items.len);599 break :blk block_local_sym_index;
596 // symbol.payload = .{600 };
597 // .regular = .{601
598 // .linkage = .translation_unit,602 const block_code = code[0 .. first_nlist.n_value - sect.addr];
599 // .address = sect.addr,603 const block_size = block_code.len;
600 // .segment_id = match.seg,604
601 // .section_id = match.sect,605 const block = try macho_file.base.allocator.create(TextBlock);
602 // .file = self,606 block.* = TextBlock.empty;
603 // .local_sym_index = local_sym_index,607 block.local_sym_index = block_local_sym_index;
604 // },608 block.size = block_size;
605 // };609 block.alignment = sect.@"align";
606 // try zld.locals.append(zld.allocator, symbol);610 try macho_file.managed_blocks.append(macho_file.base.allocator, block);
607611
608 // const block_code = code[0 .. first_nlist.n_value - sect.addr];612 try block.code.appendSlice(macho_file.base.allocator, block_code);
609 // const block_size = block_code.len;613
610614 try block.parseRelocsFromObject(self.allocator, relocs, self, .{
611 // const block = try self.allocator.create(TextBlock);615 .base_addr = 0,
612 // errdefer self.allocator.destroy(block);616 .macho_file = macho_file,
613617 });
614 // block.* = TextBlock.init(self.allocator);618
615 // block.local_sym_index = local_sym_index;619 if (macho_file.has_dices) {
616 // block.code = try self.allocator.dupe(u8, block_code);620 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
617 // block.size = block_size;621 try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len);
618 // block.alignment = sect.@"align";622
619623 for (dices) |dice| {
620 // const block_relocs = filterRelocs(relocs, 0, block_size);624 block.dices.appendAssumeCapacity(.{
621 // if (block_relocs.len > 0) {625 .offset = dice.offset - try math.cast(u32, sect.addr),
622 // try self.parseRelocs(zld, block_relocs, block, 0);626 .length = dice.length,
623 // }627 .kind = dice.kind,
624628 });
625 // if (zld.has_dices) {629 }
626 // const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);630 }
627 // try block.dices.ensureTotalCapacity(dices.len);631
628632 // Update target section's metadata
629 // for (dices) |dice| {633 // TODO should we update segment's size here too?
630 // block.dices.appendAssumeCapacity(.{634 // How does it tie with incremental space allocs?
631 // .offset = dice.offset - try math.cast(u32, sect.addr),635 const tseg = &macho_file.load_commands.items[match.seg].Segment;
632 // .length = dice.length,636 const tsect = &tseg.sections.items[match.sect];
633 // .kind = dice.kind,637 const new_alignment = math.max(tsect.@"align", block.alignment);
634 // });638 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
635 // }639 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
636 // }640 tsect.size = new_size;
637641 tsect.@"align" = new_alignment;
638 // // Update target section's metadata642
639 // // TODO should we update segment's size here too?643 if (macho_file.blocks.getPtr(match)) |last| {
640 // // How does it tie with incremental space allocs?644 last.*.next = block;
641 // const tseg = &zld.load_commands.items[match.seg].Segment;645 block.prev = last.*;
642 // const tsect = &tseg.sections.items[match.sect];646 last.* = block;
643 // const new_alignment = math.max(tsect.@"align", block.alignment);647 } else {
644 // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);648 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
645 // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;649 }
646 // tsect.size = new_size;650
647 // tsect.@"align" = new_alignment;651 try self.text_blocks.append(self.allocator, block);
648652 }
649 // if (zld.blocks.getPtr(match)) |last| {653
650 // last.*.next = block;654 var parser = TextBlockParser{
651 // block.prev = last.*;655 .allocator = self.allocator,
652 // last.* = block;656 .section = sect,
653 // } else {657 .code = code,
654 // try zld.blocks.putNoClobber(zld.allocator, match, block);658 .relocs = relocs,
655 // }659 .object = self,
656660 .macho_file = macho_file,
657 // try self.text_blocks.append(self.allocator, block);661 .nlists = filtered_nlists,
658 // }662 .match = match,
659663 };
660 // var parser = TextBlockParser{664
661 // .allocator = self.allocator,665 while (try parser.next()) |block| {
662 // .section = sect,666 const sym = macho_file.locals.items[block.local_sym_index];
663 // .code = code,667 const is_ext = blk: {
664 // .relocs = relocs,668 const orig_sym_id = self.reverse_symbol_mapping.get(block.local_sym_index) orelse unreachable;
665 // .object = self,669 break :blk MachO.symbolIsExt(self.symtab.items[orig_sym_id]);
666 // .zld = zld,670 };
667 // .nlists = filtered_nlists,671 if (is_ext) {
668 // .match = match,672 if (macho_file.symbol_resolver.get(sym.n_strx)) |resolv| {
669 // };673 assert(resolv.where == .global);
670674 const global_object = macho_file.objects.items[resolv.file];
671 // while (try parser.next()) |block| {675 if (global_object != self) {
672 // const sym = zld.locals.items[block.local_sym_index];676 log.debug("deduping definition of {s} in {s}", .{
673 // const reg = &sym.payload.regular;677 macho_file.getString(sym.n_strx),
674 // if (reg.file) |file| {678 self.name.?,
675 // if (file != self) {679 });
676 // log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? });680 log.debug(" already defined in {s}", .{global_object.name.?});
677 // block.deinit();681 continue;
678 // self.allocator.destroy(block);682 }
679 // continue;683 }
680 // }684 }
681 // }685
682686 if (sym.n_value == sect.addr) {
683 // if (reg.address == sect.addr) {687 if (self.sections_as_symbols.get(sect_id)) |alias| {
684 // 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
685 // // Add alias.689 // atom by both the actual assigned symbol and the start of the section. In this
686 // const local_sym_index = @intCast(u32, zld.locals.items.len);690 // case, we need to link the two together so add an alias.
687 // const reg_alias = &alias.payload.regular;691 try block.aliases.append(macho_file.base.allocator, alias);
688 // reg_alias.segment_id = match.seg;692 }
689 // reg_alias.section_id = match.sect;693 }
690 // reg_alias.local_sym_index = local_sym_index;694
691 // try block.aliases.append(local_sym_index);695 // Update target section's metadata
692 // try zld.locals.append(zld.allocator, alias);696 // TODO should we update segment's size here too?
693 // }697 // How does it tie with incremental space allocs?
694 // }698 const tseg = &macho_file.load_commands.items[match.seg].Segment;
695699 const tsect = &tseg.sections.items[match.sect];
696 // // Update target section's metadata700 const new_alignment = math.max(tsect.@"align", block.alignment);
697 // // TODO should we update segment's size here too?701 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
698 // // How does it tie with incremental space allocs?702 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
699 // const tseg = &zld.load_commands.items[match.seg].Segment;703 tsect.size = new_size;
700 // const tsect = &tseg.sections.items[match.sect];704 tsect.@"align" = new_alignment;
701 // const new_alignment = math.max(tsect.@"align", block.alignment);705
702 // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);706 if (macho_file.blocks.getPtr(match)) |last| {
703 // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;707 last.*.next = block;
704 // tsect.size = new_size;708 block.prev = last.*;
705 // tsect.@"align" = new_alignment;709 last.* = block;
706710 } else {
707 // if (zld.blocks.getPtr(match)) |last| {711 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
708 // last.*.next = block;712 }
709 // block.prev = last.*;713
710 // last.* = block;714 try self.text_blocks.append(self.allocator, block);
711 // } else {715 }
712 // try zld.blocks.putNoClobber(zld.allocator, match, block);716
713 // }717 break :next;
714718 }
715 // try self.text_blocks.append(self.allocator, block);
716 // }
717
718 // break :next;
719 // }
720719
721 // Since there is no symbol to refer to this block, we create720 // Since there is no symbol to refer to this block, we create
722 // a temp one, unless we already did that when working out the relocations721 // 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 {...@@ -757,7 +756,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
757756
758 if (macho_file.has_dices) {757 if (macho_file.has_dices) {
759 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size);758 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
762 for (dices) |dice| {761 for (dices) |dice| {
763 block.dices.appendAssumeCapacity(.{762 block.dices.appendAssumeCapacity(.{
...@@ -820,7 +819,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {...@@ -820,7 +819,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
820 block.prev = last.*;819 block.prev = last.*;
821 last.* = block;820 last.* = block;
822 } else {821 } else {
823 try macho_file.blocks.putNoClobber(self.allocator, match, block);822 try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
824 }823 }
825824
826 try self.text_blocks.append(self.allocator, block);825 try self.text_blocks.append(self.allocator, block);
src/link/MachO/TextBlock.zig+31-45
...@@ -75,6 +75,21 @@ pub const SymbolAtOffset = struct {...@@ -75,6 +75,21 @@ pub const SymbolAtOffset = struct {
75 local_sym_index: u32,75 local_sym_index: u32,
76 offset: u64,76 offset: u64,
77 stab: ?Stab = null,77 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 }
78};93};
7994
80pub const Stab = union(enum) {95pub const Stab = union(enum) {
...@@ -1150,53 +1165,24 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {...@@ -1150,53 +1165,24 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {
1150 }1165 }
1151}1166}
11521167
1153pub fn print_this(self: *const TextBlock, macho_file: MachO) void {1168pub fn format(self: TextBlock, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
1154 log.warn("TextBlock", .{});1169 _ = fmt;
1155 log.warn(" {}: {}", .{ self.local_sym_index, macho_file.locals.items[self.local_sym_index] });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});
1156 if (self.stab) |stab| {1182 if (self.stab) |stab| {
1157 log.warn(" stab: {}", .{stab});1183 try std.fmt.format(writer, ".stab = {any}, ", .{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);
1198 }1184 }
1199 self.print_this(macho_file);1185 try std.fmt.format(writer, "}}", .{});
1200}1186}
12011187
1202const RelocIterator = struct {1188const RelocIterator = struct {