authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-18 12:03:06+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-22 16:58:21+02:00
loga089a6dc4ff04a10360019185ecaacd0564eb84c
treed4d0bb835024ad110fdbdbff3513f2777906b70d
parent2c184f9a5fc78be4f38cc74106c203b7bc80deb4

macho: parse data-in-code when writing LINKEDIT segment


3 files changed, 55 insertions(+), 84 deletions(-)

src/link/MachO.zig+52-34
...@@ -187,7 +187,6 @@ error_flags: File.ErrorFlags = File.ErrorFlags{},...@@ -187,7 +187,6 @@ error_flags: File.ErrorFlags = File.ErrorFlags{},
187187
188load_commands_dirty: bool = false,188load_commands_dirty: bool = false,
189sections_order_dirty: bool = false,189sections_order_dirty: bool = false,
190has_dices: bool = false,
191190
192/// A helper var to indicate if we are at the start of the incremental updates, or191/// A helper var to indicate if we are at the start of the incremental updates, or
193/// already somewhere further along the update-and-run chain.192/// already somewhere further along the update-and-run chain.
...@@ -6139,55 +6138,74 @@ fn writeFunctionStarts(self: *MachO) !void {...@@ -6139,55 +6138,74 @@ fn writeFunctionStarts(self: *MachO) !void {
6139 self.load_commands_dirty = true;6138 self.load_commands_dirty = true;
6140}6139}
61416140
6142fn writeDices(self: *MachO) !void {6141fn filterDataInCode(
6143 if (!self.has_dices) return;6142 dices: []const macho.data_in_code_entry,
6143 start_addr: u64,
6144 end_addr: u64,
6145) []const macho.data_in_code_entry {
6146 const Predicate = struct {
6147 addr: u64,
61446148
6149 pub fn predicate(self: @This(), dice: macho.data_in_code_entry) bool {
6150 return dice.offset >= self.addr;
6151 }
6152 };
6153
6154 const start = MachO.findFirst(macho.data_in_code_entry, dices, 0, Predicate{ .addr = start_addr });
6155 const end = MachO.findFirst(macho.data_in_code_entry, dices, start, Predicate{ .addr = end_addr });
6156
6157 return dices[start..end];
6158}
6159
6160fn writeDataInCode(self: *MachO) !void {
6145 const tracy = trace(@src());6161 const tracy = trace(@src());
6146 defer tracy.end();6162 defer tracy.end();
61476163
6148 var buf = std.ArrayList(u8).init(self.base.allocator);6164 var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.base.allocator);
6149 defer buf.deinit();6165 defer out_dice.deinit();
61506166
6151 var atom: *Atom = self.atoms.get(.{6167 const text_sect = self.getSection(.{
6152 .seg = self.text_segment_cmd_index orelse return,6168 .seg = self.text_segment_cmd_index orelse return,
6153 .sect = self.text_section_index orelse return,6169 .sect = self.text_section_index orelse return,
6154 }) orelse return;
6155
6156 while (atom.prev) |prev| {
6157 atom = prev;
6158 }
6159
6160 const text_sect = self.getSection(.{
6161 .seg = self.text_segment_cmd_index.?,
6162 .sect = self.text_section_index.?,
6163 });6170 });
61646171
6165 while (true) {6172 for (self.objects.items) |object| {
6166 if (atom.dices.items.len > 0) {6173 const dice = object.parseDataInCode() orelse continue;
6174 const source_symtab = object.getSourceSymtab();
6175 try out_dice.ensureUnusedCapacity(dice.len);
6176
6177 for (object.managed_atoms.items) |atom| {
6167 const sym = atom.getSymbol(self);6178 const sym = atom.getSymbol(self);
6168 const base_off = math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset) orelse return error.Overflow;6179 if (sym.n_desc == N_DESC_GCED) continue;
61696180 if (atom.sym_index >= source_symtab.len) continue; // synthetic, linker generated
6170 try buf.ensureUnusedCapacity(atom.dices.items.len * @sizeOf(macho.data_in_code_entry));6181
6171 for (atom.dices.items) |dice| {6182 const match = self.getMatchingSectionFromOrdinal(sym.n_sect);
6172 const rebased_dice = macho.data_in_code_entry{6183 if (match.seg != self.text_segment_cmd_index.? and match.sect != self.text_section_index.?) {
6173 .offset = base_off + dice.offset,6184 continue;
6174 .length = dice.length,
6175 .kind = dice.kind,
6176 };
6177 buf.appendSliceAssumeCapacity(mem.asBytes(&rebased_dice));
6178 }6185 }
6179 }
61806186
6181 if (atom.next) |next| {6187 const source_sym = source_symtab[atom.sym_index];
6182 atom = next;6188 const source_addr = math.cast(u32, source_sym.n_value) orelse return error.Overflow;
6183 } else break;6189 const filtered_dice = filterDataInCode(dice, source_addr, source_addr + atom.size);
6190 const base = math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset) orelse
6191 return error.Overflow;
6192
6193 for (filtered_dice) |single| {
6194 const offset = single.offset - source_addr + base;
6195 out_dice.appendAssumeCapacity(.{
6196 .offset = offset,
6197 .length = single.length,
6198 .kind = single.kind,
6199 });
6200 }
6201 }
6184 }6202 }
61856203
6186 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;6204 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6187 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data;6205 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data;
61886206
6189 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));6207 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
6190 const datasize = buf.items.len;6208 const datasize = out_dice.items.len * @sizeOf(macho.data_in_code_entry);
6191 dice_cmd.dataoff = @intCast(u32, dataoff);6209 dice_cmd.dataoff = @intCast(u32, dataoff);
6192 dice_cmd.datasize = @intCast(u32, datasize);6210 dice_cmd.datasize = @intCast(u32, datasize);
6193 seg.inner.filesize = dice_cmd.dataoff + dice_cmd.datasize - seg.inner.fileoff;6211 seg.inner.filesize = dice_cmd.dataoff + dice_cmd.datasize - seg.inner.fileoff;
...@@ -6197,7 +6215,7 @@ fn writeDices(self: *MachO) !void {...@@ -6197,7 +6215,7 @@ fn writeDices(self: *MachO) !void {
6197 dice_cmd.dataoff + dice_cmd.datasize,6215 dice_cmd.dataoff + dice_cmd.datasize,
6198 });6216 });
61996217
6200 try self.base.file.?.pwriteAll(buf.items, dice_cmd.dataoff);6218 try self.base.file.?.pwriteAll(mem.sliceAsBytes(out_dice.items), dice_cmd.dataoff);
6201 self.load_commands_dirty = true;6219 self.load_commands_dirty = true;
6202}6220}
62036221
...@@ -6392,7 +6410,7 @@ fn writeLinkeditSegment(self: *MachO) !void {...@@ -6392,7 +6410,7 @@ fn writeLinkeditSegment(self: *MachO) !void {
63926410
6393 try self.writeDyldInfoData();6411 try self.writeDyldInfoData();
6394 try self.writeFunctionStarts();6412 try self.writeFunctionStarts();
6395 try self.writeDices();6413 try self.writeDataInCode();
6396 try self.writeSymtab();6414 try self.writeSymtab();
6397 try self.writeStrtab();6415 try self.writeStrtab();
63986416
src/link/MachO/Atom.zig-5
...@@ -59,9 +59,6 @@ bindings: std.ArrayListUnmanaged(Binding) = .{},...@@ -59,9 +59,6 @@ bindings: std.ArrayListUnmanaged(Binding) = .{},
59/// List of lazy bindings (cf bindings above).59/// List of lazy bindings (cf bindings above).
60lazy_bindings: std.ArrayListUnmanaged(Binding) = .{},60lazy_bindings: std.ArrayListUnmanaged(Binding) = .{},
6161
62/// List of data-in-code entries. This is currently specific to x86_64 only.
63dices: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
64
65/// Points to the previous and next neighbours62/// Points to the previous and next neighbours
66next: ?*Atom,63next: ?*Atom,
67prev: ?*Atom,64prev: ?*Atom,
...@@ -147,7 +144,6 @@ pub const empty = Atom{...@@ -147,7 +144,6 @@ pub const empty = Atom{
147};144};
148145
149pub fn deinit(self: *Atom, allocator: Allocator) void {146pub fn deinit(self: *Atom, allocator: Allocator) void {
150 self.dices.deinit(allocator);
151 self.lazy_bindings.deinit(allocator);147 self.lazy_bindings.deinit(allocator);
152 self.bindings.deinit(allocator);148 self.bindings.deinit(allocator);
153 self.rebases.deinit(allocator);149 self.rebases.deinit(allocator);
...@@ -157,7 +153,6 @@ pub fn deinit(self: *Atom, allocator: Allocator) void {...@@ -157,7 +153,6 @@ pub fn deinit(self: *Atom, allocator: Allocator) void {
157}153}
158154
159pub fn clearRetainingCapacity(self: *Atom) void {155pub fn clearRetainingCapacity(self: *Atom) void {
160 self.dices.clearRetainingCapacity();
161 self.lazy_bindings.clearRetainingCapacity();156 self.lazy_bindings.clearRetainingCapacity();
162 self.bindings.clearRetainingCapacity();157 self.bindings.clearRetainingCapacity();
163 self.rebases.clearRetainingCapacity();158 self.rebases.clearRetainingCapacity();
src/link/MachO/Object.zig+3-45
...@@ -177,7 +177,6 @@ pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void {...@@ -177,7 +177,6 @@ pub fn parse(self: *Object, allocator: Allocator, target: std.Target) !void {
177 }177 }
178178
179 try self.parseSymtab(allocator);179 try self.parseSymtab(allocator);
180 self.parseDataInCode();
181}180}
182181
183const Context = struct {182const Context = struct {
...@@ -264,25 +263,6 @@ fn filterRelocs(...@@ -264,25 +263,6 @@ fn filterRelocs(
264 return relocs[start..end];263 return relocs[start..end];
265}264}
266265
267fn filterDice(
268 dices: []const macho.data_in_code_entry,
269 start_addr: u64,
270 end_addr: u64,
271) []const macho.data_in_code_entry {
272 const Predicate = struct {
273 addr: u64,
274
275 pub fn predicate(self: @This(), dice: macho.data_in_code_entry) bool {
276 return dice.offset >= self.addr;
277 }
278 };
279
280 const start = MachO.findFirst(macho.data_in_code_entry, dices, 0, Predicate{ .addr = start_addr });
281 const end = MachO.findFirst(macho.data_in_code_entry, dices, start, Predicate{ .addr = end_addr });
282
283 return dices[start..end];
284}
285
286/// Splits object into atoms assuming one-shot linking mode.266/// Splits object into atoms assuming one-shot linking mode.
287pub fn splitIntoAtomsOneShot(267pub fn splitIntoAtomsOneShot(
288 self: *Object,268 self: *Object,
...@@ -378,15 +358,6 @@ pub fn splitIntoAtomsOneShot(...@@ -378,15 +358,6 @@ pub fn splitIntoAtomsOneShot(
378 context,358 context,
379 );359 );
380360
381 macho_file.has_dices = macho_file.has_dices or blk: {
382 if (self.text_section_index) |index| {
383 if (index != id) break :blk false;
384 if (self.data_in_code_entries.len == 0) break :blk false;
385 break :blk true;
386 }
387 break :blk false;
388 };
389
390 if (subsections_via_symbols and filtered_syms.len > 0) {361 if (subsections_via_symbols and filtered_syms.len > 0) {
391 // If the first nlist does not match the start of the section,362 // If the first nlist does not match the start of the section,
392 // then we need to encapsulate the memory range [section start, first symbol)363 // then we need to encapsulate the memory range [section start, first symbol)
...@@ -574,19 +545,6 @@ fn createAtomFromSubsection(...@@ -574,19 +545,6 @@ fn createAtomFromSubsection(
574 .base_offset = @intCast(i32, base_offset),545 .base_offset = @intCast(i32, base_offset),
575 });546 });
576547
577 if (macho_file.has_dices) {
578 const dices = filterDice(self.data_in_code_entries, sym.n_value, sym.n_value + size);
579 try atom.dices.ensureTotalCapacity(gpa, dices.len);
580
581 for (dices) |dice| {
582 atom.dices.appendAssumeCapacity(.{
583 .offset = dice.offset - (math.cast(u32, sym.n_value) orelse return error.Overflow),
584 .length = dice.length,
585 .kind = dice.kind,
586 });
587 }
588 }
589
590 // Since this is atom gets a helper local temporary symbol that didn't exist548 // Since this is atom gets a helper local temporary symbol that didn't exist
591 // in the object file which encompasses the entire section, we need traverse549 // in the object file which encompasses the entire section, we need traverse
592 // the filtered symbols and note which symbol is contained within so that550 // the filtered symbols and note which symbol is contained within so that
...@@ -651,11 +609,11 @@ pub fn getSourceSymtab(self: Object) []const macho.nlist_64 {...@@ -651,11 +609,11 @@ pub fn getSourceSymtab(self: Object) []const macho.nlist_64 {
651 );609 );
652}610}
653611
654fn parseDataInCode(self: *Object) void {612pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry {
655 const index = self.data_in_code_cmd_index orelse return;613 const index = self.data_in_code_cmd_index orelse return null;
656 const data_in_code = self.load_commands.items[index].linkedit_data;614 const data_in_code = self.load_commands.items[index].linkedit_data;
657 const raw_dice = self.contents[data_in_code.dataoff..][0..data_in_code.datasize];615 const raw_dice = self.contents[data_in_code.dataoff..][0..data_in_code.datasize];
658 self.data_in_code_entries = mem.bytesAsSlice(616 return mem.bytesAsSlice(
659 macho.data_in_code_entry,617 macho.data_in_code_entry,
660 @alignCast(@alignOf(macho.data_in_code_entry), raw_dice),618 @alignCast(@alignOf(macho.data_in_code_entry), raw_dice),
661 );619 );