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)...@@ -325,6 +325,21 @@ fn filterRelocs(relocs: []macho.relocation_info, start_addr: u64, end_addr: u64)
325 return relocs[start..end];325 return relocs[start..end];
326}326}
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
328const TextBlockParser = struct {343const TextBlockParser = struct {
329 allocator: *Allocator,344 allocator: *Allocator,
330 section: macho.section_64,345 section: macho.section_64,
...@@ -445,6 +460,23 @@ const TextBlockParser = struct {...@@ -445,6 +460,23 @@ const TextBlockParser = struct {
445 try self.object.parseRelocs(self.zld, relocs, block, start_addr);460 try self.object.parseRelocs(self.zld, relocs, block, start_addr);
446 }461 }
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
448 self.index += 1;480 self.index += 1;
449481
450 return block;482 return block;
...@@ -504,6 +536,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -504,6 +536,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
504 const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;536 const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
505 // const is_splittable = false;537 // 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
507 next: {549 next: {
508 if (is_splittable) blocks: {550 if (is_splittable) blocks: {
509 if (filtered_nlists.len == 0) break :blocks;551 if (filtered_nlists.len == 0) break :blocks;
...@@ -593,6 +635,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -593,6 +635,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
593 try self.parseRelocs(zld, relocs, block, 0);635 try self.parseRelocs(zld, relocs, block, 0);
594 }636 }
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
596 // Since this is block gets a helper local temporary symbol that didn't exist651 // Since this is block gets a helper local temporary symbol that didn't exist
597 // in the object file which encompasses the entire section, we need traverse652 // in the object file which encompasses the entire section, we need traverse
598 // the filtered symbols and note which symbol is contained within so that653 // 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,...@@ -114,6 +114,8 @@ stub_helper_stubs_start_off: ?u64 = null,
114114
115blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},115blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
116116
117has_dices: bool = false,
118
117pub const Output = struct {119pub const Output = struct {
118 tag: enum { exe, dylib },120 tag: enum { exe, dylib },
119 path: []const u8,121 path: []const u8,
...@@ -131,6 +133,7 @@ pub const TextBlock = struct {...@@ -131,6 +133,7 @@ pub const TextBlock = struct {
131 size: u64,133 size: u64,
132 alignment: u32,134 alignment: u32,
133 rebases: std.ArrayList(u64),135 rebases: std.ArrayList(u64),
136 dices: std.ArrayList(macho.data_in_code_entry),
134 next: ?*TextBlock = null,137 next: ?*TextBlock = null,
135 prev: ?*TextBlock = null,138 prev: ?*TextBlock = null,
136139
...@@ -149,6 +152,7 @@ pub const TextBlock = struct {...@@ -149,6 +152,7 @@ pub const TextBlock = struct {
149 .size = undefined,152 .size = undefined,
150 .alignment = undefined,153 .alignment = undefined,
151 .rebases = std.ArrayList(u64).init(allocator),154 .rebases = std.ArrayList(u64).init(allocator),
155 .dices = std.ArrayList(macho.data_in_code_entry).init(allocator),
152 };156 };
153 }157 }
154158
...@@ -163,6 +167,7 @@ pub const TextBlock = struct {...@@ -163,6 +167,7 @@ pub const TextBlock = struct {
163 self.allocator.free(self.code);167 self.allocator.free(self.code);
164 self.relocs.deinit();168 self.relocs.deinit();
165 self.rebases.deinit();169 self.rebases.deinit();
170 self.dices.deinit();
166 }171 }
167172
168 pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {173 pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void {
...@@ -205,6 +210,9 @@ pub const TextBlock = struct {...@@ -205,6 +210,9 @@ pub const TextBlock = struct {
205 if (self.rebases.items.len > 0) {210 if (self.rebases.items.len > 0) {
206 log.warn(" rebases: {any}", .{self.rebases.items});211 log.warn(" rebases: {any}", .{self.rebases.items});
207 }212 }
213 if (self.dices.items.len > 0) {
214 log.warn(" dices: {any}", .{self.dices.items});
215 }
208 log.warn(" size = {}", .{self.size});216 log.warn(" size = {}", .{self.size});
209 log.warn(" align = {}", .{self.alignment});217 log.warn(" align = {}", .{self.alignment});
210 }218 }
...@@ -2071,8 +2079,7 @@ fn flush(self: *Zld) !void {...@@ -2071,8 +2079,7 @@ fn flush(self: *Zld) !void {
2071 try self.writeBindInfoTable();2079 try self.writeBindInfoTable();
2072 try self.writeLazyBindInfoTable();2080 try self.writeLazyBindInfoTable();
2073 try self.writeExportInfo();2081 try self.writeExportInfo();
2074 // TODO DICE for x86_642082 try self.writeDices();
2075 // try self.writeDataInCode();
20762083
2077 {2084 {
2078 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2085 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
...@@ -2606,7 +2613,9 @@ fn writeStringTable(self: *Zld) !void {...@@ -2606,7 +2613,9 @@ fn writeStringTable(self: *Zld) !void {
2606 }2613 }
2607}2614}
26082615
2609fn writeDataInCode(self: *Zld) !void {2616fn writeDices(self: *Zld) !void {
2617 if (!self.has_dices) return;
2618
2610 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2619 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2611 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;2620 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
2612 const fileoff = seg.inner.fileoff + seg.inner.filesize;2621 const fileoff = seg.inner.fileoff + seg.inner.filesize;
...@@ -2614,24 +2623,40 @@ fn writeDataInCode(self: *Zld) !void {...@@ -2614,24 +2623,40 @@ fn writeDataInCode(self: *Zld) !void {
2614 var buf = std.ArrayList(u8).init(self.allocator);2623 var buf = std.ArrayList(u8).init(self.allocator);
2615 defer buf.deinit();2624 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
2617 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;2635 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2618 const text_sect = text_seg.sections.items[self.text_section_index.?];2636 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(2638 while (true) {
2624 buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry),2639 if (block.dices.items.len > 0) {
2625 );2640 const sym = self.locals.items[block.local_sym_index];
2626 for (object.data_in_code_entries.items) |dice| {2641 const reg = sym.payload.regular;
2627 const new_dice: macho.data_in_code_entry = .{2642 const base_off = try math.cast(u32, reg.address - text_sect.addr + text_sect.offset);
2628 .offset = text_sect.offset + target_map.offset + dice.offset,2643
2629 .length = dice.length,2644 try buf.ensureUnusedCapacity(block.dices.items.len * @sizeOf(macho.data_in_code_entry));
2630 .kind = dice.kind,2645 for (block.dices.items) |dice| {
2631 };2646 const rebased_dice = macho.data_in_code_entry{
2632 buf.appendSliceAssumeCapacity(mem.asBytes(&new_dice));2647 .offset = base_off + dice.offset,
2648 .length = dice.length,
2649 .kind = dice.kind,
2650 };
2651 buf.appendSliceAssumeCapacity(mem.asBytes(&rebased_dice));
2652 }
2633 }2653 }
2654
2655 if (block.next) |next| {
2656 block = next;
2657 } else break;
2634 }2658 }
2659
2635 const datasize = @intCast(u32, buf.items.len);2660 const datasize = @intCast(u32, buf.items.len);
26362661
2637 dice_cmd.dataoff = @intCast(u32, fileoff);2662 dice_cmd.dataoff = @intCast(u32, fileoff);