macho: converge populateMetadata with populateMissingMetadata

This commit is contained in:
Jakub Konka
2021-08-16 19:15:04 +02:00
parent 4c90c1ff63
commit a51edc978f

View File

@@ -386,6 +386,36 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
try self.populateMissingMetadata();
try self.writeLocalSymbol(0);
if (!self.strtab_dir.containsAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
.strtab = &self.strtab,
})) {
const import_sym_index = @intCast(u32, self.undefs.items.len);
const n_strx = try self.makeString("dyld_stub_binder");
try self.undefs.append(self.base.allocator, .{
.n_strx = n_strx,
.n_type = macho.N_UNDF | macho.N_EXT,
.n_sect = 0,
.n_desc = @intCast(u8, 1) * macho.N_SYMBOL_RESOLVER,
.n_value = 0,
});
try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
.where = .undef,
.where_index = import_sym_index,
});
const got_key = GotIndirectionKey{
.where = .undef,
.where_index = import_sym_index,
};
const got_index = @intCast(u32, self.got_entries.items.len);
try self.got_entries.append(self.base.allocator, got_key);
try self.got_entries_map.putNoClobber(self.base.allocator, got_key, got_index);
try self.writeGotEntry(got_index);
self.binding_info_dirty = true;
}
if (self.stub_helper_stubs_start_off == null) {
try self.writeStubHelperPreamble();
}
if (self.d_sym) |*ds| {
try ds.populateMissingMetadata(allocator);
try ds.writeLocalSymbol(0);
@@ -556,7 +586,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
.read = true,
.mode = link.determineMode(self.base.options),
});
try self.populateMetadata();
try self.populateMissingMetadata();
// TODO mimicking insertion of null symbol from incremental linker.
// This will need to moved.
@@ -798,6 +828,17 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
try self.allocateTextBlocks();
try self.flushZld();
} else {
// TODO this is just a temp; libsystem load command will be autoresolved when parsing libSystem from
// the linker line and actually referencing symbols.
if (self.libsystem_cmd_index == null) {
self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
var dylib_cmd = try commands.createLoadDylibCommand(self.base.allocator, mem.spanZ(LIB_SYSTEM_PATH), 2, 0, 0);
errdefer dylib_cmd.deinit(self.base.allocator);
try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
self.load_commands_dirty = true;
}
try self.addDataInCodeLC();
try self.addCodeSignatureLC();
try self.flushModule(comp);
}
}
@@ -2503,328 +2544,6 @@ fn parseTextBlocks(self: *MachO) !void {
}
}
fn populateMetadata(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 = SegmentCommand.empty("__PAGEZERO", .{
.vmsize = 0x100000000, // size always set to 4GB
}),
});
}
if (self.text_segment_cmd_index == null) {
self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty("__TEXT", .{
.vmaddr = 0x100000000, // always starts at 4GB
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
}),
});
}
if (self.text_section_index == null) {
const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
self.text_section_index = @intCast(u16, text_seg.sections.items.len);
const alignment: u2 = switch (self.base.options.target.cpu.arch) {
.x86_64 => 0,
.aarch64 => 2,
else => unreachable, // unhandled architecture type
};
try text_seg.addSection(self.base.allocator, "__text", .{
.@"align" = alignment,
.flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.text_segment_cmd_index.?,
.sect = self.text_section_index.?,
});
}
if (self.stubs_section_index == null) {
const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
self.stubs_section_index = @intCast(u16, text_seg.sections.items.len);
const alignment: u2 = switch (self.base.options.target.cpu.arch) {
.x86_64 => 0,
.aarch64 => 2,
else => unreachable, // unhandled architecture type
};
const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
.x86_64 => 6,
.aarch64 => 3 * @sizeOf(u32),
else => unreachable, // unhandled architecture type
};
try text_seg.addSection(self.base.allocator, "__stubs", .{
.@"align" = alignment,
.flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
.reserved2 = stub_size,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.text_segment_cmd_index.?,
.sect = self.stubs_section_index.?,
});
}
if (self.stub_helper_section_index == null) {
const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
self.stub_helper_section_index = @intCast(u16, text_seg.sections.items.len);
const alignment: u2 = switch (self.base.options.target.cpu.arch) {
.x86_64 => 0,
.aarch64 => 2,
else => unreachable, // unhandled architecture type
};
const stub_helper_size: u6 = switch (self.base.options.target.cpu.arch) {
.x86_64 => 15,
.aarch64 => 6 * @sizeOf(u32),
else => unreachable,
};
try text_seg.addSection(self.base.allocator, "__stub_helper", .{
.size = stub_helper_size,
.@"align" = alignment,
.flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.text_segment_cmd_index.?,
.sect = self.stub_helper_section_index.?,
});
}
if (self.data_const_segment_cmd_index == null) {
self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty("__DATA_CONST", .{
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
}),
});
}
if (self.got_section_index == null) {
const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
self.got_section_index = @intCast(u16, data_const_seg.sections.items.len);
try data_const_seg.addSection(self.base.allocator, "__got", .{
.@"align" = 3, // 2^3 = @sizeOf(u64)
.flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.data_const_segment_cmd_index.?,
.sect = self.got_section_index.?,
});
}
if (self.data_segment_cmd_index == null) {
self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty("__DATA", .{
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
}),
});
}
if (self.la_symbol_ptr_section_index == null) {
const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
self.la_symbol_ptr_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.base.allocator, "__la_symbol_ptr", .{
.@"align" = 3, // 2^3 = @sizeOf(u64)
.flags = macho.S_LAZY_SYMBOL_POINTERS,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.data_segment_cmd_index.?,
.sect = self.la_symbol_ptr_section_index.?,
});
}
if (self.data_section_index == null) {
const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
self.data_section_index = @intCast(u16, data_seg.sections.items.len);
try data_seg.addSection(self.base.allocator, "__data", .{
.@"align" = 3, // 2^3 = @sizeOf(u64)
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.data_segment_cmd_index.?,
.sect = self.data_section_index.?,
});
}
if (self.linkedit_segment_cmd_index == null) {
self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty("__LINKEDIT", .{
.maxprot = macho.VM_PROT_READ,
.initprot = macho.VM_PROT_READ,
}),
});
}
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 = .{
.cmd = macho.LC_DYLD_INFO_ONLY,
.cmdsize = @sizeOf(macho.dyld_info_command),
.rebase_off = 0,
.rebase_size = 0,
.bind_off = 0,
.bind_size = 0,
.weak_bind_off = 0,
.weak_bind_size = 0,
.lazy_bind_off = 0,
.lazy_bind_size = 0,
.export_off = 0,
.export_size = 0,
},
});
}
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 = .{
.cmd = macho.LC_SYMTAB,
.cmdsize = @sizeOf(macho.symtab_command),
.symoff = 0,
.nsyms = 0,
.stroff = 0,
.strsize = 0,
},
});
}
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 = .{
.cmd = macho.LC_DYSYMTAB,
.cmdsize = @sizeOf(macho.dysymtab_command),
.ilocalsym = 0,
.nlocalsym = 0,
.iextdefsym = 0,
.nextdefsym = 0,
.iundefsym = 0,
.nundefsym = 0,
.tocoff = 0,
.ntoc = 0,
.modtaboff = 0,
.nmodtab = 0,
.extrefsymoff = 0,
.nextrefsyms = 0,
.indirectsymoff = 0,
.nindirectsyms = 0,
.extreloff = 0,
.nextrel = 0,
.locreloff = 0,
.nlocrel = 0,
},
});
}
if (self.dylinker_cmd_index == null) {
self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);
const cmdsize = @intCast(u32, mem.alignForwardGeneric(
u64,
@sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH),
@sizeOf(u64),
));
var dylinker_cmd = commands.emptyGenericCommandWithData(macho.dylinker_command{
.cmd = macho.LC_LOAD_DYLINKER,
.cmdsize = cmdsize,
.name = @sizeOf(macho.dylinker_command),
});
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.spanZ(DEFAULT_DYLD_PATH));
try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd });
}
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 = .{
.cmd = macho.LC_MAIN,
.cmdsize = @sizeOf(macho.entry_point_command),
.entryoff = 0x0,
.stacksize = 0,
},
});
}
if (self.dylib_id_cmd_index == null and self.base.options.output_mode == .Lib) {
self.dylib_id_cmd_index = @intCast(u16, self.load_commands.items.len);
const install_name = try std.fmt.allocPrint(self.base.allocator, "@rpath/{s}", .{
self.base.options.emit.?.sub_path,
});
defer self.base.allocator.free(install_name);
var dylib_cmd = try commands.createLoadDylibCommand(
self.base.allocator,
install_name,
2,
0x10000, // TODO forward user-provided versions
0x10000,
);
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 });
}
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 = .{
.cmd = macho.LC_SOURCE_VERSION,
.cmdsize = @sizeOf(macho.source_version_command),
.version = 0x0,
},
});
}
if (self.build_version_cmd_index == null) {
self.build_version_cmd_index = @intCast(u16, self.load_commands.items.len);
const cmdsize = @intCast(u32, mem.alignForwardGeneric(
u64,
@sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version),
@sizeOf(u64),
));
const ver = self.base.options.target.os.version_range.semver.min;
const version = ver.major << 16 | ver.minor << 8 | ver.patch;
const is_simulator_abi = self.base.options.target.abi == .simulator;
var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{
.cmd = macho.LC_BUILD_VERSION,
.cmdsize = cmdsize,
.platform = switch (self.base.options.target.os.tag) {
.macos => macho.PLATFORM_MACOS,
.ios => if (is_simulator_abi) macho.PLATFORM_IOSSIMULATOR else macho.PLATFORM_IOS,
.watchos => if (is_simulator_abi) macho.PLATFORM_WATCHOSSIMULATOR else macho.PLATFORM_WATCHOS,
.tvos => if (is_simulator_abi) macho.PLATFORM_TVOSSIMULATOR else macho.PLATFORM_TVOS,
else => unreachable,
},
.minos = version,
.sdk = version,
.ntools = 1,
});
const ld_ver = macho.build_tool_version{
.tool = macho.TOOL_LD,
.version = 0x0,
};
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 });
}
if (self.uuid_cmd_index == null) {
self.uuid_cmd_index = @intCast(u16, self.load_commands.items.len);
var uuid_cmd: macho.uuid_command = .{
.cmd = macho.LC_UUID,
.cmdsize = @sizeOf(macho.uuid_command),
.uuid = undefined,
};
std.crypto.random.bytes(&uuid_cmd.uuid);
try self.load_commands.append(self.base.allocator, .{ .Uuid = uuid_cmd });
}
}
fn addDataInCodeLC(self: *MachO) !void {
if (self.data_in_code_cmd_index == null) {
self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -4004,12 +3723,6 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
}
pub fn populateMissingMetadata(self: *MachO) !void {
switch (self.base.options.output_mode) {
.Exe => {},
.Obj => return error.TODOImplementWritingObjFiles,
.Lib => return error.TODOImplementWritingLibFiles,
}
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, .{
@@ -4019,11 +3732,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
});
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 maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE;
const initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE;
const program_code_size_hint = self.base.options.program_code_size_hint;
const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
const ideal_size = self.header_pad + program_code_size_hint + 3 * got_size_hint;
@@ -4036,12 +3747,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.vmaddr = 0x100000000, // always starts at 4GB
.vmsize = needed_size,
.filesize = needed_size,
.maxprot = maxprot,
.initprot = initprot,
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE,
}),
});
self.load_commands_dirty = true;
}
if (self.text_section_index == null) {
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
self.text_section_index = @intCast(u16, text_segment.sections.items.len);
@@ -4051,7 +3763,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.aarch64 => 2,
else => unreachable, // unhandled architecture type
};
const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
const needed_size = self.base.options.program_code_size_hint;
const off = text_segment.findFreeSpace(needed_size, @as(u16, 1) << alignment, self.header_pad);
@@ -4062,10 +3773,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.size = @intCast(u32, needed_size),
.offset = @intCast(u32, off),
.@"align" = alignment,
.flags = flags,
.flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.text_segment_cmd_index.?,
.sect = self.text_section_index.?,
});
self.load_commands_dirty = true;
}
if (self.stubs_section_index == null) {
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
self.stubs_section_index = @intCast(u16, text_segment.sections.items.len);
@@ -4080,7 +3796,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.aarch64 => 3 * @sizeOf(u32),
else => unreachable, // unhandled architecture type
};
const flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad);
assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
@@ -4092,11 +3807,16 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = alignment,
.flags = flags,
.flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
.reserved2 = stub_size,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.text_segment_cmd_index.?,
.sect = self.stubs_section_index.?,
});
self.load_commands_dirty = true;
}
if (self.stub_helper_section_index == null) {
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
self.stub_helper_section_index = @intCast(u16, text_segment.sections.items.len);
@@ -4106,7 +3826,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.aarch64 => 2,
else => unreachable, // unhandled architecture type
};
const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad);
assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
@@ -4118,16 +3837,18 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = alignment,
.flags = flags,
.flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.text_segment_cmd_index.?,
.sect = self.stub_helper_section_index.?,
});
self.load_commands_dirty = true;
}
if (self.data_const_segment_cmd_index == null) {
self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE;
const initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE;
const address_and_offset = self.nextSegmentAddressAndOffset();
const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
@@ -4139,17 +3860,17 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.vmsize = needed_size,
.fileoff = address_and_offset.offset,
.filesize = needed_size,
.maxprot = maxprot,
.initprot = initprot,
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
}),
});
self.load_commands_dirty = true;
}
if (self.got_section_index == null) {
const dc_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
self.got_section_index = @intCast(u16, dc_segment.sections.items.len);
const flags = macho.S_NON_LAZY_SYMBOL_POINTERS;
const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const off = dc_segment.findFreeSpace(needed_size, @alignOf(u64), null);
assert(off + needed_size <= dc_segment.inner.fileoff + dc_segment.inner.filesize); // TODO Must expand __DATA_CONST segment.
@@ -4161,16 +3882,18 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = 3, // 2^3 = @sizeOf(u64)
.flags = flags,
.flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.data_const_segment_cmd_index.?,
.sect = self.got_section_index.?,
});
self.load_commands_dirty = true;
}
if (self.data_segment_cmd_index == null) {
self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE;
const initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE;
const address_and_offset = self.nextSegmentAddressAndOffset();
const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;
const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
@@ -4182,17 +3905,17 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.vmsize = needed_size,
.fileoff = address_and_offset.offset,
.filesize = needed_size,
.maxprot = maxprot,
.initprot = initprot,
.maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
.initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
}),
});
self.load_commands_dirty = true;
}
if (self.la_symbol_ptr_section_index == null) {
const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
self.la_symbol_ptr_section_index = @intCast(u16, data_segment.sections.items.len);
const flags = macho.S_LAZY_SYMBOL_POINTERS;
const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const off = data_segment.findFreeSpace(needed_size, @alignOf(u64), null);
assert(off + needed_size <= data_segment.inner.fileoff + data_segment.inner.filesize); // TODO Must expand __DATA segment.
@@ -4204,10 +3927,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.size = needed_size,
.offset = @intCast(u32, off),
.@"align" = 3, // 2^3 = @sizeOf(u64)
.flags = flags,
.flags = macho.S_LAZY_SYMBOL_POINTERS,
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.data_segment_cmd_index.?,
.sect = self.la_symbol_ptr_section_index.?,
});
self.load_commands_dirty = true;
}
if (self.data_section_index == null) {
const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
self.data_section_index = @intCast(u16, data_segment.sections.items.len);
@@ -4224,13 +3952,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.offset = @intCast(u32, off),
.@"align" = 3, // 2^3 = @sizeOf(u64)
});
_ = try self.section_ordinals.getOrPut(self.base.allocator, .{
.seg = self.data_segment_cmd_index.?,
.sect = self.data_section_index.?,
});
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 maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE;
const initprot = macho.VM_PROT_READ;
const address_and_offset = self.nextSegmentAddressAndOffset();
log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});
@@ -4239,12 +3969,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.Segment = SegmentCommand.empty("__LINKEDIT", .{
.vmaddr = address_and_offset.address,
.fileoff = address_and_offset.offset,
.maxprot = maxprot,
.initprot = initprot,
.maxprot = macho.VM_PROT_READ,
.initprot = macho.VM_PROT_READ,
}),
});
self.load_commands_dirty = true;
}
if (self.dyld_info_cmd_index == null) {
self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -4291,6 +4022,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
self.load_commands_dirty = true;
}
if (self.symtab_cmd_index == null) {
self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -4323,6 +4055,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
self.load_commands_dirty = true;
self.strtab_dirty = true;
}
if (self.dysymtab_cmd_index == null) {
self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -4358,6 +4091,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
});
self.load_commands_dirty = true;
}
if (self.dylinker_cmd_index == null) {
self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);
const cmdsize = @intCast(u32, mem.alignForwardGeneric(
@@ -4376,17 +4110,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd });
self.load_commands_dirty = true;
}
if (self.libsystem_cmd_index == null) {
self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
var dylib_cmd = try commands.createLoadDylibCommand(self.base.allocator, mem.spanZ(LIB_SYSTEM_PATH), 2, 0, 0);
errdefer dylib_cmd.deinit(self.base.allocator);
try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
self.load_commands_dirty = true;
}
if (self.main_cmd_index == null) {
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 = .{
@@ -4398,6 +4123,38 @@ pub fn populateMissingMetadata(self: *MachO) !void {
});
self.load_commands_dirty = true;
}
if (self.dylib_id_cmd_index == null and self.base.options.output_mode == .Lib) {
self.dylib_id_cmd_index = @intCast(u16, self.load_commands.items.len);
const install_name = try std.fmt.allocPrint(self.base.allocator, "@rpath/{s}", .{
self.base.options.emit.?.sub_path,
});
defer self.base.allocator.free(install_name);
var dylib_cmd = try commands.createLoadDylibCommand(
self.base.allocator,
install_name,
2,
0x10000, // TODO forward user-provided versions
0x10000,
);
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 });
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 = .{
.cmd = macho.LC_SOURCE_VERSION,
.cmdsize = @sizeOf(macho.source_version_command),
.version = 0x0,
},
});
self.load_commands_dirty = true;
}
if (self.build_version_cmd_index == null) {
self.build_version_cmd_index = @intCast(u16, self.load_commands.items.len);
const cmdsize = @intCast(u32, mem.alignForwardGeneric(
@@ -4430,18 +4187,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
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 });
}
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 = .{
.cmd = macho.LC_SOURCE_VERSION,
.cmdsize = @sizeOf(macho.source_version_command),
.version = 0x0,
},
});
self.load_commands_dirty = true;
}
if (self.uuid_cmd_index == null) {
self.uuid_cmd_index = @intCast(u16, self.load_commands.items.len);
var uuid_cmd: macho.uuid_command = .{
@@ -4453,47 +4201,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
try self.load_commands.append(self.base.allocator, .{ .Uuid = uuid_cmd });
self.load_commands_dirty = true;
}
if (self.code_signature_cmd_index == null and self.requires_adhoc_codesig) {
self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
try self.load_commands.append(self.base.allocator, .{
.LinkeditData = .{
.cmd = macho.LC_CODE_SIGNATURE,
.cmdsize = @sizeOf(macho.linkedit_data_command),
.dataoff = 0,
.datasize = 0,
},
});
self.load_commands_dirty = true;
}
if (!self.strtab_dir.containsAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
.strtab = &self.strtab,
})) {
const import_sym_index = @intCast(u32, self.undefs.items.len);
const n_strx = try self.makeString("dyld_stub_binder");
try self.undefs.append(self.base.allocator, .{
.n_strx = n_strx,
.n_type = macho.N_UNDF | macho.N_EXT,
.n_sect = 0,
.n_desc = @intCast(u8, 1) * macho.N_SYMBOL_RESOLVER,
.n_value = 0,
});
try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
.where = .undef,
.where_index = import_sym_index,
});
const got_key = GotIndirectionKey{
.where = .undef,
.where_index = import_sym_index,
};
const got_index = @intCast(u32, self.got_entries.items.len);
try self.got_entries.append(self.base.allocator, got_key);
try self.got_entries_map.putNoClobber(self.base.allocator, got_key, got_index);
try self.writeGotEntry(got_index);
self.binding_info_dirty = true;
}
if (self.stub_helper_stubs_start_off == null) {
try self.writeStubHelperPreamble();
}
}
fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {