| author | |
| committer | |
| log | a95ba0d10d582020dbd3e6efded53f17287ed211 |
| tree | 7f17ba0b98e18e6ff4c833d08a45779a5ce52d01 |
| parent | 908b431abeb1df5d3c3ad34d9299e720c3e06a9d |
| parent | 186577225f2a026fea01b48c7bcca47f36efc95c |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
Add fat/universal archive support to zig ld3 files changed, 68 insertions(+), 53 deletions(-)
src/link/MachO/Archive.zig+10-1| ... | ... | @@ -6,6 +6,7 @@ const fs = std.fs; |
| 6 | 6 | const log = std.log.scoped(.archive); |
| 7 | 7 | const macho = std.macho; |
| 8 | 8 | const mem = std.mem; |
| 9 | const fat = @import("fat.zig"); | |
| 9 | 10 | |
| 10 | 11 | const Allocator = mem.Allocator; |
| 11 | 12 | const Arch = std.Target.Cpu.Arch; |
| ... | ... | @@ -19,6 +20,10 @@ file: ?fs.File = null, |
| 19 | 20 | header: ?ar_hdr = null, |
| 20 | 21 | name: ?[]const u8 = null, |
| 21 | 22 | |
| 23 | // The actual contents we care about linking with will be embedded at | |
| 24 | // an offset within a file if we are linking against a fat lib | |
| 25 | library_offset: u64 = 0, | |
| 26 | ||
| 22 | 27 | /// Parsed table of contents. |
| 23 | 28 | /// Each symbol name points to a list of all definition |
| 24 | 29 | /// sites within the current static archive. |
| ... | ... | @@ -139,6 +144,10 @@ pub fn closeFile(self: Archive) void { |
| 139 | 144 | } |
| 140 | 145 | |
| 141 | 146 | pub fn parse(self: *Archive) !void { |
| 147 | self.library_offset = try fat.getLibraryOffset(self.file.?.reader(), self.arch.?); | |
| 148 | ||
| 149 | try self.file.?.seekTo(self.library_offset); | |
| 150 | ||
| 142 | 151 | var reader = self.file.?.reader(); |
| 143 | 152 | const magic = try reader.readBytesNoEof(SARMAG); |
| 144 | 153 | |
| ... | ... | @@ -226,7 +235,7 @@ fn parseTableOfContents(self: *Archive, reader: anytype) !void { |
| 226 | 235 | /// Caller owns the Object instance. |
| 227 | 236 | pub fn parseObject(self: Archive, offset: u32) !*Object { |
| 228 | 237 | var reader = self.file.?.reader(); |
| 229 | try reader.context.seekTo(offset); | |
| 238 | try reader.context.seekTo(offset + self.library_offset); | |
| 230 | 239 | |
| 231 | 240 | const object_header = try reader.readStruct(ar_hdr); |
| 232 | 241 |
src/link/MachO/Dylib.zig+3-52| ... | ... | @@ -1,7 +1,6 @@ |
| 1 | 1 | const Dylib = @This(); |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | const builtin = std.builtin; | |
| 5 | 4 | const assert = std.debug.assert; |
| 6 | 5 | const fs = std.fs; |
| 7 | 6 | const fmt = std.fmt; |
| ... | ... | @@ -9,7 +8,7 @@ const log = std.log.scoped(.dylib); |
| 9 | 8 | const macho = std.macho; |
| 10 | 9 | const math = std.math; |
| 11 | 10 | const mem = std.mem; |
| 12 | const native_endian = builtin.target.cpu.arch.endian(); | |
| 11 | const fat = @import("fat.zig"); | |
| 13 | 12 | |
| 14 | 13 | const Allocator = mem.Allocator; |
| 15 | 14 | const Arch = std.Target.Cpu.Arch; |
| ... | ... | @@ -238,42 +237,10 @@ pub fn closeFile(self: Dylib) void { |
| 238 | 237 | } |
| 239 | 238 | } |
| 240 | 239 | |
| 241 | fn decodeArch(cputype: macho.cpu_type_t) !std.Target.Cpu.Arch { | |
| 242 | const arch: Arch = switch (cputype) { | |
| 243 | macho.CPU_TYPE_ARM64 => .aarch64, | |
| 244 | macho.CPU_TYPE_X86_64 => .x86_64, | |
| 245 | else => { | |
| 246 | return error.UnsupportedCpuArchitecture; | |
| 247 | }, | |
| 248 | }; | |
| 249 | return arch; | |
| 250 | } | |
| 251 | ||
| 252 | 240 | pub fn parse(self: *Dylib) !void { |
| 253 | 241 | log.debug("parsing shared library '{s}'", .{self.name.?}); |
| 254 | 242 | |
| 255 | self.library_offset = offset: { | |
| 256 | const fat_header = try readFatStruct(self.file.?.reader(), macho.fat_header); | |
| 257 | if (fat_header.magic != macho.FAT_MAGIC) break :offset 0; | |
| 258 | ||
| 259 | var fat_arch_index: u32 = 0; | |
| 260 | while (fat_arch_index < fat_header.nfat_arch) : (fat_arch_index += 1) { | |
| 261 | const fat_arch = try readFatStruct(self.file.?.reader(), macho.fat_arch); | |
| 262 | // If we come across an architecture that we do not know how to handle, that's | |
| 263 | // fine because we can keep looking for one that might match. | |
| 264 | const lib_arch = decodeArch(fat_arch.cputype) catch |err| switch (err) { | |
| 265 | error.UnsupportedCpuArchitecture => continue, | |
| 266 | else => |e| return e, | |
| 267 | }; | |
| 268 | if (lib_arch == self.arch.?) { | |
| 269 | // We have found a matching architecture! | |
| 270 | break :offset fat_arch.offset; | |
| 271 | } | |
| 272 | } else { | |
| 273 | log.err("Could not find matching cpu architecture in fat library: expected {s}", .{self.arch.?}); | |
| 274 | return error.MismatchedCpuArchitecture; | |
| 275 | } | |
| 276 | }; | |
| 243 | self.library_offset = try fat.getLibraryOffset(self.file.?.reader(), self.arch.?); | |
| 277 | 244 | |
| 278 | 245 | try self.file.?.seekTo(self.library_offset); |
| 279 | 246 | |
| ... | ... | @@ -285,13 +252,7 @@ pub fn parse(self: *Dylib) !void { |
| 285 | 252 | return error.NotDylib; |
| 286 | 253 | } |
| 287 | 254 | |
| 288 | const this_arch: Arch = decodeArch(self.header.?.cputype) catch |err| switch (err) { | |
| 289 | error.UnsupportedCpuArchitecture => |e| { | |
| 290 | log.err("unsupported cpu architecture 0x{x}", .{self.header.?.cputype}); | |
| 291 | return e; | |
| 292 | }, | |
| 293 | else => |e| return e, | |
| 294 | }; | |
| 255 | const this_arch: Arch = try fat.decodeArch(self.header.?.cputype, true); | |
| 295 | 256 | |
| 296 | 257 | if (this_arch != self.arch.?) { |
| 297 | 258 | log.err("mismatched cpu architecture: expected {s}, found {s}", .{ self.arch.?, this_arch }); |
| ... | ... | @@ -303,16 +264,6 @@ pub fn parse(self: *Dylib) !void { |
| 303 | 264 | try self.parseSymbols(); |
| 304 | 265 | } |
| 305 | 266 | |
| 306 | fn readFatStruct(reader: anytype, comptime T: type) !T { | |
| 307 | // Fat structures (fat_header & fat_arch) are always written and read to/from | |
| 308 | // disk in big endian order. | |
| 309 | var res: T = try reader.readStruct(T); | |
| 310 | if (native_endian != builtin.Endian.Big) { | |
| 311 | mem.bswapAllFields(T, &res); | |
| 312 | } | |
| 313 | return res; | |
| 314 | } | |
| 315 | ||
| 316 | 267 | fn readLoadCommands(self: *Dylib, reader: anytype) !void { |
| 317 | 268 | const should_lookup_reexports = self.header.?.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0; |
| 318 | 269 |
src/link/MachO/fat.zig created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = std.builtin; | |
| 3 | const log = std.log.scoped(.archive); | |
| 4 | const macho = std.macho; | |
| 5 | const mem = std.mem; | |
| 6 | const native_endian = builtin.target.cpu.arch.endian(); | |
| 7 | ||
| 8 | const Arch = std.Target.Cpu.Arch; | |
| 9 | ||
| 10 | pub fn decodeArch(cputype: macho.cpu_type_t, comptime logError: bool) !std.Target.Cpu.Arch { | |
| 11 | const arch: Arch = switch (cputype) { | |
| 12 | macho.CPU_TYPE_ARM64 => .aarch64, | |
| 13 | macho.CPU_TYPE_X86_64 => .x86_64, | |
| 14 | else => { | |
| 15 | if (logError) { | |
| 16 | log.err("unsupported cpu architecture 0x{x}", .{cputype}); | |
| 17 | } | |
| 18 | return error.UnsupportedCpuArchitecture; | |
| 19 | }, | |
| 20 | }; | |
| 21 | return arch; | |
| 22 | } | |
| 23 | ||
| 24 | fn readFatStruct(reader: anytype, comptime T: type) !T { | |
| 25 | // Fat structures (fat_header & fat_arch) are always written and read to/from | |
| 26 | // disk in big endian order. | |
| 27 | var res = try reader.readStruct(T); | |
| 28 | if (native_endian != builtin.Endian.Big) { | |
| 29 | mem.bswapAllFields(T, &res); | |
| 30 | } | |
| 31 | return res; | |
| 32 | } | |
| 33 | ||
| 34 | pub fn getLibraryOffset(reader: anytype, arch: Arch) !u64 { | |
| 35 | const fat_header = try readFatStruct(reader, macho.fat_header); | |
| 36 | if (fat_header.magic != macho.FAT_MAGIC) return 0; | |
| 37 | ||
| 38 | var fat_arch_index: u32 = 0; | |
| 39 | while (fat_arch_index < fat_header.nfat_arch) : (fat_arch_index += 1) { | |
| 40 | const fat_arch = try readFatStruct(reader, macho.fat_arch); | |
| 41 | // If we come across an architecture that we do not know how to handle, that's | |
| 42 | // fine because we can keep looking for one that might match. | |
| 43 | const lib_arch = decodeArch(fat_arch.cputype, false) catch |err| switch (err) { | |
| 44 | error.UnsupportedCpuArchitecture => continue, | |
| 45 | else => |e| return e, | |
| 46 | }; | |
| 47 | if (lib_arch == arch) { | |
| 48 | // We have found a matching architecture! | |
| 49 | return fat_arch.offset; | |
| 50 | } | |
| 51 | } else { | |
| 52 | log.err("Could not find matching cpu architecture in fat library: expected {s}", .{arch}); | |
| 53 | return error.MismatchedCpuArchitecture; | |
| 54 | } | |
| 55 | } |