Commit 496903c6a8
Changed files (2)
src
link
MachO
src/link/MachO/Object.zig
@@ -325,6 +325,21 @@ fn filterRelocs(relocs: []macho.relocation_info, start_addr: u64, end_addr: u64)
return relocs[start..end];
}
+fn filterDice(dices: []macho.data_in_code_entry, start_addr: u64, end_addr: u64) []macho.data_in_code_entry {
+ const Predicate = struct {
+ addr: u64,
+
+ fn predicate(self: @This(), dice: macho.data_in_code_entry) bool {
+ return dice.offset >= self.addr;
+ }
+ };
+
+ const start = findFirst(macho.data_in_code_entry, dices, 0, Predicate{ .addr = start_addr });
+ const end = findFirst(macho.data_in_code_entry, dices, start, Predicate{ .addr = end_addr });
+
+ return dices[start..end];
+}
+
const TextBlockParser = struct {
allocator: *Allocator,
section: macho.section_64,
@@ -445,6 +460,23 @@ const TextBlockParser = struct {
try self.object.parseRelocs(self.zld, relocs, block, start_addr);
}
+ if (self.zld.has_dices) {
+ const dices = filterDice(
+ self.object.data_in_code_entries.items,
+ senior_nlist.nlist.n_value,
+ senior_nlist.nlist.n_value + size,
+ );
+ try block.dices.ensureTotalCapacity(dices.len);
+
+ for (dices) |dice| {
+ block.dices.appendAssumeCapacity(.{
+ .offset = dice.offset - try math.cast(u32, senior_nlist.nlist.n_value),
+ .length = dice.length,
+ .kind = dice.kind,
+ });
+ }
+ }
+
self.index += 1;
return block;
@@ -504,6 +536,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
// const is_splittable = false;
+ const has_dices: bool = blk: {
+ if (self.text_section_index) |index| {
+ if (index != id) break :blk false;
+ if (self.data_in_code_entries.items.len == 0) break :blk false;
+ break :blk true;
+ }
+ break :blk false;
+ };
+ zld.has_dices = has_dices;
+
next: {
if (is_splittable) blocks: {
if (filtered_nlists.len == 0) break :blocks;
@@ -593,6 +635,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
try self.parseRelocs(zld, relocs, block, 0);
}
+ if (zld.has_dices) {
+ const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.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,
+ });
+ }
+ }
+
// Since this is block gets a helper local temporary symbol that didn't exist
// in the object file which encompasses the entire section, we need traverse
// the filtered symbols and note which symbol is contained within so that
src/link/MachO/Zld.zig
@@ -114,6 +114,8 @@ stub_helper_stubs_start_off: ?u64 = null,
blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
+has_dices: bool = false,
+
pub const Output = struct {
tag: enum { exe, dylib },
path: []const u8,
@@ -131,6 +133,7 @@ pub const TextBlock = struct {
size: u64,
alignment: u32,
rebases: std.ArrayList(u64),
+ dices: std.ArrayList(macho.data_in_code_entry),
next: ?*TextBlock = null,
prev: ?*TextBlock = null,
@@ -149,6 +152,7 @@ pub const TextBlock = struct {
.size = undefined,
.alignment = undefined,
.rebases = std.ArrayList(u64).init(allocator),
+ .dices = std.ArrayList(macho.data_in_code_entry).init(allocator),
};
}
@@ -163,6 +167,7 @@ pub const TextBlock = struct {
self.allocator.free(self.code);
self.relocs.deinit();
self.rebases.deinit();
+ self.dices.deinit();
}
pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
@@ -205,6 +210,9 @@ pub const TextBlock = struct {
if (self.rebases.items.len > 0) {
log.warn(" rebases: {any}", .{self.rebases.items});
}
+ if (self.dices.items.len > 0) {
+ log.warn(" dices: {any}", .{self.dices.items});
+ }
log.warn(" size = {}", .{self.size});
log.warn(" align = {}", .{self.alignment});
}
@@ -2071,8 +2079,7 @@ fn flush(self: *Zld) !void {
try self.writeBindInfoTable();
try self.writeLazyBindInfoTable();
try self.writeExportInfo();
- // TODO DICE for x86_64
- // try self.writeDataInCode();
+ try self.writeDices();
{
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
@@ -2606,7 +2613,9 @@ fn writeStringTable(self: *Zld) !void {
}
}
-fn writeDataInCode(self: *Zld) !void {
+fn writeDices(self: *Zld) !void {
+ if (!self.has_dices) return;
+
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
const fileoff = seg.inner.fileoff + seg.inner.filesize;
@@ -2614,24 +2623,40 @@ fn writeDataInCode(self: *Zld) !void {
var buf = std.ArrayList(u8).init(self.allocator);
defer buf.deinit();
+ var block: *TextBlock = self.blocks.get(.{
+ .seg = self.text_segment_cmd_index orelse return,
+ .sect = self.text_section_index orelse return,
+ }) orelse return;
+
+ while (block.prev) |prev| {
+ block = prev;
+ }
+
const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
const text_sect = text_seg.sections.items[self.text_section_index.?];
- for (self.objects.items) |object| {
- const source_sect = object.sections.items[object.text_section_index.?];
- const target_map = source_sect.target_map orelse continue;
- try buf.ensureCapacity(
- buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry),
- );
- for (object.data_in_code_entries.items) |dice| {
- const new_dice: macho.data_in_code_entry = .{
- .offset = text_sect.offset + target_map.offset + dice.offset,
- .length = dice.length,
- .kind = dice.kind,
- };
- buf.appendSliceAssumeCapacity(mem.asBytes(&new_dice));
+ while (true) {
+ if (block.dices.items.len > 0) {
+ const sym = self.locals.items[block.local_sym_index];
+ const reg = sym.payload.regular;
+ const base_off = try math.cast(u32, reg.address - text_sect.addr + text_sect.offset);
+
+ try buf.ensureUnusedCapacity(block.dices.items.len * @sizeOf(macho.data_in_code_entry));
+ for (block.dices.items) |dice| {
+ const rebased_dice = macho.data_in_code_entry{
+ .offset = base_off + dice.offset,
+ .length = dice.length,
+ .kind = dice.kind,
+ };
+ buf.appendSliceAssumeCapacity(mem.asBytes(&rebased_dice));
+ }
}
+
+ if (block.next) |next| {
+ block = next;
+ } else break;
}
+
const datasize = @intCast(u32, buf.items.len);
dice_cmd.dataoff = @intCast(u32, fileoff);