Commit 828f61e8df
Changed files (8)
lib
std
lib/std/macho.zig
@@ -1,4 +1,12 @@
const std = @import("std");
+const builtin = @import("builtin");
+const assert = std.debug.assert;
+const io = std.io;
+const mem = std.mem;
+const meta = std.meta;
+const testing = std.testing;
+
+const Allocator = mem.Allocator;
pub const mach_header = extern struct {
magic: u32,
@@ -770,7 +778,7 @@ pub const section_64 = extern struct {
};
fn parseName(name: *const [16]u8) []const u8 {
- const len = std.mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
+ const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
return name[0..len];
}
@@ -1804,3 +1812,428 @@ pub const data_in_code_entry = extern struct {
/// A DICE_KIND value.
kind: u16,
};
+
+/// A Zig wrapper for all known MachO load commands.
+/// Provides interface to read and write the load command data to a buffer.
+pub const LoadCommand = union(enum) {
+ segment: SegmentCommand,
+ dyld_info_only: dyld_info_command,
+ symtab: symtab_command,
+ dysymtab: dysymtab_command,
+ dylinker: GenericCommandWithData(dylinker_command),
+ dylib: GenericCommandWithData(dylib_command),
+ main: entry_point_command,
+ version_min: version_min_command,
+ source_version: source_version_command,
+ build_version: GenericCommandWithData(build_version_command),
+ uuid: uuid_command,
+ linkedit_data: linkedit_data_command,
+ rpath: GenericCommandWithData(rpath_command),
+ unknown: GenericCommandWithData(load_command),
+
+ pub fn read(allocator: Allocator, reader: anytype) !LoadCommand {
+ const header = try reader.readStruct(load_command);
+ var buffer = try allocator.alloc(u8, header.cmdsize);
+ defer allocator.free(buffer);
+ mem.copy(u8, buffer, mem.asBytes(&header));
+ try reader.readNoEof(buffer[@sizeOf(load_command)..]);
+ var stream = io.fixedBufferStream(buffer);
+
+ return switch (header.cmd) {
+ LC_SEGMENT_64 => LoadCommand{
+ .segment = try SegmentCommand.read(allocator, stream.reader()),
+ },
+ LC_DYLD_INFO, LC_DYLD_INFO_ONLY => LoadCommand{
+ .dyld_info_only = try stream.reader().readStruct(dyld_info_command),
+ },
+ LC_SYMTAB => LoadCommand{
+ .symtab = try stream.reader().readStruct(symtab_command),
+ },
+ LC_DYSYMTAB => LoadCommand{
+ .dysymtab = try stream.reader().readStruct(dysymtab_command),
+ },
+ LC_ID_DYLINKER, LC_LOAD_DYLINKER, LC_DYLD_ENVIRONMENT => LoadCommand{
+ .dylinker = try GenericCommandWithData(dylinker_command).read(allocator, stream.reader()),
+ },
+ LC_ID_DYLIB, LC_LOAD_WEAK_DYLIB, LC_LOAD_DYLIB, LC_REEXPORT_DYLIB => LoadCommand{
+ .dylib = try GenericCommandWithData(dylib_command).read(allocator, stream.reader()),
+ },
+ LC_MAIN => LoadCommand{
+ .main = try stream.reader().readStruct(entry_point_command),
+ },
+ LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS => LoadCommand{
+ .version_min = try stream.reader().readStruct(version_min_command),
+ },
+ LC_SOURCE_VERSION => LoadCommand{
+ .source_version = try stream.reader().readStruct(source_version_command),
+ },
+ LC_BUILD_VERSION => LoadCommand{
+ .build_version = try GenericCommandWithData(build_version_command).read(allocator, stream.reader()),
+ },
+ LC_UUID => LoadCommand{
+ .uuid = try stream.reader().readStruct(uuid_command),
+ },
+ LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_CODE_SIGNATURE => LoadCommand{
+ .linkedit_data = try stream.reader().readStruct(linkedit_data_command),
+ },
+ LC_RPATH => LoadCommand{
+ .rpath = try GenericCommandWithData(rpath_command).read(allocator, stream.reader()),
+ },
+ else => LoadCommand{
+ .unknown = try GenericCommandWithData(load_command).read(allocator, stream.reader()),
+ },
+ };
+ }
+
+ pub fn write(self: LoadCommand, writer: anytype) !void {
+ return switch (self) {
+ .dyld_info_only => |x| writeStruct(x, writer),
+ .symtab => |x| writeStruct(x, writer),
+ .dysymtab => |x| writeStruct(x, writer),
+ .main => |x| writeStruct(x, writer),
+ .version_min => |x| writeStruct(x, writer),
+ .source_version => |x| writeStruct(x, writer),
+ .uuid => |x| writeStruct(x, writer),
+ .linkedit_data => |x| writeStruct(x, writer),
+ .segment => |x| x.write(writer),
+ .dylinker => |x| x.write(writer),
+ .dylib => |x| x.write(writer),
+ .rpath => |x| x.write(writer),
+ .build_version => |x| x.write(writer),
+ .unknown => |x| x.write(writer),
+ };
+ }
+
+ pub fn cmd(self: LoadCommand) u32 {
+ return switch (self) {
+ .dyld_info_only => |x| x.cmd,
+ .symtab => |x| x.cmd,
+ .dysymtab => |x| x.cmd,
+ .main => |x| x.cmd,
+ .version_min => |x| x.cmd,
+ .source_version => |x| x.cmd,
+ .uuid => |x| x.cmd,
+ .linkedit_data => |x| x.cmd,
+ .segment => |x| x.inner.cmd,
+ .dylinker => |x| x.inner.cmd,
+ .dylib => |x| x.inner.cmd,
+ .rpath => |x| x.inner.cmd,
+ .build_version => |x| x.inner.cmd,
+ .unknown => |x| x.inner.cmd,
+ };
+ }
+
+ pub fn cmdsize(self: LoadCommand) u32 {
+ return switch (self) {
+ .dyld_info_only => |x| x.cmdsize,
+ .symtab => |x| x.cmdsize,
+ .dysymtab => |x| x.cmdsize,
+ .main => |x| x.cmdsize,
+ .version_min => |x| x.cmdsize,
+ .source_version => |x| x.cmdsize,
+ .linkedit_data => |x| x.cmdsize,
+ .uuid => |x| x.cmdsize,
+ .segment => |x| x.inner.cmdsize,
+ .dylinker => |x| x.inner.cmdsize,
+ .dylib => |x| x.inner.cmdsize,
+ .rpath => |x| x.inner.cmdsize,
+ .build_version => |x| x.inner.cmdsize,
+ .unknown => |x| x.inner.cmdsize,
+ };
+ }
+
+ pub fn deinit(self: *LoadCommand, allocator: Allocator) void {
+ return switch (self.*) {
+ .segment => |*x| x.deinit(allocator),
+ .dylinker => |*x| x.deinit(allocator),
+ .dylib => |*x| x.deinit(allocator),
+ .rpath => |*x| x.deinit(allocator),
+ .build_version => |*x| x.deinit(allocator),
+ .unknown => |*x| x.deinit(allocator),
+ else => {},
+ };
+ }
+
+ fn writeStruct(command: anytype, writer: anytype) !void {
+ return writer.writeAll(mem.asBytes(&command));
+ }
+
+ pub fn eql(self: LoadCommand, other: LoadCommand) bool {
+ if (@as(meta.Tag(LoadCommand), self) != @as(meta.Tag(LoadCommand), other)) return false;
+ return switch (self) {
+ .dyld_info_only => |x| meta.eql(x, other.dyld_info_only),
+ .symtab => |x| meta.eql(x, other.symtab),
+ .dysymtab => |x| meta.eql(x, other.dysymtab),
+ .main => |x| meta.eql(x, other.main),
+ .version_min => |x| meta.eql(x, other.version_min),
+ .source_version => |x| meta.eql(x, other.source_version),
+ .build_version => |x| x.eql(other.build_version),
+ .uuid => |x| meta.eql(x, other.uuid),
+ .linkedit_data => |x| meta.eql(x, other.linkedit_data),
+ .segment => |x| x.eql(other.segment),
+ .dylinker => |x| x.eql(other.dylinker),
+ .dylib => |x| x.eql(other.dylib),
+ .rpath => |x| x.eql(other.rpath),
+ .unknown => |x| x.eql(other.unknown),
+ };
+ }
+};
+
+/// A Zig wrapper for segment_command_64.
+/// Encloses the extern struct together with a list of sections for this segment.
+pub const SegmentCommand = struct {
+ inner: segment_command_64,
+ sections: std.ArrayListUnmanaged(section_64) = .{},
+
+ pub fn read(allocator: Allocator, reader: anytype) !SegmentCommand {
+ const inner = try reader.readStruct(segment_command_64);
+ var segment = SegmentCommand{
+ .inner = inner,
+ };
+ try segment.sections.ensureTotalCapacityPrecise(allocator, inner.nsects);
+
+ var i: usize = 0;
+ while (i < inner.nsects) : (i += 1) {
+ const sect = try reader.readStruct(section_64);
+ segment.sections.appendAssumeCapacity(sect);
+ }
+
+ return segment;
+ }
+
+ pub fn write(self: SegmentCommand, writer: anytype) !void {
+ try writer.writeAll(mem.asBytes(&self.inner));
+ for (self.sections.items) |sect| {
+ try writer.writeAll(mem.asBytes(§));
+ }
+ }
+
+ pub fn deinit(self: *SegmentCommand, allocator: Allocator) void {
+ self.sections.deinit(allocator);
+ }
+
+ pub fn eql(self: SegmentCommand, other: SegmentCommand) bool {
+ if (!meta.eql(self.inner, other.inner)) return false;
+ const lhs = self.sections.items;
+ const rhs = other.sections.items;
+ var i: usize = 0;
+ while (i < self.inner.nsects) : (i += 1) {
+ if (!meta.eql(lhs[i], rhs[i])) return false;
+ }
+ return true;
+ }
+};
+
+pub fn emptyGenericCommandWithData(cmd: anytype) GenericCommandWithData(@TypeOf(cmd)) {
+ return .{ .inner = cmd };
+}
+
+/// A Zig wrapper for a generic load command with variable-length data.
+pub fn GenericCommandWithData(comptime Cmd: type) type {
+ return struct {
+ inner: Cmd,
+ /// This field remains undefined until `read` is called.
+ data: []u8 = undefined,
+
+ const Self = @This();
+
+ pub fn read(allocator: Allocator, reader: anytype) !Self {
+ const inner = try reader.readStruct(Cmd);
+ var data = try allocator.alloc(u8, inner.cmdsize - @sizeOf(Cmd));
+ errdefer allocator.free(data);
+ try reader.readNoEof(data);
+ return Self{
+ .inner = inner,
+ .data = data,
+ };
+ }
+
+ pub fn write(self: Self, writer: anytype) !void {
+ try writer.writeAll(mem.asBytes(&self.inner));
+ try writer.writeAll(self.data);
+ }
+
+ pub fn deinit(self: *Self, allocator: Allocator) void {
+ allocator.free(self.data);
+ }
+
+ pub fn eql(self: Self, other: Self) bool {
+ if (!meta.eql(self.inner, other.inner)) return false;
+ return mem.eql(u8, self.data, other.data);
+ }
+ };
+}
+
+pub fn createLoadDylibCommand(
+ allocator: Allocator,
+ name: []const u8,
+ timestamp: u32,
+ current_version: u32,
+ compatibility_version: u32,
+) !GenericCommandWithData(dylib_command) {
+ const cmdsize = @intCast(u32, mem.alignForwardGeneric(
+ u64,
+ @sizeOf(dylib_command) + name.len + 1, // +1 for nul
+ @sizeOf(u64),
+ ));
+
+ var dylib_cmd = emptyGenericCommandWithData(dylib_command{
+ .cmd = LC_LOAD_DYLIB,
+ .cmdsize = cmdsize,
+ .dylib = .{
+ .name = @sizeOf(dylib_command),
+ .timestamp = timestamp,
+ .current_version = current_version,
+ .compatibility_version = compatibility_version,
+ },
+ });
+ dylib_cmd.data = try allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
+
+ mem.set(u8, dylib_cmd.data, 0);
+ mem.copy(u8, dylib_cmd.data, name);
+
+ return dylib_cmd;
+}
+
+fn testRead(allocator: Allocator, buffer: []const u8, expected: anytype) !void {
+ var stream = io.fixedBufferStream(buffer);
+ var given = try LoadCommand.read(allocator, stream.reader());
+ defer given.deinit(allocator);
+ try testing.expect(expected.eql(given));
+}
+
+fn testWrite(buffer: []u8, cmd: LoadCommand, expected: []const u8) !void {
+ var stream = io.fixedBufferStream(buffer);
+ try cmd.write(stream.writer());
+ try testing.expect(mem.eql(u8, expected, buffer[0..expected.len]));
+}
+
+fn makeStaticString(bytes: []const u8) [16]u8 {
+ var buf = [_]u8{0} ** 16;
+ assert(bytes.len <= buf.len);
+ mem.copy(u8, &buf, bytes);
+ return buf;
+}
+
+test "read-write segment command" {
+ // TODO compiling for macOS from big-endian arch
+ if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest;
+
+ var gpa = testing.allocator;
+ const in_buffer = &[_]u8{
+ 0x19, 0x00, 0x00, 0x00, // cmd
+ 0x98, 0x00, 0x00, 0x00, // cmdsize
+ 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // vmaddr
+ 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // vmsize
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // fileoff
+ 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // filesize
+ 0x07, 0x00, 0x00, 0x00, // maxprot
+ 0x05, 0x00, 0x00, 0x00, // initprot
+ 0x01, 0x00, 0x00, 0x00, // nsects
+ 0x00, 0x00, 0x00, 0x00, // flags
+ 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sectname
+ 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname
+ 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // address
+ 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size
+ 0x00, 0x40, 0x00, 0x00, // offset
+ 0x02, 0x00, 0x00, 0x00, // alignment
+ 0x00, 0x00, 0x00, 0x00, // reloff
+ 0x00, 0x00, 0x00, 0x00, // nreloc
+ 0x00, 0x04, 0x00, 0x80, // flags
+ 0x00, 0x00, 0x00, 0x00, // reserved1
+ 0x00, 0x00, 0x00, 0x00, // reserved2
+ 0x00, 0x00, 0x00, 0x00, // reserved3
+ };
+ var cmd = SegmentCommand{
+ .inner = .{
+ .cmdsize = 152,
+ .segname = makeStaticString("__TEXT"),
+ .vmaddr = 4294967296,
+ .vmsize = 294912,
+ .filesize = 294912,
+ .maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE,
+ .initprot = VM_PROT_EXECUTE | VM_PROT_READ,
+ .nsects = 1,
+ },
+ };
+ try cmd.sections.append(gpa, .{
+ .sectname = makeStaticString("__text"),
+ .segname = makeStaticString("__TEXT"),
+ .addr = 4294983680,
+ .size = 448,
+ .offset = 16384,
+ .@"align" = 2,
+ .flags = S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS,
+ });
+ defer cmd.deinit(gpa);
+ try testRead(gpa, in_buffer, LoadCommand{ .segment = cmd });
+
+ var out_buffer: [in_buffer.len]u8 = undefined;
+ try testWrite(&out_buffer, LoadCommand{ .segment = cmd }, in_buffer);
+}
+
+test "read-write generic command with data" {
+ // TODO compiling for macOS from big-endian arch
+ if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest;
+
+ var gpa = testing.allocator;
+ const in_buffer = &[_]u8{
+ 0x0c, 0x00, 0x00, 0x00, // cmd
+ 0x20, 0x00, 0x00, 0x00, // cmdsize
+ 0x18, 0x00, 0x00, 0x00, // name
+ 0x02, 0x00, 0x00, 0x00, // timestamp
+ 0x00, 0x00, 0x00, 0x00, // current_version
+ 0x00, 0x00, 0x00, 0x00, // compatibility_version
+ 0x2f, 0x75, 0x73, 0x72, 0x00, 0x00, 0x00, 0x00, // data
+ };
+ var cmd = GenericCommandWithData(dylib_command){
+ .inner = .{
+ .cmd = LC_LOAD_DYLIB,
+ .cmdsize = 32,
+ .dylib = .{
+ .name = 24,
+ .timestamp = 2,
+ .current_version = 0,
+ .compatibility_version = 0,
+ },
+ },
+ };
+ cmd.data = try gpa.alloc(u8, 8);
+ defer gpa.free(cmd.data);
+ cmd.data[0] = 0x2f;
+ cmd.data[1] = 0x75;
+ cmd.data[2] = 0x73;
+ cmd.data[3] = 0x72;
+ cmd.data[4] = 0x0;
+ cmd.data[5] = 0x0;
+ cmd.data[6] = 0x0;
+ cmd.data[7] = 0x0;
+ try testRead(gpa, in_buffer, LoadCommand{ .dylib = cmd });
+
+ var out_buffer: [in_buffer.len]u8 = undefined;
+ try testWrite(&out_buffer, LoadCommand{ .dylib = cmd }, in_buffer);
+}
+
+test "read-write C struct command" {
+ // TODO compiling for macOS from big-endian arch
+ if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest;
+
+ var gpa = testing.allocator;
+ const in_buffer = &[_]u8{
+ 0x28, 0x00, 0x00, 0x80, // cmd
+ 0x18, 0x00, 0x00, 0x00, // cmdsize
+ 0x04, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // entryoff
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // stacksize
+ };
+ const cmd = .{
+ .cmd = LC_MAIN,
+ .cmdsize = 24,
+ .entryoff = 16644,
+ .stacksize = 0,
+ };
+ try testRead(gpa, in_buffer, LoadCommand{ .main = cmd });
+
+ var out_buffer: [in_buffer.len]u8 = undefined;
+ try testWrite(&out_buffer, LoadCommand{ .main = cmd }, in_buffer);
+}
src/link/MachO/Atom.zig
@@ -341,7 +341,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
if (rel.r_extern == 0) {
const sect_id = @intCast(u16, rel.r_symbolnum - 1);
const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: {
- const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment;
+ const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].segment;
const sect = seg.sections.items[sect_id];
const match = (try context.macho_file.getMatchingSection(sect)) orelse
unreachable;
@@ -397,7 +397,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
else
mem.readIntLittle(i32, self.code.items[offset..][0..4]);
if (rel.r_extern == 0) {
- const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment;
+ const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].segment;
const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
addend -= @intCast(i64, target_sect_base_addr);
}
@@ -424,7 +424,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
else
mem.readIntLittle(i32, self.code.items[offset..][0..4]);
if (rel.r_extern == 0) {
- const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment;
+ const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].segment;
const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
addend -= @intCast(i64, target_sect_base_addr);
}
@@ -446,7 +446,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
if (rel.r_extern == 0) {
// Note for the future self: when r_extern == 0, we should subtract correction from the
// addend.
- const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment;
+ const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].segment;
const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
addend += @intCast(i64, context.base_addr + offset + 4) -
@intCast(i64, target_sect_base_addr);
@@ -489,7 +489,7 @@ fn addPtrBindingOrRebase(
.local => {
const source_sym = context.macho_file.locals.items[self.local_sym_index];
const match = context.macho_file.section_ordinals.keys()[source_sym.n_sect - 1];
- const seg = context.macho_file.load_commands.items[match.seg].Segment;
+ const seg = context.macho_file.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
const sect_type = sect.type_();
@@ -704,7 +704,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
const is_tlv = is_tlv: {
const source_sym = macho_file.locals.items[self.local_sym_index];
const match = macho_file.section_ordinals.keys()[source_sym.n_sect - 1];
- const seg = macho_file.load_commands.items[match.seg].Segment;
+ const seg = macho_file.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
break :is_tlv sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
};
@@ -714,7 +714,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
// defined TLV template init section in the following order:
// * wrt to __thread_data if defined, then
// * wrt to __thread_bss
- const seg = macho_file.load_commands.items[macho_file.data_segment_cmd_index.?].Segment;
+ const seg = macho_file.load_commands.items[macho_file.data_segment_cmd_index.?].segment;
const base_address = inner: {
if (macho_file.tlv_data_section_index) |i| {
break :inner seg.sections.items[i].addr;
src/link/MachO/commands.zig
@@ -1,463 +0,0 @@
-const std = @import("std");
-const fs = std.fs;
-const io = std.io;
-const mem = std.mem;
-const meta = std.meta;
-const macho = std.macho;
-const testing = std.testing;
-const assert = std.debug.assert;
-
-const Allocator = std.mem.Allocator;
-const MachO = @import("../MachO.zig");
-const makeStaticString = MachO.makeStaticString;
-const padToIdeal = MachO.padToIdeal;
-
-pub const LoadCommand = union(enum) {
- Segment: SegmentCommand,
- DyldInfoOnly: macho.dyld_info_command,
- Symtab: macho.symtab_command,
- Dysymtab: macho.dysymtab_command,
- Dylinker: GenericCommandWithData(macho.dylinker_command),
- Dylib: GenericCommandWithData(macho.dylib_command),
- Main: macho.entry_point_command,
- VersionMin: macho.version_min_command,
- SourceVersion: macho.source_version_command,
- BuildVersion: GenericCommandWithData(macho.build_version_command),
- Uuid: macho.uuid_command,
- LinkeditData: macho.linkedit_data_command,
- Rpath: GenericCommandWithData(macho.rpath_command),
- Unknown: GenericCommandWithData(macho.load_command),
-
- pub fn read(allocator: Allocator, reader: anytype) !LoadCommand {
- const header = try reader.readStruct(macho.load_command);
- var buffer = try allocator.alloc(u8, header.cmdsize);
- defer allocator.free(buffer);
- mem.copy(u8, buffer, mem.asBytes(&header));
- try reader.readNoEof(buffer[@sizeOf(macho.load_command)..]);
- var stream = io.fixedBufferStream(buffer);
-
- return switch (header.cmd) {
- macho.LC_SEGMENT_64 => LoadCommand{
- .Segment = try SegmentCommand.read(allocator, stream.reader()),
- },
- macho.LC_DYLD_INFO,
- macho.LC_DYLD_INFO_ONLY,
- => LoadCommand{
- .DyldInfoOnly = try stream.reader().readStruct(macho.dyld_info_command),
- },
- macho.LC_SYMTAB => LoadCommand{
- .Symtab = try stream.reader().readStruct(macho.symtab_command),
- },
- macho.LC_DYSYMTAB => LoadCommand{
- .Dysymtab = try stream.reader().readStruct(macho.dysymtab_command),
- },
- macho.LC_ID_DYLINKER,
- macho.LC_LOAD_DYLINKER,
- macho.LC_DYLD_ENVIRONMENT,
- => LoadCommand{
- .Dylinker = try GenericCommandWithData(macho.dylinker_command).read(allocator, stream.reader()),
- },
- macho.LC_ID_DYLIB,
- macho.LC_LOAD_WEAK_DYLIB,
- macho.LC_LOAD_DYLIB,
- macho.LC_REEXPORT_DYLIB,
- => LoadCommand{
- .Dylib = try GenericCommandWithData(macho.dylib_command).read(allocator, stream.reader()),
- },
- macho.LC_MAIN => LoadCommand{
- .Main = try stream.reader().readStruct(macho.entry_point_command),
- },
- macho.LC_VERSION_MIN_MACOSX,
- macho.LC_VERSION_MIN_IPHONEOS,
- macho.LC_VERSION_MIN_WATCHOS,
- macho.LC_VERSION_MIN_TVOS,
- => LoadCommand{
- .VersionMin = try stream.reader().readStruct(macho.version_min_command),
- },
- macho.LC_SOURCE_VERSION => LoadCommand{
- .SourceVersion = try stream.reader().readStruct(macho.source_version_command),
- },
- macho.LC_BUILD_VERSION => LoadCommand{
- .BuildVersion = try GenericCommandWithData(macho.build_version_command).read(allocator, stream.reader()),
- },
- macho.LC_UUID => LoadCommand{
- .Uuid = try stream.reader().readStruct(macho.uuid_command),
- },
- macho.LC_FUNCTION_STARTS,
- macho.LC_DATA_IN_CODE,
- macho.LC_CODE_SIGNATURE,
- => LoadCommand{
- .LinkeditData = try stream.reader().readStruct(macho.linkedit_data_command),
- },
- macho.LC_RPATH => LoadCommand{
- .Rpath = try GenericCommandWithData(macho.rpath_command).read(allocator, stream.reader()),
- },
- else => LoadCommand{
- .Unknown = try GenericCommandWithData(macho.load_command).read(allocator, stream.reader()),
- },
- };
- }
-
- pub fn write(self: LoadCommand, writer: anytype) !void {
- return switch (self) {
- .DyldInfoOnly => |x| writeStruct(x, writer),
- .Symtab => |x| writeStruct(x, writer),
- .Dysymtab => |x| writeStruct(x, writer),
- .Main => |x| writeStruct(x, writer),
- .VersionMin => |x| writeStruct(x, writer),
- .SourceVersion => |x| writeStruct(x, writer),
- .Uuid => |x| writeStruct(x, writer),
- .LinkeditData => |x| writeStruct(x, writer),
- .Segment => |x| x.write(writer),
- .Dylinker => |x| x.write(writer),
- .Dylib => |x| x.write(writer),
- .Rpath => |x| x.write(writer),
- .BuildVersion => |x| x.write(writer),
- .Unknown => |x| x.write(writer),
- };
- }
-
- pub fn cmd(self: LoadCommand) u32 {
- return switch (self) {
- .DyldInfoOnly => |x| x.cmd,
- .Symtab => |x| x.cmd,
- .Dysymtab => |x| x.cmd,
- .Main => |x| x.cmd,
- .VersionMin => |x| x.cmd,
- .SourceVersion => |x| x.cmd,
- .Uuid => |x| x.cmd,
- .LinkeditData => |x| x.cmd,
- .Segment => |x| x.inner.cmd,
- .Dylinker => |x| x.inner.cmd,
- .Dylib => |x| x.inner.cmd,
- .Rpath => |x| x.inner.cmd,
- .BuildVersion => |x| x.inner.cmd,
- .Unknown => |x| x.inner.cmd,
- };
- }
-
- pub fn cmdsize(self: LoadCommand) u32 {
- return switch (self) {
- .DyldInfoOnly => |x| x.cmdsize,
- .Symtab => |x| x.cmdsize,
- .Dysymtab => |x| x.cmdsize,
- .Main => |x| x.cmdsize,
- .VersionMin => |x| x.cmdsize,
- .SourceVersion => |x| x.cmdsize,
- .LinkeditData => |x| x.cmdsize,
- .Uuid => |x| x.cmdsize,
- .Segment => |x| x.inner.cmdsize,
- .Dylinker => |x| x.inner.cmdsize,
- .Dylib => |x| x.inner.cmdsize,
- .Rpath => |x| x.inner.cmdsize,
- .BuildVersion => |x| x.inner.cmdsize,
- .Unknown => |x| x.inner.cmdsize,
- };
- }
-
- pub fn deinit(self: *LoadCommand, allocator: Allocator) void {
- return switch (self.*) {
- .Segment => |*x| x.deinit(allocator),
- .Dylinker => |*x| x.deinit(allocator),
- .Dylib => |*x| x.deinit(allocator),
- .Rpath => |*x| x.deinit(allocator),
- .BuildVersion => |*x| x.deinit(allocator),
- .Unknown => |*x| x.deinit(allocator),
- else => {},
- };
- }
-
- fn writeStruct(command: anytype, writer: anytype) !void {
- return writer.writeAll(mem.asBytes(&command));
- }
-
- fn eql(self: LoadCommand, other: LoadCommand) bool {
- if (@as(meta.Tag(LoadCommand), self) != @as(meta.Tag(LoadCommand), other)) return false;
- return switch (self) {
- .DyldInfoOnly => |x| meta.eql(x, other.DyldInfoOnly),
- .Symtab => |x| meta.eql(x, other.Symtab),
- .Dysymtab => |x| meta.eql(x, other.Dysymtab),
- .Main => |x| meta.eql(x, other.Main),
- .VersionMin => |x| meta.eql(x, other.VersionMin),
- .SourceVersion => |x| meta.eql(x, other.SourceVersion),
- .BuildVersion => |x| x.eql(other.BuildVersion),
- .Uuid => |x| meta.eql(x, other.Uuid),
- .LinkeditData => |x| meta.eql(x, other.LinkeditData),
- .Segment => |x| x.eql(other.Segment),
- .Dylinker => |x| x.eql(other.Dylinker),
- .Dylib => |x| x.eql(other.Dylib),
- .Rpath => |x| x.eql(other.Rpath),
- .Unknown => |x| x.eql(other.Unknown),
- };
- }
-};
-
-pub const SegmentCommand = struct {
- inner: macho.segment_command_64,
- sections: std.ArrayListUnmanaged(macho.section_64) = .{},
-
- pub fn read(alloc: Allocator, reader: anytype) !SegmentCommand {
- const inner = try reader.readStruct(macho.segment_command_64);
- var segment = SegmentCommand{
- .inner = inner,
- };
- try segment.sections.ensureTotalCapacityPrecise(alloc, inner.nsects);
-
- var i: usize = 0;
- while (i < inner.nsects) : (i += 1) {
- const section = try reader.readStruct(macho.section_64);
- segment.sections.appendAssumeCapacity(section);
- }
-
- return segment;
- }
-
- pub fn write(self: SegmentCommand, writer: anytype) !void {
- try writer.writeAll(mem.asBytes(&self.inner));
- for (self.sections.items) |sect| {
- try writer.writeAll(mem.asBytes(§));
- }
- }
-
- pub fn deinit(self: *SegmentCommand, alloc: Allocator) void {
- self.sections.deinit(alloc);
- }
-
- pub fn allocatedSize(self: SegmentCommand, start: u64) u64 {
- assert(start >= self.inner.fileoff);
- var min_pos: u64 = self.inner.fileoff + self.inner.filesize;
- for (self.sections.items) |section| {
- if (section.offset <= start) continue;
- if (section.offset < min_pos) min_pos = section.offset;
- }
- return min_pos - start;
- }
-
- fn detectAllocCollision(self: SegmentCommand, start: u64, size: u64) ?u64 {
- const end = start + padToIdeal(size);
- for (self.sections.items) |section| {
- const increased_size = padToIdeal(section.size);
- const test_end = section.offset + increased_size;
- if (end > section.offset and start < test_end) {
- return test_end;
- }
- }
- return null;
- }
-
- pub fn findFreeSpace(self: SegmentCommand, object_size: u64, min_alignment: u64, start: ?u64) u64 {
- var offset: u64 = if (start) |v| v else self.inner.fileoff;
- while (self.detectAllocCollision(offset, object_size)) |item_end| {
- offset = mem.alignForwardGeneric(u64, item_end, min_alignment);
- }
- return offset;
- }
-
- fn eql(self: SegmentCommand, other: SegmentCommand) bool {
- if (!meta.eql(self.inner, other.inner)) return false;
- const lhs = self.sections.items;
- const rhs = other.sections.items;
- var i: usize = 0;
- while (i < self.inner.nsects) : (i += 1) {
- if (!meta.eql(lhs[i], rhs[i])) return false;
- }
- return true;
- }
-};
-
-pub fn emptyGenericCommandWithData(cmd: anytype) GenericCommandWithData(@TypeOf(cmd)) {
- return .{ .inner = cmd };
-}
-
-pub fn GenericCommandWithData(comptime Cmd: type) type {
- return struct {
- inner: Cmd,
- /// This field remains undefined until `read` is called.
- data: []u8 = undefined,
-
- const Self = @This();
-
- pub fn read(allocator: Allocator, reader: anytype) !Self {
- const inner = try reader.readStruct(Cmd);
- var data = try allocator.alloc(u8, inner.cmdsize - @sizeOf(Cmd));
- errdefer allocator.free(data);
- try reader.readNoEof(data);
- return Self{
- .inner = inner,
- .data = data,
- };
- }
-
- pub fn write(self: Self, writer: anytype) !void {
- try writer.writeAll(mem.asBytes(&self.inner));
- try writer.writeAll(self.data);
- }
-
- pub fn deinit(self: *Self, allocator: Allocator) void {
- allocator.free(self.data);
- }
-
- fn eql(self: Self, other: Self) bool {
- if (!meta.eql(self.inner, other.inner)) return false;
- return mem.eql(u8, self.data, other.data);
- }
- };
-}
-
-pub fn createLoadDylibCommand(
- allocator: Allocator,
- name: []const u8,
- timestamp: u32,
- current_version: u32,
- compatibility_version: u32,
-) !GenericCommandWithData(macho.dylib_command) {
- const cmdsize = @intCast(u32, mem.alignForwardGeneric(
- u64,
- @sizeOf(macho.dylib_command) + name.len + 1, // +1 for nul
- @sizeOf(u64),
- ));
-
- var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{
- .cmd = macho.LC_LOAD_DYLIB,
- .cmdsize = cmdsize,
- .dylib = .{
- .name = @sizeOf(macho.dylib_command),
- .timestamp = timestamp,
- .current_version = current_version,
- .compatibility_version = compatibility_version,
- },
- });
- dylib_cmd.data = try allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
-
- mem.set(u8, dylib_cmd.data, 0);
- mem.copy(u8, dylib_cmd.data, name);
-
- return dylib_cmd;
-}
-
-fn testRead(allocator: Allocator, buffer: []const u8, expected: anytype) !void {
- var stream = io.fixedBufferStream(buffer);
- var given = try LoadCommand.read(allocator, stream.reader());
- defer given.deinit(allocator);
- try testing.expect(expected.eql(given));
-}
-
-fn testWrite(buffer: []u8, cmd: LoadCommand, expected: []const u8) !void {
- var stream = io.fixedBufferStream(buffer);
- try cmd.write(stream.writer());
- try testing.expect(mem.eql(u8, expected, buffer[0..expected.len]));
-}
-
-test "read-write segment command" {
- var gpa = testing.allocator;
- const in_buffer = &[_]u8{
- 0x19, 0x00, 0x00, 0x00, // cmd
- 0x98, 0x00, 0x00, 0x00, // cmdsize
- 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // vmaddr
- 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // vmsize
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // fileoff
- 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // filesize
- 0x07, 0x00, 0x00, 0x00, // maxprot
- 0x05, 0x00, 0x00, 0x00, // initprot
- 0x01, 0x00, 0x00, 0x00, // nsects
- 0x00, 0x00, 0x00, 0x00, // flags
- 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sectname
- 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname
- 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // address
- 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size
- 0x00, 0x40, 0x00, 0x00, // offset
- 0x02, 0x00, 0x00, 0x00, // alignment
- 0x00, 0x00, 0x00, 0x00, // reloff
- 0x00, 0x00, 0x00, 0x00, // nreloc
- 0x00, 0x04, 0x00, 0x80, // flags
- 0x00, 0x00, 0x00, 0x00, // reserved1
- 0x00, 0x00, 0x00, 0x00, // reserved2
- 0x00, 0x00, 0x00, 0x00, // reserved3
- };
- var cmd = SegmentCommand{
- .inner = .{
- .cmdsize = 152,
- .segname = makeStaticString("__TEXT"),
- .vmaddr = 4294967296,
- .vmsize = 294912,
- .filesize = 294912,
- .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE,
- .initprot = macho.VM_PROT_EXECUTE | macho.VM_PROT_READ,
- .nsects = 1,
- },
- };
- try cmd.sections.append(gpa, .{
- .sectname = makeStaticString("__text"),
- .segname = makeStaticString("__TEXT"),
- .addr = 4294983680,
- .size = 448,
- .offset = 16384,
- .@"align" = 2,
- .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
- });
- defer cmd.deinit(gpa);
- try testRead(gpa, in_buffer, LoadCommand{ .Segment = cmd });
-
- var out_buffer: [in_buffer.len]u8 = undefined;
- try testWrite(&out_buffer, LoadCommand{ .Segment = cmd }, in_buffer);
-}
-
-test "read-write generic command with data" {
- var gpa = testing.allocator;
- const in_buffer = &[_]u8{
- 0x0c, 0x00, 0x00, 0x00, // cmd
- 0x20, 0x00, 0x00, 0x00, // cmdsize
- 0x18, 0x00, 0x00, 0x00, // name
- 0x02, 0x00, 0x00, 0x00, // timestamp
- 0x00, 0x00, 0x00, 0x00, // current_version
- 0x00, 0x00, 0x00, 0x00, // compatibility_version
- 0x2f, 0x75, 0x73, 0x72, 0x00, 0x00, 0x00, 0x00, // data
- };
- var cmd = GenericCommandWithData(macho.dylib_command){
- .inner = .{
- .cmd = macho.LC_LOAD_DYLIB,
- .cmdsize = 32,
- .dylib = .{
- .name = 24,
- .timestamp = 2,
- .current_version = 0,
- .compatibility_version = 0,
- },
- },
- };
- cmd.data = try gpa.alloc(u8, 8);
- defer gpa.free(cmd.data);
- cmd.data[0] = 0x2f;
- cmd.data[1] = 0x75;
- cmd.data[2] = 0x73;
- cmd.data[3] = 0x72;
- cmd.data[4] = 0x0;
- cmd.data[5] = 0x0;
- cmd.data[6] = 0x0;
- cmd.data[7] = 0x0;
- try testRead(gpa, in_buffer, LoadCommand{ .Dylib = cmd });
-
- var out_buffer: [in_buffer.len]u8 = undefined;
- try testWrite(&out_buffer, LoadCommand{ .Dylib = cmd }, in_buffer);
-}
-
-test "read-write C struct command" {
- var gpa = testing.allocator;
- const in_buffer = &[_]u8{
- 0x28, 0x00, 0x00, 0x80, // cmd
- 0x18, 0x00, 0x00, 0x00, // cmdsize
- 0x04, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // entryoff
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // stacksize
- };
- const cmd = .{
- .cmd = macho.LC_MAIN,
- .cmdsize = 24,
- .entryoff = 16644,
- .stacksize = 0,
- };
- try testRead(gpa, in_buffer, LoadCommand{ .Main = cmd });
-
- var out_buffer: [in_buffer.len]u8 = undefined;
- try testWrite(&out_buffer, LoadCommand{ .Main = cmd }, in_buffer);
-}
src/link/MachO/DebugSymbols.zig
@@ -12,15 +12,12 @@ const leb = std.leb;
const Allocator = mem.Allocator;
const build_options = @import("build_options");
-const commands = @import("commands.zig");
const trace = @import("../../tracy.zig").trace;
-const LoadCommand = commands.LoadCommand;
const Module = @import("../../Module.zig");
const Type = @import("../../type.zig").Type;
const link = @import("../../link.zig");
const MachO = @import("../MachO.zig");
const TextBlock = MachO.TextBlock;
-const SegmentCommand = commands.SegmentCommand;
const SrcFn = MachO.SrcFn;
const makeStaticString = MachO.makeStaticString;
const padToIdeal = MachO.padToIdeal;
@@ -31,7 +28,7 @@ base: *MachO,
file: fs.File,
/// Table of all load commands
-load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
+load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
/// __PAGEZERO segment
pagezero_segment_cmd_index: ?u16 = null,
/// __TEXT segment
@@ -113,7 +110,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
}
if (self.symtab_cmd_index == null) {
self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
- const base_cmd = self.base.load_commands.items[self.base.symtab_cmd_index.?].Symtab;
+ const base_cmd = self.base.load_commands.items[self.base.symtab_cmd_index.?].symtab;
const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64);
const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64));
@@ -124,7 +121,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize });
try self.load_commands.append(allocator, .{
- .Symtab = .{
+ .symtab = .{
.cmd = macho.LC_SYMTAB,
.cmdsize = @sizeOf(macho.symtab_command),
.symoff = @intCast(u32, symtab_off),
@@ -138,48 +135,48 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
}
if (self.pagezero_segment_cmd_index == null) {
self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
- const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].Segment;
+ const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].segment;
const cmd = try self.copySegmentCommand(allocator, base_cmd);
- try self.load_commands.append(allocator, .{ .Segment = cmd });
+ try self.load_commands.append(allocator, .{ .segment = cmd });
self.load_commands_dirty = true;
}
if (self.text_segment_cmd_index == null) {
self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
- const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].Segment;
+ const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].segment;
const cmd = try self.copySegmentCommand(allocator, base_cmd);
- try self.load_commands.append(allocator, .{ .Segment = cmd });
+ try self.load_commands.append(allocator, .{ .segment = cmd });
self.load_commands_dirty = true;
}
if (self.data_const_segment_cmd_index == null) outer: {
if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional
self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
- const base_cmd = self.base.load_commands.items[self.base.data_const_segment_cmd_index.?].Segment;
+ const base_cmd = self.base.load_commands.items[self.base.data_const_segment_cmd_index.?].segment;
const cmd = try self.copySegmentCommand(allocator, base_cmd);
- try self.load_commands.append(allocator, .{ .Segment = cmd });
+ try self.load_commands.append(allocator, .{ .segment = cmd });
self.load_commands_dirty = true;
}
if (self.data_segment_cmd_index == null) outer: {
if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional
self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
- const base_cmd = self.base.load_commands.items[self.base.data_segment_cmd_index.?].Segment;
+ const base_cmd = self.base.load_commands.items[self.base.data_segment_cmd_index.?].segment;
const cmd = try self.copySegmentCommand(allocator, base_cmd);
- try self.load_commands.append(allocator, .{ .Segment = cmd });
+ try self.load_commands.append(allocator, .{ .segment = cmd });
self.load_commands_dirty = true;
}
if (self.linkedit_segment_cmd_index == null) {
self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
- const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].Segment;
+ const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].segment;
var cmd = try self.copySegmentCommand(allocator, base_cmd);
cmd.inner.vmsize = self.linkedit_size;
cmd.inner.fileoff = self.linkedit_off;
cmd.inner.filesize = self.linkedit_size;
- try self.load_commands.append(allocator, .{ .Segment = cmd });
+ try self.load_commands.append(allocator, .{ .segment = cmd });
self.load_commands_dirty = true;
}
if (self.dwarf_segment_cmd_index == null) {
self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
- const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
const ideal_size: u16 = 200 + 128 + 160 + 250;
const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size);
const off = linkedit.inner.fileoff + linkedit.inner.filesize;
@@ -188,7 +185,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try self.load_commands.append(allocator, .{
- .Segment = .{
+ .segment = .{
.inner = .{
.segname = makeStaticString("__DWARF"),
.vmaddr = vmaddr,
@@ -228,7 +225,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
}
fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u16 {
- const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
var sect = macho.section_64{
.sectname = makeStaticString(sectname),
.segname = seg.inner.segname,
@@ -236,7 +233,7 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
.@"align" = alignment,
};
const alignment_pow_2 = try math.powi(u32, 2, alignment);
- const off = seg.findFreeSpace(size, alignment_pow_2, null);
+ const off = self.findFreeSpace(size, alignment_pow_2);
assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand
@@ -268,6 +265,28 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
return index;
}
+fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {
+ const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
+ const end = start + padToIdeal(size);
+ for (seg.sections.items) |section| {
+ const increased_size = padToIdeal(section.size);
+ const test_end = section.offset + increased_size;
+ if (end > section.offset and start < test_end) {
+ return test_end;
+ }
+ }
+ return null;
+}
+
+fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {
+ const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
+ var offset: u64 = seg.inner.fileoff;
+ while (self.detectAllocCollision(offset, object_size)) |item_end| {
+ offset = mem.alignForwardGeneric(u64, item_end, min_alignment);
+ }
+ return offset;
+}
+
pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Options) !void {
// TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the
// Zig source code.
@@ -275,7 +294,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
const init_len_size: usize = 4;
if (self.debug_abbrev_section_dirty) {
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const debug_abbrev_sect = &dwarf_segment.sections.items[self.debug_abbrev_section_index.?];
// These are LEB encoded but since the values are all less than 127
@@ -320,10 +339,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
};
const needed_size = abbrev_buf.len;
- const allocated_size = dwarf_segment.allocatedSize(debug_abbrev_sect.offset);
+ const allocated_size = self.allocatedSize(debug_abbrev_sect.offset);
if (needed_size > allocated_size) {
debug_abbrev_sect.size = 0; // free the space
- const offset = dwarf_segment.findFreeSpace(needed_size, 1, null);
+ const offset = self.findFreeSpace(needed_size, 1);
debug_abbrev_sect.offset = @intCast(u32, offset);
debug_abbrev_sect.addr = dwarf_segment.inner.vmaddr + offset - dwarf_segment.inner.fileoff;
}
@@ -345,7 +364,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
// leave debug_info_header_dirty=true.
const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info;
const last_dbg_info_decl = self.dbg_info_decl_last.?;
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
// We have a function to compute the upper bound size, because it's needed
@@ -372,7 +391,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
const producer_strp = try self.makeDebugString(allocator, link.producer_string);
// Currently only one compilation unit is supported, so the address range is simply
// identical to the main program header virtual address and memory size.
- const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;
const text_section = text_segment.sections.items[self.text_section_index.?];
const low_pc = text_section.addr;
const high_pc = text_section.addr + text_section.size;
@@ -399,7 +418,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
}
if (self.debug_aranges_section_dirty) {
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const debug_aranges_sect = &dwarf_segment.sections.items[self.debug_aranges_section_index.?];
// Enough for all the data without resizing. When support for more compilation units
@@ -426,7 +445,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
// Currently only one compilation unit is supported, so the address range is simply
// identical to the main program header virtual address and memory size.
- const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;
const text_section = text_segment.sections.items[self.text_section_index.?];
mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.addr);
mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size);
@@ -442,10 +461,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len));
const needed_size = di_buf.items.len;
- const allocated_size = dwarf_segment.allocatedSize(debug_aranges_sect.offset);
+ const allocated_size = self.allocatedSize(debug_aranges_sect.offset);
if (needed_size > allocated_size) {
debug_aranges_sect.size = 0; // free the space
- const new_offset = dwarf_segment.findFreeSpace(needed_size, 16, null);
+ const new_offset = self.findFreeSpace(needed_size, 16);
debug_aranges_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;
debug_aranges_sect.offset = @intCast(u32, new_offset);
}
@@ -467,7 +486,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
const dbg_line_prg_end = self.getDebugLineProgramEnd();
assert(dbg_line_prg_end != 0);
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];
// The size of this header is variable, depending on the number of directories,
@@ -540,15 +559,15 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
self.debug_line_header_dirty = false;
}
{
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const debug_strtab_sect = &dwarf_segment.sections.items[self.debug_str_section_index.?];
if (self.debug_string_table_dirty or self.debug_string_table.items.len != debug_strtab_sect.size) {
- const allocated_size = dwarf_segment.allocatedSize(debug_strtab_sect.offset);
+ const allocated_size = self.allocatedSize(debug_strtab_sect.offset);
const needed_size = self.debug_string_table.items.len;
if (needed_size > allocated_size) {
debug_strtab_sect.size = 0; // free the space
- const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null);
+ const new_offset = self.findFreeSpace(needed_size, 1);
debug_strtab_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;
debug_strtab_sect.offset = @intCast(u32, new_offset);
}
@@ -588,8 +607,12 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {
self.file.close();
}
-fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: SegmentCommand) !SegmentCommand {
- var cmd = SegmentCommand{
+fn copySegmentCommand(
+ self: *DebugSymbols,
+ allocator: Allocator,
+ base_cmd: macho.SegmentCommand,
+) !macho.SegmentCommand {
+ var cmd = macho.SegmentCommand{
.inner = .{
.segname = undefined,
.cmdsize = base_cmd.inner.cmdsize,
@@ -633,7 +656,7 @@ fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: Segme
}
fn updateDwarfSegment(self: *DebugSymbols) void {
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
var file_size: u64 = 0;
for (dwarf_segment.sections.items) |sect| {
file_size += sect.size;
@@ -702,7 +725,7 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {
var min_pos: u64 = std.math.maxInt(u64);
if (self.symtab_cmd_index) |idx| {
- const symtab = self.load_commands.items[idx].Symtab;
+ const symtab = self.load_commands.items[idx].symtab;
if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff;
if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff;
}
@@ -710,12 +733,23 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {
return min_pos - start;
}
+fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
+ const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
+ assert(start >= seg.inner.fileoff);
+ var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize;
+ for (seg.sections.items) |section| {
+ if (section.offset <= start) continue;
+ if (section.offset < min_pos) min_pos = section.offset;
+ }
+ return min_pos - start;
+}
+
fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 {
const end = start + padToIdeal(size);
if (self.symtab_cmd_index) |idx| outer: {
if (self.load_commands.items.len == idx) break :outer;
- const symtab = self.load_commands.items[idx].Symtab;
+ const symtab = self.load_commands.items[idx].symtab;
{
// Symbol table
const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
@@ -747,7 +781,7 @@ fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u
}
fn relocateSymbolTable(self: *DebugSymbols) !void {
- const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
+ const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
const nlocals = self.base.locals.items.len;
const nglobals = self.base.globals.items.len;
const nsyms = nlocals + nglobals;
@@ -780,7 +814,7 @@ pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void {
const tracy = trace(@src());
defer tracy.end();
try self.relocateSymbolTable();
- const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
+ const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;
log.debug("writing local symbol {} at 0x{x}", .{ index, off });
try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off);
@@ -792,7 +826,7 @@ fn writeStringTable(self: *DebugSymbols) !void {
const tracy = trace(@src());
defer tracy.end();
- const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
+ const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);
const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64));
@@ -816,7 +850,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
const func = decl.val.castTag(.function).?.data;
const line_off = @intCast(u28, decl.src_line + func.lbrace_line);
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?];
const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff();
var data: [4]u8 = undefined;
@@ -982,7 +1016,7 @@ pub fn commitDeclDebugInfo(
// `TextBlock` and the .debug_info. If you are editing this logic, you
// probably need to edit that logic too.
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];
const src_fn = &decl.fn_link.macho;
src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
@@ -1028,8 +1062,8 @@ pub fn commitDeclDebugInfo(
const last_src_fn = self.dbg_line_fn_last.?;
const needed_size = last_src_fn.off + last_src_fn.len;
if (needed_size != debug_line_sect.size) {
- if (needed_size > dwarf_segment.allocatedSize(debug_line_sect.offset)) {
- const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null);
+ if (needed_size > self.allocatedSize(debug_line_sect.offset)) {
+ const new_offset = self.findFreeSpace(needed_size, 1);
const existing_size = last_src_fn.off;
log.debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{
@@ -1151,7 +1185,7 @@ fn updateDeclDebugInfoAllocation(
// `SrcFn` and the line number programs. If you are editing this logic, you
// probably need to edit that logic too.
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
text_block.dbg_info_len = len;
if (self.dbg_info_decl_last) |last| blk: {
@@ -1202,15 +1236,15 @@ fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_buf:
// `SrcFn` and the line number programs. If you are editing this logic, you
// probably need to edit that logic too.
- const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
+ const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
const last_decl = self.dbg_info_decl_last.?;
// +1 for a trailing zero to end the children of the decl tag.
const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1;
if (needed_size != debug_info_sect.size) {
- if (needed_size > dwarf_segment.allocatedSize(debug_info_sect.offset)) {
- const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null);
+ if (needed_size > self.allocatedSize(debug_info_sect.offset)) {
+ const new_offset = self.findFreeSpace(needed_size, 1);
const existing_size = last_decl.dbg_info_off;
log.debug("moving __debug_info section: {} bytes from 0x{x} to 0x{x}", .{
src/link/MachO/Dylib.zig
@@ -9,11 +9,9 @@ const macho = std.macho;
const math = std.math;
const mem = std.mem;
const fat = @import("fat.zig");
-const commands = @import("commands.zig");
const Allocator = mem.Allocator;
const LibStub = @import("../tapi.zig").LibStub;
-const LoadCommand = commands.LoadCommand;
const MachO = @import("../MachO.zig");
file: fs.File,
@@ -25,7 +23,7 @@ header: ?macho.mach_header_64 = null,
// an offset within a file if we are linking against a fat lib
library_offset: u64 = 0,
-load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
+load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
symtab_cmd_index: ?u16 = null,
dysymtab_cmd_index: ?u16 = null,
@@ -53,7 +51,7 @@ pub const Id = struct {
};
}
- pub fn fromLoadCommand(allocator: Allocator, lc: commands.GenericCommandWithData(macho.dylib_command)) !Id {
+ pub fn fromLoadCommand(allocator: Allocator, lc: macho.GenericCommandWithData(macho.dylib_command)) !Id {
const dylib = lc.inner.dylib;
const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]);
const name = try allocator.dupe(u8, mem.sliceTo(dylib_name, 0));
@@ -177,7 +175,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende
var i: u16 = 0;
while (i < self.header.?.ncmds) : (i += 1) {
- var cmd = try LoadCommand.read(allocator, reader);
+ var cmd = try macho.LoadCommand.read(allocator, reader);
switch (cmd.cmd()) {
macho.LC_SYMTAB => {
self.symtab_cmd_index = i;
@@ -191,7 +189,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende
macho.LC_REEXPORT_DYLIB => {
if (should_lookup_reexports) {
// Parse install_name to dependent dylib.
- var id = try Id.fromLoadCommand(allocator, cmd.Dylib);
+ var id = try Id.fromLoadCommand(allocator, cmd.dylib);
try dependent_libs.writeItem(id);
}
},
@@ -209,12 +207,12 @@ fn parseId(self: *Dylib, allocator: Allocator) !void {
self.id = try Id.default(allocator, self.name);
return;
};
- self.id = try Id.fromLoadCommand(allocator, self.load_commands.items[index].Dylib);
+ self.id = try Id.fromLoadCommand(allocator, self.load_commands.items[index].dylib);
}
fn parseSymbols(self: *Dylib, allocator: Allocator) !void {
const index = self.symtab_cmd_index orelse return;
- const symtab_cmd = self.load_commands.items[index].Symtab;
+ const symtab_cmd = self.load_commands.items[index].symtab;
var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
defer allocator.free(symtab);
src/link/MachO/Object.zig
@@ -15,7 +15,6 @@ const trace = @import("../../tracy.zig").trace;
const Allocator = mem.Allocator;
const Atom = @import("Atom.zig");
-const LoadCommand = @import("commands.zig").LoadCommand;
const MachO = @import("../MachO.zig");
file: fs.File,
@@ -25,7 +24,7 @@ file_offset: ?u32 = null,
header: ?macho.mach_header_64 = null,
-load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
+load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
segment_cmd_index: ?u16 = null,
text_section_index: ?u16 = null,
@@ -268,11 +267,11 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
var i: u16 = 0;
while (i < header.ncmds) : (i += 1) {
- var cmd = try LoadCommand.read(allocator, reader);
+ var cmd = try macho.LoadCommand.read(allocator, reader);
switch (cmd.cmd()) {
macho.LC_SEGMENT_64 => {
self.segment_cmd_index = i;
- var seg = cmd.Segment;
+ var seg = cmd.segment;
for (seg.sections.items) |*sect, j| {
const index = @intCast(u16, j);
const segname = sect.segName();
@@ -305,8 +304,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
},
macho.LC_SYMTAB => {
self.symtab_cmd_index = i;
- cmd.Symtab.symoff += offset;
- cmd.Symtab.stroff += offset;
+ cmd.symtab.symoff += offset;
+ cmd.symtab.stroff += offset;
},
macho.LC_DYSYMTAB => {
self.dysymtab_cmd_index = i;
@@ -316,7 +315,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
},
macho.LC_DATA_IN_CODE => {
self.data_in_code_cmd_index = i;
- cmd.LinkeditData.dataoff += offset;
+ cmd.linkedit_data.dataoff += offset;
},
else => {
log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
@@ -382,7 +381,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
const tracy = trace(@src());
defer tracy.end();
- const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
+ const seg = self.load_commands.items[self.segment_cmd_index.?].segment;
log.debug("analysing {s}", .{self.name});
@@ -405,7 +404,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
// Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
// have to infer the start of undef section in the symtab ourselves.
const iundefsym = if (self.dysymtab_cmd_index) |cmd_index| blk: {
- const dysymtab = self.load_commands.items[cmd_index].Dysymtab;
+ const dysymtab = self.load_commands.items[cmd_index].dysymtab;
break :blk dysymtab.iundefsym;
} else blk: {
var iundefsym: usize = sorted_all_nlists.items.len;
@@ -553,7 +552,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
fn parseSymtab(self: *Object, allocator: Allocator) !void {
const index = self.symtab_cmd_index orelse return;
- const symtab_cmd = self.load_commands.items[index].Symtab;
+ const symtab_cmd = self.load_commands.items[index].symtab;
var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
defer allocator.free(symtab);
@@ -601,7 +600,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {
pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {
const index = self.data_in_code_cmd_index orelse return;
- const data_in_code = self.load_commands.items[index].LinkeditData;
+ const data_in_code = self.load_commands.items[index].linkedit_data;
var buffer = try allocator.alloc(u8, data_in_code.datasize);
defer allocator.free(buffer);
@@ -620,7 +619,7 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {
}
fn readSection(self: Object, allocator: Allocator, index: u16) ![]u8 {
- const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
+ const seg = self.load_commands.items[self.segment_cmd_index.?].segment;
const sect = seg.sections.items[index];
var buffer = try allocator.alloc(u8, @intCast(usize, sect.size));
_ = try self.file.preadAll(buffer, sect.offset);
src/link/MachO.zig
@@ -15,7 +15,6 @@ const meta = std.meta;
const aarch64 = @import("../arch/aarch64/bits.zig");
const bind = @import("MachO/bind.zig");
const codegen = @import("../codegen.zig");
-const commands = @import("MachO/commands.zig");
const link = @import("../link.zig");
const llvm_backend = @import("../codegen/llvm.zig");
const target_util = @import("../target.zig");
@@ -35,9 +34,7 @@ const Object = @import("MachO/Object.zig");
const LibStub = @import("tapi.zig").LibStub;
const Liveness = @import("../Liveness.zig");
const LlvmObject = @import("../codegen/llvm.zig").Object;
-const LoadCommand = commands.LoadCommand;
const Module = @import("../Module.zig");
-const SegmentCommand = commands.SegmentCommand;
const StringIndexAdapter = std.hash_map.StringIndexAdapter;
const StringIndexContext = std.hash_map.StringIndexContext;
const Trie = @import("MachO/Trie.zig");
@@ -83,7 +80,7 @@ dylibs: std.ArrayListUnmanaged(Dylib) = .{},
dylibs_map: std.StringHashMapUnmanaged(u16) = .{},
referenced_dylibs: std.AutoArrayHashMapUnmanaged(u16, void) = .{},
-load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
+load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
pagezero_segment_cmd_index: ?u16 = null,
text_segment_cmd_index: ?u16 = null,
@@ -783,7 +780,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
@sizeOf(macho.rpath_command) + rpath.len + 1,
@sizeOf(u64),
));
- var rpath_cmd = commands.emptyGenericCommandWithData(macho.rpath_command{
+ var rpath_cmd = macho.emptyGenericCommandWithData(macho.rpath_command{
.cmd = macho.LC_RPATH,
.cmdsize = cmdsize,
.path = @sizeOf(macho.rpath_command),
@@ -791,7 +788,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path);
mem.set(u8, rpath_cmd.data, 0);
mem.copy(u8, rpath_cmd.data, rpath);
- try self.load_commands.append(self.base.allocator, .{ .Rpath = rpath_cmd });
+ try self.load_commands.append(self.base.allocator, .{ .rpath = rpath_cmd });
try rpath_table.putNoClobber(rpath, {});
self.load_commands_dirty = true;
}
@@ -861,12 +858,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
}
if (self.bss_section_index) |idx| {
- const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
const sect = &seg.sections.items[idx];
sect.offset = self.bss_file_offset;
}
if (self.tlv_bss_section_index) |idx| {
- const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
const sect = &seg.sections.items[idx];
sect.offset = self.tlv_bss_file_offset;
}
@@ -942,13 +939,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
}
if (self.bss_section_index) |idx| {
- const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
const sect = &seg.sections.items[idx];
self.bss_file_offset = sect.offset;
sect.offset = 0;
}
if (self.tlv_bss_section_index) |idx| {
- const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
const sect = &seg.sections.items[idx];
self.tlv_bss_file_offset = sect.offset;
sect.offset = 0;
@@ -1865,7 +1862,7 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment:
}
pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {
- const seg = self.load_commands.items[match.seg].Segment;
+ const seg = self.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
const sym = self.locals.items[atom.local_sym_index];
const file_offset = sect.offset + sym.n_value - sect.addr;
@@ -1885,7 +1882,7 @@ fn allocateLocals(self: *MachO) !void {
}
const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
- const seg = self.load_commands.items[match.seg].Segment;
+ const seg = self.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
var base_vaddr = sect.addr;
@@ -1976,7 +1973,7 @@ fn writeAllAtoms(self: *MachO) !void {
var it = self.atoms.iterator();
while (it.next()) |entry| {
const match = entry.key_ptr.*;
- const seg = self.load_commands.items[match.seg].Segment;
+ const seg = self.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
var atom: *Atom = entry.value_ptr.*;
@@ -2028,7 +2025,7 @@ fn writeAtoms(self: *MachO) !void {
var it = self.atoms.iterator();
while (it.next()) |entry| {
const match = entry.key_ptr.*;
- const seg = self.load_commands.items[match.seg].Segment;
+ const seg = self.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
var atom: *Atom = entry.value_ptr.*;
@@ -2992,7 +2989,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
const first_atom = atom;
- const seg = self.load_commands.items[match.seg].Segment;
+ const seg = self.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
const metadata = try section_metadata.getOrPut(match);
if (!metadata.found_existing) {
@@ -3043,7 +3040,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
while (it.next()) |entry| {
const match = entry.key_ptr.*;
const metadata = entry.value_ptr.*;
- const seg = &self.load_commands.items[match.seg].Segment;
+ const seg = &self.load_commands.items[match.seg].segment;
const sect = &seg.sections.items[match.sect];
log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{
sect.segName(),
@@ -3067,7 +3064,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
self.data_segment_cmd_index,
}) |maybe_seg_id| {
const seg_id = maybe_seg_id orelse continue;
- const seg = self.load_commands.items[seg_id].Segment;
+ const seg = self.load_commands.items[seg_id].segment;
for (seg.sections.items) |sect, sect_id| {
const match = MatchingSection{
@@ -3137,7 +3134,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
fn addLoadDylibLC(self: *MachO, id: u16) !void {
const dylib = self.dylibs.items[id];
const dylib_id = dylib.id orelse unreachable;
- var dylib_cmd = try commands.createLoadDylibCommand(
+ var dylib_cmd = try macho.createLoadDylibCommand(
self.base.allocator,
dylib_id.name,
dylib_id.timestamp,
@@ -3145,7 +3142,7 @@ fn addLoadDylibLC(self: *MachO, id: u16) !void {
dylib_id.compatibility_version,
);
errdefer dylib_cmd.deinit(self.base.allocator);
- try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
+ try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd });
self.load_commands_dirty = true;
}
@@ -3153,7 +3150,7 @@ fn addCodeSignatureLC(self: *MachO) !void {
if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return;
self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
- .LinkeditData = .{
+ .linkedit_data = .{
.cmd = macho.LC_CODE_SIGNATURE,
.cmdsize = @sizeOf(macho.linkedit_data_command),
.dataoff = 0,
@@ -3168,7 +3165,7 @@ fn setEntryPoint(self: *MachO) !void {
// TODO we should respect the -entry flag passed in by the user to set a custom
// entrypoint. For now, assume default of `_main`.
- const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;
const n_strx = self.strtab_dir.getKeyAdapted(@as([]const u8, "_main"), StringIndexAdapter{
.bytes = &self.strtab,
}) orelse {
@@ -3178,7 +3175,7 @@ fn setEntryPoint(self: *MachO) !void {
const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
assert(resolv.where == .global);
const sym = self.globals.items[resolv.where_index];
- const ec = &self.load_commands.items[self.main_cmd_index.?].Main;
+ const ec = &self.load_commands.items[self.main_cmd_index.?].main;
ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr);
ec.stacksize = self.base.options.stack_size_override orelse 0;
self.entry_addr = sym.n_value;
@@ -3875,7 +3872,7 @@ fn populateMissingMetadata(self: *MachO) !void {
if (self.pagezero_segment_cmd_index == null) {
self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
- .Segment = .{
+ .segment = .{
.inner = .{
.segname = makeStaticString("__PAGEZERO"),
.vmsize = pagezero_vmsize,
@@ -3896,7 +3893,7 @@ fn populateMissingMetadata(self: *MachO) !void {
break :blk needed_size;
} else 0;
try self.load_commands.append(self.base.allocator, .{
- .Segment = .{
+ .segment = .{
.inner = .{
.segname = makeStaticString("__TEXT"),
.vmaddr = pagezero_vmsize,
@@ -4000,7 +3997,7 @@ fn populateMissingMetadata(self: *MachO) !void {
});
}
try self.load_commands.append(self.base.allocator, .{
- .Segment = .{
+ .segment = .{
.inner = .{
.segname = makeStaticString("__DATA_CONST"),
.vmaddr = vmaddr,
@@ -4049,7 +4046,7 @@ fn populateMissingMetadata(self: *MachO) !void {
});
}
try self.load_commands.append(self.base.allocator, .{
- .Segment = .{
+ .segment = .{
.inner = .{
.segname = makeStaticString("__DATA"),
.vmaddr = vmaddr,
@@ -4133,7 +4130,7 @@ fn populateMissingMetadata(self: *MachO) !void {
.flags = macho.S_THREAD_LOCAL_ZEROFILL,
},
);
- const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;
const sect = seg.sections.items[self.tlv_bss_section_index.?];
self.tlv_bss_file_offset = sect.offset;
}
@@ -4150,7 +4147,7 @@ fn populateMissingMetadata(self: *MachO) !void {
.flags = macho.S_ZEROFILL,
},
);
- const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;
const sect = seg.sections.items[self.bss_section_index.?];
self.bss_file_offset = sect.offset;
}
@@ -4166,7 +4163,7 @@ fn populateMissingMetadata(self: *MachO) !void {
log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});
}
try self.load_commands.append(self.base.allocator, .{
- .Segment = .{
+ .segment = .{
.inner = .{
.segname = makeStaticString("__LINKEDIT"),
.vmaddr = vmaddr,
@@ -4182,7 +4179,7 @@ fn populateMissingMetadata(self: *MachO) !void {
if (self.dyld_info_cmd_index == null) {
self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
- .DyldInfoOnly = .{
+ .dyld_info_only = .{
.cmd = macho.LC_DYLD_INFO_ONLY,
.cmdsize = @sizeOf(macho.dyld_info_command),
.rebase_off = 0,
@@ -4203,7 +4200,7 @@ fn populateMissingMetadata(self: *MachO) !void {
if (self.symtab_cmd_index == null) {
self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
- .Symtab = .{
+ .symtab = .{
.cmd = macho.LC_SYMTAB,
.cmdsize = @sizeOf(macho.symtab_command),
.symoff = 0,
@@ -4218,7 +4215,7 @@ fn populateMissingMetadata(self: *MachO) !void {
if (self.dysymtab_cmd_index == null) {
self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
- .Dysymtab = .{
+ .dysymtab = .{
.cmd = macho.LC_DYSYMTAB,
.cmdsize = @sizeOf(macho.dysymtab_command),
.ilocalsym = 0,
@@ -4251,7 +4248,7 @@ fn populateMissingMetadata(self: *MachO) !void {
@sizeOf(macho.dylinker_command) + mem.sliceTo(default_dyld_path, 0).len,
@sizeOf(u64),
));
- var dylinker_cmd = commands.emptyGenericCommandWithData(macho.dylinker_command{
+ var dylinker_cmd = macho.emptyGenericCommandWithData(macho.dylinker_command{
.cmd = macho.LC_LOAD_DYLINKER,
.cmdsize = cmdsize,
.name = @sizeOf(macho.dylinker_command),
@@ -4259,14 +4256,14 @@ fn populateMissingMetadata(self: *MachO) !void {
dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name);
mem.set(u8, dylinker_cmd.data, 0);
mem.copy(u8, dylinker_cmd.data, mem.sliceTo(default_dyld_path, 0));
- try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd });
+ try self.load_commands.append(self.base.allocator, .{ .dylinker = dylinker_cmd });
self.load_commands_dirty = true;
}
if (self.main_cmd_index == null and self.base.options.output_mode == .Exe) {
self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
- .Main = .{
+ .main = .{
.cmd = macho.LC_MAIN,
.cmdsize = @sizeOf(macho.entry_point_command),
.entryoff = 0x0,
@@ -4286,7 +4283,7 @@ fn populateMissingMetadata(self: *MachO) !void {
std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };
const compat_version = self.base.options.compatibility_version orelse
std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };
- var dylib_cmd = try commands.createLoadDylibCommand(
+ var dylib_cmd = try macho.createLoadDylibCommand(
self.base.allocator,
install_name,
2,
@@ -4295,14 +4292,14 @@ fn populateMissingMetadata(self: *MachO) !void {
);
errdefer dylib_cmd.deinit(self.base.allocator);
dylib_cmd.inner.cmd = macho.LC_ID_DYLIB;
- try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
+ try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd });
self.load_commands_dirty = true;
}
if (self.source_version_cmd_index == null) {
self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
- .SourceVersion = .{
+ .source_version = .{
.cmd = macho.LC_SOURCE_VERSION,
.cmdsize = @sizeOf(macho.source_version_command),
.version = 0x0,
@@ -4329,7 +4326,7 @@ fn populateMissingMetadata(self: *MachO) !void {
break :blk sdk_version;
} else platform_version;
const is_simulator_abi = self.base.options.target.abi == .simulator;
- var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{
+ var cmd = macho.emptyGenericCommandWithData(macho.build_version_command{
.cmd = macho.LC_BUILD_VERSION,
.cmdsize = cmdsize,
.platform = switch (self.base.options.target.os.tag) {
@@ -4350,7 +4347,7 @@ fn populateMissingMetadata(self: *MachO) !void {
cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command));
mem.set(u8, cmd.data, 0);
mem.copy(u8, cmd.data, mem.asBytes(&ld_ver));
- try self.load_commands.append(self.base.allocator, .{ .BuildVersion = cmd });
+ try self.load_commands.append(self.base.allocator, .{ .build_version = cmd });
self.load_commands_dirty = true;
}
@@ -4362,14 +4359,14 @@ fn populateMissingMetadata(self: *MachO) !void {
.uuid = undefined,
};
std.crypto.random.bytes(&uuid_cmd.uuid);
- try self.load_commands.append(self.base.allocator, .{ .Uuid = uuid_cmd });
+ try self.load_commands.append(self.base.allocator, .{ .uuid = uuid_cmd });
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 = .{
+ .linkedit_data = .{
.cmd = macho.LC_FUNCTION_STARTS,
.cmdsize = @sizeOf(macho.linkedit_data_command),
.dataoff = 0,
@@ -4382,7 +4379,7 @@ fn populateMissingMetadata(self: *MachO) !void {
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, .{
- .LinkeditData = .{
+ .linkedit_data = .{
.cmd = macho.LC_DATA_IN_CODE,
.cmdsize = @sizeOf(macho.linkedit_data_command),
.dataoff = 0,
@@ -4396,8 +4393,8 @@ fn populateMissingMetadata(self: *MachO) !void {
}
fn allocateTextSegment(self: *MachO) !void {
- const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
- const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
+ const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment;
+ const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].segment.inner.vmsize;
seg.inner.fileoff = 0;
seg.inner.vmaddr = base_vmaddr;
@@ -4433,30 +4430,30 @@ fn allocateTextSegment(self: *MachO) !void {
}
fn allocateDataConstSegment(self: *MachO) !void {
- const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
- const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
+ const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;
seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
}
fn allocateDataSegment(self: *MachO) !void {
- const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
- const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
+ const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;
try self.allocateSegment(self.data_segment_cmd_index.?, 0);
}
fn allocateLinkeditSegment(self: *MachO) void {
- const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
- const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
+ const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;
seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;
seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;
}
fn allocateSegment(self: *MachO, index: u16, offset: u64) !void {
- const seg = &self.load_commands.items[index].Segment;
+ const seg = &self.load_commands.items[index].segment;
// Allocate the sections according to their alignment at the beginning of the segment.
var start: u64 = offset;
@@ -4488,7 +4485,7 @@ fn initSection(
alignment: u32,
opts: InitSectionOpts,
) !u16 {
- const seg = &self.load_commands.items[segment_id].Segment;
+ const seg = &self.load_commands.items[segment_id].segment;
var sect = macho.section_64{
.sectname = makeStaticString(sectname),
.segname = seg.inner.segname,
@@ -4532,7 +4529,7 @@ fn initSection(
}
fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64 {
- const seg = self.load_commands.items[segment_id].Segment;
+ const seg = self.load_commands.items[segment_id].segment;
if (seg.sections.items.len == 0) {
return if (start) |v| v else seg.inner.fileoff;
}
@@ -4542,7 +4539,7 @@ fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64
}
fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
- const seg = &self.load_commands.items[seg_id].Segment;
+ const seg = &self.load_commands.items[seg_id].segment;
const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);
assert(new_seg_size > seg.inner.filesize);
const offset_amt = new_seg_size - seg.inner.filesize;
@@ -4564,13 +4561,13 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
// TODO We should probably nop the expanded by distance, or put 0s.
// TODO copyRangeAll doesn't automatically extend the file on macOS.
- const ledit_seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const ledit_seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize;
try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1);
var next: usize = seg_id + 1;
while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) {
- const next_seg = &self.load_commands.items[next].Segment;
+ const next_seg = &self.load_commands.items[next].segment;
_ = try self.base.file.?.copyRangeAll(
next_seg.inner.fileoff,
self.base.file.?,
@@ -4613,7 +4610,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
const tracy = trace(@src());
defer tracy.end();
- const seg = &self.load_commands.items[match.seg].Segment;
+ const seg = &self.load_commands.items[match.seg].segment;
const sect = &seg.sections.items[match.sect];
const alignment = try math.powi(u32, 2, sect.@"align");
@@ -4684,7 +4681,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
}
fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 {
- const seg = self.load_commands.items[segment_id].Segment;
+ const seg = self.load_commands.items[segment_id].segment;
assert(start >= seg.inner.fileoff);
var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize;
if (start > min_pos) return 0;
@@ -4696,7 +4693,7 @@ fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 {
}
fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u32 {
- const seg = self.load_commands.items[segment_id].Segment;
+ const seg = self.load_commands.items[segment_id].segment;
var max_alignment: u32 = 1;
var next = start_sect_id;
while (next < seg.sections.items.len) : (next += 1) {
@@ -4711,7 +4708,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
const tracy = trace(@src());
defer tracy.end();
- const seg = &self.load_commands.items[match.seg].Segment;
+ const seg = &self.load_commands.items[match.seg].segment;
const sect = &seg.sections.items[match.sect];
var free_list = self.atom_free_lists.get(match).?;
const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;
@@ -4815,7 +4812,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
}
fn addAtomAndBumpSectionSize(self: *MachO, atom: *Atom, match: MatchingSection) !void {
- const seg = &self.load_commands.items[match.seg].Segment;
+ const seg = &self.load_commands.items[match.seg].segment;
const sect = &seg.sections.items[match.sect];
const alignment = try math.powi(u32, 2, atom.alignment);
sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size;
@@ -4862,11 +4859,11 @@ const NextSegmentAddressAndOffset = struct {
fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
var prev_segment_idx: ?usize = null; // We use optional here for safety.
for (self.load_commands.items) |cmd, i| {
- if (cmd == .Segment) {
+ if (cmd == .segment) {
prev_segment_idx = i;
}
}
- const prev_segment = self.load_commands.items[prev_segment_idx.?].Segment;
+ const prev_segment = self.load_commands.items[prev_segment_idx.?].segment;
const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize;
const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize;
return .{
@@ -4885,7 +4882,7 @@ fn sortSections(self: *MachO) !void {
{
// __TEXT segment
- const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment;
var sections = seg.sections.toOwnedSlice(self.base.allocator);
defer self.base.allocator.free(sections);
try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
@@ -4917,7 +4914,7 @@ fn sortSections(self: *MachO) !void {
{
// __DATA_CONST segment
- const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
var sections = seg.sections.toOwnedSlice(self.base.allocator);
defer self.base.allocator.free(sections);
try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
@@ -4944,7 +4941,7 @@ fn sortSections(self: *MachO) !void {
{
// __DATA segment
- const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
var sections = seg.sections.toOwnedSlice(self.base.allocator);
defer self.base.allocator.free(sections);
try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
@@ -5000,7 +4997,7 @@ fn sortSections(self: *MachO) !void {
{
// Create new section ordinals.
self.section_ordinals.clearRetainingCapacity();
- const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;
for (text_seg.sections.items) |_, sect_id| {
const res = self.section_ordinals.getOrPutAssumeCapacity(.{
.seg = self.text_segment_cmd_index.?,
@@ -5008,7 +5005,7 @@ fn sortSections(self: *MachO) !void {
});
assert(!res.found_existing);
}
- const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
+ const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
for (data_const_seg.sections.items) |_, sect_id| {
const res = self.section_ordinals.getOrPutAssumeCapacity(.{
.seg = self.data_const_segment_cmd_index.?,
@@ -5016,7 +5013,7 @@ fn sortSections(self: *MachO) !void {
});
assert(!res.found_existing);
}
- const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;
for (data_seg.sections.items) |_, sect_id| {
const res = self.section_ordinals.getOrPutAssumeCapacity(.{
.seg = self.data_segment_cmd_index.?,
@@ -5041,9 +5038,9 @@ fn updateSectionOrdinals(self: *MachO) !void {
var new_ordinal: u8 = 0;
for (self.load_commands.items) |lc, lc_id| {
- if (lc != .Segment) break;
+ if (lc != .segment) break;
- for (lc.Segment.sections.items) |_, sect_id| {
+ for (lc.segment.sections.items) |_, sect_id| {
const match = MatchingSection{
.seg = @intCast(u16, lc_id),
.sect = @intCast(u16, sect_id),
@@ -5086,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO) !void {
if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
- const seg = self.load_commands.items[match.seg].Segment;
+ const seg = self.load_commands.items[match.seg].segment;
while (true) {
const sym = self.locals.items[atom.local_sym_index];
@@ -5156,7 +5153,7 @@ fn writeDyldInfoData(self: *MachO) !void {
{
// TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
log.debug("generating export trie", .{});
- const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;
const base_address = text_segment.inner.vmaddr;
for (self.globals.items) |sym| {
@@ -5174,8 +5171,8 @@ fn writeDyldInfoData(self: *MachO) !void {
try trie.finalize(self.base.allocator);
}
- const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
- const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
+ const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].dyld_info_only;
const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
const bind_size = try bind.bindInfoSize(bind_pointers.items);
const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
@@ -5245,7 +5242,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
.sect = self.la_symbol_ptr_section_index.?,
}).?;
const base_addr = blk: {
- const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;
break :blk seg.inner.vmaddr;
};
@@ -5309,7 +5306,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
}
const sect = blk: {
- const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;
break :blk seg.sections.items[self.stub_helper_section_index.?];
};
const stub_offset: u4 = switch (self.base.options.target.cpu.arch) {
@@ -5350,7 +5347,7 @@ fn writeFunctionStarts(self: *MachO) !void {
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;
+ const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;
var last_off: u32 = 0;
while (true) {
@@ -5407,8 +5404,8 @@ fn writeFunctionStarts(self: *MachO) !void {
}
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;
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
+ const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].linkedit_data;
fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
fn_cmd.datasize = needed_size;
@@ -5441,7 +5438,7 @@ fn writeDices(self: *MachO) !void {
atom = prev;
}
- const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;
const text_sect = text_seg.sections.items[self.text_section_index.?];
while (true) {
@@ -5465,8 +5462,8 @@ fn writeDices(self: *MachO) !void {
} else break;
}
- 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 seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
+ const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data;
const needed_size = @intCast(u32, buf.items.len);
dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
@@ -5486,8 +5483,8 @@ fn writeSymbolTable(self: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
- const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
- const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
+ const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
@@ -5591,18 +5588,18 @@ fn writeSymbolTable(self: *MachO) !void {
seg.inner.filesize += locals_size + exports_size + undefs_size;
// Update dynamic symbol table.
- const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
+ const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].dysymtab;
dysymtab.nlocalsym = @intCast(u32, nlocals);
dysymtab.iextdefsym = dysymtab.nlocalsym;
dysymtab.nextdefsym = @intCast(u32, nexports);
dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;
dysymtab.nundefsym = @intCast(u32, nundefs);
- const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].segment;
const stubs = &text_segment.sections.items[self.stubs_section_index.?];
- const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
+ const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
const got = &data_const_segment.sections.items[self.got_section_index.?];
- const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
const nstubs = @intCast(u32, self.stubs_map.keys().len);
@@ -5665,8 +5662,8 @@ fn writeStringTable(self: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
- const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
- const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
+ const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
seg.inner.filesize += symtab.strsize;
@@ -5686,7 +5683,7 @@ fn writeLinkeditSegment(self: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
- const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
+ const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
seg.inner.filesize = 0;
try self.writeDyldInfoData();
@@ -5702,8 +5699,8 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
- const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
- const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
+ const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
+ const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
const needed_size = CodeSignature.calcCodeSignaturePaddingSize(
self.base.options.emit.?.sub_path,
@@ -5729,8 +5726,8 @@ fn writeCodeSignature(self: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
- const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
- const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
+ const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;
+ const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
var code_sig: CodeSignature = .{};
defer code_sig.deinit(self.base.allocator);
@@ -5955,7 +5952,7 @@ fn snapshotState(self: *MachO) !void {
var nodes = std.ArrayList(Snapshot.Node).init(arena);
for (self.section_ordinals.keys()) |key| {
- const seg = self.load_commands.items[key.seg].Segment;
+ const seg = self.load_commands.items[key.seg].segment;
const sect = seg.sections.items[key.sect];
const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() });
try nodes.append(.{
@@ -6028,12 +6025,12 @@ fn snapshotState(self: *MachO) !void {
const is_tlv = is_tlv: {
const source_sym = self.locals.items[atom.local_sym_index];
const match = self.section_ordinals.keys()[source_sym.n_sect - 1];
- const match_seg = self.load_commands.items[match.seg].Segment;
+ const match_seg = self.load_commands.items[match.seg].segment;
const match_sect = match_seg.sections.items[match.sect];
break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
};
if (is_tlv) {
- const match_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
+ const match_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;
const base_address = inner: {
if (self.tlv_data_section_index) |i| {
break :inner match_seg.sections.items[i].addr;
@@ -6193,7 +6190,7 @@ fn logSymtab(self: MachO) void {
fn logSectionOrdinals(self: MachO) void {
for (self.section_ordinals.keys()) |match, i| {
- const seg = self.load_commands.items[match.seg].Segment;
+ const seg = self.load_commands.items[match.seg].segment;
const sect = seg.sections.items[match.sect];
log.debug("ord {d}: {d},{d} => {s},{s}", .{
i + 1,
CMakeLists.txt
@@ -590,7 +590,6 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
"${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
"${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig"
- "${CMAKE_SOURCE_DIR}/src/link/MachO/commands.zig"
"${CMAKE_SOURCE_DIR}/src/link/Plan9.zig"
"${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
"${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"