authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-11 23:34:35+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log496903c6a807389b3c4940370601ea338b9047f7
treeacaa611eef7230384a11d0061f3894800453378d
parente3fe9a9df55e36f8ee402b8edb26267b5145ce08

zld: add DICE support mainly for x86_64-macos


2 files changed, 96 insertions(+), 16 deletions(-)

src/link/MachO/Object.zig+55
......@@ -325,6 +325,21 @@ fn filterRelocs(relocs: []macho.relocation_info, start_addr: u64, end_addr: u64)
325325 return relocs[start..end];
326326}
327327
328fn filterDice(dices: []macho.data_in_code_entry, start_addr: u64, end_addr: u64) []macho.data_in_code_entry {
329 const Predicate = struct {
330 addr: u64,
331
332 fn predicate(self: @This(), dice: macho.data_in_code_entry) bool {
333 return dice.offset >= self.addr;
334 }
335 };
336
337 const start = findFirst(macho.data_in_code_entry, dices, 0, Predicate{ .addr = start_addr });
338 const end = findFirst(macho.data_in_code_entry, dices, start, Predicate{ .addr = end_addr });
339
340 return dices[start..end];
341}
342
328343const TextBlockParser = struct {
329344 allocator: *Allocator,
330345 section: macho.section_64,
......@@ -445,6 +460,23 @@ const TextBlockParser = struct {
445460 try self.object.parseRelocs(self.zld, relocs, block, start_addr);
446461 }
447462
463 if (self.zld.has_dices) {
464 const dices = filterDice(
465 self.object.data_in_code_entries.items,
466 senior_nlist.nlist.n_value,
467 senior_nlist.nlist.n_value + size,
468 );
469 try block.dices.ensureTotalCapacity(dices.len);
470
471 for (dices) |dice| {
472 block.dices.appendAssumeCapacity(.{
473 .offset = dice.offset - try math.cast(u32, senior_nlist.nlist.n_value),
474 .length = dice.length,
475 .kind = dice.kind,
476 });
477 }
478 }
479
448480 self.index += 1;
449481
450482 return block;
......@@ -504,6 +536,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
504536 const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
505537 // const is_splittable = false;
506538
539 const has_dices: bool = blk: {
540 if (self.text_section_index) |index| {
541 if (index != id) break :blk false;
542 if (self.data_in_code_entries.items.len == 0) break :blk false;
543 break :blk true;
544 }
545 break :blk false;
546 };
547 zld.has_dices = has_dices;
548
507549 next: {
508550 if (is_splittable) blocks: {
509551 if (filtered_nlists.len == 0) break :blocks;
......@@ -593,6 +635,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
593635 try self.parseRelocs(zld, relocs, block, 0);
594636 }
595637
638 if (zld.has_dices) {
639 const dices = filterDice(self.data_in_code_entries.items, sect.addr, sect.addr + sect.size);
640 try block.dices.ensureTotalCapacity(dices.len);
641
642 for (dices) |dice| {
643 block.dices.appendAssumeCapacity(.{
644 .offset = dice.offset - try math.cast(u32, sect.addr),
645 .length = dice.length,
646 .kind = dice.kind,
647 });
648 }
649 }
650
596651 // Since this is block gets a helper local temporary symbol that didn't exist
597652 // in the object file which encompasses the entire section, we need traverse
598653 // the filtered symbols and note which symbol is contained within so that
src/link/MachO/Zld.zig+41-16
......@@ -114,6 +114,8 @@ stub_helper_stubs_start_off: ?u64 = null,
114114
115115blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
116116
117has_dices: bool = false,
118
117119pub const Output = struct {
118120 tag: enum { exe, dylib },
119121 path: []const u8,
......@@ -131,6 +133,7 @@ pub const TextBlock = struct {
131133 size: u64,
132134 alignment: u32,
133135 rebases: std.ArrayList(u64),
136 dices: std.ArrayList(macho.data_in_code_entry),
134137 next: ?*TextBlock = null,
135138 prev: ?*TextBlock = null,
136139
......@@ -149,6 +152,7 @@ pub const TextBlock = struct {
149152 .size = undefined,
150153 .alignment = undefined,
151154 .rebases = std.ArrayList(u64).init(allocator),
155 .dices = std.ArrayList(macho.data_in_code_entry).init(allocator),
152156 };
153157 }
154158
......@@ -163,6 +167,7 @@ pub const TextBlock = struct {
163167 self.allocator.free(self.code);
164168 self.relocs.deinit();
165169 self.rebases.deinit();
170 self.dices.deinit();
166171 }
167172
168173 pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
......@@ -205,6 +210,9 @@ pub const TextBlock = struct {
205210 if (self.rebases.items.len > 0) {
206211 log.warn(" rebases: {any}", .{self.rebases.items});
207212 }
213 if (self.dices.items.len > 0) {
214 log.warn(" dices: {any}", .{self.dices.items});
215 }
208216 log.warn(" size = {}", .{self.size});
209217 log.warn(" align = {}", .{self.alignment});
210218 }
......@@ -2071,8 +2079,7 @@ fn flush(self: *Zld) !void {
20712079 try self.writeBindInfoTable();
20722080 try self.writeLazyBindInfoTable();
20732081 try self.writeExportInfo();
2074 // TODO DICE for x86_64
2075 // try self.writeDataInCode();
2082 try self.writeDices();
20762083
20772084 {
20782085 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
......@@ -2606,7 +2613,9 @@ fn writeStringTable(self: *Zld) !void {
26062613 }
26072614}
26082615
2609fn writeDataInCode(self: *Zld) !void {
2616fn writeDices(self: *Zld) !void {
2617 if (!self.has_dices) return;
2618
26102619 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
26112620 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
26122621 const fileoff = seg.inner.fileoff + seg.inner.filesize;
......@@ -2614,24 +2623,40 @@ fn writeDataInCode(self: *Zld) !void {
26142623 var buf = std.ArrayList(u8).init(self.allocator);
26152624 defer buf.deinit();
26162625
2626 var block: *TextBlock = self.blocks.get(.{
2627 .seg = self.text_segment_cmd_index orelse return,
2628 .sect = self.text_section_index orelse return,
2629 }) orelse return;
2630
2631 while (block.prev) |prev| {
2632 block = prev;
2633 }
2634
26172635 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
26182636 const text_sect = text_seg.sections.items[self.text_section_index.?];
2619 for (self.objects.items) |object| {
2620 const source_sect = object.sections.items[object.text_section_index.?];
2621 const target_map = source_sect.target_map orelse continue;
26222637
2623 try buf.ensureCapacity(
2624 buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry),
2625 );
2626 for (object.data_in_code_entries.items) |dice| {
2627 const new_dice: macho.data_in_code_entry = .{
2628 .offset = text_sect.offset + target_map.offset + dice.offset,
2629 .length = dice.length,
2630 .kind = dice.kind,
2631 };
2632 buf.appendSliceAssumeCapacity(mem.asBytes(&new_dice));
2638 while (true) {
2639 if (block.dices.items.len > 0) {
2640 const sym = self.locals.items[block.local_sym_index];
2641 const reg = sym.payload.regular;
2642 const base_off = try math.cast(u32, reg.address - text_sect.addr + text_sect.offset);
2643
2644 try buf.ensureUnusedCapacity(block.dices.items.len * @sizeOf(macho.data_in_code_entry));
2645 for (block.dices.items) |dice| {
2646 const rebased_dice = macho.data_in_code_entry{
2647 .offset = base_off + dice.offset,
2648 .length = dice.length,
2649 .kind = dice.kind,
2650 };
2651 buf.appendSliceAssumeCapacity(mem.asBytes(&rebased_dice));
2652 }
26332653 }
2654
2655 if (block.next) |next| {
2656 block = next;
2657 } else break;
26342658 }
2659
26352660 const datasize = @intCast(u32, buf.items.len);
26362661
26372662 dice_cmd.dataoff = @intCast(u32, fileoff);