authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-16 16:32:27+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-05-18 09:28:00+02:00
log138cecc0283fdc3ec1b4343c15001e2802ed29de
tree135a487f95e754102c35d5a9f470d776870acc7e
parent35c694d614c8687ffa99ac187e60d831f9d7f29d

zld: add prelim way of linking dylibs

The support is minimalistic in the sense that we only support actual dylib files and not stubs/tbds yet, and we also don't support re-exports just yet.

6 files changed, 386 insertions(+), 54 deletions(-)

CMakeLists.txt+1
...@@ -568,6 +568,7 @@ set(ZIG_STAGE2_SOURCES...@@ -568,6 +568,7 @@ set(ZIG_STAGE2_SOURCES
568 "${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig"568 "${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig"
569 "${CMAKE_SOURCE_DIR}/src/link/MachO/CodeSignature.zig"569 "${CMAKE_SOURCE_DIR}/src/link/MachO/CodeSignature.zig"
570 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"570 "${CMAKE_SOURCE_DIR}/src/link/MachO/DebugSymbols.zig"
571 "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig"
571 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"572 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
572 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"573 "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig"
573 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"574 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
src/link/MachO.zig+117-14
...@@ -548,7 +548,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -548,7 +548,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
548 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;548 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
549 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;549 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
550 const target = self.base.options.target;550 const target = self.base.options.target;
551 const stack_size = self.base.options.stack_size_override orelse 16777216;551 const stack_size = self.base.options.stack_size_override orelse 0;
552 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;552 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
553553
554 const id_symlink_basename = "lld.id";554 const id_symlink_basename = "lld.id";
...@@ -675,22 +675,114 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -675,22 +675,114 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
675 zld.deinit();675 zld.deinit();
676 }676 }
677 zld.arch = target.cpu.arch;677 zld.arch = target.cpu.arch;
678 zld.stack_size = stack_size;
678679
679 var input_files = std.ArrayList([]const u8).init(self.base.allocator);680 // Positional arguments to the linker such as object files and static archives.
680 defer input_files.deinit();681 var positionals = std.ArrayList([]const u8).init(self.base.allocator);
681 // Positional arguments to the linker such as object files.682 defer positionals.deinit();
682 try input_files.appendSlice(self.base.options.objects);683
684 try positionals.appendSlice(self.base.options.objects);
683 for (comp.c_object_table.items()) |entry| {685 for (comp.c_object_table.items()) |entry| {
684 try input_files.append(entry.key.status.success.object_path);686 try positionals.append(entry.key.status.success.object_path);
685 }687 }
686 if (module_obj_path) |p| {688 if (module_obj_path) |p| {
687 try input_files.append(p);689 try positionals.append(p);
688 }690 }
689 try input_files.append(comp.compiler_rt_static_lib.?.full_object_path);691 try positionals.append(comp.compiler_rt_static_lib.?.full_object_path);
692
690 // libc++ dep693 // libc++ dep
691 if (self.base.options.link_libcpp) {694 if (self.base.options.link_libcpp) {
692 try input_files.append(comp.libcxxabi_static_lib.?.full_object_path);695 try positionals.append(comp.libcxxabi_static_lib.?.full_object_path);
693 try input_files.append(comp.libcxx_static_lib.?.full_object_path);696 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
697 }
698
699 if (self.base.options.is_native_os) {}
700
701 // Shared libraries.
702 var shared_libs = std.ArrayList([]const u8).init(self.base.allocator);
703 defer {
704 for (shared_libs.items) |sh| {
705 self.base.allocator.free(sh);
706 }
707 shared_libs.deinit();
708 }
709
710 var search_lib_names = std.ArrayList([]const u8).init(self.base.allocator);
711 defer search_lib_names.deinit();
712
713 const system_libs = self.base.options.system_libs.items();
714 for (system_libs) |entry| {
715 const link_lib = entry.key;
716 // By this time, we depend on these libs being dynamically linked libraries and not static libraries
717 // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which
718 // case we want to avoid prepending "-l".
719 if (Compilation.classifyFileExt(link_lib) == .shared_library) {
720 const path = try self.base.allocator.dupe(u8, link_lib);
721 try shared_libs.append(path);
722 continue;
723 }
724
725 try search_lib_names.append(link_lib);
726 }
727
728 for (search_lib_names.items) |l_name| {
729 // TODO text-based API, or .tbd files.
730 const l_name_ext = try std.fmt.allocPrint(self.base.allocator, "lib{s}.dylib", .{l_name});
731 defer self.base.allocator.free(l_name_ext);
732
733 var found = false;
734 if (self.base.options.syslibroot) |syslibroot| {
735 for (self.base.options.lib_dirs) |lib_dir| {
736 const path = try fs.path.join(self.base.allocator, &[_][]const u8{
737 syslibroot,
738 lib_dir,
739 l_name_ext,
740 });
741
742 const tmp = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
743 error.FileNotFound => {
744 self.base.allocator.free(path);
745 continue;
746 },
747 else => |e| return e,
748 };
749 defer tmp.close();
750
751 try shared_libs.append(path);
752 found = true;
753 break;
754 }
755 }
756
757 for (self.base.options.lib_dirs) |lib_dir| {
758 const path = try fs.path.join(self.base.allocator, &[_][]const u8{ lib_dir, l_name_ext });
759
760 const tmp = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
761 error.FileNotFound => {
762 self.base.allocator.free(path);
763 continue;
764 },
765 else => |e| return e,
766 };
767 defer tmp.close();
768
769 try shared_libs.append(path);
770 found = true;
771 break;
772 }
773
774 if (!found) {
775 log.warn("library '-l{s}' not found", .{l_name});
776 log.warn("searched paths:", .{});
777 if (self.base.options.syslibroot) |syslibroot| {
778 for (self.base.options.lib_dirs) |lib_dir| {
779 log.warn(" {s}/{s}", .{ syslibroot, lib_dir });
780 }
781 }
782 for (self.base.options.lib_dirs) |lib_dir| {
783 log.warn(" {s}/", .{lib_dir});
784 }
785 }
694 }786 }
695787
696 if (self.base.options.verbose_link) {788 if (self.base.options.verbose_link) {
...@@ -700,17 +792,28 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -700,17 +792,28 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
700 try argv.append("zig");792 try argv.append("zig");
701 try argv.append("ld");793 try argv.append("ld");
702794
703 try argv.appendSlice(input_files.items);795 if (self.base.options.syslibroot) |syslibroot| {
796 try argv.append("-syslibroot");
797 try argv.append(syslibroot);
798 }
799
800 try argv.appendSlice(positionals.items);
704801
705 try argv.append("-o");802 try argv.append("-o");
706 try argv.append(full_out_path);803 try argv.append(full_out_path);
707804
805 for (search_lib_names.items) |l_name| {
806 try argv.append(try std.fmt.allocPrint(self.base.allocator, "-l{s}", .{l_name}));
807 }
808
809 for (self.base.options.lib_dirs) |lib_dir| {
810 try argv.append(try std.fmt.allocPrint(self.base.allocator, "-L{s}", .{lib_dir}));
811 }
812
708 Compilation.dump_argv(argv.items);813 Compilation.dump_argv(argv.items);
709 }814 }
710815
711 try zld.link(input_files.items, full_out_path, .{816 try zld.link(positionals.items, shared_libs.items, full_out_path);
712 .stack_size = self.base.options.stack_size_override,
713 });
714817
715 break :outer;818 break :outer;
716 }819 }
src/link/MachO/Dylib.zig created+137
...@@ -0,0 +1,137 @@
1const Dylib = @This();
2
3const std = @import("std");
4const fs = std.fs;
5const log = std.log.scoped(.dylib);
6const macho = std.macho;
7const mem = std.mem;
8
9const Allocator = mem.Allocator;
10const Symbol = @import("Symbol.zig");
11
12usingnamespace @import("commands.zig");
13
14allocator: *Allocator,
15arch: ?std.Target.Cpu.Arch = null,
16header: ?macho.mach_header_64 = null,
17file: ?fs.File = null,
18name: ?[]const u8 = null,
19
20ordinal: ?u16 = null,
21
22load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
23
24symtab_cmd_index: ?u16 = null,
25dysymtab_cmd_index: ?u16 = null,
26
27symbols: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
28
29pub fn init(allocator: *Allocator) Dylib {
30 return .{ .allocator = allocator };
31}
32
33pub fn deinit(self: *Dylib) void {
34 for (self.load_commands.items) |*lc| {
35 lc.deinit(self.allocator);
36 }
37 self.load_commands.deinit(self.allocator);
38
39 for (self.symbols.items()) |entry| {
40 entry.value.deinit(self.allocator);
41 self.allocator.destroy(entry.value);
42 }
43 self.symbols.deinit(self.allocator);
44
45 if (self.name) |name| {
46 self.allocator.free(name);
47 }
48}
49
50pub fn closeFile(self: Dylib) void {
51 if (self.file) |file| {
52 file.close();
53 }
54}
55
56pub fn parse(self: *Dylib) !void {
57 log.warn("parsing shared library '{s}'", .{self.name.?});
58
59 var reader = self.file.?.reader();
60 self.header = try reader.readStruct(macho.mach_header_64);
61
62 if (self.header.?.filetype != macho.MH_DYLIB) {
63 log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
64 return error.MalformedDylib;
65 }
66
67 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
68 macho.CPU_TYPE_ARM64 => .aarch64,
69 macho.CPU_TYPE_X86_64 => .x86_64,
70 else => |value| {
71 log.err("unsupported cpu architecture 0x{x}", .{value});
72 return error.UnsupportedCpuArchitecture;
73 },
74 };
75 if (this_arch != self.arch.?) {
76 log.err("mismatched cpu architecture: expected {s}, found {s}", .{ self.arch.?, this_arch });
77 return error.MismatchedCpuArchitecture;
78 }
79
80 try self.readLoadCommands(reader);
81 try self.parseSymbols();
82}
83
84pub fn readLoadCommands(self: *Dylib, reader: anytype) !void {
85 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);
86
87 var i: u16 = 0;
88 while (i < self.header.?.ncmds) : (i += 1) {
89 var cmd = try LoadCommand.read(self.allocator, reader);
90 switch (cmd.cmd()) {
91 macho.LC_SYMTAB => {
92 self.symtab_cmd_index = i;
93 },
94 macho.LC_DYSYMTAB => {
95 self.dysymtab_cmd_index = i;
96 },
97 else => {
98 log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
99 },
100 }
101 self.load_commands.appendAssumeCapacity(cmd);
102 }
103}
104
105pub fn parseSymbols(self: *Dylib) !void {
106 const index = self.symtab_cmd_index orelse return;
107 const symtab_cmd = self.load_commands.items[index].Symtab;
108
109 var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
110 defer self.allocator.free(symtab);
111 _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff);
112 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));
113
114 var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize);
115 defer self.allocator.free(strtab);
116 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);
117
118 for (slice) |sym| {
119 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
120
121 if (!(Symbol.isSect(sym) and Symbol.isExt(sym))) continue;
122
123 const name = try self.allocator.dupe(u8, sym_name);
124 const proxy = try self.allocator.create(Symbol.Proxy);
125 errdefer self.allocator.destroy(proxy);
126
127 proxy.* = .{
128 .base = .{
129 .@"type" = .proxy,
130 .name = name,
131 },
132 .dylib = self,
133 };
134
135 try self.symbols.putNoClobber(self.allocator, name, &proxy.base);
136 }
137}
src/link/MachO/Symbol.zig+4-3
...@@ -5,6 +5,7 @@ const macho = std.macho;...@@ -5,6 +5,7 @@ const macho = std.macho;
5const mem = std.mem;5const mem = std.mem;
66
7const Allocator = mem.Allocator;7const Allocator = mem.Allocator;
8const Dylib = @import("Dylib.zig");
8const Object = @import("Object.zig");9const Object = @import("Object.zig");
910
10pub const Type = enum {11pub const Type = enum {
...@@ -43,7 +44,7 @@ pub const Regular = struct {...@@ -43,7 +44,7 @@ pub const Regular = struct {
43 /// Whether the symbol is a weak ref.44 /// Whether the symbol is a weak ref.
44 weak_ref: bool,45 weak_ref: bool,
4546
46 /// File where to locate this symbol.47 /// Object file where to locate this symbol.
47 file: *Object,48 file: *Object,
4849
49 /// Debug stab if defined.50 /// Debug stab if defined.
...@@ -78,8 +79,8 @@ pub const Regular = struct {...@@ -78,8 +79,8 @@ pub const Regular = struct {
78pub const Proxy = struct {79pub const Proxy = struct {
79 base: Symbol,80 base: Symbol,
8081
81 /// Dylib ordinal.82 /// Dylib where to locate this symbol.
82 dylib: u16,83 dylib: ?*Dylib = null,
8384
84 pub const base_type: Symbol.Type = .proxy;85 pub const base_type: Symbol.Type = .proxy;
85};86};
src/link/MachO/Zld.zig+106-32
...@@ -15,6 +15,7 @@ const reloc = @import("reloc.zig");...@@ -15,6 +15,7 @@ const reloc = @import("reloc.zig");
15const Allocator = mem.Allocator;15const Allocator = mem.Allocator;
16const Archive = @import("Archive.zig");16const Archive = @import("Archive.zig");
17const CodeSignature = @import("CodeSignature.zig");17const CodeSignature = @import("CodeSignature.zig");
18const Dylib = @import("Dylib.zig");
18const Object = @import("Object.zig");19const Object = @import("Object.zig");
19const Symbol = @import("Symbol.zig");20const Symbol = @import("Symbol.zig");
20const Trie = @import("Trie.zig");21const Trie = @import("Trie.zig");
...@@ -35,6 +36,7 @@ stack_size: u64 = 0,...@@ -35,6 +36,7 @@ stack_size: u64 = 0,
3536
36objects: std.ArrayListUnmanaged(*Object) = .{},37objects: std.ArrayListUnmanaged(*Object) = .{},
37archives: std.ArrayListUnmanaged(*Archive) = .{},38archives: std.ArrayListUnmanaged(*Archive) = .{},
39dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
3840
39load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},41load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
4042
...@@ -151,10 +153,18 @@ pub fn deinit(self: *Zld) void {...@@ -151,10 +153,18 @@ pub fn deinit(self: *Zld) void {
151 }153 }
152 self.archives.deinit(self.allocator);154 self.archives.deinit(self.allocator);
153155
156 for (self.dylibs.items) |dylib| {
157 dylib.deinit();
158 self.allocator.destroy(dylib);
159 }
160 self.dylibs.deinit(self.allocator);
161
154 self.mappings.deinit(self.allocator);162 self.mappings.deinit(self.allocator);
155 self.unhandled_sections.deinit(self.allocator);163 self.unhandled_sections.deinit(self.allocator);
156164
157 self.globals.deinit(self.allocator);165 self.globals.deinit(self.allocator);
166 self.imports.deinit(self.allocator);
167 self.unresolved.deinit(self.allocator);
158 self.strtab.deinit(self.allocator);168 self.strtab.deinit(self.allocator);
159169
160 {170 {
...@@ -176,11 +186,7 @@ pub fn closeFiles(self: Zld) void {...@@ -176,11 +186,7 @@ pub fn closeFiles(self: Zld) void {
176 if (self.file) |f| f.close();186 if (self.file) |f| f.close();
177}187}
178188
179const LinkArgs = struct {189pub fn link(self: *Zld, files: []const []const u8, shared_libs: []const []const u8, out_path: []const u8) !void {
180 stack_size: ?u64 = null,
181};
182
183pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void {
184 if (files.len == 0) return error.NoInputFiles;190 if (files.len == 0) return error.NoInputFiles;
185 if (out_path.len == 0) return error.EmptyOutputPath;191 if (out_path.len == 0) return error.EmptyOutputPath;
186192
...@@ -214,10 +220,10 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L...@@ -214,10 +220,10 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
214 .read = true,220 .read = true,
215 .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777,221 .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777,
216 });222 });
217 self.stack_size = args.stack_size orelse 0;
218223
219 try self.populateMetadata();224 try self.populateMetadata();
220 try self.parseInputFiles(files);225 try self.parseInputFiles(files);
226 try self.parseDylibs(shared_libs);
221 try self.resolveSymbols();227 try self.resolveSymbols();
222 try self.resolveStubsAndGotEntries();228 try self.resolveStubsAndGotEntries();
223 try self.updateMetadata();229 try self.updateMetadata();
...@@ -315,6 +321,48 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -315,6 +321,48 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
315 }321 }
316}322}
317323
324fn parseDylibs(self: *Zld, shared_libs: []const []const u8) !void {
325 for (shared_libs) |lib| {
326 const dylib = try self.allocator.create(Dylib);
327 errdefer self.allocator.destroy(dylib);
328
329 dylib.* = Dylib.init(self.allocator);
330 dylib.arch = self.arch.?;
331 dylib.name = try self.allocator.dupe(u8, lib);
332 dylib.file = try fs.cwd().openFile(lib, .{});
333
334 const ordinal = @intCast(u16, self.dylibs.items.len);
335 dylib.ordinal = ordinal + 2; // TODO +2 since 1 is reserved for libSystem
336
337 // TODO Defer parsing of the dylibs until they are actually needed
338 try dylib.parse();
339 try self.dylibs.append(self.allocator, dylib);
340
341 // Add LC_LOAD_DYLIB command
342 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
343 u64,
344 @sizeOf(macho.dylib_command) + dylib.name.?.len,
345 @sizeOf(u64),
346 ));
347 // TODO Read the min version from the dylib itself.
348 const min_version = 0x0;
349 var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{
350 .cmd = macho.LC_LOAD_DYLIB,
351 .cmdsize = cmdsize,
352 .dylib = .{
353 .name = @sizeOf(macho.dylib_command),
354 .timestamp = 2, // TODO parse from the dylib.
355 .current_version = min_version,
356 .compatibility_version = min_version,
357 },
358 });
359 dylib_cmd.data = try self.allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
360 mem.set(u8, dylib_cmd.data, 0);
361 mem.copy(u8, dylib_cmd.data, dylib.name.?);
362 try self.load_commands.append(self.allocator, .{ .Dylib = dylib_cmd });
363 }
364}
365
318fn mapAndUpdateSections(366fn mapAndUpdateSections(
319 self: *Zld,367 self: *Zld,
320 object_id: u16,368 object_id: u16,
...@@ -1398,35 +1446,51 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1398,35 +1446,51 @@ fn resolveSymbols(self: *Zld) !void {
1398 // Third pass, resolve symbols in dynamic libraries.1446 // Third pass, resolve symbols in dynamic libraries.
1399 // TODO Implement libSystem as a hard-coded library, or ship with1447 // TODO Implement libSystem as a hard-coded library, or ship with
1400 // a libSystem.B.tbd definition file?1448 // a libSystem.B.tbd definition file?
1401 try self.imports.ensureCapacity(self.allocator, self.unresolved.count());1449 var unresolved = std.ArrayList(*Symbol).init(self.allocator);
1402 for (self.unresolved.items()) |entry| {1450 defer unresolved.deinit();
1403 const proxy = try self.allocator.create(Symbol.Proxy);
1404 errdefer self.allocator.destroy(proxy);
14051451
1406 proxy.* = .{1452 try unresolved.ensureCapacity(self.unresolved.count());
1407 .base = .{1453 for (self.unresolved.items()) |entry| {
1408 .@"type" = .proxy,1454 unresolved.appendAssumeCapacity(entry.value);
1409 .name = try self.allocator.dupe(u8, entry.key),
1410 },
1411 .dylib = 0,
1412 };
1413
1414 self.imports.putAssumeCapacityNoClobber(proxy.base.name, &proxy.base);
1415 entry.value.alias = &proxy.base;
1416 }1455 }
1417 self.unresolved.clearAndFree(self.allocator);1456 self.unresolved.clearAndFree(self.allocator);
14181457
1419 // If there are any undefs left, flag an error.1458 var has_undefined = false;
1420 if (self.unresolved.count() > 0) {1459 while (unresolved.popOrNull()) |undef| {
1421 for (self.unresolved.items()) |entry| {1460 var found = false;
1422 log.err("undefined reference to symbol '{s}'", .{entry.key});1461 for (self.dylibs.items) |dylib| {
1423 log.err(" | referenced in {s}", .{1462 const proxy = dylib.symbols.get(undef.name) orelse continue;
1424 entry.value.cast(Symbol.Unresolved).?.file.name.?,1463 try self.imports.putNoClobber(self.allocator, proxy.name, proxy);
1425 });1464 undef.alias = proxy;
1465 found = true;
1466 }
1467
1468 if (!found) {
1469 // TODO we currently hardcode all unresolved symbols to libSystem
1470 const proxy = try self.allocator.create(Symbol.Proxy);
1471 errdefer self.allocator.destroy(proxy);
1472
1473 proxy.* = .{
1474 .base = .{
1475 .@"type" = .proxy,
1476 .name = try self.allocator.dupe(u8, undef.name),
1477 },
1478 .dylib = null, // TODO null means libSystem
1479 };
1480
1481 try self.imports.putNoClobber(self.allocator, proxy.base.name, &proxy.base);
1482 undef.alias = &proxy.base;
1483
1484 // log.err("undefined reference to symbol '{s}'", .{undef.name});
1485 // log.err(" | referenced in {s}", .{
1486 // undef.cast(Symbol.Unresolved).?.file.name.?,
1487 // });
1488 // has_undefined = true;
1426 }1489 }
1427 return error.UndefinedSymbolReference;
1428 }1490 }
14291491
1492 if (has_undefined) return error.UndefinedSymbolReference;
1493
1430 // Finally put dyld_stub_binder as an Import1494 // Finally put dyld_stub_binder as an Import
1431 const dyld_stub_binder = try self.allocator.create(Symbol.Proxy);1495 const dyld_stub_binder = try self.allocator.create(Symbol.Proxy);
1432 errdefer self.allocator.destroy(dyld_stub_binder);1496 errdefer self.allocator.destroy(dyld_stub_binder);
...@@ -1436,7 +1500,7 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1436,7 +1500,7 @@ fn resolveSymbols(self: *Zld) !void {
1436 .@"type" = .proxy,1500 .@"type" = .proxy,
1437 .name = try self.allocator.dupe(u8, "dyld_stub_binder"),1501 .name = try self.allocator.dupe(u8, "dyld_stub_binder"),
1438 },1502 },
1439 .dylib = 0,1503 .dylib = null, // TODO null means libSystem
1440 };1504 };
14411505
1442 try self.imports.putNoClobber(1506 try self.imports.putNoClobber(
...@@ -2303,7 +2367,10 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2303,7 +2367,10 @@ fn writeBindInfoTable(self: *Zld) !void {
23032367
2304 for (self.got_entries.items) |sym| {2368 for (self.got_entries.items) |sym| {
2305 if (sym.cast(Symbol.Proxy)) |proxy| {2369 if (sym.cast(Symbol.Proxy)) |proxy| {
2306 const dylib_ordinal = proxy.dylib + 1;2370 const dylib_ordinal = ordinal: {
2371 const dylib = proxy.dylib orelse break :ordinal 1; // TODO embedded libSystem
2372 break :ordinal dylib.ordinal.?;
2373 };
2307 try pointers.append(.{2374 try pointers.append(.{
2308 .offset = base_offset + proxy.base.got_index.? * @sizeOf(u64),2375 .offset = base_offset + proxy.base.got_index.? * @sizeOf(u64),
2309 .segment_id = segment_id,2376 .segment_id = segment_id,
...@@ -2322,7 +2389,10 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2322,7 +2389,10 @@ fn writeBindInfoTable(self: *Zld) !void {
23222389
2323 const sym = self.imports.get("__tlv_bootstrap") orelse unreachable;2390 const sym = self.imports.get("__tlv_bootstrap") orelse unreachable;
2324 const proxy = sym.cast(Symbol.Proxy) orelse unreachable;2391 const proxy = sym.cast(Symbol.Proxy) orelse unreachable;
2325 const dylib_ordinal = proxy.dylib + 1;2392 const dylib_ordinal = ordinal: {
2393 const dylib = proxy.dylib orelse break :ordinal 1; // TODO embedded libSystem
2394 break :ordinal dylib.ordinal.?;
2395 };
23262396
2327 try pointers.append(.{2397 try pointers.append(.{
2328 .offset = base_offset,2398 .offset = base_offset,
...@@ -2364,7 +2434,11 @@ fn writeLazyBindInfoTable(self: *Zld) !void {...@@ -2364,7 +2434,11 @@ fn writeLazyBindInfoTable(self: *Zld) !void {
23642434
2365 for (self.stubs.items) |sym| {2435 for (self.stubs.items) |sym| {
2366 const proxy = sym.cast(Symbol.Proxy) orelse unreachable;2436 const proxy = sym.cast(Symbol.Proxy) orelse unreachable;
2367 const dylib_ordinal = proxy.dylib + 1;2437 const dylib_ordinal = ordinal: {
2438 const dylib = proxy.dylib orelse break :ordinal 1; // TODO embedded libSystem
2439 break :ordinal dylib.ordinal.?;
2440 };
2441
2368 pointers.appendAssumeCapacity(.{2442 pointers.appendAssumeCapacity(.{
2369 .offset = base_offset + sym.stubs_index.? * @sizeOf(u64),2443 .offset = base_offset + sym.stubs_index.? * @sizeOf(u64),
2370 .segment_id = segment_id,2444 .segment_id = segment_id,
src/link/MachO/commands.zig+21-5
...@@ -38,7 +38,9 @@ pub const LoadCommand = union(enum) {...@@ -38,7 +38,9 @@ pub const LoadCommand = union(enum) {
38 macho.LC_SEGMENT_64 => LoadCommand{38 macho.LC_SEGMENT_64 => LoadCommand{
39 .Segment = try SegmentCommand.read(allocator, stream.reader()),39 .Segment = try SegmentCommand.read(allocator, stream.reader()),
40 },40 },
41 macho.LC_DYLD_INFO, macho.LC_DYLD_INFO_ONLY => LoadCommand{41 macho.LC_DYLD_INFO,
42 macho.LC_DYLD_INFO_ONLY,
43 => LoadCommand{
42 .DyldInfoOnly = try stream.reader().readStruct(macho.dyld_info_command),44 .DyldInfoOnly = try stream.reader().readStruct(macho.dyld_info_command),
43 },45 },
44 macho.LC_SYMTAB => LoadCommand{46 macho.LC_SYMTAB => LoadCommand{
...@@ -47,16 +49,27 @@ pub const LoadCommand = union(enum) {...@@ -47,16 +49,27 @@ pub const LoadCommand = union(enum) {
47 macho.LC_DYSYMTAB => LoadCommand{49 macho.LC_DYSYMTAB => LoadCommand{
48 .Dysymtab = try stream.reader().readStruct(macho.dysymtab_command),50 .Dysymtab = try stream.reader().readStruct(macho.dysymtab_command),
49 },51 },
50 macho.LC_ID_DYLINKER, macho.LC_LOAD_DYLINKER, macho.LC_DYLD_ENVIRONMENT => LoadCommand{52 macho.LC_ID_DYLINKER,
53 macho.LC_LOAD_DYLINKER,
54 macho.LC_DYLD_ENVIRONMENT,
55 => LoadCommand{
51 .Dylinker = try GenericCommandWithData(macho.dylinker_command).read(allocator, stream.reader()),56 .Dylinker = try GenericCommandWithData(macho.dylinker_command).read(allocator, stream.reader()),
52 },57 },
53 macho.LC_ID_DYLIB, macho.LC_LOAD_WEAK_DYLIB, macho.LC_LOAD_DYLIB, macho.LC_REEXPORT_DYLIB => LoadCommand{58 macho.LC_ID_DYLIB,
59 macho.LC_LOAD_WEAK_DYLIB,
60 macho.LC_LOAD_DYLIB,
61 macho.LC_REEXPORT_DYLIB,
62 => LoadCommand{
54 .Dylib = try GenericCommandWithData(macho.dylib_command).read(allocator, stream.reader()),63 .Dylib = try GenericCommandWithData(macho.dylib_command).read(allocator, stream.reader()),
55 },64 },
56 macho.LC_MAIN => LoadCommand{65 macho.LC_MAIN => LoadCommand{
57 .Main = try stream.reader().readStruct(macho.entry_point_command),66 .Main = try stream.reader().readStruct(macho.entry_point_command),
58 },67 },
59 macho.LC_VERSION_MIN_MACOSX, macho.LC_VERSION_MIN_IPHONEOS, macho.LC_VERSION_MIN_WATCHOS, macho.LC_VERSION_MIN_TVOS => LoadCommand{68 macho.LC_VERSION_MIN_MACOSX,
69 macho.LC_VERSION_MIN_IPHONEOS,
70 macho.LC_VERSION_MIN_WATCHOS,
71 macho.LC_VERSION_MIN_TVOS,
72 => LoadCommand{
60 .VersionMin = try stream.reader().readStruct(macho.version_min_command),73 .VersionMin = try stream.reader().readStruct(macho.version_min_command),
61 },74 },
62 macho.LC_SOURCE_VERSION => LoadCommand{75 macho.LC_SOURCE_VERSION => LoadCommand{
...@@ -65,7 +78,10 @@ pub const LoadCommand = union(enum) {...@@ -65,7 +78,10 @@ pub const LoadCommand = union(enum) {
65 macho.LC_UUID => LoadCommand{78 macho.LC_UUID => LoadCommand{
66 .Uuid = try stream.reader().readStruct(macho.uuid_command),79 .Uuid = try stream.reader().readStruct(macho.uuid_command),
67 },80 },
68 macho.LC_FUNCTION_STARTS, macho.LC_DATA_IN_CODE, macho.LC_CODE_SIGNATURE => LoadCommand{81 macho.LC_FUNCTION_STARTS,
82 macho.LC_DATA_IN_CODE,
83 macho.LC_CODE_SIGNATURE,
84 => LoadCommand{
69 .LinkeditData = try stream.reader().readStruct(macho.linkedit_data_command),85 .LinkeditData = try stream.reader().readStruct(macho.linkedit_data_command),
70 },86 },
71 else => LoadCommand{87 else => LoadCommand{