macho: allocate sections, segments and atoms
This commit is contained in:
@@ -110,6 +110,8 @@ compatibility_version: ?std.SemanticVersion,
|
||||
entry_name: ?[]const u8,
|
||||
platform: Platform,
|
||||
sdk_version: ?std.SemanticVersion,
|
||||
/// Rpath table
|
||||
rpath_table: std.StringArrayHashMapUnmanaged(void) = .{},
|
||||
|
||||
/// Hot-code swapping state.
|
||||
hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
|
||||
@@ -200,6 +202,12 @@ pub fn createEmpty(
|
||||
.mode = link.File.determineMode(false, output_mode, link_mode),
|
||||
});
|
||||
|
||||
// Filter rpaths
|
||||
try self.rpath_table.ensureUnusedCapacity(gpa, self.base.rpath_list.len);
|
||||
for (options.rpath_list) |rpath| {
|
||||
_ = self.rpath_table.putAssumeCapacity(rpath, {});
|
||||
}
|
||||
|
||||
// Append null file
|
||||
try self.files.append(gpa, .null);
|
||||
// Atom at index 0 is reserved as null atom
|
||||
@@ -317,6 +325,7 @@ pub fn deinit(self: *MachO) void {
|
||||
}
|
||||
self.thunks.deinit(gpa);
|
||||
self.unwind_records.deinit(gpa);
|
||||
self.rpath_table.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
|
||||
@@ -378,15 +387,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
|
||||
|
||||
if (module_obj_path) |path| try positionals.append(.{ .path = path });
|
||||
|
||||
// rpaths
|
||||
var rpath_table = std.StringArrayHashMap(void).init(gpa);
|
||||
defer rpath_table.deinit();
|
||||
try rpath_table.ensureUnusedCapacity(self.base.rpath_list.len);
|
||||
|
||||
for (self.base.rpath_list) |rpath| {
|
||||
_ = rpath_table.putAssumeCapacity(rpath, {});
|
||||
}
|
||||
|
||||
for (positionals.items) |obj| {
|
||||
self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
|
||||
error.MalformedObject,
|
||||
@@ -533,6 +533,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
|
||||
try self.generateUnwindInfo();
|
||||
try self.initSegments();
|
||||
|
||||
try self.allocateSections();
|
||||
self.allocateSegments();
|
||||
self.allocateAtoms();
|
||||
self.allocateSyntheticSymbols();
|
||||
|
||||
state_log.debug("{}", .{self.dumpState()});
|
||||
|
||||
@panic("TODO");
|
||||
@@ -613,7 +618,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
|
||||
try argv.append(syslibroot);
|
||||
}
|
||||
|
||||
for (self.base.rpath_list) |rpath| {
|
||||
for (self.rpath_table.keys()) |rpath| {
|
||||
try argv.append("-rpath");
|
||||
try argv.append(rpath);
|
||||
}
|
||||
@@ -2016,6 +2021,171 @@ fn initSegments(self: *MachO) !void {
|
||||
self.linkedit_seg_index = self.getSegmentByName("__LINKEDIT").?;
|
||||
}
|
||||
|
||||
fn allocateSections(self: *MachO) !void {
|
||||
const headerpad = load_commands.calcMinHeaderPadSize(self);
|
||||
var vmaddr: u64 = if (self.pagezero_seg_index) |index|
|
||||
self.segments.items[index].vmaddr + self.segments.items[index].vmsize
|
||||
else
|
||||
0;
|
||||
vmaddr += headerpad;
|
||||
var fileoff = headerpad;
|
||||
|
||||
const page_size = self.getPageSize();
|
||||
const slice = self.sections.slice();
|
||||
|
||||
var next_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0;
|
||||
for (slice.items(.header), slice.items(.segment_id)) |*header, seg_id| {
|
||||
if (seg_id != next_seg_id) {
|
||||
vmaddr = mem.alignForward(u64, vmaddr, page_size);
|
||||
fileoff = mem.alignForward(u32, fileoff, page_size);
|
||||
}
|
||||
|
||||
const alignment = try math.powi(u32, 2, header.@"align");
|
||||
|
||||
vmaddr = mem.alignForward(u64, vmaddr, alignment);
|
||||
header.addr = vmaddr;
|
||||
vmaddr += header.size;
|
||||
|
||||
if (!header.isZerofill()) {
|
||||
fileoff = mem.alignForward(u32, fileoff, alignment);
|
||||
header.offset = fileoff;
|
||||
fileoff += @intCast(header.size);
|
||||
}
|
||||
|
||||
next_seg_id = seg_id;
|
||||
}
|
||||
}
|
||||
|
||||
fn allocateSegments(self: *MachO) void {
|
||||
const page_size = self.getPageSize();
|
||||
var vmaddr = if (self.pagezero_seg_index) |index|
|
||||
self.segments.items[index].vmaddr + self.segments.items[index].vmsize
|
||||
else
|
||||
0;
|
||||
var fileoff: u64 = 0;
|
||||
const index = if (self.pagezero_seg_index) |index| index + 1 else 0;
|
||||
|
||||
const slice = self.sections.slice();
|
||||
var next_sect_id: u8 = 0;
|
||||
for (self.segments.items[index..], index..) |*seg, seg_id| {
|
||||
seg.vmaddr = vmaddr;
|
||||
seg.fileoff = fileoff;
|
||||
|
||||
for (
|
||||
slice.items(.header)[next_sect_id..],
|
||||
slice.items(.segment_id)[next_sect_id..],
|
||||
) |header, sid| {
|
||||
if (seg_id != sid) break;
|
||||
|
||||
vmaddr = header.addr + header.size;
|
||||
if (!header.isZerofill()) {
|
||||
fileoff = header.offset + header.size;
|
||||
}
|
||||
|
||||
next_sect_id += 1;
|
||||
}
|
||||
|
||||
vmaddr = mem.alignForward(u64, vmaddr, page_size);
|
||||
fileoff = mem.alignForward(u64, fileoff, page_size);
|
||||
|
||||
seg.vmsize = vmaddr - seg.vmaddr;
|
||||
seg.filesize = fileoff - seg.fileoff;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocateAtoms(self: *MachO) void {
|
||||
const slice = self.sections.slice();
|
||||
for (slice.items(.header), slice.items(.atoms)) |header, atoms| {
|
||||
if (atoms.items.len == 0) continue;
|
||||
for (atoms.items) |atom_index| {
|
||||
const atom = self.getAtom(atom_index).?;
|
||||
assert(atom.flags.alive);
|
||||
atom.value += header.addr;
|
||||
}
|
||||
}
|
||||
|
||||
for (self.thunks.items) |*thunk| {
|
||||
const header = self.sections.items(.header)[thunk.out_n_sect];
|
||||
thunk.value += header.addr;
|
||||
}
|
||||
}
|
||||
|
||||
fn allocateSyntheticSymbols(self: *MachO) void {
|
||||
const text_seg = self.getTextSegment();
|
||||
|
||||
if (self.mh_execute_header_index) |index| {
|
||||
const global = self.getSymbol(index);
|
||||
global.value = text_seg.vmaddr;
|
||||
}
|
||||
|
||||
if (self.data_sect_index) |idx| {
|
||||
const sect = self.sections.items(.header)[idx];
|
||||
for (&[_]?Symbol.Index{
|
||||
self.dso_handle_index,
|
||||
self.mh_dylib_header_index,
|
||||
self.dyld_private_index,
|
||||
}) |maybe_index| {
|
||||
if (maybe_index) |index| {
|
||||
const global = self.getSymbol(index);
|
||||
global.value = sect.addr;
|
||||
global.out_n_sect = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (self.boundary_symbols.items) |sym_index| {
|
||||
const sym = self.getSymbol(sym_index);
|
||||
const name = sym.getName(self);
|
||||
|
||||
sym.flags.@"export" = false;
|
||||
sym.value = text_seg.vmaddr;
|
||||
|
||||
if (mem.startsWith(u8, name, "segment$start$")) {
|
||||
const segname = name["segment$start$".len..];
|
||||
if (self.getSegmentByName(segname)) |seg_id| {
|
||||
const seg = self.segments.items[seg_id];
|
||||
sym.value = seg.vmaddr;
|
||||
}
|
||||
} else if (mem.startsWith(u8, name, "segment$stop$")) {
|
||||
const segname = name["segment$stop$".len..];
|
||||
if (self.getSegmentByName(segname)) |seg_id| {
|
||||
const seg = self.segments.items[seg_id];
|
||||
sym.value = seg.vmaddr + seg.vmsize;
|
||||
}
|
||||
} else if (mem.startsWith(u8, name, "section$start$")) {
|
||||
const actual_name = name["section$start$".len..];
|
||||
const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic
|
||||
const segname = actual_name[0..sep];
|
||||
const sectname = actual_name[sep + 1 ..];
|
||||
if (self.getSectionByName(segname, sectname)) |sect_id| {
|
||||
const sect = self.sections.items(.header)[sect_id];
|
||||
sym.value = sect.addr;
|
||||
sym.out_n_sect = sect_id;
|
||||
}
|
||||
} else if (mem.startsWith(u8, name, "section$stop$")) {
|
||||
const actual_name = name["section$stop$".len..];
|
||||
const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic
|
||||
const segname = actual_name[0..sep];
|
||||
const sectname = actual_name[sep + 1 ..];
|
||||
if (self.getSectionByName(segname, sectname)) |sect_id| {
|
||||
const sect = self.sections.items(.header)[sect_id];
|
||||
sym.value = sect.addr + sect.size;
|
||||
sym.out_n_sect = sect_id;
|
||||
}
|
||||
} else unreachable;
|
||||
}
|
||||
|
||||
if (self.objc_stubs.symbols.items.len > 0) {
|
||||
const addr = self.sections.items(.header)[self.objc_stubs_sect_index.?].addr;
|
||||
|
||||
for (self.objc_stubs.symbols.items, 0..) |sym_index, idx| {
|
||||
const sym = self.getSymbol(sym_index);
|
||||
sym.value = addr + idx * ObjcStubsSection.entrySize(self.getTarget().cpu.arch);
|
||||
sym.out_n_sect = self.objc_stubs_sect_index.?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void {
|
||||
_ = self;
|
||||
_ = atom_index;
|
||||
@@ -2952,8 +3122,8 @@ pub const Platform = struct {
|
||||
|
||||
pub fn isBuildVersionCompatible(plat: Platform) bool {
|
||||
inline for (supported_platforms) |sup_plat| {
|
||||
if (sup_plat[0] == plat.platform) {
|
||||
return sup_plat[1] <= plat.version.value;
|
||||
if (sup_plat[0] == plat.os_tag and sup_plat[1] == plat.abi) {
|
||||
return sup_plat[2] <= plat.toAppleVersion();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -18,7 +18,6 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool
|
||||
}
|
||||
|
||||
pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {
|
||||
const options = &macho_file.options;
|
||||
var sizeofcmds: u64 = 0;
|
||||
|
||||
// LC_SEGMENT_64
|
||||
@@ -44,14 +43,14 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {
|
||||
false,
|
||||
);
|
||||
// LC_MAIN
|
||||
if (!options.dylib) {
|
||||
if (!macho_file.base.isDynLib()) {
|
||||
sizeofcmds += @sizeOf(macho.entry_point_command);
|
||||
}
|
||||
// LC_ID_DYLIB
|
||||
if (options.dylib) {
|
||||
if (macho_file.base.isDynLib()) {
|
||||
sizeofcmds += blk: {
|
||||
const emit = options.emit;
|
||||
const install_name = options.install_name orelse emit.sub_path;
|
||||
const emit = macho_file.base.emit;
|
||||
const install_name = macho_file.install_name orelse emit.sub_path;
|
||||
break :blk calcInstallNameLen(
|
||||
@sizeOf(macho.dylib_command),
|
||||
install_name,
|
||||
@@ -61,7 +60,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {
|
||||
}
|
||||
// LC_RPATH
|
||||
{
|
||||
for (options.rpath_list) |rpath| {
|
||||
for (macho_file.rpath_table.keys()) |rpath| {
|
||||
sizeofcmds += calcInstallNameLen(
|
||||
@sizeOf(macho.rpath_command),
|
||||
rpath,
|
||||
@@ -71,14 +70,12 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {
|
||||
}
|
||||
// LC_SOURCE_VERSION
|
||||
sizeofcmds += @sizeOf(macho.source_version_command);
|
||||
if (options.platform) |platform| {
|
||||
if (platform.isBuildVersionCompatible()) {
|
||||
// LC_BUILD_VERSION
|
||||
sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
|
||||
} else {
|
||||
// LC_VERSION_MIN_*
|
||||
sizeofcmds += @sizeOf(macho.version_min_command);
|
||||
}
|
||||
if (macho_file.platform.isBuildVersionCompatible()) {
|
||||
// LC_BUILD_VERSION
|
||||
sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
|
||||
} else {
|
||||
// LC_VERSION_MIN_*
|
||||
sizeofcmds += @sizeOf(macho.version_min_command);
|
||||
}
|
||||
// LC_UUID
|
||||
sizeofcmds += @sizeOf(macho.uuid_command);
|
||||
@@ -134,11 +131,10 @@ pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {
|
||||
}
|
||||
|
||||
pub fn calcMinHeaderPadSize(macho_file: *MachO) u32 {
|
||||
const options = &macho_file.options;
|
||||
var padding: u32 = calcLoadCommandsSize(macho_file, false) + (options.headerpad orelse 0);
|
||||
var padding: u32 = calcLoadCommandsSize(macho_file, false) + (macho_file.headerpad_size orelse 0);
|
||||
log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});
|
||||
|
||||
if (options.headerpad_max_install_names) {
|
||||
if (macho_file.headerpad_max_install_names) {
|
||||
const min_headerpad_size: u32 = calcLoadCommandsSize(macho_file, true);
|
||||
log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{
|
||||
min_headerpad_size + @sizeOf(macho.mach_header_64),
|
||||
|
||||
Reference in New Issue
Block a user