Commit 51e334af44
Changed files (2)
src
link
MachO
src/link/MachO/Object.zig
@@ -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;
-
- return switch (rreg.linkage) {
- .global => true,
- .linkage_unit => lreg.linkage == .translation_unit,
- else => false,
+ nlists: []NlistWithIndex,
+ index: u32 = 0,
+
+ 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 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];
+ var parser = TextBlockParser{
+ .allocator = self.allocator,
+ .section = sect,
+ .code = code,
+ .object = self,
+ .zld = zld,
+ .nlists = filtered_nlists,
+ };
+
+ 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,
};
src/link/MachO/Zld.zig
@@ -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