| author | |
| committer | |
| log | 177b1b6bf9a7402eb688159dfa94ea5a5ea6f550 |
| tree | 2b14f44eb4fd81a0f3e0067190f71e09f8a2cffb |
| parent | 2d2a6ed1a46349355650bfdd68688738c67bbf9c |
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; |
| 430 | 430 | ||
| 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 | } |
| 435 | 435 | ||
| ... | @@ -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 | } |
| 446 | 446 | ||
| 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; |
| 480 | 480 | ||
| 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 | } |
| 485 | 485 | ||
| ... | @@ -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 | } |
| 496 | 496 | ||
| 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 | } |
| 533 | 533 | ||
| 534 | pub 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 | } | ||
| 540 | test "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 | |||
| 554 | pub const EI_NIDENT = 16; | 534 | pub const EI_NIDENT = 16; |
| 555 | 535 | ||
| 556 | pub const EI_CLASS = 4; | 536 | pub 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 | }; |
| 26 | 26 | ||
| 27 | pub const fat_header = extern struct { | ||
| 28 | magic: u32, | ||
| 29 | nfat_arch: u32, | ||
| 30 | }; | ||
| 31 | |||
| 32 | pub 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 | |||
| 27 | pub const load_command = extern struct { | 40 | pub 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. |
| 1041 | pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000; | 1054 | pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000; |
| 1042 | 1055 | ||
| 1056 | // Constants for the flags field of the fat_header | ||
| 1057 | |||
| 1058 | /// the fat magic number | ||
| 1059 | pub const FAT_MAGIC = 0xcafebabe; | ||
| 1060 | |||
| 1061 | /// NXSwapLong(FAT_MAGIC) | ||
| 1062 | pub const FAT_CIGAM = 0xbebafeca; | ||
| 1063 | |||
| 1064 | /// the 64-bit fat magic number | ||
| 1065 | pub const FAT_MAGIC_64 = 0xcafebabf; | ||
| 1066 | |||
| 1067 | /// NXSwapLong(FAT_MAGIC_64) | ||
| 1068 | pub const FAT_CIGAM_64 = 0xbfbafeca; | ||
| 1069 | |||
| 1043 | /// The flags field of a section structure is separated into two parts a section | 1070 | /// 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 (it | 1071 | /// 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 more | 1072 | /// 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 | } |
| 1541 | 1541 | ||
| 1542 | /// Swap the byte order of all the members of the fields of a struct | ||
| 1543 | /// (Changing their endianess) | ||
| 1544 | pub 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 | |||
| 1551 | test "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 not | 1570 | /// 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 @@ |
| 1 | const Dylib = @This(); | 1 | const Dylib = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const builtin = std.builtin; | ||
| 4 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 5 | const fs = std.fs; | 6 | const fs = std.fs; |
| 6 | const fmt = std.fmt; | 7 | const fmt = std.fmt; |
| ... | @@ -8,6 +9,7 @@ const log = std.log.scoped(.dylib); | ... | @@ -8,6 +9,7 @@ const log = std.log.scoped(.dylib); |
| 8 | const macho = std.macho; | 9 | const macho = std.macho; |
| 9 | const math = std.math; | 10 | const math = std.math; |
| 10 | const mem = std.mem; | 11 | const mem = std.mem; |
| 12 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 11 | 13 | ||
| 12 | const Allocator = mem.Allocator; | 14 | const Allocator = mem.Allocator; |
| 13 | const Arch = std.Target.Cpu.Arch; | 15 | const Arch = std.Target.Cpu.Arch; |
| ... | @@ -26,6 +28,10 @@ syslibroot: ?[]const u8 = null, | ... | @@ -26,6 +28,10 @@ syslibroot: ?[]const u8 = null, |
| 26 | 28 | ||
| 27 | ordinal: ?u16 = null, | 29 | ordinal: ?u16 = null, |
| 28 | 30 | ||
| 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 | ||
| 33 | library_offset: u64 = 0, | ||
| 34 | |||
| 29 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 35 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 30 | 36 | ||
| 31 | symtab_cmd_index: ?u16 = null, | 37 | symtab_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 | } |
| 207 | 213 | ||
| 214 | fn 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 | |||
| 208 | pub fn parse(self: *Dylib) !void { | 225 | pub fn parse(self: *Dylib) !void { |
| 209 | log.debug("parsing shared library '{s}'", .{self.name.?}); | 226 | log.debug("parsing shared library '{s}'", .{self.name.?}); |
| 210 | 227 | ||
| 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); |
| 213 | 255 | ||
| ... | @@ -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 | } |
| 218 | 260 | ||
| 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 | } |
| 236 | 278 | ||
| 279 | fn 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 | |||
| 237 | fn readLoadCommands(self: *Dylib, reader: anytype) !void { | 289 | fn 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); |
| 239 | 291 | ||
| ... | @@ -285,12 +337,12 @@ fn parseSymbols(self: *Dylib) !void { | ... | @@ -285,12 +337,12 @@ fn parseSymbols(self: *Dylib) !void { |
| 285 | 337 | ||
| 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)); |
| 290 | 342 | ||
| 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); |
| 294 | 346 | ||
| 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 | } |
| 249 | 249 | ||
| 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 | }); | ||
| 257 | 251 | ||
| 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 | } |
| 260 | 256 | ||
| 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 | } |
| 273 | 269 | ||
| 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(); |