authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-05 12:59:28+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-17 10:04:53+01:00
log2e7883c59726a0832c3af6581fd96bf69a0fa3a6
tree0e798ee09923af2d8ea1be3982ff8af1c1ef6701
parenteb528a9cbc4baebe16dda686bdc55d0feee82087

lld+macho: lld xcomp to x86_64 macos now works


2 files changed, 106 insertions(+), 1 deletions(-)

lib/std/macho.zig+27
...@@ -1257,6 +1257,33 @@ pub const VM_PROT_WRITE: vm_prot_t = 0x2;...@@ -1257,6 +1257,33 @@ pub const VM_PROT_WRITE: vm_prot_t = 0x2;
1257/// VM execute permission1257/// VM execute permission
1258pub const VM_PROT_EXECUTE: vm_prot_t = 0x4;1258pub const VM_PROT_EXECUTE: vm_prot_t = 0x4;
12591259
1260pub const BIND_TYPE_POINTER: u8 = 1;
1261pub const BIND_TYPE_TEXT_ABSOLUTE32: u8 = 2;
1262pub const BIND_TYPE_TEXT_PCREL32: u8 = 3;
1263
1264pub const BIND_SPECIAL_DYLIB_SELF: i8 = 0;
1265pub const BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE: i8 = -1;
1266pub const BIND_SPECIAL_DYLIB_FLAT_LOOKUP: i8 = -2;
1267
1268pub const BIND_SYMBOL_FLAGS_WEAK_IMPORT: u8 = 0x1;
1269pub const BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION: u8 = 0x8;
1270
1271pub const BIND_OPCODE_MASK: u8 = 0xf0;
1272pub const BIND_IMMEDIATE_MASK: u8 = 0x0f;
1273pub const BIND_OPCODE_DONE: u8 = 0x00;
1274pub const BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: u8 = 0x10;
1275pub const BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: u8 = 0x20;
1276pub const BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: u8 = 0x30;
1277pub const BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: u8 = 0x40;
1278pub const BIND_OPCODE_SET_TYPE_IMM: u8 = 0x50;
1279pub const BIND_OPCODE_SET_ADDEND_SLEB: u8 = 0x60;
1280pub const BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x70;
1281pub const BIND_OPCODE_ADD_ADDR_ULEB: 0x80;
1282pub const BIND_OPCODE_DO_BIND: u8 = 0x90;
1283pub const BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: u8 = 0xa0;
1284pub const BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: u8 = 0xb0;
1285pub const BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: u8 = xc0;
1286
1260pub const reloc_type_x86_64 = packed enum(u4) {1287pub const reloc_type_x86_64 = packed enum(u4) {
1261 /// for absolute addresses1288 /// for absolute addresses
1262 X86_64_RELOC_UNSIGNED = 0,1289 X86_64_RELOC_UNSIGNED = 0,
src/link/MachO.zig+79-1
...@@ -107,6 +107,7 @@ offset_table: std.ArrayListUnmanaged(u64) = .{},...@@ -107,6 +107,7 @@ offset_table: std.ArrayListUnmanaged(u64) = .{},
107error_flags: File.ErrorFlags = File.ErrorFlags{},107error_flags: File.ErrorFlags = File.ErrorFlags{},
108108
109cmd_table_dirty: bool = false,109cmd_table_dirty: bool = false,
110other_dylibs_present: bool = false,
110111
111/// A list of text blocks that have surplus capacity. This list can have false112/// A list of text blocks that have surplus capacity. This list can have false
112/// positives, as functions grow and shrink over time, only sometimes being added113/// positives, as functions grow and shrink over time, only sometimes being added
...@@ -755,6 +756,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -755,6 +756,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
755 const out_file = try directory.handle.openFile(self.base.options.emit.?.sub_path, .{ .write = true });756 const out_file = try directory.handle.openFile(self.base.options.emit.?.sub_path, .{ .write = true });
756 try self.parseFromFile(out_file);757 try self.parseFromFile(out_file);
757 if (self.libsystem_cmd_index == null) {758 if (self.libsystem_cmd_index == null) {
759 if (self.other_dylibs_present) return; // TODO We cannot handle this situation yet.
758 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;760 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
759 const text_section = text_segment.sections.items[self.text_section_index.?];761 const text_section = text_segment.sections.items[self.text_section_index.?];
760 const after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64);762 const after_last_cmd_offset = self.header.?.sizeofcmds + @sizeOf(macho.mach_header_64);
...@@ -787,7 +789,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -787,7 +789,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
787 mem.set(u8, dylib_cmd.data, 0);789 mem.set(u8, dylib_cmd.data, 0);
788 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));790 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
789 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });791 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
790 // TODO Fixup linkedit data792 // Parse dyld info
793 try self.parseBindingInfo();
794 try self.parseLazyBindingInfo();
791 // Write updated load commands and the header795 // Write updated load commands and the header
792 try self.writeLoadCommands();796 try self.writeLoadCommands();
793 try self.writeHeader();797 try self.writeHeader();
...@@ -2002,6 +2006,8 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {...@@ -2002,6 +2006,8 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {
2002 const x = cmd.Dylib;2006 const x = cmd.Dylib;
2003 if (parseAndCmpName(x.data, mem.spanZ(LIB_SYSTEM_PATH))) {2007 if (parseAndCmpName(x.data, mem.spanZ(LIB_SYSTEM_PATH))) {
2004 self.libsystem_cmd_index = i;2008 self.libsystem_cmd_index = i;
2009 } else {
2010 self.other_dylibs_present = true;
2005 }2011 }
2006 },2012 },
2007 macho.LC_FUNCTION_STARTS => {2013 macho.LC_FUNCTION_STARTS => {
...@@ -2030,3 +2036,75 @@ fn parseAndCmpName(name: []const u8, needle: []const u8) bool {...@@ -2030,3 +2036,75 @@ fn parseAndCmpName(name: []const u8, needle: []const u8) bool {
2030 const len = mem.indexOfScalar(u8, name[0..], @as(u8, 0)) orelse name.len;2036 const len = mem.indexOfScalar(u8, name[0..], @as(u8, 0)) orelse name.len;
2031 return mem.eql(u8, name[0..len], needle);2037 return mem.eql(u8, name[0..len], needle);
2032}2038}
2039
2040fn parseBindingInfo(self: *MachO) !void {
2041 const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
2042 var buffer = try self.base.allocator.alloc(u8, dyld_info.bind_size);
2043 defer self.base.allocator.free(buffer);
2044 const nread = try self.base.file.?.preadAll(buffer, dyld_info.bind_off);
2045 assert(nread == buffer.len);
2046 if (try parseAndFixupBindingInfoBuffer(self.base.allocator, buffer)) {
2047 try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);
2048 }
2049}
2050
2051fn parseLazyBindingInfo(self: *MachO) !void {
2052 const dyld_info = self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
2053 var buffer = try self.base.allocator.alloc(u8, dyld_info.lazy_bind_size);
2054 defer self.base.allocator.free(buffer);
2055 const nread = try self.base.file.?.preadAll(buffer, dyld_info.lazy_bind_off);
2056 assert(nread == buffer.len);
2057 if (try parseAndFixupBindingInfoBuffer(self.base.allocator, buffer)) {
2058 try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);
2059 }
2060}
2061
2062fn parseAndFixupBindingInfoBuffer(allocator: *Allocator, buffer: []u8) !bool{
2063 var stream = std.io.fixedBufferStream(buffer);
2064 var reader = stream.reader();
2065 var done = false;
2066 var fixups = std.ArrayList(usize).init(allocator);
2067 defer fixups.deinit();
2068
2069 while (true) {
2070 const inst = reader.readByte() catch |err| switch (err) {
2071 error.EndOfStream => break,
2072 else => return err,
2073 };
2074 const imm: u8 = inst & macho.BIND_IMMEDIATE_MASK;
2075 const opcode: u8 = inst & macho.BIND_OPCODE_MASK;
2076 switch (opcode) {
2077 macho.BIND_OPCODE_DONE => {
2078 done = true; // TODO There appear to be multiple BIND_OPCODE_DONE in lazy binding info...
2079 },
2080 macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => {
2081 var next = try reader.readByte();
2082 while (next != @as(u8, 0)) {
2083 next = try reader.readByte();
2084 }
2085 },
2086 macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {
2087 const uleb_enc = try std.leb.readULEB128(u64, reader);
2088 },
2089 macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM => {
2090 // We note the position in the stream to fixup later.
2091 const pos = try reader.context.getPos();
2092 try fixups.append(pos - 1);
2093 },
2094 else => {},
2095 }
2096 }
2097 assert(done);
2098
2099 var buffer_dirty = false;
2100 try stream.seekTo(0);
2101 var writer = stream.writer();
2102 for (fixups.items) |pos| {
2103 try writer.context.seekTo(pos);
2104 const inst = macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | 1;
2105 _ = try writer.write(&[_]u8{inst});
2106 buffer_dirty = true;
2107 }
2108
2109 return buffer_dirty;
2110}