diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-12-08 17:08:40 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-12-08 23:24:40 +0100 |
| commit | 64e2bfaa236c14b403103c92691fa6774e1fdc83 (patch) | |
| tree | 6d4539883ffa1268e54e57e21fdd33994dd7ac7a /src | |
| parent | 98e36ea6b9aff3403685af3a76ffa998249c9b84 (diff) | |
| download | zig-64e2bfaa236c14b403103c92691fa6774e1fdc83.tar.gz zig-64e2bfaa236c14b403103c92691fa6774e1fdc83.zip | |
macho: write out LC_FUNCTION_START data
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 84614e9b40..12562f8c5e 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -4369,6 +4369,19 @@ fn populateMissingMetadata(self: *MachO) !void { self.load_commands_dirty = true; } + if (self.function_starts_cmd_index == null) { + self.function_starts_cmd_index = @intCast(u16, self.load_commands.items.len); + try self.load_commands.append(self.base.allocator, .{ + .LinkeditData = .{ + .cmd = macho.LC_FUNCTION_STARTS, + .cmdsize = @sizeOf(macho.linkedit_data_command), + .dataoff = 0, + .datasize = 0, + }, + }); + self.load_commands_dirty = true; + } + if (self.data_in_code_cmd_index == null) { self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len); try self.load_commands.append(self.base.allocator, .{ @@ -5324,6 +5337,95 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { } } +fn writeFunctionStarts(self: *MachO) !void { + var atom = self.atoms.get(.{ + .seg = self.text_segment_cmd_index orelse return, + .sect = self.text_section_index orelse return, + }) orelse return; + + const tracy = trace(@src()); + defer tracy.end(); + + while (atom.prev) |prev| { + atom = prev; + } + + var offsets = std.ArrayList(u32).init(self.base.allocator); + defer offsets.deinit(); + + const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; + var last_off: u32 = 0; + + while (true) { + const atom_sym = self.locals.items[atom.local_sym_index]; + + if (atom_sym.n_strx != 0) blk: { + if (self.symbol_resolver.get(atom_sym.n_strx)) |resolv| { + assert(resolv.where == .global); + if (resolv.local_sym_index != atom.local_sym_index) break :blk; + } + + const offset = @intCast(u32, atom_sym.n_value - text_seg.inner.vmaddr); + const diff = offset - last_off; + + if (diff == 0) break :blk; + + try offsets.append(diff); + last_off = offset; + } + + for (atom.contained.items) |cont| { + const cont_sym = self.locals.items[cont.local_sym_index]; + + if (cont_sym.n_strx == 0) continue; + if (self.symbol_resolver.get(cont_sym.n_strx)) |resolv| { + assert(resolv.where == .global); + if (resolv.local_sym_index != cont.local_sym_index) continue; + } + + const offset = @intCast(u32, cont_sym.n_value - text_seg.inner.vmaddr); + const diff = offset - last_off; + + if (diff == 0) continue; + + try offsets.append(diff); + last_off = offset; + } + + if (atom.next) |next| { + atom = next; + } else break; + } + + const max_size = @intCast(usize, offsets.items.len * @sizeOf(u64)); + var buffer = try self.base.allocator.alloc(u8, max_size); + defer self.base.allocator.free(buffer); + mem.set(u8, buffer, 0); + + var stream = std.io.fixedBufferStream(buffer); + var writer = stream.writer(); + + for (offsets.items) |offset| { + try std.leb.writeULEB128(writer, offset); + } + + const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64))); + const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; + const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].LinkeditData; + + fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); + fn_cmd.datasize = needed_size; + seg.inner.filesize += needed_size; + + log.debug("writing function starts info from 0x{x} to 0x{x}", .{ + fn_cmd.dataoff, + fn_cmd.dataoff + fn_cmd.datasize, + }); + + try self.base.file.?.pwriteAll(buffer[0..needed_size], fn_cmd.dataoff); + self.load_commands_dirty = true; +} + fn writeDices(self: *MachO) !void { if (!self.has_dices) return; @@ -5591,6 +5693,7 @@ fn writeLinkeditSegment(self: *MachO) !void { seg.inner.filesize = 0; try self.writeDyldInfoData(); + try self.writeFunctionStarts(); try self.writeDices(); try self.writeSymbolTable(); try self.writeStringTable(); |
