authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-29 17:46:23+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-29 17:46:23+02:00
log8211cef77c15d37d3ec9b92943476c7755ef7efc
tree2c3df4c5f939f6bc959e11806d3b587067320a38
parent069fcf1c95dafa7c711b4f5c7d1041eaab54a9e5

zld: we can now create basic dylibs targeting macOS!


2 files changed, 128 insertions(+), 60 deletions(-)

src/link/MachO.zig+33-5
......@@ -626,12 +626,12 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
626626
627627 const is_lib = self.base.options.output_mode == .Lib;
628628 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
629 // const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
629 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
630630 const target = self.base.options.target;
631631 const stack_size = self.base.options.stack_size_override orelse 0;
632632 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
633633
634 const id_symlink_basename = "lld.id";
634 const id_symlink_basename = "zld.id";
635635
636636 var man: Cache.Manifest = undefined;
637637 defer if (!self.base.options.disable_lld_caching) man.deinit();
......@@ -731,7 +731,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
731731 zld.closeFiles();
732732 zld.deinit();
733733 }
734 zld.arch = target.cpu.arch;
734 zld.target = target;
735735 zld.stack_size = stack_size;
736736
737737 // Positional arguments to the linker such as object files and static archives.
......@@ -876,12 +876,40 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
876876 rpaths.appendAssumeCapacity(key.*);
877877 }
878878
879 const output: Zld.Output = output: {
880 if (is_dyn_lib) {
881 const install_name = try std.fmt.allocPrint(arena, "@rpath/{s}", .{
882 self.base.options.emit.?.sub_path,
883 });
884 break :output .{
885 .tag = .dylib,
886 .path = full_out_path,
887 .install_name = install_name,
888 };
889 }
890 break :output .{
891 .tag = .exe,
892 .path = full_out_path,
893 };
894 };
895
879896 if (self.base.options.verbose_link) {
880897 var argv = std.ArrayList([]const u8).init(arena);
881898
882899 try argv.append("zig");
883900 try argv.append("ld");
884901
902 if (is_exe_or_dyn_lib) {
903 try argv.append("-dynamic");
904 }
905
906 if (is_dyn_lib) {
907 try argv.append("-dylib");
908
909 try argv.append("-install_name");
910 try argv.append(output.install_name.?);
911 }
912
885913 if (self.base.options.sysroot) |syslibroot| {
886914 try argv.append("-syslibroot");
887915 try argv.append(syslibroot);
......@@ -895,7 +923,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
895923 try argv.appendSlice(positionals.items);
896924
897925 try argv.append("-o");
898 try argv.append(full_out_path);
926 try argv.append(output.path);
899927
900928 if (native_libsystem_available) {
901929 try argv.append("-lSystem");
......@@ -913,7 +941,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
913941 Compilation.dump_argv(argv.items);
914942 }
915943
916 try zld.link(positionals.items, full_out_path, .{
944 try zld.link(positionals.items, output, .{
917945 .syslibroot = self.base.options.sysroot,
918946 .libs = libs.items,
919947 .rpaths = rpaths.items,
src/link/MachO/Zld.zig+95-55
......@@ -25,10 +25,10 @@ usingnamespace @import("bind.zig");
2525
2626allocator: *Allocator,
2727
28arch: ?std.Target.Cpu.Arch = null,
28target: ?std.Target = null,
2929page_size: ?u16 = null,
3030file: ?fs.File = null,
31out_path: ?[]const u8 = null,
31output: ?Output = null,
3232
3333// TODO these args will become obselete once Zld is coalesced with incremental
3434// linker.
......@@ -54,6 +54,7 @@ dylinker_cmd_index: ?u16 = null,
5454data_in_code_cmd_index: ?u16 = null,
5555function_starts_cmd_index: ?u16 = null,
5656main_cmd_index: ?u16 = null,
57dylib_id_cmd_index: ?u16 = null,
5758version_min_cmd_index: ?u16 = null,
5859source_version_cmd_index: ?u16 = null,
5960uuid_cmd_index: ?u16 = null,
......@@ -118,6 +119,12 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
118119
119120stub_helper_stubs_start_off: ?u64 = null,
120121
122pub const Output = struct {
123 tag: enum { exe, dylib },
124 path: []const u8,
125 install_name: ?[]const u8 = null,
126};
127
121128const TlvOffset = struct {
122129 source_addr: u64,
123130 offset: u64,
......@@ -200,36 +207,17 @@ const LinkArgs = struct {
200207 rpaths: []const []const u8,
201208};
202209
203pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void {
210pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArgs) !void {
204211 if (files.len == 0) return error.NoInputFiles;
205 if (out_path.len == 0) return error.EmptyOutputPath;
206
207 if (self.arch == null) {
208 // Try inferring the arch from the object files.
209 self.arch = blk: {
210 const file = try fs.cwd().openFile(files[0], .{});
211 defer file.close();
212 var reader = file.reader();
213 const header = try reader.readStruct(macho.mach_header_64);
214 const arch: std.Target.Cpu.Arch = switch (header.cputype) {
215 macho.CPU_TYPE_X86_64 => .x86_64,
216 macho.CPU_TYPE_ARM64 => .aarch64,
217 else => |value| {
218 log.err("unsupported cpu architecture 0x{x}", .{value});
219 return error.UnsupportedCpuArchitecture;
220 },
221 };
222 break :blk arch;
223 };
224 }
212 if (output.path.len == 0) return error.EmptyOutputPath;
225213
226 self.page_size = switch (self.arch.?) {
214 self.page_size = switch (self.target.?.cpu.arch) {
227215 .aarch64 => 0x4000,
228216 .x86_64 => 0x1000,
229217 else => unreachable,
230218 };
231 self.out_path = out_path;
232 self.file = try fs.cwd().createFile(out_path, .{
219 self.output = output;
220 self.file = try fs.cwd().createFile(self.output.?.path, .{
233221 .truncate = true,
234222 .read = true,
235223 .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777,
......@@ -263,19 +251,19 @@ fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u
263251 break :full_path try self.allocator.dupe(u8, path);
264252 };
265253
266 if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| {
254 if (try Object.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, full_path)) |object| {
267255 try self.objects.append(self.allocator, object);
268256 continue;
269257 }
270258
271 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| {
259 if (try Archive.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, full_path)) |archive| {
272260 try self.archives.append(self.allocator, archive);
273261 continue;
274262 }
275263
276264 if (try Dylib.createAndParseFromPath(
277265 self.allocator,
278 self.arch.?,
266 self.target.?.cpu.arch,
279267 full_path,
280268 .{ .syslibroot = syslibroot },
281269 )) |dylibs| {
......@@ -292,7 +280,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi
292280 for (libs) |lib| {
293281 if (try Dylib.createAndParseFromPath(
294282 self.allocator,
295 self.arch.?,
283 self.target.?.cpu.arch,
296284 lib,
297285 .{ .syslibroot = syslibroot },
298286 )) |dylibs| {
......@@ -301,7 +289,7 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi
301289 continue;
302290 }
303291
304 if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| {
292 if (try Archive.createAndParseFromPath(self.allocator, self.target.?.cpu.arch, lib)) |archive| {
305293 try self.archives.append(self.allocator, archive);
306294 continue;
307295 }
......@@ -989,7 +977,7 @@ fn allocateTextSegment(self: *Zld) !void {
989977 const stub_helper = &seg.sections.items[self.stub_helper_section_index.?];
990978 stubs.size += nstubs * stubs.reserved2;
991979
992 const stub_size: u4 = switch (self.arch.?) {
980 const stub_size: u4 = switch (self.target.?.cpu.arch) {
993981 .x86_64 => 10,
994982 .aarch64 => 3 * @sizeOf(u32),
995983 else => unreachable,
......@@ -1226,7 +1214,7 @@ fn writeStubHelperCommon(self: *Zld) !void {
12261214 const data = &data_segment.sections.items[self.data_section_index.?];
12271215
12281216 self.stub_helper_stubs_start_off = blk: {
1229 switch (self.arch.?) {
1217 switch (self.target.?.cpu.arch) {
12301218 .x86_64 => {
12311219 const code_size = 15;
12321220 var code: [code_size]u8 = undefined;
......@@ -1358,7 +1346,7 @@ fn writeLazySymbolPointer(self: *Zld, index: u32) !void {
13581346 const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
13591347 const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?];
13601348
1361 const stub_size: u4 = switch (self.arch.?) {
1349 const stub_size: u4 = switch (self.target.?.cpu.arch) {
13621350 .x86_64 => 10,
13631351 .aarch64 => 3 * @sizeOf(u32),
13641352 else => unreachable,
......@@ -1384,7 +1372,7 @@ fn writeStub(self: *Zld, index: u32) !void {
13841372 log.debug("writing stub at 0x{x}", .{stub_off});
13851373 var code = try self.allocator.alloc(u8, stubs.reserved2);
13861374 defer self.allocator.free(code);
1387 switch (self.arch.?) {
1375 switch (self.target.?.cpu.arch) {
13881376 .x86_64 => {
13891377 assert(la_ptr_addr >= stub_addr + stubs.reserved2);
13901378 const displacement = try math.cast(u32, la_ptr_addr - stub_addr - stubs.reserved2);
......@@ -1447,7 +1435,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {
14471435 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
14481436 const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?];
14491437
1450 const stub_size: u4 = switch (self.arch.?) {
1438 const stub_size: u4 = switch (self.target.?.cpu.arch) {
14511439 .x86_64 => 10,
14521440 .aarch64 => 3 * @sizeOf(u32),
14531441 else => unreachable,
......@@ -1455,7 +1443,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {
14551443 const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size;
14561444 var code = try self.allocator.alloc(u8, stub_size);
14571445 defer self.allocator.free(code);
1458 switch (self.arch.?) {
1446 switch (self.target.?.cpu.arch) {
14591447 .x86_64 => {
14601448 const displacement = try math.cast(
14611449 i32,
......@@ -1999,7 +1987,7 @@ fn populateMetadata(self: *Zld) !void {
19991987 if (self.text_section_index == null) {
20001988 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
20011989 self.text_section_index = @intCast(u16, text_seg.sections.items.len);
2002 const alignment: u2 = switch (self.arch.?) {
1990 const alignment: u2 = switch (self.target.?.cpu.arch) {
20031991 .x86_64 => 0,
20041992 .aarch64 => 2,
20051993 else => unreachable, // unhandled architecture type
......@@ -2013,12 +2001,12 @@ fn populateMetadata(self: *Zld) !void {
20132001 if (self.stubs_section_index == null) {
20142002 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
20152003 self.stubs_section_index = @intCast(u16, text_seg.sections.items.len);
2016 const alignment: u2 = switch (self.arch.?) {
2004 const alignment: u2 = switch (self.target.?.cpu.arch) {
20172005 .x86_64 => 0,
20182006 .aarch64 => 2,
20192007 else => unreachable, // unhandled architecture type
20202008 };
2021 const stub_size: u4 = switch (self.arch.?) {
2009 const stub_size: u4 = switch (self.target.?.cpu.arch) {
20222010 .x86_64 => 6,
20232011 .aarch64 => 3 * @sizeOf(u32),
20242012 else => unreachable, // unhandled architecture type
......@@ -2033,12 +2021,12 @@ fn populateMetadata(self: *Zld) !void {
20332021 if (self.stub_helper_section_index == null) {
20342022 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
20352023 self.stub_helper_section_index = @intCast(u16, text_seg.sections.items.len);
2036 const alignment: u2 = switch (self.arch.?) {
2024 const alignment: u2 = switch (self.target.?.cpu.arch) {
20372025 .x86_64 => 0,
20382026 .aarch64 => 2,
20392027 else => unreachable, // unhandled architecture type
20402028 };
2041 const stub_helper_size: u6 = switch (self.arch.?) {
2029 const stub_helper_size: u6 = switch (self.target.?.cpu.arch) {
20422030 .x86_64 => 15,
20432031 .aarch64 => 6 * @sizeOf(u32),
20442032 else => unreachable,
......@@ -2187,7 +2175,7 @@ fn populateMetadata(self: *Zld) !void {
21872175 try self.load_commands.append(self.allocator, .{ .Dylinker = dylinker_cmd });
21882176 }
21892177
2190 if (self.main_cmd_index == null) {
2178 if (self.main_cmd_index == null and self.output.?.tag == .exe) {
21912179 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
21922180 try self.load_commands.append(self.allocator, .{
21932181 .Main = .{
......@@ -2199,6 +2187,41 @@ fn populateMetadata(self: *Zld) !void {
21992187 });
22002188 }
22012189
2190 if (self.dylib_id_cmd_index == null and self.output.?.tag == .dylib) {
2191 self.dylib_id_cmd_index = @intCast(u16, self.load_commands.items.len);
2192 var dylib_cmd = try createLoadDylibCommand(
2193 self.allocator,
2194 self.output.?.install_name.?,
2195 2,
2196 0x10000, // TODO forward user-provided versions
2197 0x10000,
2198 );
2199 errdefer dylib_cmd.deinit(self.allocator);
2200 dylib_cmd.inner.cmd = macho.LC_ID_DYLIB;
2201 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
2202 }
2203
2204 if (self.version_min_cmd_index == null) {
2205 self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len);
2206 const cmd: u32 = switch (self.target.?.os.tag) {
2207 .macos => macho.LC_VERSION_MIN_MACOSX,
2208 .ios => macho.LC_VERSION_MIN_IPHONEOS,
2209 .tvos => macho.LC_VERSION_MIN_TVOS,
2210 .watchos => macho.LC_VERSION_MIN_WATCHOS,
2211 else => unreachable, // wrong OS
2212 };
2213 const ver = self.target.?.os.version_range.semver.min;
2214 const version = ver.major << 16 | ver.minor << 8 | ver.patch;
2215 try self.load_commands.append(self.allocator, .{
2216 .VersionMin = .{
2217 .cmd = cmd,
2218 .cmdsize = @sizeOf(macho.version_min_command),
2219 .version = version,
2220 .sdk = version,
2221 },
2222 });
2223 }
2224
22022225 if (self.source_version_cmd_index == null) {
22032226 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
22042227 try self.load_commands.append(self.allocator, .{
......@@ -2237,7 +2260,7 @@ fn addDataInCodeLC(self: *Zld) !void {
22372260}
22382261
22392262fn addCodeSignatureLC(self: *Zld) !void {
2240 if (self.code_signature_cmd_index == null and self.arch.? == .aarch64) {
2263 if (self.code_signature_cmd_index == null and self.target.?.cpu.arch == .aarch64) {
22412264 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
22422265 try self.load_commands.append(self.allocator, .{
22432266 .LinkeditData = .{
......@@ -2355,19 +2378,20 @@ fn flush(self: *Zld) !void {
23552378 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size.?);
23562379 }
23572380
2358 if (self.arch.? == .aarch64) {
2381 if (self.target.?.cpu.arch == .aarch64) {
23592382 try self.writeCodeSignaturePadding();
23602383 }
23612384
23622385 try self.writeLoadCommands();
23632386 try self.writeHeader();
23642387
2365 if (self.arch.? == .aarch64) {
2388 if (self.target.?.cpu.arch == .aarch64) {
23662389 try self.writeCodeSignature();
23672390 }
23682391
23692392 if (comptime std.Target.current.isDarwin() and std.Target.current.cpu.arch == .aarch64) {
2370 try fs.cwd().copyFile(self.out_path.?, fs.cwd(), self.out_path.?, .{});
2393 const out_path = self.output.?.path;
2394 try fs.cwd().copyFile(out_path, fs.cwd(), out_path, .{});
23712395 }
23722396}
23732397
......@@ -2392,6 +2416,8 @@ fn writeGotEntries(self: *Zld) !void {
23922416}
23932417
23942418fn setEntryPoint(self: *Zld) !void {
2419 if (self.output.?.tag != .exe) return;
2420
23952421 // TODO we should respect the -entry flag passed in by the user to set a custom
23962422 // entrypoint. For now, assume default of `_main`.
23972423 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
......@@ -2636,12 +2662,12 @@ fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
26362662 }
26372663 assert(self.stubs.items.len <= offsets.items.len);
26382664
2639 const stub_size: u4 = switch (self.arch.?) {
2665 const stub_size: u4 = switch (self.target.?.cpu.arch) {
26402666 .x86_64 => 10,
26412667 .aarch64 => 3 * @sizeOf(u32),
26422668 else => unreachable,
26432669 };
2644 const off: u4 = switch (self.arch.?) {
2670 const off: u4 = switch (self.target.?.cpu.arch) {
26452671 .x86_64 => 1,
26462672 .aarch64 => 2 * @sizeOf(u32),
26472673 else => unreachable,
......@@ -2998,7 +3024,7 @@ fn writeStringTable(self: *Zld) !void {
29983024
29993025 try self.file.?.pwriteAll(self.strtab.items, symtab.stroff);
30003026
3001 if (symtab.strsize > self.strtab.items.len and self.arch.? == .x86_64) {
3027 if (symtab.strsize > self.strtab.items.len and self.target.?.cpu.arch == .x86_64) {
30023028 // This is the last section, so we need to pad it out.
30033029 try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
30043030 }
......@@ -3046,7 +3072,7 @@ fn writeCodeSignaturePadding(self: *Zld) !void {
30463072 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
30473073 const fileoff = seg.inner.fileoff + seg.inner.filesize;
30483074 const needed_size = CodeSignature.calcCodeSignaturePaddingSize(
3049 self.out_path.?,
3075 self.output.?.path,
30503076 fileoff,
30513077 self.page_size.?,
30523078 );
......@@ -3072,7 +3098,7 @@ fn writeCodeSignature(self: *Zld) !void {
30723098 defer code_sig.deinit();
30733099 try code_sig.calcAdhocSignature(
30743100 self.file.?,
3075 self.out_path.?,
3101 self.output.?.path,
30763102 text_seg.inner,
30773103 code_sig_cmd,
30783104 .Exe,
......@@ -3114,7 +3140,7 @@ fn writeHeader(self: *Zld) !void {
31143140 cpu_subtype: macho.cpu_subtype_t,
31153141 };
31163142
3117 const cpu_info: CpuInfo = switch (self.arch.?) {
3143 const cpu_info: CpuInfo = switch (self.target.?.cpu.arch) {
31183144 .aarch64 => .{
31193145 .cpu_type = macho.CPU_TYPE_ARM64,
31203146 .cpu_subtype = macho.CPU_SUBTYPE_ARM_ALL,
......@@ -3127,8 +3153,22 @@ fn writeHeader(self: *Zld) !void {
31273153 };
31283154 header.cputype = cpu_info.cpu_type;
31293155 header.cpusubtype = cpu_info.cpu_subtype;
3130 header.filetype = macho.MH_EXECUTE;
3131 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
3156
3157 switch (self.output.?.tag) {
3158 .exe => {
3159 header.filetype = macho.MH_EXECUTE;
3160 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
3161 },
3162 .dylib => {
3163 header.filetype = macho.MH_DYLIB;
3164 header.flags = macho.MH_NOUNDEFS |
3165 macho.MH_DYLDLINK |
3166 macho.MH_PIE |
3167 macho.MH_TWOLEVEL |
3168 macho.MH_NO_REEXPORTED_DYLIBS;
3169 },
3170 }
3171
31323172 header.reserved = 0;
31333173
31343174 if (self.tlv_section_index) |_|