mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
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.
This commit is contained in:
parent
a4feb97cdf
commit
1beda818e1
@ -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});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
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;
|
||||
// };
|
||||
// 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 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_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_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);
|
||||
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);
|
||||
|
||||
// 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";
|
||||
try block.code.appendSlice(macho_file.base.allocator, block_code);
|
||||
|
||||
// const block_relocs = filterRelocs(relocs, 0, block_size);
|
||||
// if (block_relocs.len > 0) {
|
||||
// try self.parseRelocs(zld, block_relocs, block, 0);
|
||||
// }
|
||||
try block.parseRelocsFromObject(self.allocator, relocs, self, .{
|
||||
.base_addr = 0,
|
||||
.macho_file = macho_file,
|
||||
});
|
||||
|
||||
// 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);
|
||||
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,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
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;
|
||||
// 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 (zld.blocks.getPtr(match)) |last| {
|
||||
// last.*.next = block;
|
||||
// block.prev = last.*;
|
||||
// last.* = block;
|
||||
// } else {
|
||||
// try zld.blocks.putNoClobber(zld.allocator, match, block);
|
||||
// }
|
||||
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);
|
||||
// }
|
||||
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,
|
||||
// };
|
||||
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 = 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;
|
||||
// }
|
||||
// }
|
||||
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 (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);
|
||||
// }
|
||||
// }
|
||||
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 = &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;
|
||||
// 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 (zld.blocks.getPtr(match)) |last| {
|
||||
// last.*.next = block;
|
||||
// block.prev = last.*;
|
||||
// last.* = block;
|
||||
// } else {
|
||||
// try zld.blocks.putNoClobber(zld.allocator, match, block);
|
||||
// }
|
||||
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);
|
||||
// }
|
||||
try self.text_blocks.append(self.allocator, block);
|
||||
}
|
||||
|
||||
// break :next;
|
||||
// }
|
||||
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);
|
||||
|
||||
@ -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});
|
||||
try std.fmt.format(writer, ".stab = {any}, ", .{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);
|
||||
}
|
||||
self.print_this(macho_file);
|
||||
try std.fmt.format(writer, "}}", .{});
|
||||
}
|
||||
|
||||
const RelocIterator = struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user