authorgravatar for readcuttingt@gmail.comTom Read Cutting <readcuttingt@gmail.com> 2021-06-24 23:29:39+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-25 08:38:47+02:00
log177b1b6bf9a7402eb688159dfa94ea5a5ea6f550
tree2b14f44eb4fd81a0f3e0067190f71e09f8a2cffb
parent2d2a6ed1a46349355650bfdd68688738c67bbf9c

Add fat/universal dylib support to zig ld

With this change zig ld can link with dynamic libraries contained within a fat/universal file that had multiple seperate binaries embedded within it for multi-arch support (in macOS). Whilst zig can still only create single-architecture executables - the ability to link with fat libraries is useful for cases where they are the easiest (or only) option to link against.

6 files changed, 137 insertions(+), 52 deletions(-)

lib/std/elf.zig+4-24
...@@ -429,7 +429,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {...@@ -429,7 +429,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {
429 if (self.elf_header.endian == native_endian) return phdr;429 if (self.elf_header.endian == native_endian) return phdr;
430430
431 // Convert fields to native endianness.431 // Convert fields to native endianness.
432 bswapAllFields(Elf64_Phdr, &phdr);432 mem.bswapAllFields(Elf64_Phdr, &phdr);
433 return phdr;433 return phdr;
434 }434 }
435435
...@@ -441,7 +441,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {...@@ -441,7 +441,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {
441 // ELF endianness does NOT match native endianness.441 // ELF endianness does NOT match native endianness.
442 if (self.elf_header.endian != native_endian) {442 if (self.elf_header.endian != native_endian) {
443 // Convert fields to native endianness.443 // Convert fields to native endianness.
444 bswapAllFields(Elf32_Phdr, &phdr);444 mem.bswapAllFields(Elf32_Phdr, &phdr);
445 }445 }
446446
447 // Convert 32-bit header to 64-bit.447 // Convert 32-bit header to 64-bit.
...@@ -479,7 +479,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type {...@@ -479,7 +479,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type {
479 if (self.elf_header.endian == native_endian) return shdr;479 if (self.elf_header.endian == native_endian) return shdr;
480480
481 // Convert fields to native endianness.481 // Convert fields to native endianness.
482 bswapAllFields(Elf64_Shdr, &shdr);482 mem.bswapAllFields(Elf64_Shdr, &shdr);
483 return shdr;483 return shdr;
484 }484 }
485485
...@@ -491,7 +491,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type {...@@ -491,7 +491,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type {
491 // ELF endianness does NOT match native endianness.491 // ELF endianness does NOT match native endianness.
492 if (self.elf_header.endian != native_endian) {492 if (self.elf_header.endian != native_endian) {
493 // Convert fields to native endianness.493 // Convert fields to native endianness.
494 bswapAllFields(Elf32_Shdr, &shdr);494 mem.bswapAllFields(Elf32_Shdr, &shdr);
495 }495 }
496496
497 // Convert 32-bit header to 64-bit.497 // Convert 32-bit header to 64-bit.
...@@ -531,26 +531,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {...@@ -531,26 +531,6 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
531 }531 }
532}532}
533533
534pub fn bswapAllFields(comptime S: type, ptr: *S) void {
535 if (@typeInfo(S) != .Struct) @compileError("bswapAllFields expects a struct as the first argument");
536 inline for (std.meta.fields(S)) |f| {
537 @field(ptr, f.name) = @byteSwap(f.field_type, @field(ptr, f.name));
538 }
539}
540test "bswapAllFields" {
541 var s: Elf32_Chdr = .{
542 .ch_type = 0x12341234,
543 .ch_size = 0x56785678,
544 .ch_addralign = 0x12124242,
545 };
546 bswapAllFields(Elf32_Chdr, &s);
547 try std.testing.expectEqual(Elf32_Chdr{
548 .ch_type = 0x34123412,
549 .ch_size = 0x78567856,
550 .ch_addralign = 0x42421212,
551 }, s);
552}
553
554pub const EI_NIDENT = 16;534pub const EI_NIDENT = 16;
555535
556pub const EI_CLASS = 4;536pub const EI_CLASS = 4;
lib/std/macho.zig+27
...@@ -24,6 +24,19 @@ pub const mach_header_64 = extern struct {...@@ -24,6 +24,19 @@ pub const mach_header_64 = extern struct {
24 reserved: u32,24 reserved: u32,
25};25};
2626
27pub const fat_header = extern struct {
28 magic: u32,
29 nfat_arch: u32,
30};
31
32pub const fat_arch = extern struct {
33 cputype: cpu_type_t,
34 cpusubtype: cpu_subtype_t,
35 offset: u32,
36 size: u32,
37 @"align": u32,
38};
39
27pub const load_command = extern struct {40pub const load_command = extern struct {
28 cmd: u32,41 cmd: u32,
29 cmdsize: u32,42 cmdsize: u32,
...@@ -1040,6 +1053,20 @@ pub const MH_APP_EXTENSION_SAFE = 0x02000000;...@@ -1040,6 +1053,20 @@ pub const MH_APP_EXTENSION_SAFE = 0x02000000;
1040/// The external symbols listed in the nlist symbol table do not include all the symbols listed in the dyld info.1053/// The external symbols listed in the nlist symbol table do not include all the symbols listed in the dyld info.
1041pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000;1054pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000;
10421055
1056// Constants for the flags field of the fat_header
1057
1058/// the fat magic number
1059pub const FAT_MAGIC = 0xcafebabe;
1060
1061/// NXSwapLong(FAT_MAGIC)
1062pub const FAT_CIGAM = 0xbebafeca;
1063
1064/// the 64-bit fat magic number
1065pub const FAT_MAGIC_64 = 0xcafebabf;
1066
1067/// NXSwapLong(FAT_MAGIC_64)
1068pub const FAT_CIGAM_64 = 0xbfbafeca;
1069
1043/// The flags field of a section structure is separated into two parts a section1070/// The flags field of a section structure is separated into two parts a section
1044/// type and section attributes. The section types are mutually exclusive (it1071/// type and section attributes. The section types are mutually exclusive (it
1045/// can only have one type) but the section attributes are not (it may have more1072/// can only have one type) but the section attributes are not (it may have more
lib/std/mem.zig+28
...@@ -1539,6 +1539,34 @@ test "writeIntBig and writeIntLittle" {...@@ -1539,6 +1539,34 @@ test "writeIntBig and writeIntLittle" {
1539 try testing.expect(eql(u8, buf2[0..], &[_]u8{ 0xfc, 0xff }));1539 try testing.expect(eql(u8, buf2[0..], &[_]u8{ 0xfc, 0xff }));
1540}1540}
15411541
1542/// Swap the byte order of all the members of the fields of a struct
1543/// (Changing their endianess)
1544pub fn bswapAllFields(comptime S: type, ptr: *S) void {
1545 if (@typeInfo(S) != .Struct) @compileError("bswapAllFields expects a struct as the first argument");
1546 inline for (std.meta.fields(S)) |f| {
1547 @field(ptr, f.name) = @byteSwap(f.field_type, @field(ptr, f.name));
1548 }
1549}
1550
1551test "bswapAllFields" {
1552 const T = extern struct {
1553 f0: u8,
1554 f1: u16,
1555 f2: u32,
1556 };
1557 var s = T{
1558 .f0 = 0x12,
1559 .f1 = 0x1234,
1560 .f2 = 0x12345678,
1561 };
1562 bswapAllFields(T, &s);
1563 try std.testing.expectEqual(T{
1564 .f0 = 0x12,
1565 .f1 = 0x3412,
1566 .f2 = 0x78563412,
1567 }, s);
1568}
1569
1542/// Returns an iterator that iterates over the slices of `buffer` that are not1570/// Returns an iterator that iterates over the slices of `buffer` that are not
1543/// any of the bytes in `delimiter_bytes`.1571/// any of the bytes in `delimiter_bytes`.
1544/// tokenize(" abc def ghi ", " ")1572/// tokenize(" abc def ghi ", " ")
src/link/Elf.zig+12-12
...@@ -1108,7 +1108,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -1108,7 +1108,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
1108 for (buf) |*phdr, i| {1108 for (buf) |*phdr, i| {
1109 phdr.* = progHeaderTo32(self.program_headers.items[i]);1109 phdr.* = progHeaderTo32(self.program_headers.items[i]);
1110 if (foreign_endian) {1110 if (foreign_endian) {
1111 std.elf.bswapAllFields(elf.Elf32_Phdr, phdr);1111 mem.bswapAllFields(elf.Elf32_Phdr, phdr);
1112 }1112 }
1113 }1113 }
1114 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);1114 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
...@@ -1120,7 +1120,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -1120,7 +1120,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
1120 for (buf) |*phdr, i| {1120 for (buf) |*phdr, i| {
1121 phdr.* = self.program_headers.items[i];1121 phdr.* = self.program_headers.items[i];
1122 if (foreign_endian) {1122 if (foreign_endian) {
1123 std.elf.bswapAllFields(elf.Elf64_Phdr, phdr);1123 mem.bswapAllFields(elf.Elf64_Phdr, phdr);
1124 }1124 }
1125 }1125 }
1126 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);1126 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
...@@ -1197,7 +1197,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -1197,7 +1197,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
1197 shdr.* = sectHeaderTo32(self.sections.items[i]);1197 shdr.* = sectHeaderTo32(self.sections.items[i]);
1198 log.debug("writing section {}", .{shdr.*});1198 log.debug("writing section {}", .{shdr.*});
1199 if (foreign_endian) {1199 if (foreign_endian) {
1200 std.elf.bswapAllFields(elf.Elf32_Shdr, shdr);1200 mem.bswapAllFields(elf.Elf32_Shdr, shdr);
1201 }1201 }
1202 }1202 }
1203 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);1203 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
...@@ -1210,7 +1210,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -1210,7 +1210,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
1210 shdr.* = self.sections.items[i];1210 shdr.* = self.sections.items[i];
1211 log.debug("writing section {}", .{shdr.*});1211 log.debug("writing section {}", .{shdr.*});
1212 if (foreign_endian) {1212 if (foreign_endian) {
1213 std.elf.bswapAllFields(elf.Elf64_Shdr, shdr);1213 mem.bswapAllFields(elf.Elf64_Shdr, shdr);
1214 }1214 }
1215 }1215 }
1216 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);1216 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
...@@ -2740,14 +2740,14 @@ fn writeProgHeader(self: *Elf, index: usize) !void {...@@ -2740,14 +2740,14 @@ fn writeProgHeader(self: *Elf, index: usize) !void {
2740 .p32 => {2740 .p32 => {
2741 var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])};2741 var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])};
2742 if (foreign_endian) {2742 if (foreign_endian) {
2743 std.elf.bswapAllFields(elf.Elf32_Phdr, &phdr[0]);2743 mem.bswapAllFields(elf.Elf32_Phdr, &phdr[0]);
2744 }2744 }
2745 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);2745 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
2746 },2746 },
2747 .p64 => {2747 .p64 => {
2748 var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]};2748 var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]};
2749 if (foreign_endian) {2749 if (foreign_endian) {
2750 std.elf.bswapAllFields(elf.Elf64_Phdr, &phdr[0]);2750 mem.bswapAllFields(elf.Elf64_Phdr, &phdr[0]);
2751 }2751 }
2752 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);2752 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
2753 },2753 },
...@@ -2761,7 +2761,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {...@@ -2761,7 +2761,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
2761 var shdr: [1]elf.Elf32_Shdr = undefined;2761 var shdr: [1]elf.Elf32_Shdr = undefined;
2762 shdr[0] = sectHeaderTo32(self.sections.items[index]);2762 shdr[0] = sectHeaderTo32(self.sections.items[index]);
2763 if (foreign_endian) {2763 if (foreign_endian) {
2764 std.elf.bswapAllFields(elf.Elf32_Shdr, &shdr[0]);2764 mem.bswapAllFields(elf.Elf32_Shdr, &shdr[0]);
2765 }2765 }
2766 const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr);2766 const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf32_Shdr);
2767 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);2767 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
...@@ -2769,7 +2769,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {...@@ -2769,7 +2769,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
2769 .p64 => {2769 .p64 => {
2770 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};2770 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};
2771 if (foreign_endian) {2771 if (foreign_endian) {
2772 std.elf.bswapAllFields(elf.Elf64_Shdr, &shdr[0]);2772 mem.bswapAllFields(elf.Elf64_Shdr, &shdr[0]);
2773 }2773 }
2774 const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr);2774 const offset = self.shdr_table_offset.? + index * @sizeOf(elf.Elf64_Shdr);
2775 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);2775 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
...@@ -2867,7 +2867,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2867,7 +2867,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2867 },2867 },
2868 };2868 };
2869 if (foreign_endian) {2869 if (foreign_endian) {
2870 std.elf.bswapAllFields(elf.Elf32_Sym, &sym[0]);2870 mem.bswapAllFields(elf.Elf32_Sym, &sym[0]);
2871 }2871 }
2872 const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index;2872 const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index;
2873 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);2873 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
...@@ -2875,7 +2875,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2875,7 +2875,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2875 .p64 => {2875 .p64 => {
2876 var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]};2876 var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]};
2877 if (foreign_endian) {2877 if (foreign_endian) {
2878 std.elf.bswapAllFields(elf.Elf64_Sym, &sym[0]);2878 mem.bswapAllFields(elf.Elf64_Sym, &sym[0]);
2879 }2879 }
2880 const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index;2880 const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index;
2881 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);2881 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
...@@ -2906,7 +2906,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void {...@@ -2906,7 +2906,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void {
2906 .st_shndx = self.global_symbols.items[i].st_shndx,2906 .st_shndx = self.global_symbols.items[i].st_shndx,
2907 };2907 };
2908 if (foreign_endian) {2908 if (foreign_endian) {
2909 std.elf.bswapAllFields(elf.Elf32_Sym, sym);2909 mem.bswapAllFields(elf.Elf32_Sym, sym);
2910 }2910 }
2911 }2911 }
2912 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);2912 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
...@@ -2925,7 +2925,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void {...@@ -2925,7 +2925,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void {
2925 .st_shndx = self.global_symbols.items[i].st_shndx,2925 .st_shndx = self.global_symbols.items[i].st_shndx,
2926 };2926 };
2927 if (foreign_endian) {2927 if (foreign_endian) {
2928 std.elf.bswapAllFields(elf.Elf64_Sym, sym);2928 mem.bswapAllFields(elf.Elf64_Sym, sym);
2929 }2929 }
2930 }2930 }
2931 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);2931 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
src/link/MachO/Dylib.zig+60-8
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const Dylib = @This();1const Dylib = @This();
22
3const std = @import("std");3const std = @import("std");
4const builtin = std.builtin;
4const assert = std.debug.assert;5const assert = std.debug.assert;
5const fs = std.fs;6const fs = std.fs;
6const fmt = std.fmt;7const fmt = std.fmt;
...@@ -8,6 +9,7 @@ const log = std.log.scoped(.dylib);...@@ -8,6 +9,7 @@ const log = std.log.scoped(.dylib);
8const macho = std.macho;9const macho = std.macho;
9const math = std.math;10const math = std.math;
10const mem = std.mem;11const mem = std.mem;
12const native_endian = builtin.target.cpu.arch.endian();
1113
12const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
13const Arch = std.Target.Cpu.Arch;15const Arch = std.Target.Cpu.Arch;
...@@ -26,6 +28,10 @@ syslibroot: ?[]const u8 = null,...@@ -26,6 +28,10 @@ syslibroot: ?[]const u8 = null,
2628
27ordinal: ?u16 = null,29ordinal: ?u16 = null,
2830
31// The actual dylib contents we care about linking with will be embedded at
32// an offset within a file if we are linking against a fat lib
33library_offset: u64 = 0,
34
29load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},35load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
3036
31symtab_cmd_index: ?u16 = null,37symtab_cmd_index: ?u16 = null,
...@@ -205,9 +211,45 @@ pub fn closeFile(self: Dylib) void {...@@ -205,9 +211,45 @@ pub fn closeFile(self: Dylib) void {
205 }211 }
206}212}
207213
214fn decodeArch(cputype: macho.cpu_type_t) !std.Target.Cpu.Arch {
215 const arch: Arch = switch (cputype) {
216 macho.CPU_TYPE_ARM64 => .aarch64,
217 macho.CPU_TYPE_X86_64 => .x86_64,
218 else => {
219 return error.UnsupportedCpuArchitecture;
220 },
221 };
222 return arch;
223}
224
208pub fn parse(self: *Dylib) !void {225pub fn parse(self: *Dylib) !void {
209 log.debug("parsing shared library '{s}'", .{self.name.?});226 log.debug("parsing shared library '{s}'", .{self.name.?});
210227
228 self.library_offset = offset: {
229 const fat_header = try readFatStruct(self.file.?.reader(), macho.fat_header);
230 if (fat_header.magic != macho.FAT_MAGIC) break :offset 0;
231
232 var fat_arch_index: u32 = 0;
233 while (fat_arch_index < fat_header.nfat_arch) : (fat_arch_index += 1) {
234 const fat_arch = try readFatStruct(self.file.?.reader(), macho.fat_arch);
235 // If we come across an architecture that we do not know how to handle, that's
236 // fine because we can keep looking for one that might match.
237 const lib_arch = decodeArch(fat_arch.cputype) catch |err| switch (err) {
238 error.UnsupportedCpuArchitecture => continue,
239 else => |e| return e,
240 };
241 if (lib_arch == self.arch.?) {
242 // We have found a matching architecture!
243 break :offset fat_arch.offset;
244 }
245 } else {
246 log.err("Could not find matching cpu architecture in fat library: expected {s}", .{self.arch.?});
247 return error.MismatchedCpuArchitecture;
248 }
249 };
250
251 try self.file.?.seekTo(self.library_offset);
252
211 var reader = self.file.?.reader();253 var reader = self.file.?.reader();
212 self.header = try reader.readStruct(macho.mach_header_64);254 self.header = try reader.readStruct(macho.mach_header_64);
213255
...@@ -216,14 +258,14 @@ pub fn parse(self: *Dylib) !void {...@@ -216,14 +258,14 @@ pub fn parse(self: *Dylib) !void {
216 return error.NotDylib;258 return error.NotDylib;
217 }259 }
218260
219 const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {261 const this_arch: Arch = decodeArch(self.header.?.cputype) catch |err| switch (err) {
220 macho.CPU_TYPE_ARM64 => .aarch64,262 error.UnsupportedCpuArchitecture => |e| {
221 macho.CPU_TYPE_X86_64 => .x86_64,263 log.err("unsupported cpu architecture 0x{x}", .{self.header.?.cputype});
222 else => |value| {264 return e;
223 log.err("unsupported cpu architecture 0x{x}", .{value});
224 return error.UnsupportedCpuArchitecture;
225 },265 },
266 else => |e| return e,
226 };267 };
268
227 if (this_arch != self.arch.?) {269 if (this_arch != self.arch.?) {
228 log.err("mismatched cpu architecture: expected {s}, found {s}", .{ self.arch.?, this_arch });270 log.err("mismatched cpu architecture: expected {s}, found {s}", .{ self.arch.?, this_arch });
229 return error.MismatchedCpuArchitecture;271 return error.MismatchedCpuArchitecture;
...@@ -234,6 +276,16 @@ pub fn parse(self: *Dylib) !void {...@@ -234,6 +276,16 @@ pub fn parse(self: *Dylib) !void {
234 try self.parseSymbols();276 try self.parseSymbols();
235}277}
236278
279fn readFatStruct(reader: anytype, comptime T: type) !T {
280 // Fat structures (fat_header & fat_arch) are always written and read to/from
281 // disk in big endian order.
282 var res: T = try reader.readStruct(T);
283 if (native_endian != builtin.Endian.Big) {
284 mem.bswapAllFields(T, &res);
285 }
286 return res;
287}
288
237fn readLoadCommands(self: *Dylib, reader: anytype) !void {289fn readLoadCommands(self: *Dylib, reader: anytype) !void {
238 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);290 try self.load_commands.ensureCapacity(self.allocator, self.header.?.ncmds);
239291
...@@ -285,12 +337,12 @@ fn parseSymbols(self: *Dylib) !void {...@@ -285,12 +337,12 @@ fn parseSymbols(self: *Dylib) !void {
285337
286 var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);338 var symtab = try self.allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
287 defer self.allocator.free(symtab);339 defer self.allocator.free(symtab);
288 _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff);340 _ = try self.file.?.preadAll(symtab, symtab_cmd.symoff + self.library_offset);
289 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));341 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));
290342
291 var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize);343 var strtab = try self.allocator.alloc(u8, symtab_cmd.strsize);
292 defer self.allocator.free(strtab);344 defer self.allocator.free(strtab);
293 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);345 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff + self.library_offset);
294346
295 for (slice) |sym| {347 for (slice) |sym| {
296 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));348 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
src/link/MachO/Object.zig+6-8
...@@ -247,18 +247,14 @@ pub fn parse(self: *Object) !void {...@@ -247,18 +247,14 @@ pub fn parse(self: *Object) !void {
247 try reader.context.seekTo(offset);247 try reader.context.seekTo(offset);
248 }248 }
249249
250 self.header = try reader.readStruct(macho.mach_header_64);250 const header = try reader.readStruct(macho.mach_header_64);
251
252 if (self.header.?.filetype != macho.MH_OBJECT) {
253 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{
254 macho.MH_OBJECT,
255 self.header.?.filetype,
256 });
257251
252 if (header.filetype != macho.MH_OBJECT) {
253 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_OBJECT, header.filetype });
258 return error.NotObject;254 return error.NotObject;
259 }255 }
260256
261 const this_arch: Arch = switch (self.header.?.cputype) {257 const this_arch: Arch = switch (header.cputype) {
262 macho.CPU_TYPE_ARM64 => .aarch64,258 macho.CPU_TYPE_ARM64 => .aarch64,
263 macho.CPU_TYPE_X86_64 => .x86_64,259 macho.CPU_TYPE_X86_64 => .x86_64,
264 else => |value| {260 else => |value| {
...@@ -271,6 +267,8 @@ pub fn parse(self: *Object) !void {...@@ -271,6 +267,8 @@ pub fn parse(self: *Object) !void {
271 return error.MismatchedCpuArchitecture;267 return error.MismatchedCpuArchitecture;
272 }268 }
273269
270 self.header = header;
271
274 try self.readLoadCommands(reader);272 try self.readLoadCommands(reader);
275 try self.parseSymbols();273 try self.parseSymbols();
276 try self.parseSections();274 try self.parseSections();