Commit 1beda818e1
Changed files (3)
src
link
src/link/MachO/Object.zig
@@ -55,7 +55,11 @@ mtime: ?u64 = null,
text_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{},
+
+// TODO symbol mapping and its inverse can probably be simple arrays
+// instead of hash maps.
symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},
+reverse_symbol_mapping: std.AutoHashMapUnmanaged(u32, u32) = .{},
const DebugInfo = struct {
inner: dwarf.DwarfInfo,
@@ -164,6 +168,7 @@ pub fn deinit(self: *Object) void {
self.text_blocks.deinit(self.allocator);
self.sections_as_symbols.deinit(self.allocator);
self.symbol_mapping.deinit(self.allocator);
+ self.reverse_symbol_mapping.deinit(self.allocator);
if (self.debug_info) |*db| {
db.deinit(self.allocator);
@@ -367,7 +372,7 @@ const TextBlockParser = struct {
} else if (MachO.symbolIsPext(rhs.nlist) or MachO.symbolIsWeakDef(rhs.nlist)) {
return !MachO.symbolIsExt(lhs.nlist);
} else {
- return true;
+ return false;
}
}
@@ -392,15 +397,7 @@ const TextBlockParser = struct {
} else null;
for (aliases.items) |*nlist_with_index| {
- nlist_with_index.index = self.symbol_mapping.get(nlist_with_index.index);
- const sym = self.object.symbols.items[nlist_with_index.index];
- if (sym.payload != .regular) {
- log.err("expected a regular symbol, found {s}", .{sym.payload});
- log.err(" when remapping {s}", .{self.macho_file.getString(sym.strx)});
- return error.SymbolIsNotRegular;
- }
- assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.
- nlist_with_index.index = sym.payload.regular.local_sym_index;
+ nlist_with_index.index = self.object.symbol_mapping.get(nlist_with_index.index) orelse unreachable;
}
if (aliases.items.len > 1) {
@@ -409,15 +406,13 @@ const TextBlockParser = struct {
NlistWithIndex,
aliases.items,
SeniorityContext{ .object = self.object },
- @This().lessThanBySeniority,
+ TextBlockParser.lessThanBySeniority,
);
}
const senior_nlist = aliases.pop();
- const senior_sym = self.macho_file.locals.items[senior_nlist.index];
- assert(senior_sym.payload == .regular);
- senior_sym.payload.regular.segment_id = self.match.seg;
- senior_sym.payload.regular.section_id = self.match.sect;
+ const senior_sym = &self.macho_file.locals.items[senior_nlist.index];
+ senior_sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable;
const start_addr = senior_nlist.nlist.n_value - self.section.addr;
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 {
}
}
}
- if (self.macho_file.globals.contains(self.macho_file.getString(senior_sym.strx))) break :blk .global;
+ // TODO
+ // if (self.macho_file.globals.contains(self.macho_file.getString(senior_sym.strx))) break :blk .global;
break :blk .static;
} else null;
- const block = try self.allocator.create(TextBlock);
- errdefer self.allocator.destroy(block);
-
- block.* = TextBlock.init(self.allocator);
+ const block = try self.macho_file.base.allocator.create(TextBlock);
+ block.* = TextBlock.empty;
block.local_sym_index = senior_nlist.index;
block.stab = stab;
- block.code = try self.allocator.dupe(u8, code);
block.size = size;
block.alignment = actual_align;
+ try self.macho_file.managed_blocks.append(self.macho_file.base.allocator, block);
- if (aliases.items.len > 0) {
- try block.aliases.ensureTotalCapacity(aliases.items.len);
- for (aliases.items) |alias| {
- block.aliases.appendAssumeCapacity(alias.index);
+ try block.code.appendSlice(self.macho_file.base.allocator, code);
- const sym = self.macho_file.locals.items[alias.index];
- const reg = &sym.payload.regular;
- reg.segment_id = self.match.seg;
- reg.section_id = self.match.sect;
- }
+ try block.aliases.ensureTotalCapacity(self.macho_file.base.allocator, aliases.items.len);
+ for (aliases.items) |alias| {
+ block.aliases.appendAssumeCapacity(alias.index);
+ const sym = &self.macho_file.locals.items[alias.index];
+ sym.n_sect = self.macho_file.section_to_ordinal.get(self.match) orelse unreachable;
}
- try block.parseRelocsFromObject(self.allocator, relocs, object, .{
+ try block.parseRelocsFromObject(self.macho_file.base.allocator, self.relocs, self.object, .{
.base_addr = start_addr,
.macho_file = self.macho_file,
});
@@ -479,7 +470,7 @@ const TextBlockParser = struct {
senior_nlist.nlist.n_value,
senior_nlist.nlist.n_value + size,
);
- try block.dices.ensureTotalCapacity(dices.len);
+ try block.dices.ensureTotalCapacity(self.macho_file.base.allocator, dices.len);
for (dices) |dice| {
block.dices.appendAssumeCapacity(.{
@@ -518,10 +509,22 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
sort.sort(NlistWithIndex, sorted_all_nlists.items, {}, NlistWithIndex.lessThan);
- const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
+ // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
+ // have to infer the start of undef section in the symtab ourselves.
+ const iundefsym = if (self.dysymtab_cmd_index) |cmd_index| blk: {
+ const dysymtab = self.load_commands.items[cmd_index].Dysymtab;
+ break :blk dysymtab.iundefsym;
+ } else blk: {
+ var iundefsym: usize = sorted_all_nlists.items.len;
+ while (iundefsym > 0) : (iundefsym -= 1) {
+ const nlist = sorted_all_nlists.items[iundefsym];
+ if (MachO.symbolIsSect(nlist.nlist)) break;
+ }
+ break :blk iundefsym;
+ };
// We only care about defined symbols, so filter every other out.
- const sorted_nlists = sorted_all_nlists.items[dysymtab.ilocalsym..dysymtab.iundefsym];
+ const sorted_nlists = sorted_all_nlists.items[0..iundefsym];
for (seg.sections.items) |sect, id| {
const sect_id = @intCast(u8, id);
@@ -550,11 +553,12 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
// Symbols within this section only.
const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists, sect);
- // Is there any padding between symbols within the section?
- // const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
- // TODO is it perhaps worth skip parsing subsections in Debug mode and not worry about
- // duplicates at all? Need some benchmarks!
- // const is_splittable = false;
+ // In release mode, if the object file was generated with dead code stripping optimisations,
+ // note it now and parse sections as atoms.
+ const is_splittable = blk: {
+ if (macho_file.base.options.optimize_mode == .Debug) break :blk false;
+ break :blk self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
+ };
macho_file.has_dices = blk: {
if (self.text_section_index) |index| {
@@ -566,157 +570,152 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
};
macho_file.has_stabs = macho_file.has_stabs or self.debug_info != null;
- {
- // next: {
- // if (is_splittable) blocks: {
- // if (filtered_nlists.len == 0) break :blocks;
-
- // // If the first nlist does not match the start of the section,
- // // then we need encapsulate the memory range [section start, first symbol)
- // // as a temporary symbol and insert the matching TextBlock.
- // const first_nlist = filtered_nlists[0].nlist;
- // if (first_nlist.n_value > sect.addr) {
- // const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: {
- // const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
- // self.name.?,
- // segmentName(sect),
- // sectionName(sect),
- // });
- // defer self.allocator.free(name);
- // const symbol = try zld.allocator.create(Symbol);
- // symbol.* = .{
- // .strx = try zld.makeString(name),
- // .payload = .{ .undef = .{} },
- // };
- // try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
- // break :symbol symbol;
- // };
-
- // const local_sym_index = @intCast(u32, zld.locals.items.len);
- // symbol.payload = .{
- // .regular = .{
- // .linkage = .translation_unit,
- // .address = sect.addr,
- // .segment_id = match.seg,
- // .section_id = match.sect,
- // .file = self,
- // .local_sym_index = local_sym_index,
- // },
- // };
- // try zld.locals.append(zld.allocator, symbol);
-
- // const block_code = code[0 .. first_nlist.n_value - sect.addr];
- // const block_size = block_code.len;
-
- // const block = try self.allocator.create(TextBlock);
- // errdefer self.allocator.destroy(block);
-
- // block.* = TextBlock.init(self.allocator);
- // block.local_sym_index = local_sym_index;
- // block.code = try self.allocator.dupe(u8, block_code);
- // block.size = block_size;
- // block.alignment = sect.@"align";
-
- // const block_relocs = filterRelocs(relocs, 0, block_size);
- // if (block_relocs.len > 0) {
- // try self.parseRelocs(zld, block_relocs, block, 0);
- // }
-
- // if (zld.has_dices) {
- // const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
- // try block.dices.ensureTotalCapacity(dices.len);
-
- // for (dices) |dice| {
- // block.dices.appendAssumeCapacity(.{
- // .offset = dice.offset - try math.cast(u32, sect.addr),
- // .length = dice.length,
- // .kind = dice.kind,
- // });
- // }
- // }
-
- // // Update target section's metadata
- // // TODO should we update segment's size here too?
- // // How does it tie with incremental space allocs?
- // const tseg = &zld.load_commands.items[match.seg].Segment;
- // const tsect = &tseg.sections.items[match.sect];
- // const new_alignment = math.max(tsect.@"align", block.alignment);
- // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
- // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
- // tsect.size = new_size;
- // tsect.@"align" = new_alignment;
-
- // if (zld.blocks.getPtr(match)) |last| {
- // last.*.next = block;
- // block.prev = last.*;
- // last.* = block;
- // } else {
- // try zld.blocks.putNoClobber(zld.allocator, match, block);
- // }
-
- // try self.text_blocks.append(self.allocator, block);
- // }
-
- // var parser = TextBlockParser{
- // .allocator = self.allocator,
- // .section = sect,
- // .code = code,
- // .relocs = relocs,
- // .object = self,
- // .zld = zld,
- // .nlists = filtered_nlists,
- // .match = match,
- // };
-
- // while (try parser.next()) |block| {
- // const sym = zld.locals.items[block.local_sym_index];
- // const reg = &sym.payload.regular;
- // if (reg.file) |file| {
- // if (file != self) {
- // log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? });
- // block.deinit();
- // self.allocator.destroy(block);
- // continue;
- // }
- // }
-
- // if (reg.address == sect.addr) {
- // if (self.sections_as_symbols.get(sect_id)) |alias| {
- // // Add alias.
- // const local_sym_index = @intCast(u32, zld.locals.items.len);
- // const reg_alias = &alias.payload.regular;
- // reg_alias.segment_id = match.seg;
- // reg_alias.section_id = match.sect;
- // reg_alias.local_sym_index = local_sym_index;
- // try block.aliases.append(local_sym_index);
- // try zld.locals.append(zld.allocator, alias);
- // }
- // }
-
- // // Update target section's metadata
- // // TODO should we update segment's size here too?
- // // How does it tie with incremental space allocs?
- // const tseg = &zld.load_commands.items[match.seg].Segment;
- // const tsect = &tseg.sections.items[match.sect];
- // const new_alignment = math.max(tsect.@"align", block.alignment);
- // const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
- // const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
- // tsect.size = new_size;
- // tsect.@"align" = new_alignment;
-
- // if (zld.blocks.getPtr(match)) |last| {
- // last.*.next = block;
- // block.prev = last.*;
- // last.* = block;
- // } else {
- // try zld.blocks.putNoClobber(zld.allocator, match, block);
- // }
-
- // try self.text_blocks.append(self.allocator, block);
- // }
-
- // break :next;
- // }
+ next: {
+ if (is_splittable) blocks: {
+ if (filtered_nlists.len == 0) break :blocks;
+
+ // If the first nlist does not match the start of the section,
+ // then we need to encapsulate the memory range [section start, first symbol)
+ // as a temporary symbol and insert the matching TextBlock.
+ const first_nlist = filtered_nlists[0].nlist;
+ if (first_nlist.n_value > sect.addr) {
+ const sym_name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{
+ self.name.?,
+ segmentName(sect),
+ sectionName(sect),
+ });
+ defer self.allocator.free(sym_name);
+
+ const block_local_sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {
+ const block_local_sym_index = @intCast(u32, macho_file.locals.items.len);
+ try macho_file.locals.append(macho_file.base.allocator, .{
+ .n_strx = try macho_file.makeString(sym_name),
+ .n_type = macho.N_SECT,
+ .n_sect = macho_file.section_to_ordinal.get(match) orelse unreachable,
+ .n_desc = 0,
+ .n_value = sect.addr,
+ });
+ try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, block_local_sym_index);
+ break :blk block_local_sym_index;
+ };
+
+ const block_code = code[0 .. first_nlist.n_value - sect.addr];
+ const block_size = block_code.len;
+
+ const block = try macho_file.base.allocator.create(TextBlock);
+ block.* = TextBlock.empty;
+ block.local_sym_index = block_local_sym_index;
+ block.size = block_size;
+ block.alignment = sect.@"align";
+ try macho_file.managed_blocks.append(macho_file.base.allocator, block);
+
+ try block.code.appendSlice(macho_file.base.allocator, block_code);
+
+ try block.parseRelocsFromObject(self.allocator, relocs, self, .{
+ .base_addr = 0,
+ .macho_file = macho_file,
+ });
+
+ if (macho_file.has_dices) {
+ const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + block_size);
+ try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len);
+
+ for (dices) |dice| {
+ block.dices.appendAssumeCapacity(.{
+ .offset = dice.offset - try math.cast(u32, sect.addr),
+ .length = dice.length,
+ .kind = dice.kind,
+ });
+ }
+ }
+
+ // Update target section's metadata
+ // TODO should we update segment's size here too?
+ // How does it tie with incremental space allocs?
+ const tseg = &macho_file.load_commands.items[match.seg].Segment;
+ const tsect = &tseg.sections.items[match.sect];
+ const new_alignment = math.max(tsect.@"align", block.alignment);
+ const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
+ const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
+ tsect.size = new_size;
+ tsect.@"align" = new_alignment;
+
+ if (macho_file.blocks.getPtr(match)) |last| {
+ last.*.next = block;
+ block.prev = last.*;
+ last.* = block;
+ } else {
+ try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
+ }
+
+ try self.text_blocks.append(self.allocator, block);
+ }
+
+ var parser = TextBlockParser{
+ .allocator = self.allocator,
+ .section = sect,
+ .code = code,
+ .relocs = relocs,
+ .object = self,
+ .macho_file = macho_file,
+ .nlists = filtered_nlists,
+ .match = match,
+ };
+
+ while (try parser.next()) |block| {
+ const sym = macho_file.locals.items[block.local_sym_index];
+ const is_ext = blk: {
+ const orig_sym_id = self.reverse_symbol_mapping.get(block.local_sym_index) orelse unreachable;
+ break :blk MachO.symbolIsExt(self.symtab.items[orig_sym_id]);
+ };
+ if (is_ext) {
+ if (macho_file.symbol_resolver.get(sym.n_strx)) |resolv| {
+ assert(resolv.where == .global);
+ const global_object = macho_file.objects.items[resolv.file];
+ if (global_object != self) {
+ log.debug("deduping definition of {s} in {s}", .{
+ macho_file.getString(sym.n_strx),
+ self.name.?,
+ });
+ log.debug(" already defined in {s}", .{global_object.name.?});
+ continue;
+ }
+ }
+ }
+
+ if (sym.n_value == sect.addr) {
+ if (self.sections_as_symbols.get(sect_id)) |alias| {
+ // In x86_64 relocs, it can so happen that the compiler refers to the same
+ // atom by both the actual assigned symbol and the start of the section. In this
+ // case, we need to link the two together so add an alias.
+ try block.aliases.append(macho_file.base.allocator, alias);
+ }
+ }
+
+ // Update target section's metadata
+ // TODO should we update segment's size here too?
+ // How does it tie with incremental space allocs?
+ const tseg = &macho_file.load_commands.items[match.seg].Segment;
+ const tsect = &tseg.sections.items[match.sect];
+ const new_alignment = math.max(tsect.@"align", block.alignment);
+ const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
+ const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
+ tsect.size = new_size;
+ tsect.@"align" = new_alignment;
+
+ if (macho_file.blocks.getPtr(match)) |last| {
+ last.*.next = block;
+ block.prev = last.*;
+ last.* = block;
+ } else {
+ try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
+ }
+
+ try self.text_blocks.append(self.allocator, block);
+ }
+
+ break :next;
+ }
// Since there is no symbol to refer to this block, we create
// 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 {
if (macho_file.has_dices) {
const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size);
- try block.dices.ensureTotalCapacity(self.allocator, dices.len);
+ try block.dices.ensureTotalCapacity(macho_file.base.allocator, dices.len);
for (dices) |dice| {
block.dices.appendAssumeCapacity(.{
@@ -820,7 +819,7 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
block.prev = last.*;
last.* = block;
} else {
- try macho_file.blocks.putNoClobber(self.allocator, match, block);
+ try macho_file.blocks.putNoClobber(macho_file.base.allocator, match, block);
}
try self.text_blocks.append(self.allocator, block);
src/link/MachO/TextBlock.zig
@@ -75,6 +75,21 @@ pub const SymbolAtOffset = struct {
local_sym_index: u32,
offset: u64,
stab: ?Stab = null,
+
+ pub fn format(
+ self: SymbolAtOffset,
+ comptime fmt: []const u8,
+ options: std.fmt.FormatOptions,
+ writer: anytype,
+ ) !void {
+ _ = fmt;
+ _ = options;
+ try std.fmt.format(writer, "{{ {d}: .offset = {d}", .{ self.local_sym_index, self.offset });
+ if (self.stab) |stab| {
+ try std.fmt.format(writer, ", .stab = {any}", .{stab});
+ }
+ try std.fmt.format(writer, " }}", .{});
+ }
};
pub const Stab = union(enum) {
@@ -1150,53 +1165,24 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {
}
}
-pub fn print_this(self: *const TextBlock, macho_file: MachO) void {
- log.warn("TextBlock", .{});
- log.warn(" {}: {}", .{ self.local_sym_index, macho_file.locals.items[self.local_sym_index] });
+pub fn format(self: TextBlock, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
+ _ = fmt;
+ _ = options;
+ try std.fmt.format(writer, "TextBlock {{ ", .{});
+ try std.fmt.format(writer, ".local_sym_index = {d}, ", .{self.local_sym_index});
+ try std.fmt.format(writer, ".aliases = {any}, ", .{self.aliases.items});
+ try std.fmt.format(writer, ".contained = {any}, ", .{self.contained.items});
+ try std.fmt.format(writer, ".code = {*}, ", .{self.code.items});
+ try std.fmt.format(writer, ".size = {d}, ", .{self.size});
+ try std.fmt.format(writer, ".alignment = {d}, ", .{self.alignment});
+ try std.fmt.format(writer, ".relocs = {any}, ", .{self.relocs.items});
+ try std.fmt.format(writer, ".rebases = {any}, ", .{self.rebases.items});
+ try std.fmt.format(writer, ".bindings = {any}, ", .{self.bindings.items});
+ try std.fmt.format(writer, ".dices = {any}, ", .{self.dices.items});
if (self.stab) |stab| {
- log.warn(" stab: {}", .{stab});
- }
- if (self.aliases.items.len > 0) {
- log.warn(" aliases: {any}", .{self.aliases.items});
- }
- if (self.references.count() > 0) {
- log.warn(" references: {any}", .{self.references.keys()});
- }
- if (self.contained) |contained| {
- log.warn(" contained symbols:", .{});
- for (contained) |sym_at_off| {
- if (sym_at_off.stab) |stab| {
- log.warn(" {}: {}, stab: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index, stab });
- } else {
- log.warn(" {}: {}", .{ sym_at_off.offset, sym_at_off.local_sym_index });
- }
- }
- }
- log.warn(" code.len = {}", .{self.code.items.len});
- if (self.relocs.items.len > 0) {
- log.warn(" relocations:", .{});
- for (self.relocs.items) |rel| {
- log.warn(" {}", .{rel});
- }
- }
- if (self.rebases.items.len > 0) {
- log.warn(" rebases: {any}", .{self.rebases.items});
- }
- if (self.bindings.items.len > 0) {
- log.warn(" bindings: {any}", .{self.bindings.items});
- }
- if (self.dices.items.len > 0) {
- log.warn(" dices: {any}", .{self.dices.items});
- }
- log.warn(" size = {}", .{self.size});
- log.warn(" align = {}", .{self.alignment});
-}
-
-pub fn print(self: *const TextBlock, macho_file: MachO) void {
- if (self.prev) |prev| {
- prev.print(macho_file);
+ try std.fmt.format(writer, ".stab = {any}, ", .{stab});
}
- self.print_this(macho_file);
+ try std.fmt.format(writer, "}}", .{});
}
const RelocIterator = struct {
src/link/MachO.zig
@@ -965,60 +965,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
try self.allocateDataSegment();
self.allocateLinkeditSegment();
try self.allocateTextBlocks();
-
- // log.warn("locals", .{});
- // for (self.locals.items) |sym, id| {
- // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
- // }
-
- // log.warn("globals", .{});
- // for (self.globals.items) |sym, id| {
- // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
- // }
-
- // log.warn("tentatives", .{});
- // for (self.tentatives.items) |sym, id| {
- // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
- // }
-
- // log.warn("undefines", .{});
- // for (self.undefs.items) |sym, id| {
- // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
- // }
-
- // log.warn("imports", .{});
- // for (self.imports.items) |sym, id| {
- // log.warn(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
- // }
-
- // log.warn("symbol resolver", .{});
- // for (self.symbol_resolver.keys()) |key| {
- // log.warn(" {s} => {}", .{ key, self.symbol_resolver.get(key).? });
- // }
-
- // log.warn("mappings", .{});
- // for (self.objects.items) |object, id| {
- // const object_id = @intCast(u16, id);
- // log.warn(" in object {s}", .{object.name.?});
- // for (object.symtab.items) |sym, sym_id| {
- // if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| {
- // log.warn(" | {d} => {d}", .{ sym_id, local_id });
- // } else {
- // log.warn(" | {d} no local mapping for {s}", .{ sym_id, object.getString(sym.n_strx) });
- // }
- // }
- // }
-
- // var it = self.blocks.iterator();
- // while (it.next()) |entry| {
- // const seg = self.load_commands.items[entry.key_ptr.seg].Segment;
- // const sect = seg.sections.items[entry.key_ptr.sect];
-
- // log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
- // log.warn(" {}", .{sect});
- // entry.value_ptr.*.print(self);
- // }
-
+ self.printSymtabAndTextBlock();
try self.flushZld();
}
@@ -2086,6 +2033,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
.n_value = sym.n_value,
});
try object.symbol_mapping.putNoClobber(self.base.allocator, sym_id, local_sym_index);
+ try object.reverse_symbol_mapping.putNoClobber(self.base.allocator, local_sym_index, sym_id);
// If the symbol's scope is not local aka translation unit, then we need work out
// 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 {
try self.section_ordinals.append(self.base.allocator, match);
try self.section_to_ordinal.putNoClobber(self.base.allocator, match, ordinal);
}
+
+fn printSymtabAndTextBlock(self: *MachO) void {
+ log.debug("locals", .{});
+ for (self.locals.items) |sym, id| {
+ log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
+ }
+
+ log.debug("globals", .{});
+ for (self.globals.items) |sym, id| {
+ log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
+ }
+
+ log.debug("tentatives", .{});
+ for (self.tentatives.items) |sym, id| {
+ log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
+ }
+
+ log.debug("undefines", .{});
+ for (self.undefs.items) |sym, id| {
+ log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
+ }
+
+ log.debug("imports", .{});
+ for (self.imports.items) |sym, id| {
+ log.debug(" {d}: {s}, {}", .{ id, self.getString(sym.n_strx), sym });
+ }
+
+ {
+ log.debug("symbol resolver", .{});
+ var it = self.symbol_resolver.keyIterator();
+ while (it.next()) |key_ptr| {
+ const sym_name = self.getString(key_ptr.*);
+ log.debug(" {s} => {}", .{ sym_name, self.symbol_resolver.get(key_ptr.*).? });
+ }
+ }
+
+ log.debug("mappings", .{});
+ for (self.objects.items) |object| {
+ log.debug(" in object {s}", .{object.name.?});
+ for (object.symtab.items) |sym, sym_id| {
+ if (object.symbol_mapping.get(@intCast(u32, sym_id))) |local_id| {
+ log.debug(" | {d} => {d}", .{ sym_id, local_id });
+ } else {
+ log.debug(" | {d} no local mapping for {s}", .{ sym_id, object.getString(sym.n_strx) });
+ }
+ }
+ }
+
+ {
+ var it = self.blocks.iterator();
+ while (it.next()) |entry| {
+ const seg = self.load_commands.items[entry.key_ptr.seg].Segment;
+ const sect = seg.sections.items[entry.key_ptr.sect];
+
+ var block: *TextBlock = entry.value_ptr.*;
+
+ log.debug("\n\n{s},{s} contents:", .{ commands.segmentName(sect), commands.sectionName(sect) });
+ log.debug("{}", .{sect});
+ log.debug("{}", .{block});
+
+ while (block.prev) |prev| {
+ block = prev;
+ log.debug("{}", .{block});
+ }
+ }
+ }
+}