mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
macho: remove now obsolete LLD fixups
This commit is contained in:
parent
7516dfff83
commit
861ea64009
@ -947,119 +947,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
log.warn("unexpected LLD stderr:\n{s}", .{stderr});
|
||||
}
|
||||
}
|
||||
|
||||
// At this stage, LLD has done its job. It is time to patch the resultant
|
||||
// binaries up!
|
||||
const out_file = try directory.handle.openFile(self.base.options.emit.?.sub_path, .{ .write = true });
|
||||
try self.parseFromFile(out_file);
|
||||
|
||||
if (self.libsystem_cmd_index == null and self.header.?.filetype == macho.MH_EXECUTE) {
|
||||
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 after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64);
|
||||
const needed_size = padToIdeal(@sizeOf(macho.linkedit_data_command));
|
||||
|
||||
if (needed_size + after_last_cmd_offset > text_section.offset) {
|
||||
log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
|
||||
log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
|
||||
log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
|
||||
return error.NotEnoughPadding;
|
||||
}
|
||||
|
||||
// Calculate next available dylib ordinal.
|
||||
const next_ordinal = blk: {
|
||||
var ordinal: u32 = 1;
|
||||
for (self.load_commands.items) |cmd| {
|
||||
switch (cmd) {
|
||||
.Dylib => ordinal += 1,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
break :blk ordinal;
|
||||
};
|
||||
|
||||
// Add load dylib load command
|
||||
self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
|
||||
const cmdsize = @intCast(u32, mem.alignForwardGeneric(
|
||||
u64,
|
||||
@sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH),
|
||||
@sizeOf(u64),
|
||||
));
|
||||
// TODO Find a way to work out runtime version from the OS version triple stored in std.Target.
|
||||
// In the meantime, we're gonna hardcode to the minimum compatibility version of 0.0.0.
|
||||
const min_version = 0x0;
|
||||
var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{
|
||||
.cmd = macho.LC_LOAD_DYLIB,
|
||||
.cmdsize = cmdsize,
|
||||
.dylib = .{
|
||||
.name = @sizeOf(macho.dylib_command),
|
||||
.timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files
|
||||
.current_version = min_version,
|
||||
.compatibility_version = min_version,
|
||||
},
|
||||
});
|
||||
dylib_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
|
||||
mem.set(u8, dylib_cmd.data, 0);
|
||||
mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
|
||||
try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
|
||||
self.header_dirty = true;
|
||||
self.load_commands_dirty = true;
|
||||
|
||||
if (self.symtab_cmd_index == null or self.dysymtab_cmd_index == null) {
|
||||
log.err("Incomplete Mach-O binary: no LC_SYMTAB or LC_DYSYMTAB load command found!", .{});
|
||||
log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{});
|
||||
return error.NoSymbolTableFound;
|
||||
}
|
||||
|
||||
// Patch dyld info
|
||||
try self.fixupBindInfo(next_ordinal);
|
||||
try self.fixupLazyBindInfo(next_ordinal);
|
||||
|
||||
// Write updated load commands and the header
|
||||
try self.writeLoadCommands();
|
||||
try self.writeHeader();
|
||||
|
||||
assert(!self.header_dirty);
|
||||
assert(!self.load_commands_dirty);
|
||||
}
|
||||
if (self.code_signature_cmd_index == null) outer: {
|
||||
if (target.cpu.arch != .aarch64) break :outer; // This is currently needed only for aarch64 targets.
|
||||
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 after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64);
|
||||
const needed_size = padToIdeal(@sizeOf(macho.linkedit_data_command));
|
||||
|
||||
if (needed_size + after_last_cmd_offset > text_section.offset) {
|
||||
log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
|
||||
log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
|
||||
log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
|
||||
return error.NotEnoughPadding;
|
||||
}
|
||||
|
||||
// Add code signature load command
|
||||
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.header_dirty = true;
|
||||
self.load_commands_dirty = true;
|
||||
|
||||
// Pad out space for code signature
|
||||
try self.writeCodeSignaturePadding();
|
||||
// Write updated load commands and the header
|
||||
try self.writeLoadCommands();
|
||||
try self.writeHeader();
|
||||
// Generate adhoc code signature
|
||||
try self.writeCodeSignature();
|
||||
|
||||
assert(!self.header_dirty);
|
||||
assert(!self.load_commands_dirty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3375,177 +3262,6 @@ fn writeHeader(self: *MachO) !void {
|
||||
self.header_dirty = false;
|
||||
}
|
||||
|
||||
/// Parse MachO contents from existing binary file.
|
||||
fn parseFromFile(self: *MachO, file: fs.File) !void {
|
||||
self.base.file = file;
|
||||
var reader = file.reader();
|
||||
const header = try reader.readStruct(macho.mach_header_64);
|
||||
try self.load_commands.ensureCapacity(self.base.allocator, header.ncmds);
|
||||
var i: u16 = 0;
|
||||
while (i < header.ncmds) : (i += 1) {
|
||||
const cmd = try LoadCommand.read(self.base.allocator, reader);
|
||||
switch (cmd.cmd()) {
|
||||
macho.LC_SEGMENT_64 => {
|
||||
const x = cmd.Segment;
|
||||
if (parseAndCmpName(&x.inner.segname, "__PAGEZERO")) {
|
||||
self.pagezero_segment_cmd_index = i;
|
||||
} else if (parseAndCmpName(&x.inner.segname, "__LINKEDIT")) {
|
||||
self.linkedit_segment_cmd_index = i;
|
||||
} else if (parseAndCmpName(&x.inner.segname, "__TEXT")) {
|
||||
self.text_segment_cmd_index = i;
|
||||
for (x.sections.items) |sect, j| {
|
||||
if (parseAndCmpName(§.sectname, "__text")) {
|
||||
self.text_section_index = @intCast(u16, j);
|
||||
}
|
||||
}
|
||||
} else if (parseAndCmpName(&x.inner.segname, "__DATA")) {
|
||||
self.data_segment_cmd_index = i;
|
||||
} else if (parseAndCmpName(&x.inner.segname, "__DATA_CONST")) {
|
||||
self.data_const_segment_cmd_index = i;
|
||||
}
|
||||
},
|
||||
macho.LC_DYLD_INFO_ONLY => {
|
||||
self.dyld_info_cmd_index = i;
|
||||
},
|
||||
macho.LC_SYMTAB => {
|
||||
self.symtab_cmd_index = i;
|
||||
},
|
||||
macho.LC_DYSYMTAB => {
|
||||
self.dysymtab_cmd_index = i;
|
||||
},
|
||||
macho.LC_LOAD_DYLINKER => {
|
||||
self.dylinker_cmd_index = i;
|
||||
},
|
||||
macho.LC_VERSION_MIN_MACOSX, macho.LC_VERSION_MIN_IPHONEOS, macho.LC_VERSION_MIN_WATCHOS, macho.LC_VERSION_MIN_TVOS => {
|
||||
self.version_min_cmd_index = i;
|
||||
},
|
||||
macho.LC_SOURCE_VERSION => {
|
||||
self.source_version_cmd_index = i;
|
||||
},
|
||||
macho.LC_UUID => {
|
||||
self.uuid_cmd_index = i;
|
||||
},
|
||||
macho.LC_MAIN => {
|
||||
self.main_cmd_index = i;
|
||||
},
|
||||
macho.LC_LOAD_DYLIB => {
|
||||
const x = cmd.Dylib;
|
||||
if (parseAndCmpName(x.data, mem.spanZ(LIB_SYSTEM_PATH))) {
|
||||
self.libsystem_cmd_index = i;
|
||||
}
|
||||
},
|
||||
macho.LC_FUNCTION_STARTS => {
|
||||
self.function_starts_cmd_index = i;
|
||||
},
|
||||
macho.LC_DATA_IN_CODE => {
|
||||
self.data_in_code_cmd_index = i;
|
||||
},
|
||||
macho.LC_CODE_SIGNATURE => {
|
||||
self.code_signature_cmd_index = i;
|
||||
},
|
||||
else => {
|
||||
log.warn("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
|
||||
},
|
||||
}
|
||||
self.load_commands.appendAssumeCapacity(cmd);
|
||||
}
|
||||
self.header = header;
|
||||
}
|
||||
|
||||
fn parseAndCmpName(name: []const u8, needle: []const u8) bool {
|
||||
const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
|
||||
return mem.eql(u8, name[0..len], needle);
|
||||
}
|
||||
|
||||
fn parseSymbolTable(self: *MachO) !void {
|
||||
const symtab = self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
|
||||
|
||||
var buffer = try self.base.allocator.alloc(macho.nlist_64, symtab.nsyms);
|
||||
defer self.base.allocator.free(buffer);
|
||||
const nread = try self.base.file.?.preadAll(@ptrCast([*]u8, buffer)[0 .. symtab.nsyms * @sizeOf(macho.nlist_64)], symtab.symoff);
|
||||
assert(@divExact(nread, @sizeOf(macho.nlist_64)) == buffer.len);
|
||||
|
||||
try self.locals.ensureCapacity(self.base.allocator, dysymtab.nlocalsym);
|
||||
try self.globals.ensureCapacity(self.base.allocator, dysymtab.nextdefsym);
|
||||
try self.undef_symbols.ensureCapacity(self.base.allocator, dysymtab.nundefsym);
|
||||
|
||||
self.locals.appendSliceAssumeCapacity(buffer[dysymtab.ilocalsym .. dysymtab.ilocalsym + dysymtab.nlocalsym]);
|
||||
self.globals.appendSliceAssumeCapacity(buffer[dysymtab.iextdefsym .. dysymtab.iextdefsym + dysymtab.nextdefsym]);
|
||||
self.undef_symbols.appendSliceAssumeCapacity(buffer[dysymtab.iundefsym .. dysymtab.iundefsym + dysymtab.nundefsym]);
|
||||
}
|
||||
|
||||
fn parseStringTable(self: *MachO) !void {
|
||||
const symtab = self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
|
||||
var buffer = try self.base.allocator.alloc(u8, symtab.strsize);
|
||||
defer self.base.allocator.free(buffer);
|
||||
const nread = try self.base.file.?.preadAll(buffer, symtab.stroff);
|
||||
assert(nread == buffer.len);
|
||||
|
||||
try self.string_table.ensureCapacity(self.base.allocator, symtab.strsize);
|
||||
self.string_table.appendSliceAssumeCapacity(buffer);
|
||||
}
|
||||
|
||||
fn fixupBindInfo(self: *MachO, dylib_ordinal: u32) !void {
|
||||
const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
|
||||
var buffer = try self.base.allocator.alloc(u8, dyld_info.bind_size);
|
||||
defer self.base.allocator.free(buffer);
|
||||
const nread = try self.base.file.?.preadAll(buffer, dyld_info.bind_off);
|
||||
assert(nread == buffer.len);
|
||||
try self.fixupInfoCommon(buffer, dylib_ordinal);
|
||||
try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
|
||||
}
|
||||
|
||||
fn fixupLazyBindInfo(self: *MachO, dylib_ordinal: u32) !void {
|
||||
const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
|
||||
var buffer = try self.base.allocator.alloc(u8, dyld_info.lazy_bind_size);
|
||||
defer self.base.allocator.free(buffer);
|
||||
const nread = try self.base.file.?.preadAll(buffer, dyld_info.lazy_bind_off);
|
||||
assert(nread == buffer.len);
|
||||
try self.fixupInfoCommon(buffer, dylib_ordinal);
|
||||
try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
|
||||
}
|
||||
|
||||
fn fixupInfoCommon(self: *MachO, buffer: []u8, dylib_ordinal: u32) !void {
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
var reader = stream.reader();
|
||||
|
||||
while (true) {
|
||||
const inst = reader.readByte() catch |err| switch (err) {
|
||||
error.EndOfStream => break,
|
||||
else => return err,
|
||||
};
|
||||
const imm: u8 = inst & macho.BIND_IMMEDIATE_MASK;
|
||||
const opcode: u8 = inst & macho.BIND_OPCODE_MASK;
|
||||
|
||||
switch (opcode) {
|
||||
macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
|
||||
var next = try reader.readByte();
|
||||
while (next != @as(u8, 0)) {
|
||||
next = try reader.readByte();
|
||||
}
|
||||
},
|
||||
macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {
|
||||
_ = try std.leb.readULEB128(u64, reader);
|
||||
},
|
||||
macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => {
|
||||
// Perform the fixup.
|
||||
try stream.seekBy(-1);
|
||||
var writer = stream.writer();
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @truncate(u4, dylib_ordinal));
|
||||
},
|
||||
macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB => {
|
||||
_ = try std.leb.readULEB128(u64, reader);
|
||||
},
|
||||
macho.BIND_OPCODE_SET_ADDEND_SLEB => {
|
||||
_ = try std.leb.readILEB128(i64, reader);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
|
||||
// TODO https://github.com/ziglang/zig/issues/1284
|
||||
return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
|
||||
|
Loading…
Reference in New Issue
Block a user