mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 21:08:36 +00:00
lld+macho: lld xcomp to x86_64 macos now works
This commit is contained in:
parent
eb528a9cbc
commit
2e7883c597
@ -1257,6 +1257,33 @@ pub const VM_PROT_WRITE: vm_prot_t = 0x2;
|
||||
/// VM execute permission
|
||||
pub const VM_PROT_EXECUTE: vm_prot_t = 0x4;
|
||||
|
||||
pub const BIND_TYPE_POINTER: u8 = 1;
|
||||
pub const BIND_TYPE_TEXT_ABSOLUTE32: u8 = 2;
|
||||
pub const BIND_TYPE_TEXT_PCREL32: u8 = 3;
|
||||
|
||||
pub const BIND_SPECIAL_DYLIB_SELF: i8 = 0;
|
||||
pub const BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE: i8 = -1;
|
||||
pub const BIND_SPECIAL_DYLIB_FLAT_LOOKUP: i8 = -2;
|
||||
|
||||
pub const BIND_SYMBOL_FLAGS_WEAK_IMPORT: u8 = 0x1;
|
||||
pub const BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION: u8 = 0x8;
|
||||
|
||||
pub const BIND_OPCODE_MASK: u8 = 0xf0;
|
||||
pub const BIND_IMMEDIATE_MASK: u8 = 0x0f;
|
||||
pub const BIND_OPCODE_DONE: u8 = 0x00;
|
||||
pub const BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: u8 = 0x10;
|
||||
pub const BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: u8 = 0x20;
|
||||
pub const BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: u8 = 0x30;
|
||||
pub const BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: u8 = 0x40;
|
||||
pub const BIND_OPCODE_SET_TYPE_IMM: u8 = 0x50;
|
||||
pub const BIND_OPCODE_SET_ADDEND_SLEB: u8 = 0x60;
|
||||
pub const BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x70;
|
||||
pub const BIND_OPCODE_ADD_ADDR_ULEB: 0x80;
|
||||
pub const BIND_OPCODE_DO_BIND: u8 = 0x90;
|
||||
pub const BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: u8 = 0xa0;
|
||||
pub const BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: u8 = 0xb0;
|
||||
pub const BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: u8 = xc0;
|
||||
|
||||
pub const reloc_type_x86_64 = packed enum(u4) {
|
||||
/// for absolute addresses
|
||||
X86_64_RELOC_UNSIGNED = 0,
|
||||
|
||||
@ -107,6 +107,7 @@ offset_table: std.ArrayListUnmanaged(u64) = .{},
|
||||
error_flags: File.ErrorFlags = File.ErrorFlags{},
|
||||
|
||||
cmd_table_dirty: bool = false,
|
||||
other_dylibs_present: bool = false,
|
||||
|
||||
/// A list of text blocks that have surplus capacity. This list can have false
|
||||
/// positives, as functions grow and shrink over time, only sometimes being added
|
||||
@ -755,6 +756,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
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) {
|
||||
if (self.other_dylibs_present) return; // TODO We cannot handle this situation yet.
|
||||
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);
|
||||
@ -787,7 +789,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
|
||||
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 });
|
||||
// TODO Fixup linkedit data
|
||||
// Parse dyld info
|
||||
try self.parseBindingInfo();
|
||||
try self.parseLazyBindingInfo();
|
||||
// Write updated load commands and the header
|
||||
try self.writeLoadCommands();
|
||||
try self.writeHeader();
|
||||
@ -2002,6 +2006,8 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {
|
||||
const x = cmd.Dylib;
|
||||
if (parseAndCmpName(x.data, mem.spanZ(LIB_SYSTEM_PATH))) {
|
||||
self.libsystem_cmd_index = i;
|
||||
} else {
|
||||
self.other_dylibs_present = true;
|
||||
}
|
||||
},
|
||||
macho.LC_FUNCTION_STARTS => {
|
||||
@ -2030,3 +2036,75 @@ fn parseAndCmpName(name: []const u8, needle: []const u8) bool {
|
||||
const len = mem.indexOfScalar(u8, name[0..], @as(u8, 0)) orelse name.len;
|
||||
return mem.eql(u8, name[0..len], needle);
|
||||
}
|
||||
|
||||
fn parseBindingInfo(self: *MachO) !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);
|
||||
if (try parseAndFixupBindingInfoBuffer(self.base.allocator, buffer)) {
|
||||
try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
|
||||
}
|
||||
}
|
||||
|
||||
fn parseLazyBindingInfo(self: *MachO) !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);
|
||||
if (try parseAndFixupBindingInfoBuffer(self.base.allocator, buffer)) {
|
||||
try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
|
||||
}
|
||||
}
|
||||
|
||||
fn parseAndFixupBindingInfoBuffer(allocator: *Allocator, buffer: []u8) !bool{
|
||||
var stream = std.io.fixedBufferStream(buffer);
|
||||
var reader = stream.reader();
|
||||
var done = false;
|
||||
var fixups = std.ArrayList(usize).init(allocator);
|
||||
defer fixups.deinit();
|
||||
|
||||
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_DONE => {
|
||||
done = true; // TODO There appear to be multiple BIND_OPCODE_DONE in lazy binding info...
|
||||
},
|
||||
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 => {
|
||||
const uleb_enc = try std.leb.readULEB128(u64, reader);
|
||||
},
|
||||
macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM => {
|
||||
// We note the position in the stream to fixup later.
|
||||
const pos = try reader.context.getPos();
|
||||
try fixups.append(pos - 1);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
assert(done);
|
||||
|
||||
var buffer_dirty = false;
|
||||
try stream.seekTo(0);
|
||||
var writer = stream.writer();
|
||||
for (fixups.items) |pos| {
|
||||
try writer.context.seekTo(pos);
|
||||
const inst = macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | 1;
|
||||
_ = try writer.write(&[_]u8{inst});
|
||||
buffer_dirty = true;
|
||||
}
|
||||
|
||||
return buffer_dirty;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user