| author | |
| committer | |
| log | 5ac5cd9de7c5387e37baa4f287d609c5d2f34564 |
| tree | 65d97ee06e85f411493dbef7a5b1688e627f70c6 |
| parent | 3cb6b6bd90c3b304bf771b37e974dd943c060e2b |
6 files changed, 263 insertions(+), 234 deletions(-)
src/link/MachO.zig+1| ... | ... | @@ -789,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 789 | 789 | zld.deinit(); |
| 790 | 790 | } |
| 791 | 791 | zld.arch = target.cpu.arch; |
| 792 | zld.syslibroot = self.base.options.syslibroot; | |
| 792 | 793 | zld.stack_size = stack_size; |
| 793 | 794 | |
| 794 | 795 | // Positional arguments to the linker such as object files and static archives. |
src/link/MachO/Archive.zig+41-22| ... | ... | @@ -8,12 +8,13 @@ const macho = std.macho; |
| 8 | 8 | const mem = std.mem; |
| 9 | 9 | |
| 10 | 10 | const Allocator = mem.Allocator; |
| 11 | const Arch = std.Target.Cpu.Arch; | |
| 11 | 12 | const Object = @import("Object.zig"); |
| 12 | 13 | |
| 13 | 14 | usingnamespace @import("commands.zig"); |
| 14 | 15 | |
| 15 | 16 | allocator: *Allocator, |
| 16 | arch: ?std.Target.Cpu.Arch = null, | |
| 17 | arch: ?Arch = null, | |
| 17 | 18 | file: ?fs.File = null, |
| 18 | 19 | header: ?ar_hdr = null, |
| 19 | 20 | name: ?[]const u8 = null, |
| ... | ... | @@ -85,10 +86,36 @@ const ar_hdr = extern struct { |
| 85 | 86 | } |
| 86 | 87 | }; |
| 87 | 88 | |
| 88 | pub fn init(allocator: *Allocator) Archive { | |
| 89 | return .{ | |
| 89 | pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Archive { | |
| 90 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | |
| 91 | error.FileNotFound => return null, | |
| 92 | else => |e| return e, | |
| 93 | }; | |
| 94 | errdefer file.close(); | |
| 95 | ||
| 96 | const archive = try allocator.create(Archive); | |
| 97 | errdefer allocator.destroy(archive); | |
| 98 | ||
| 99 | const name = try allocator.dupe(u8, path); | |
| 100 | errdefer allocator.free(name); | |
| 101 | ||
| 102 | archive.* = .{ | |
| 90 | 103 | .allocator = allocator, |
| 104 | .arch = arch, | |
| 105 | .name = name, | |
| 106 | .file = file, | |
| 107 | }; | |
| 108 | ||
| 109 | archive.parse() catch |err| switch (err) { | |
| 110 | error.EndOfStream, error.NotArchive => { | |
| 111 | archive.deinit(); | |
| 112 | allocator.destroy(archive); | |
| 113 | return null; | |
| 114 | }, | |
| 115 | else => |e| return e, | |
| 91 | 116 | }; |
| 117 | ||
| 118 | return archive; | |
| 92 | 119 | } |
| 93 | 120 | |
| 94 | 121 | pub fn deinit(self: *Archive) void { |
| ... | ... | @@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void { |
| 116 | 143 | const magic = try reader.readBytesNoEof(SARMAG); |
| 117 | 144 | |
| 118 | 145 | if (!mem.eql(u8, &magic, ARMAG)) { |
| 119 | log.err("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic }); | |
| 120 | return error.MalformedArchive; | |
| 146 | log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic }); | |
| 147 | return error.NotArchive; | |
| 121 | 148 | } |
| 122 | 149 | |
| 123 | 150 | self.header = try reader.readStruct(ar_hdr); |
| 124 | 151 | |
| 125 | 152 | if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) { |
| 126 | log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag }); | |
| 127 | return error.MalformedArchive; | |
| 153 | log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag }); | |
| 154 | return error.NotArchive; | |
| 128 | 155 | } |
| 129 | 156 | |
| 130 | 157 | var embedded_name = try parseName(self.allocator, self.header.?, reader); |
| ... | ... | @@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object { |
| 222 | 249 | var object = try self.allocator.create(Object); |
| 223 | 250 | errdefer self.allocator.destroy(object); |
| 224 | 251 | |
| 225 | object.* = Object.init(self.allocator); | |
| 226 | object.arch = self.arch.?; | |
| 227 | object.file = try fs.cwd().openFile(self.name.?, .{}); | |
| 228 | object.name = name; | |
| 229 | object.file_offset = @intCast(u32, try reader.context.getPos()); | |
| 252 | object.* = .{ | |
| 253 | .allocator = self.allocator, | |
| 254 | .arch = self.arch.?, | |
| 255 | .file = try fs.cwd().openFile(self.name.?, .{}), | |
| 256 | .name = name, | |
| 257 | .file_offset = @intCast(u32, try reader.context.getPos()), | |
| 258 | }; | |
| 230 | 259 | try object.parse(); |
| 231 | ||
| 232 | 260 | try reader.context.seekTo(0); |
| 233 | 261 | |
| 234 | 262 | return object; |
| 235 | 263 | } |
| 236 | ||
| 237 | pub fn isArchive(file: fs.File) !bool { | |
| 238 | const magic = file.reader().readBytesNoEof(Archive.SARMAG) catch |err| switch (err) { | |
| 239 | error.EndOfStream => return false, | |
| 240 | else => |e| return e, | |
| 241 | }; | |
| 242 | try file.seekTo(0); | |
| 243 | return mem.eql(u8, &magic, Archive.ARMAG); | |
| 244 | } |
src/link/MachO/Dylib.zig+129-19| ... | ... | @@ -8,6 +8,7 @@ const macho = std.macho; |
| 8 | 8 | const mem = std.mem; |
| 9 | 9 | |
| 10 | 10 | const Allocator = mem.Allocator; |
| 11 | const Arch = std.Target.Cpu.Arch; | |
| 11 | 12 | const Symbol = @import("Symbol.zig"); |
| 12 | 13 | const LibStub = @import("../tapi.zig").LibStub; |
| 13 | 14 | |
| ... | ... | @@ -15,10 +16,11 @@ usingnamespace @import("commands.zig"); |
| 15 | 16 | |
| 16 | 17 | allocator: *Allocator, |
| 17 | 18 | |
| 18 | arch: ?std.Target.Cpu.Arch = null, | |
| 19 | arch: ?Arch = null, | |
| 19 | 20 | header: ?macho.mach_header_64 = null, |
| 20 | 21 | file: ?fs.File = null, |
| 21 | 22 | name: ?[]const u8 = null, |
| 23 | syslibroot: ?[]const u8 = null, | |
| 22 | 24 | |
| 23 | 25 | ordinal: ?u16 = null, |
| 24 | 26 | |
| ... | ... | @@ -35,6 +37,11 @@ id: ?Id = null, |
| 35 | 37 | /// a symbol is referenced by an object file. |
| 36 | 38 | symbols: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 37 | 39 | |
| 40 | // TODO we should keep track of already parsed dylibs so that | |
| 41 | // we don't unnecessarily reparse them again. | |
| 42 | // TODO add dylib dep analysis and extraction for .dylib files. | |
| 43 | dylibs: std.ArrayListUnmanaged(*Dylib) = .{}, | |
| 44 | ||
| 38 | 45 | pub const Id = struct { |
| 39 | 46 | name: []const u8, |
| 40 | 47 | timestamp: u32, |
| ... | ... | @@ -46,8 +53,57 @@ pub const Id = struct { |
| 46 | 53 | } |
| 47 | 54 | }; |
| 48 | 55 | |
| 49 | pub fn init(allocator: *Allocator) Dylib { | |
| 50 | return .{ .allocator = allocator }; | |
| 56 | pub const Error = error{ | |
| 57 | OutOfMemory, | |
| 58 | EmptyStubFile, | |
| 59 | MismatchedCpuArchitecture, | |
| 60 | UnsupportedCpuArchitecture, | |
| 61 | } || fs.File.OpenError || std.os.PReadError; | |
| 62 | ||
| 63 | pub fn createAndParseFromPath( | |
| 64 | allocator: *Allocator, | |
| 65 | arch: Arch, | |
| 66 | path: []const u8, | |
| 67 | syslibroot: ?[]const u8, | |
| 68 | recurse_libs: bool, | |
| 69 | ) Error!?*Dylib { | |
| 70 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | |
| 71 | error.FileNotFound => return null, | |
| 72 | else => |e| return e, | |
| 73 | }; | |
| 74 | errdefer file.close(); | |
| 75 | ||
| 76 | const dylib = try allocator.create(Dylib); | |
| 77 | errdefer allocator.destroy(dylib); | |
| 78 | ||
| 79 | const name = try allocator.dupe(u8, path); | |
| 80 | errdefer allocator.free(name); | |
| 81 | ||
| 82 | dylib.* = .{ | |
| 83 | .allocator = allocator, | |
| 84 | .arch = arch, | |
| 85 | .name = name, | |
| 86 | .file = file, | |
| 87 | .syslibroot = syslibroot, | |
| 88 | }; | |
| 89 | ||
| 90 | dylib.parse(recurse_libs) catch |err| switch (err) { | |
| 91 | error.EndOfStream, error.NotDylib => { | |
| 92 | try file.seekTo(0); | |
| 93 | ||
| 94 | var lib_stub = LibStub.loadFromFile(allocator, file) catch { | |
| 95 | dylib.deinit(); | |
| 96 | allocator.destroy(dylib); | |
| 97 | return null; | |
| 98 | }; | |
| 99 | defer lib_stub.deinit(); | |
| 100 | ||
| 101 | try dylib.parseFromStub(lib_stub, recurse_libs); | |
| 102 | }, | |
| 103 | else => |e| return e, | |
| 104 | }; | |
| 105 | ||
| 106 | return dylib; | |
| 51 | 107 | } |
| 52 | 108 | |
| 53 | 109 | pub fn deinit(self: *Dylib) void { |
| ... | ... | @@ -60,6 +116,7 @@ pub fn deinit(self: *Dylib) void { |
| 60 | 116 | self.allocator.free(key); |
| 61 | 117 | } |
| 62 | 118 | self.symbols.deinit(self.allocator); |
| 119 | self.dylibs.deinit(self.allocator); | |
| 63 | 120 | |
| 64 | 121 | if (self.name) |name| { |
| 65 | 122 | self.allocator.free(name); |
| ... | ... | @@ -76,15 +133,15 @@ pub fn closeFile(self: Dylib) void { |
| 76 | 133 | } |
| 77 | 134 | } |
| 78 | 135 | |
| 79 | pub fn parse(self: *Dylib) !void { | |
| 136 | pub fn parse(self: *Dylib, recurse_libs: bool) !void { | |
| 80 | 137 | log.debug("parsing shared library '{s}'", .{self.name.?}); |
| 81 | 138 | |
| 82 | 139 | var reader = self.file.?.reader(); |
| 83 | 140 | self.header = try reader.readStruct(macho.mach_header_64); |
| 84 | 141 | |
| 85 | 142 | if (self.header.?.filetype != macho.MH_DYLIB) { |
| 86 | log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype }); | |
| 87 | return error.MalformedDylib; | |
| 143 | log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype }); | |
| 144 | return error.NotDylib; | |
| 88 | 145 | } |
| 89 | 146 | |
| 90 | 147 | const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) { |
| ... | ... | @@ -190,7 +247,7 @@ fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void { |
| 190 | 247 | } |
| 191 | 248 | } |
| 192 | 249 | |
| 193 | pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { | |
| 250 | pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void { | |
| 194 | 251 | if (lib_stub.inner.len == 0) return error.EmptyStubFile; |
| 195 | 252 | |
| 196 | 253 | log.debug("parsing shared library from stub '{s}'", .{self.name.?}); |
| ... | ... | @@ -236,9 +293,17 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { |
| 236 | 293 | for (reexports) |reexp| { |
| 237 | 294 | if (!hasTarget(reexp.targets, target_string)) continue; |
| 238 | 295 | |
| 239 | for (reexp.symbols) |sym_name| { | |
| 240 | if (self.symbols.contains(sym_name)) continue; | |
| 241 | try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {}); | |
| 296 | if (reexp.symbols) |symbols| { | |
| 297 | for (symbols) |sym_name| { | |
| 298 | if (self.symbols.contains(sym_name)) continue; | |
| 299 | try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {}); | |
| 300 | } | |
| 301 | } | |
| 302 | ||
| 303 | if (reexp.objc_classes) |classes| { | |
| 304 | for (classes) |sym_name| { | |
| 305 | try self.addObjCClassSymbols(sym_name); | |
| 306 | } | |
| 242 | 307 | } |
| 243 | 308 | } |
| 244 | 309 | } |
| ... | ... | @@ -249,6 +314,60 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void { |
| 249 | 314 | } |
| 250 | 315 | } |
| 251 | 316 | } |
| 317 | ||
| 318 | for (lib_stub.inner) |stub| { | |
| 319 | if (!hasTarget(stub.targets, target_string)) continue; | |
| 320 | ||
| 321 | if (stub.reexported_libraries) |reexports| reexports: { | |
| 322 | if (!recurse_libs) break :reexports; | |
| 323 | ||
| 324 | for (reexports) |reexp| { | |
| 325 | if (!hasTarget(reexp.targets, target_string)) continue; | |
| 326 | ||
| 327 | outer: for (reexp.libraries) |lib| { | |
| 328 | const dirname = fs.path.dirname(lib) orelse { | |
| 329 | log.warn("unable to resolve dependency {s}", .{lib}); | |
| 330 | continue; | |
| 331 | }; | |
| 332 | const filename = fs.path.basename(lib); | |
| 333 | const without_ext = if (mem.lastIndexOfScalar(u8, filename, '.')) |index| | |
| 334 | filename[0..index] | |
| 335 | else | |
| 336 | filename; | |
| 337 | ||
| 338 | for (&[_][]const u8{ "dylib", "tbd" }) |ext| { | |
| 339 | const with_ext = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ | |
| 340 | without_ext, | |
| 341 | ext, | |
| 342 | }); | |
| 343 | defer self.allocator.free(with_ext); | |
| 344 | ||
| 345 | const lib_path = if (self.syslibroot) |syslibroot| | |
| 346 | try fs.path.join(self.allocator, &.{ syslibroot, dirname, with_ext }) | |
| 347 | else | |
| 348 | try fs.path.join(self.allocator, &.{ dirname, with_ext }); | |
| 349 | ||
| 350 | log.debug("trying dependency at fully resolved path {s}", .{lib_path}); | |
| 351 | ||
| 352 | const dylib = (try createAndParseFromPath( | |
| 353 | self.allocator, | |
| 354 | self.arch.?, | |
| 355 | lib_path, | |
| 356 | self.syslibroot, | |
| 357 | true, | |
| 358 | )) orelse { | |
| 359 | continue; | |
| 360 | }; | |
| 361 | ||
| 362 | try self.dylibs.append(self.allocator, dylib); | |
| 363 | continue :outer; | |
| 364 | } else { | |
| 365 | log.warn("unable to resolve dependency {s}", .{lib}); | |
| 366 | } | |
| 367 | } | |
| 368 | } | |
| 369 | } | |
| 370 | } | |
| 252 | 371 | } |
| 253 | 372 | |
| 254 | 373 | fn hasTarget(targets: []const []const u8, target: []const u8) bool { |
| ... | ... | @@ -258,15 +377,6 @@ fn hasTarget(targets: []const []const u8, target: []const u8) bool { |
| 258 | 377 | return false; |
| 259 | 378 | } |
| 260 | 379 | |
| 261 | pub fn isDylib(file: fs.File) !bool { | |
| 262 | const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) { | |
| 263 | error.EndOfStream => return false, | |
| 264 | else => |e| return e, | |
| 265 | }; | |
| 266 | try file.seekTo(0); | |
| 267 | return header.filetype == macho.MH_DYLIB; | |
| 268 | } | |
| 269 | ||
| 270 | 380 | pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol { |
| 271 | 381 | if (!self.symbols.contains(sym_name)) return null; |
| 272 | 382 |
src/link/MachO/Object.zig+37-15| ... | ... | @@ -11,6 +11,7 @@ const mem = std.mem; |
| 11 | 11 | const reloc = @import("reloc.zig"); |
| 12 | 12 | |
| 13 | 13 | const Allocator = mem.Allocator; |
| 14 | const Arch = std.Target.Cpu.Arch; | |
| 14 | 15 | const Relocation = reloc.Relocation; |
| 15 | 16 | const Symbol = @import("Symbol.zig"); |
| 16 | 17 | const parseName = @import("Zld.zig").parseName; |
| ... | ... | @@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName; |
| 18 | 19 | usingnamespace @import("commands.zig"); |
| 19 | 20 | |
| 20 | 21 | allocator: *Allocator, |
| 21 | arch: ?std.Target.Cpu.Arch = null, | |
| 22 | arch: ?Arch = null, | |
| 22 | 23 | header: ?macho.mach_header_64 = null, |
| 23 | 24 | file: ?fs.File = null, |
| 24 | 25 | file_offset: ?u32 = null, |
| ... | ... | @@ -173,10 +174,36 @@ const DebugInfo = struct { |
| 173 | 174 | } |
| 174 | 175 | }; |
| 175 | 176 | |
| 176 | pub fn init(allocator: *Allocator) Object { | |
| 177 | return .{ | |
| 177 | pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object { | |
| 178 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { | |
| 179 | error.FileNotFound => return null, | |
| 180 | else => |e| return e, | |
| 181 | }; | |
| 182 | errdefer file.close(); | |
| 183 | ||
| 184 | const object = try allocator.create(Object); | |
| 185 | errdefer allocator.destroy(object); | |
| 186 | ||
| 187 | const name = try allocator.dupe(u8, path); | |
| 188 | errdefer allocator.free(name); | |
| 189 | ||
| 190 | object.* = .{ | |
| 178 | 191 | .allocator = allocator, |
| 192 | .arch = arch, | |
| 193 | .name = name, | |
| 194 | .file = file, | |
| 179 | 195 | }; |
| 196 | ||
| 197 | object.parse() catch |err| switch (err) { | |
| 198 | error.EndOfStream, error.NotObject => { | |
| 199 | object.deinit(); | |
| 200 | allocator.destroy(object); | |
| 201 | return null; | |
| 202 | }, | |
| 203 | else => |e| return e, | |
| 204 | }; | |
| 205 | ||
| 206 | return object; | |
| 180 | 207 | } |
| 181 | 208 | |
| 182 | 209 | pub fn deinit(self: *Object) void { |
| ... | ... | @@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void { |
| 223 | 250 | self.header = try reader.readStruct(macho.mach_header_64); |
| 224 | 251 | |
| 225 | 252 | if (self.header.?.filetype != macho.MH_OBJECT) { |
| 226 | log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_OBJECT, self.header.?.filetype }); | |
| 227 | return error.MalformedObject; | |
| 253 | log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ | |
| 254 | macho.MH_OBJECT, | |
| 255 | self.header.?.filetype, | |
| 256 | }); | |
| 257 | ||
| 258 | return error.NotObject; | |
| 228 | 259 | } |
| 229 | 260 | |
| 230 | const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) { | |
| 261 | const this_arch: Arch = switch (self.header.?.cputype) { | |
| 231 | 262 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 232 | 263 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 233 | 264 | else => |value| { |
| ... | ... | @@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void { |
| 533 | 564 | try self.data_in_code_entries.append(self.allocator, dice); |
| 534 | 565 | } |
| 535 | 566 | } |
| 536 | ||
| 537 | pub fn isObject(file: fs.File) !bool { | |
| 538 | const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) { | |
| 539 | error.EndOfStream => return false, | |
| 540 | else => |e| return e, | |
| 541 | }; | |
| 542 | try file.seekTo(0); | |
| 543 | return header.filetype == macho.MH_OBJECT; | |
| 544 | } |
src/link/MachO/Zld.zig+53-177| ... | ... | @@ -16,7 +16,6 @@ const Allocator = mem.Allocator; |
| 16 | 16 | const Archive = @import("Archive.zig"); |
| 17 | 17 | const CodeSignature = @import("CodeSignature.zig"); |
| 18 | 18 | const Dylib = @import("Dylib.zig"); |
| 19 | const LibStub = @import("../tapi.zig").LibStub; | |
| 20 | 19 | const Object = @import("Object.zig"); |
| 21 | 20 | const Symbol = @import("Symbol.zig"); |
| 22 | 21 | const Trie = @import("Trie.zig"); |
| ... | ... | @@ -33,6 +32,7 @@ out_path: ?[]const u8 = null, |
| 33 | 32 | |
| 34 | 33 | // TODO these args will become obselete once Zld is coalesced with incremental |
| 35 | 34 | // linker. |
| 35 | syslibroot: ?[]const u8 = null, | |
| 36 | 36 | stack_size: u64 = 0, |
| 37 | 37 | |
| 38 | 38 | objects: std.ArrayListUnmanaged(*Object) = .{}, |
| ... | ... | @@ -257,214 +257,90 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L |
| 257 | 257 | } |
| 258 | 258 | |
| 259 | 259 | fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 260 | const Input = struct { | |
| 261 | kind: union(enum) { | |
| 262 | object: fs.File, | |
| 263 | archive: fs.File, | |
| 264 | dylib: fs.File, | |
| 265 | stub: LibStub, | |
| 266 | }, | |
| 267 | name: []const u8, | |
| 268 | ||
| 269 | fn deinit(input: *@This()) void { | |
| 270 | switch (input.kind) { | |
| 271 | .stub => |*stub| { | |
| 272 | stub.deinit(); | |
| 273 | }, | |
| 274 | else => {}, | |
| 275 | } | |
| 276 | } | |
| 277 | }; | |
| 278 | var classified = std.ArrayList(Input).init(self.allocator); | |
| 279 | defer { | |
| 280 | for (classified.items) |*input| { | |
| 281 | input.deinit(); | |
| 282 | } | |
| 283 | classified.deinit(); | |
| 284 | } | |
| 285 | ||
| 286 | // First, classify input files: object, archive, dylib or stub (tbd). | |
| 287 | 260 | for (files) |file_name| { |
| 288 | const file = try fs.cwd().openFile(file_name, .{}); | |
| 289 | 261 | const full_path = full_path: { |
| 290 | 262 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 291 | 263 | const path = try std.fs.realpath(file_name, &buffer); |
| 292 | 264 | break :full_path try self.allocator.dupe(u8, path); |
| 293 | 265 | }; |
| 294 | 266 | |
| 295 | try_object: { | |
| 296 | if (!(try Object.isObject(file))) break :try_object; | |
| 297 | try classified.append(.{ | |
| 298 | .kind = .{ .object = file }, | |
| 299 | .name = full_path, | |
| 300 | }); | |
| 301 | continue; | |
| 302 | } | |
| 303 | ||
| 304 | try_archive: { | |
| 305 | if (!(try Archive.isArchive(file))) break :try_archive; | |
| 306 | try classified.append(.{ | |
| 307 | .kind = .{ .archive = file }, | |
| 308 | .name = full_path, | |
| 309 | }); | |
| 267 | if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| { | |
| 268 | try self.objects.append(self.allocator, object); | |
| 310 | 269 | continue; |
| 311 | 270 | } |
| 312 | 271 | |
| 313 | try_dylib: { | |
| 314 | if (!(try Dylib.isDylib(file))) break :try_dylib; | |
| 315 | try classified.append(.{ | |
| 316 | .kind = .{ .dylib = file }, | |
| 317 | .name = full_path, | |
| 318 | }); | |
| 272 | if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| { | |
| 273 | try self.archives.append(self.allocator, archive); | |
| 319 | 274 | continue; |
| 320 | 275 | } |
| 321 | 276 | |
| 322 | try_stub: { | |
| 323 | var lib_stub = LibStub.loadFromFile(self.allocator, file) catch { | |
| 324 | break :try_stub; | |
| 325 | }; | |
| 326 | try classified.append(.{ | |
| 327 | .kind = .{ .stub = lib_stub }, | |
| 328 | .name = full_path, | |
| 329 | }); | |
| 330 | file.close(); | |
| 277 | if (try Dylib.createAndParseFromPath( | |
| 278 | self.allocator, | |
| 279 | self.arch.?, | |
| 280 | full_path, | |
| 281 | self.syslibroot, | |
| 282 | true, | |
| 283 | )) |dylib| { | |
| 284 | try self.dylibs.append(self.allocator, dylib); | |
| 331 | 285 | continue; |
| 332 | 286 | } |
| 333 | 287 | |
| 334 | file.close(); | |
| 335 | 288 | log.warn("unknown filetype for positional input file: '{s}'", .{file_name}); |
| 336 | 289 | } |
| 337 | ||
| 338 | // Based on our classification, proceed with parsing. | |
| 339 | for (classified.items) |input| { | |
| 340 | switch (input.kind) { | |
| 341 | .object => |file| { | |
| 342 | const object = try self.allocator.create(Object); | |
| 343 | errdefer self.allocator.destroy(object); | |
| 344 | ||
| 345 | object.* = Object.init(self.allocator); | |
| 346 | object.arch = self.arch.?; | |
| 347 | object.name = input.name; | |
| 348 | object.file = file; | |
| 349 | ||
| 350 | try object.parse(); | |
| 351 | try self.objects.append(self.allocator, object); | |
| 352 | }, | |
| 353 | .archive => |file| { | |
| 354 | const archive = try self.allocator.create(Archive); | |
| 355 | errdefer self.allocator.destroy(archive); | |
| 356 | ||
| 357 | archive.* = Archive.init(self.allocator); | |
| 358 | archive.arch = self.arch.?; | |
| 359 | archive.name = input.name; | |
| 360 | archive.file = file; | |
| 361 | ||
| 362 | try archive.parse(); | |
| 363 | try self.archives.append(self.allocator, archive); | |
| 364 | }, | |
| 365 | .dylib, .stub => { | |
| 366 | const dylib = try self.allocator.create(Dylib); | |
| 367 | errdefer self.allocator.destroy(dylib); | |
| 368 | ||
| 369 | dylib.* = Dylib.init(self.allocator); | |
| 370 | dylib.arch = self.arch.?; | |
| 371 | dylib.name = input.name; | |
| 372 | ||
| 373 | if (input.kind == .dylib) { | |
| 374 | dylib.file = input.kind.dylib; | |
| 375 | try dylib.parse(); | |
| 376 | } else { | |
| 377 | try dylib.parseFromStub(input.kind.stub); | |
| 378 | } | |
| 379 | ||
| 380 | try self.dylibs.append(self.allocator, dylib); | |
| 381 | }, | |
| 382 | } | |
| 383 | } | |
| 384 | 290 | } |
| 385 | 291 | |
| 386 | 292 | fn parseLibs(self: *Zld, libs: []const []const u8) !void { |
| 387 | for (libs) |lib| { | |
| 388 | const file = try fs.cwd().openFile(lib, .{}); | |
| 389 | ||
| 390 | var kind: ?union(enum) { | |
| 391 | archive, | |
| 392 | dylib, | |
| 393 | stub: LibStub, | |
| 394 | } = kind: { | |
| 395 | if (try Archive.isArchive(file)) break :kind .archive; | |
| 396 | if (try Dylib.isDylib(file)) break :kind .dylib; | |
| 397 | var lib_stub = LibStub.loadFromFile(self.allocator, file) catch { | |
| 398 | break :kind null; | |
| 399 | }; | |
| 400 | break :kind .{ .stub = lib_stub }; | |
| 401 | }; | |
| 402 | defer { | |
| 403 | if (kind) |*kk| { | |
| 404 | switch (kk.*) { | |
| 405 | .stub => |*stub| { | |
| 406 | stub.deinit(); | |
| 407 | }, | |
| 408 | else => {}, | |
| 409 | } | |
| 293 | const DylibDeps = struct { | |
| 294 | fn bubbleUp(out: *std.ArrayList(*Dylib), next: *Dylib) error{OutOfMemory}!void { | |
| 295 | try out.ensureUnusedCapacity(next.dylibs.items.len); | |
| 296 | for (next.dylibs.items) |dylib| { | |
| 297 | out.appendAssumeCapacity(dylib); | |
| 298 | } | |
| 299 | for (next.dylibs.items) |dylib| { | |
| 300 | try bubbleUp(out, dylib); | |
| 410 | 301 | } |
| 411 | 302 | } |
| 303 | }; | |
| 412 | 304 | |
| 413 | const unwrapped = kind orelse { | |
| 414 | file.close(); | |
| 415 | log.warn("unknown filetype for a library: '{s}'", .{lib}); | |
| 305 | for (libs) |lib| { | |
| 306 | if (try Dylib.createAndParseFromPath( | |
| 307 | self.allocator, | |
| 308 | self.arch.?, | |
| 309 | lib, | |
| 310 | self.syslibroot, | |
| 311 | true, | |
| 312 | )) |dylib| { | |
| 313 | try self.dylibs.append(self.allocator, dylib); | |
| 416 | 314 | continue; |
| 417 | }; | |
| 418 | switch (unwrapped) { | |
| 419 | .archive => { | |
| 420 | const archive = try self.allocator.create(Archive); | |
| 421 | errdefer self.allocator.destroy(archive); | |
| 422 | ||
| 423 | archive.* = Archive.init(self.allocator); | |
| 424 | archive.arch = self.arch.?; | |
| 425 | archive.name = try self.allocator.dupe(u8, lib); | |
| 426 | archive.file = file; | |
| 427 | ||
| 428 | try archive.parse(); | |
| 429 | try self.archives.append(self.allocator, archive); | |
| 430 | }, | |
| 431 | .dylib, .stub => { | |
| 432 | const dylib = try self.allocator.create(Dylib); | |
| 433 | errdefer self.allocator.destroy(dylib); | |
| 434 | ||
| 435 | dylib.* = Dylib.init(self.allocator); | |
| 436 | dylib.arch = self.arch.?; | |
| 437 | dylib.name = try self.allocator.dupe(u8, lib); | |
| 438 | ||
| 439 | if (unwrapped == .dylib) { | |
| 440 | dylib.file = file; | |
| 441 | try dylib.parse(); | |
| 442 | } else { | |
| 443 | try dylib.parseFromStub(unwrapped.stub); | |
| 444 | } | |
| 445 | ||
| 446 | try self.dylibs.append(self.allocator, dylib); | |
| 447 | }, | |
| 448 | 315 | } |
| 449 | } | |
| 450 | } | |
| 451 | 316 | |
| 452 | fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void { | |
| 453 | const file = try fs.cwd().openFile(libc_stub_path, .{}); | |
| 454 | defer file.close(); | |
| 317 | if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| { | |
| 318 | try self.archives.append(self.allocator, archive); | |
| 319 | continue; | |
| 320 | } | |
| 455 | 321 | |
| 456 | var lib_stub = try LibStub.loadFromFile(self.allocator, file); | |
| 457 | defer lib_stub.deinit(); | |
| 322 | log.warn("unknown filetype for a library: '{s}'", .{lib}); | |
| 323 | } | |
| 458 | 324 | |
| 459 | const dylib = try self.allocator.create(Dylib); | |
| 460 | errdefer self.allocator.destroy(dylib); | |
| 325 | // Flatten out any parsed dependencies. | |
| 326 | var deps = std.ArrayList(*Dylib).init(self.allocator); | |
| 327 | defer deps.deinit(); | |
| 461 | 328 | |
| 462 | dylib.* = Dylib.init(self.allocator); | |
| 463 | dylib.arch = self.arch.?; | |
| 464 | dylib.name = try self.allocator.dupe(u8, libc_stub_path); | |
| 329 | for (self.dylibs.items) |dylib| { | |
| 330 | try DylibDeps.bubbleUp(&deps, dylib); | |
| 331 | } | |
| 465 | 332 | |
| 466 | try dylib.parseFromStub(lib_stub); | |
| 333 | try self.dylibs.appendSlice(self.allocator, deps.toOwnedSlice()); | |
| 334 | } | |
| 467 | 335 | |
| 336 | fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void { | |
| 337 | const dylib = (try Dylib.createAndParseFromPath( | |
| 338 | self.allocator, | |
| 339 | self.arch.?, | |
| 340 | libc_stub_path, | |
| 341 | self.syslibroot, | |
| 342 | false, | |
| 343 | )) orelse return error.FailedToParseLibSystem; | |
| 468 | 344 | self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len); |
| 469 | 345 | try self.dylibs.append(self.allocator, dylib); |
| 470 | 346 |
src/link/tapi.zig+2-1| ... | ... | @@ -41,7 +41,8 @@ pub const LibStub = struct { |
| 41 | 41 | }, |
| 42 | 42 | reexports: ?[]const struct { |
| 43 | 43 | targets: []const []const u8, |
| 44 | symbols: []const []const u8, | |
| 44 | symbols: ?[]const []const u8, | |
| 45 | objc_classes: ?[]const []const u8, | |
| 45 | 46 | }, |
| 46 | 47 | allowable_clients: ?[]const struct { |
| 47 | 48 | targets: []const []const u8, |