aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-12-10 14:13:43 +0100
committerJakub Konka <kubkon@jakubkonka.com>2021-12-10 18:18:28 +0100
commit828f61e8dfcf17e0f7c42552311e6589bb187880 (patch)
tree6972d08f0c0292d27ebb1e8a74bc7c9a3087feae /src
parent81e7d8505c086a93accb74e9f1a84abb8ff7cf24 (diff)
downloadzig-828f61e8dfcf17e0f7c42552311e6589bb187880.tar.gz
zig-828f61e8dfcf17e0f7c42552311e6589bb187880.zip
macho: move all helpers from commands.zig into std.macho
This way we will finally be able to share common parsing logic between different Zig components and 3rd party packages.
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO.zig199
-rw-r--r--src/link/MachO/Atom.zig14
-rw-r--r--src/link/MachO/DebugSymbols.zig132
-rw-r--r--src/link/MachO/Dylib.zig14
-rw-r--r--src/link/MachO/Object.zig23
-rw-r--r--src/link/MachO/commands.zig463
6 files changed, 205 insertions, 640 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index f255eaba47..a67d3a4452 100644
--- a/src/link/MachO.zig
+++ b/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,
diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig
index c35b4d13ab..71183f4157 100644
--- a/src/link/MachO/Atom.zig
+++ b/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;
diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig
index 49e1462015..8babb5d647 100644
--- a/src/link/MachO/DebugSymbols.zig
+++ b/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}", .{
diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig
index 5f7bd9b763..31a8b357c2 100644
--- a/src/link/MachO/Dylib.zig
+++ b/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);
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index 6647321944..7f4a49d0d5 100644
--- a/src/link/MachO/Object.zig
+++ b/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);
diff --git a/src/link/MachO/commands.zig b/src/link/MachO/commands.zig
deleted file mode 100644
index 278be33f30..0000000000
--- a/src/link/MachO/commands.zig
+++ /dev/null
@@ -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(&sect));
- }
- }
-
- 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);
-}