zld: refactor section into TextBlocks conversion
This commit is contained in:
@@ -276,11 +276,11 @@ const NlistWithIndex = struct {
|
||||
nlist: macho.nlist_64,
|
||||
index: u32,
|
||||
|
||||
pub fn cmp(_: void, lhs: @This(), rhs: @This()) bool {
|
||||
fn lessThan(_: void, lhs: @This(), rhs: @This()) bool {
|
||||
return lhs.nlist.n_value < rhs.nlist.n_value;
|
||||
}
|
||||
|
||||
fn filterNlistsInSection(symbols: []@This(), sect_id: u8) []@This() {
|
||||
fn filterInSection(symbols: []@This(), sect_id: u8) []@This() {
|
||||
var start: usize = 0;
|
||||
var end: usize = symbols.len;
|
||||
|
||||
@@ -327,19 +327,111 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r
|
||||
return relocs[start_id..end_id];
|
||||
}
|
||||
|
||||
const SeniorityContext = struct {
|
||||
const TextBlockParser = struct {
|
||||
allocator: *Allocator,
|
||||
section: macho.section_64,
|
||||
code: []u8,
|
||||
object: *Object,
|
||||
zld: *Zld,
|
||||
};
|
||||
fn cmpSymBySeniority(context: SeniorityContext, lhs: u32, rhs: u32) bool {
|
||||
const lreg = context.zld.locals.items[lhs].payload.regular;
|
||||
const rreg = context.zld.locals.items[rhs].payload.regular;
|
||||
nlists: []NlistWithIndex,
|
||||
index: u32 = 0,
|
||||
|
||||
return switch (rreg.linkage) {
|
||||
.global => true,
|
||||
.linkage_unit => lreg.linkage == .translation_unit,
|
||||
else => false,
|
||||
fn peek(self: *TextBlockParser) ?NlistWithIndex {
|
||||
return if (self.index + 1 < self.nlists.len) self.nlists[self.index + 1] else null;
|
||||
}
|
||||
|
||||
const SeniorityContext = struct {
|
||||
zld: *Zld,
|
||||
};
|
||||
}
|
||||
|
||||
fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
|
||||
const lreg = context.zld.locals.items[lhs.index].payload.regular;
|
||||
const rreg = context.zld.locals.items[rhs.index].payload.regular;
|
||||
|
||||
return switch (rreg.linkage) {
|
||||
.global => true,
|
||||
.linkage_unit => lreg.linkage == .translation_unit,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next(self: *TextBlockParser) !?*TextBlock {
|
||||
if (self.index == self.nlists.len) return null;
|
||||
|
||||
var aliases = std.ArrayList(NlistWithIndex).init(self.allocator);
|
||||
defer aliases.deinit();
|
||||
|
||||
const next_nlist: ?NlistWithIndex = blk: while (true) {
|
||||
const curr_nlist = self.nlists[self.index];
|
||||
try aliases.append(curr_nlist);
|
||||
|
||||
if (self.peek()) |next_nlist| {
|
||||
if (curr_nlist.nlist.n_value == next_nlist.nlist.n_value) {
|
||||
self.index += 1;
|
||||
continue;
|
||||
}
|
||||
break :blk next_nlist;
|
||||
}
|
||||
break :blk null;
|
||||
} else null;
|
||||
|
||||
for (aliases.items) |*nlist_with_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}", .{sym.name});
|
||||
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;
|
||||
}
|
||||
|
||||
if (aliases.items.len > 1) {
|
||||
// Bubble-up senior symbol as the main link to the text block.
|
||||
std.sort.sort(
|
||||
NlistWithIndex,
|
||||
aliases.items,
|
||||
SeniorityContext{ .zld = self.zld },
|
||||
@This().lessThanBySeniority,
|
||||
);
|
||||
}
|
||||
|
||||
const senior_nlist = aliases.pop();
|
||||
const senior_sym = self.zld.locals.items[senior_nlist.index];
|
||||
assert(senior_sym.payload == .regular);
|
||||
|
||||
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;
|
||||
|
||||
const code = self.code[start_addr..end_addr];
|
||||
const size = code.len;
|
||||
|
||||
const alias_only_indices = if (aliases.items.len > 0) blk: {
|
||||
var out = std.ArrayList(u32).init(self.allocator);
|
||||
try out.ensureTotalCapacity(aliases.items.len);
|
||||
for (aliases.items) |alias| {
|
||||
out.appendAssumeCapacity(alias.index);
|
||||
}
|
||||
break :blk out.toOwnedSlice();
|
||||
} else null;
|
||||
|
||||
const block = try self.allocator.create(TextBlock);
|
||||
errdefer self.allocator.destroy(block);
|
||||
|
||||
block.* = .{
|
||||
.local_sym_index = senior_nlist.index,
|
||||
.aliases = alias_only_indices,
|
||||
.code = code,
|
||||
.size = size,
|
||||
.alignment = self.section.@"align",
|
||||
};
|
||||
|
||||
self.index += 1;
|
||||
block.print_this(self.zld);
|
||||
|
||||
return block;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
|
||||
const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
|
||||
@@ -361,7 +453,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
|
||||
});
|
||||
}
|
||||
|
||||
std.sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.cmp);
|
||||
std.sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan);
|
||||
|
||||
var last_block: ?*TextBlock = null;
|
||||
|
||||
@@ -385,53 +477,26 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
|
||||
// Is there any padding between symbols within the section?
|
||||
const is_padded = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
|
||||
|
||||
// Section alignment will be the assumed alignment per symbol.
|
||||
const alignment = sect.@"align";
|
||||
|
||||
next: {
|
||||
if (is_padded) blocks: {
|
||||
const filtered_nlists = NlistWithIndex.filterNlistsInSection(
|
||||
const filtered_nlists = NlistWithIndex.filterInSection(
|
||||
sorted_nlists.items,
|
||||
@intCast(u8, sect_id + 1),
|
||||
);
|
||||
|
||||
if (filtered_nlists.len == 0) break :blocks;
|
||||
|
||||
var nlist_indices = std.ArrayList(u32).init(self.allocator);
|
||||
defer nlist_indices.deinit();
|
||||
var parser = TextBlockParser{
|
||||
.allocator = self.allocator,
|
||||
.section = sect,
|
||||
.code = code,
|
||||
.object = self,
|
||||
.zld = zld,
|
||||
.nlists = filtered_nlists,
|
||||
};
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < filtered_nlists.len) : (i += 1) {
|
||||
const curr = filtered_nlists[i];
|
||||
try nlist_indices.append(curr.index);
|
||||
|
||||
const next: ?NlistWithIndex = if (i + 1 < filtered_nlists.len)
|
||||
filtered_nlists[i + 1]
|
||||
else
|
||||
null;
|
||||
|
||||
if (next) |n| {
|
||||
if (curr.nlist.n_value == n.nlist.n_value) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Bubble-up senior symbol as the main link to the text block.
|
||||
for (nlist_indices.items) |*index| {
|
||||
const sym = self.symbols.items[index.*];
|
||||
if (sym.payload != .regular) {
|
||||
log.err("expected a regular symbol, found {s}", .{sym.payload});
|
||||
log.err(" when remapping {s}", .{sym.name});
|
||||
return error.SymbolIsNotRegular;
|
||||
}
|
||||
assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.
|
||||
index.* = sym.payload.regular.local_sym_index;
|
||||
}
|
||||
|
||||
std.sort.sort(u32, nlist_indices.items, SeniorityContext{ .zld = zld }, cmpSymBySeniority);
|
||||
|
||||
const local_sym_index = nlist_indices.pop();
|
||||
const sym = zld.locals.items[local_sym_index];
|
||||
while (try parser.next()) |block| {
|
||||
const sym = zld.locals.items[block.local_sym_index];
|
||||
if (sym.payload.regular.file) |file| {
|
||||
if (file != self) {
|
||||
log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
|
||||
@@ -439,27 +504,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
|
||||
}
|
||||
}
|
||||
|
||||
const start_addr = curr.nlist.n_value - sect.addr;
|
||||
const end_addr = if (next) |n| n.nlist.n_value - sect.addr else sect.size;
|
||||
|
||||
const tb_code = code[start_addr..end_addr];
|
||||
const size = tb_code.len;
|
||||
|
||||
const block = try self.allocator.create(TextBlock);
|
||||
errdefer self.allocator.destroy(block);
|
||||
|
||||
block.* = .{
|
||||
.local_sym_index = local_sym_index,
|
||||
.aliases = std.ArrayList(u32).init(self.allocator),
|
||||
.references = std.ArrayList(u32).init(self.allocator),
|
||||
.code = tb_code,
|
||||
.relocs = std.ArrayList(*Relocation).init(self.allocator),
|
||||
.size = size,
|
||||
.alignment = alignment,
|
||||
.segment_id = match.seg,
|
||||
.section_id = match.sect,
|
||||
};
|
||||
try block.aliases.appendSlice(nlist_indices.items);
|
||||
block.segment_id = match.seg;
|
||||
block.section_id = match.sect;
|
||||
|
||||
// TODO parse relocs
|
||||
|
||||
@@ -468,8 +514,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
|
||||
block.prev = last;
|
||||
}
|
||||
last_block = block;
|
||||
|
||||
nlist_indices.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
break :next;
|
||||
@@ -498,12 +542,9 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
|
||||
|
||||
block.* = .{
|
||||
.local_sym_index = local_sym_index,
|
||||
.aliases = std.ArrayList(u32).init(self.allocator),
|
||||
.references = std.ArrayList(u32).init(self.allocator),
|
||||
.code = code,
|
||||
.relocs = std.ArrayList(*Relocation).init(self.allocator),
|
||||
.size = sect.size,
|
||||
.alignment = alignment,
|
||||
.alignment = sect.@"align",
|
||||
.segment_id = match.seg,
|
||||
.section_id = match.sect,
|
||||
};
|
||||
|
||||
@@ -139,47 +139,60 @@ const TlvOffset = struct {
|
||||
|
||||
pub const TextBlock = struct {
|
||||
local_sym_index: u32,
|
||||
aliases: std.ArrayList(u32),
|
||||
references: std.ArrayList(u32),
|
||||
aliases: ?[]u32 = null,
|
||||
references: ?[]u32 = null,
|
||||
code: []u8,
|
||||
relocs: std.ArrayList(*Relocation),
|
||||
relocs: ?[]*Relocation = null,
|
||||
size: u64,
|
||||
alignment: u32,
|
||||
segment_id: u16,
|
||||
section_id: u16,
|
||||
segment_id: u16 = 0,
|
||||
section_id: u16 = 0,
|
||||
next: ?*TextBlock = null,
|
||||
prev: ?*TextBlock = null,
|
||||
|
||||
pub fn deinit(block: *TextBlock, allocator: *Allocator) void {
|
||||
block.aliases.deinit();
|
||||
block.references.deinit();
|
||||
if (block.aliases) |aliases| {
|
||||
allocator.free(aliases);
|
||||
}
|
||||
if (block.references) |references| {
|
||||
allocator.free(references);
|
||||
}
|
||||
for (block.relocs.items) |reloc| {
|
||||
allocator.destroy(reloc);
|
||||
}
|
||||
block.relocs.deinit();
|
||||
if (block.relocs) |relocs| {
|
||||
allocator.free(relocs);
|
||||
}
|
||||
allocator.free(code);
|
||||
}
|
||||
|
||||
fn print(self: *const TextBlock, zld: *Zld) void {
|
||||
if (self.prev) |prev| {
|
||||
prev.print(zld);
|
||||
}
|
||||
|
||||
pub fn print_this(self: *const TextBlock, zld: *Zld) void {
|
||||
log.warn("TextBlock", .{});
|
||||
log.warn(" | {}: '{s}'", .{ self.local_sym_index, zld.locals.items[self.local_sym_index].name });
|
||||
log.warn(" | Aliases:", .{});
|
||||
for (self.aliases.items) |index| {
|
||||
log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
|
||||
if (self.aliases) |aliases| {
|
||||
log.warn(" | Aliases:", .{});
|
||||
for (aliases) |index| {
|
||||
log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
|
||||
}
|
||||
}
|
||||
log.warn(" | References:", .{});
|
||||
for (self.references.items) |index| {
|
||||
log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
|
||||
if (self.references) |references| {
|
||||
log.warn(" | References:", .{});
|
||||
for (references) |index| {
|
||||
log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });
|
||||
}
|
||||
}
|
||||
log.warn(" | size = {}", .{self.size});
|
||||
log.warn(" | align = {}", .{self.alignment});
|
||||
log.warn(" | segment_id = {}", .{self.segment_id});
|
||||
log.warn(" | section_id = {}", .{self.section_id});
|
||||
}
|
||||
|
||||
pub fn print(self: *const TextBlock, zld: *Zld) void {
|
||||
if (self.prev) |prev| {
|
||||
prev.print(zld);
|
||||
}
|
||||
self.print_this(zld);
|
||||
}
|
||||
};
|
||||
|
||||
/// Default path to dyld
|
||||
|
||||
Reference in New Issue
Block a user