| author | |
| committer | |
| log | 75f3e7a4a05db7ea805e581f78117a41768945ae |
| tree | 6972d08f0c0292d27ebb1e8a74bc7c9a3087feae |
| parent | 77836e08a2384450b5e7933094511b61e3c22140 |
| parent | 828f61e8dfcf17e0f7c42552311e6589bb187880 |
| signature |
macho: move load command wrappers and parsing utils to std.macho8 files changed, 723 insertions(+), 757 deletions(-)
CMakeLists.txt-1| ... | @@ -590,7 +590,6 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -590,7 +590,6 @@ set(ZIG_STAGE2_SOURCES |
| 590 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig" | 590 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig" |
| 591 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig" | 591 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig" |
| 592 | "${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig" | 592 | "${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig" |
| 593 | "${CMAKE_SOURCE_DIR}/src/link/MachO/commands.zig" | ||
| 594 | "${CMAKE_SOURCE_DIR}/src/link/Plan9.zig" | 593 | "${CMAKE_SOURCE_DIR}/src/link/Plan9.zig" |
| 595 | "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig" | 594 | "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig" |
| 596 | "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig" | 595 | "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig" |
lib/std/macho.zig+485-8| ... | @@ -1,3 +1,13 @@ | ... | @@ -1,3 +1,13 @@ |
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const io = std.io; | ||
| 5 | const mem = std.mem; | ||
| 6 | const meta = std.meta; | ||
| 7 | const testing = std.testing; | ||
| 8 | |||
| 9 | const Allocator = mem.Allocator; | ||
| 10 | |||
| 1 | pub const mach_header = extern struct { | 11 | pub const mach_header = extern struct { |
| 2 | magic: u32, | 12 | magic: u32, |
| 3 | cputype: cpu_type_t, | 13 | cputype: cpu_type_t, |
| ... | @@ -9,14 +19,14 @@ pub const mach_header = extern struct { | ... | @@ -9,14 +19,14 @@ pub const mach_header = extern struct { |
| 9 | }; | 19 | }; |
| 10 | 20 | ||
| 11 | pub const mach_header_64 = extern struct { | 21 | pub const mach_header_64 = extern struct { |
| 12 | magic: u32, | 22 | magic: u32 = MH_MAGIC_64, |
| 13 | cputype: cpu_type_t, | 23 | cputype: cpu_type_t = 0, |
| 14 | cpusubtype: cpu_subtype_t, | 24 | cpusubtype: cpu_subtype_t = 0, |
| 15 | filetype: u32, | 25 | filetype: u32 = 0, |
| 16 | ncmds: u32, | 26 | ncmds: u32 = 0, |
| 17 | sizeofcmds: u32, | 27 | sizeofcmds: u32 = 0, |
| 18 | flags: u32, | 28 | flags: u32 = 0, |
| 19 | reserved: u32, | 29 | reserved: u32 = 0, |
| 20 | }; | 30 | }; |
| 21 | 31 | ||
| 22 | pub const fat_header = extern struct { | 32 | pub const fat_header = extern struct { |
| ... | @@ -630,6 +640,10 @@ pub const segment_command_64 = extern struct { | ... | @@ -630,6 +640,10 @@ pub const segment_command_64 = extern struct { |
| 630 | /// number of sections in segment | 640 | /// number of sections in segment |
| 631 | nsects: u32 = 0, | 641 | nsects: u32 = 0, |
| 632 | flags: u32 = 0, | 642 | flags: u32 = 0, |
| 643 | |||
| 644 | pub fn segName(seg: segment_command_64) []const u8 { | ||
| 645 | return parseName(&seg.segname); | ||
| 646 | } | ||
| 633 | }; | 647 | }; |
| 634 | 648 | ||
| 635 | /// A segment is made up of zero or more sections. Non-MH_OBJECT files have | 649 | /// A segment is made up of zero or more sections. Non-MH_OBJECT files have |
| ... | @@ -728,8 +742,46 @@ pub const section_64 = extern struct { | ... | @@ -728,8 +742,46 @@ pub const section_64 = extern struct { |
| 728 | 742 | ||
| 729 | /// reserved | 743 | /// reserved |
| 730 | reserved3: u32 = 0, | 744 | reserved3: u32 = 0, |
| 745 | |||
| 746 | pub fn sectName(sect: section_64) []const u8 { | ||
| 747 | return parseName(&sect.sectname); | ||
| 748 | } | ||
| 749 | |||
| 750 | pub fn segName(sect: section_64) []const u8 { | ||
| 751 | return parseName(&sect.segname); | ||
| 752 | } | ||
| 753 | |||
| 754 | pub fn type_(sect: section_64) u8 { | ||
| 755 | return @truncate(u8, sect.flags & 0xff); | ||
| 756 | } | ||
| 757 | |||
| 758 | pub fn attrs(sect: section_64) u32 { | ||
| 759 | return sect.flags & 0xffffff00; | ||
| 760 | } | ||
| 761 | |||
| 762 | pub fn isCode(sect: section_64) bool { | ||
| 763 | const attr = sect.attrs(); | ||
| 764 | return attr & S_ATTR_PURE_INSTRUCTIONS != 0 or attr & S_ATTR_SOME_INSTRUCTIONS != 0; | ||
| 765 | } | ||
| 766 | |||
| 767 | pub fn isDebug(sect: section_64) bool { | ||
| 768 | return sect.attrs() & S_ATTR_DEBUG != 0; | ||
| 769 | } | ||
| 770 | |||
| 771 | pub fn isDontDeadStrip(sect: section_64) bool { | ||
| 772 | return sect.attrs() & S_ATTR_NO_DEAD_STRIP != 0; | ||
| 773 | } | ||
| 774 | |||
| 775 | pub fn isDontDeadStripIfReferencesLive(sect: section_64) bool { | ||
| 776 | return sect.attrs() & S_ATTR_LIVE_SUPPORT != 0; | ||
| 777 | } | ||
| 731 | }; | 778 | }; |
| 732 | 779 | ||
| 780 | fn parseName(name: *const [16]u8) []const u8 { | ||
| 781 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; | ||
| 782 | return name[0..len]; | ||
| 783 | } | ||
| 784 | |||
| 733 | pub const nlist = extern struct { | 785 | pub const nlist = extern struct { |
| 734 | n_strx: u32, | 786 | n_strx: u32, |
| 735 | n_type: u8, | 787 | n_type: u8, |
| ... | @@ -1760,3 +1812,428 @@ pub const data_in_code_entry = extern struct { | ... | @@ -1760,3 +1812,428 @@ pub const data_in_code_entry = extern struct { |
| 1760 | /// A DICE_KIND value. | 1812 | /// A DICE_KIND value. |
| 1761 | kind: u16, | 1813 | kind: u16, |
| 1762 | }; | 1814 | }; |
| 1815 | |||
| 1816 | /// A Zig wrapper for all known MachO load commands. | ||
| 1817 | /// Provides interface to read and write the load command data to a buffer. | ||
| 1818 | pub const LoadCommand = union(enum) { | ||
| 1819 | segment: SegmentCommand, | ||
| 1820 | dyld_info_only: dyld_info_command, | ||
| 1821 | symtab: symtab_command, | ||
| 1822 | dysymtab: dysymtab_command, | ||
| 1823 | dylinker: GenericCommandWithData(dylinker_command), | ||
| 1824 | dylib: GenericCommandWithData(dylib_command), | ||
| 1825 | main: entry_point_command, | ||
| 1826 | version_min: version_min_command, | ||
| 1827 | source_version: source_version_command, | ||
| 1828 | build_version: GenericCommandWithData(build_version_command), | ||
| 1829 | uuid: uuid_command, | ||
| 1830 | linkedit_data: linkedit_data_command, | ||
| 1831 | rpath: GenericCommandWithData(rpath_command), | ||
| 1832 | unknown: GenericCommandWithData(load_command), | ||
| 1833 | |||
| 1834 | pub fn read(allocator: Allocator, reader: anytype) !LoadCommand { | ||
| 1835 | const header = try reader.readStruct(load_command); | ||
| 1836 | var buffer = try allocator.alloc(u8, header.cmdsize); | ||
| 1837 | defer allocator.free(buffer); | ||
| 1838 | mem.copy(u8, buffer, mem.asBytes(&header)); | ||
| 1839 | try reader.readNoEof(buffer[@sizeOf(load_command)..]); | ||
| 1840 | var stream = io.fixedBufferStream(buffer); | ||
| 1841 | |||
| 1842 | return switch (header.cmd) { | ||
| 1843 | LC_SEGMENT_64 => LoadCommand{ | ||
| 1844 | .segment = try SegmentCommand.read(allocator, stream.reader()), | ||
| 1845 | }, | ||
| 1846 | LC_DYLD_INFO, LC_DYLD_INFO_ONLY => LoadCommand{ | ||
| 1847 | .dyld_info_only = try stream.reader().readStruct(dyld_info_command), | ||
| 1848 | }, | ||
| 1849 | LC_SYMTAB => LoadCommand{ | ||
| 1850 | .symtab = try stream.reader().readStruct(symtab_command), | ||
| 1851 | }, | ||
| 1852 | LC_DYSYMTAB => LoadCommand{ | ||
| 1853 | .dysymtab = try stream.reader().readStruct(dysymtab_command), | ||
| 1854 | }, | ||
| 1855 | LC_ID_DYLINKER, LC_LOAD_DYLINKER, LC_DYLD_ENVIRONMENT => LoadCommand{ | ||
| 1856 | .dylinker = try GenericCommandWithData(dylinker_command).read(allocator, stream.reader()), | ||
| 1857 | }, | ||
| 1858 | LC_ID_DYLIB, LC_LOAD_WEAK_DYLIB, LC_LOAD_DYLIB, LC_REEXPORT_DYLIB => LoadCommand{ | ||
| 1859 | .dylib = try GenericCommandWithData(dylib_command).read(allocator, stream.reader()), | ||
| 1860 | }, | ||
| 1861 | LC_MAIN => LoadCommand{ | ||
| 1862 | .main = try stream.reader().readStruct(entry_point_command), | ||
| 1863 | }, | ||
| 1864 | LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_WATCHOS, LC_VERSION_MIN_TVOS => LoadCommand{ | ||
| 1865 | .version_min = try stream.reader().readStruct(version_min_command), | ||
| 1866 | }, | ||
| 1867 | LC_SOURCE_VERSION => LoadCommand{ | ||
| 1868 | .source_version = try stream.reader().readStruct(source_version_command), | ||
| 1869 | }, | ||
| 1870 | LC_BUILD_VERSION => LoadCommand{ | ||
| 1871 | .build_version = try GenericCommandWithData(build_version_command).read(allocator, stream.reader()), | ||
| 1872 | }, | ||
| 1873 | LC_UUID => LoadCommand{ | ||
| 1874 | .uuid = try stream.reader().readStruct(uuid_command), | ||
| 1875 | }, | ||
| 1876 | LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_CODE_SIGNATURE => LoadCommand{ | ||
| 1877 | .linkedit_data = try stream.reader().readStruct(linkedit_data_command), | ||
| 1878 | }, | ||
| 1879 | LC_RPATH => LoadCommand{ | ||
| 1880 | .rpath = try GenericCommandWithData(rpath_command).read(allocator, stream.reader()), | ||
| 1881 | }, | ||
| 1882 | else => LoadCommand{ | ||
| 1883 | .unknown = try GenericCommandWithData(load_command).read(allocator, stream.reader()), | ||
| 1884 | }, | ||
| 1885 | }; | ||
| 1886 | } | ||
| 1887 | |||
| 1888 | pub fn write(self: LoadCommand, writer: anytype) !void { | ||
| 1889 | return switch (self) { | ||
| 1890 | .dyld_info_only => |x| writeStruct(x, writer), | ||
| 1891 | .symtab => |x| writeStruct(x, writer), | ||
| 1892 | .dysymtab => |x| writeStruct(x, writer), | ||
| 1893 | .main => |x| writeStruct(x, writer), | ||
| 1894 | .version_min => |x| writeStruct(x, writer), | ||
| 1895 | .source_version => |x| writeStruct(x, writer), | ||
| 1896 | .uuid => |x| writeStruct(x, writer), | ||
| 1897 | .linkedit_data => |x| writeStruct(x, writer), | ||
| 1898 | .segment => |x| x.write(writer), | ||
| 1899 | .dylinker => |x| x.write(writer), | ||
| 1900 | .dylib => |x| x.write(writer), | ||
| 1901 | .rpath => |x| x.write(writer), | ||
| 1902 | .build_version => |x| x.write(writer), | ||
| 1903 | .unknown => |x| x.write(writer), | ||
| 1904 | }; | ||
| 1905 | } | ||
| 1906 | |||
| 1907 | pub fn cmd(self: LoadCommand) u32 { | ||
| 1908 | return switch (self) { | ||
| 1909 | .dyld_info_only => |x| x.cmd, | ||
| 1910 | .symtab => |x| x.cmd, | ||
| 1911 | .dysymtab => |x| x.cmd, | ||
| 1912 | .main => |x| x.cmd, | ||
| 1913 | .version_min => |x| x.cmd, | ||
| 1914 | .source_version => |x| x.cmd, | ||
| 1915 | .uuid => |x| x.cmd, | ||
| 1916 | .linkedit_data => |x| x.cmd, | ||
| 1917 | .segment => |x| x.inner.cmd, | ||
| 1918 | .dylinker => |x| x.inner.cmd, | ||
| 1919 | .dylib => |x| x.inner.cmd, | ||
| 1920 | .rpath => |x| x.inner.cmd, | ||
| 1921 | .build_version => |x| x.inner.cmd, | ||
| 1922 | .unknown => |x| x.inner.cmd, | ||
| 1923 | }; | ||
| 1924 | } | ||
| 1925 | |||
| 1926 | pub fn cmdsize(self: LoadCommand) u32 { | ||
| 1927 | return switch (self) { | ||
| 1928 | .dyld_info_only => |x| x.cmdsize, | ||
| 1929 | .symtab => |x| x.cmdsize, | ||
| 1930 | .dysymtab => |x| x.cmdsize, | ||
| 1931 | .main => |x| x.cmdsize, | ||
| 1932 | .version_min => |x| x.cmdsize, | ||
| 1933 | .source_version => |x| x.cmdsize, | ||
| 1934 | .linkedit_data => |x| x.cmdsize, | ||
| 1935 | .uuid => |x| x.cmdsize, | ||
| 1936 | .segment => |x| x.inner.cmdsize, | ||
| 1937 | .dylinker => |x| x.inner.cmdsize, | ||
| 1938 | .dylib => |x| x.inner.cmdsize, | ||
| 1939 | .rpath => |x| x.inner.cmdsize, | ||
| 1940 | .build_version => |x| x.inner.cmdsize, | ||
| 1941 | .unknown => |x| x.inner.cmdsize, | ||
| 1942 | }; | ||
| 1943 | } | ||
| 1944 | |||
| 1945 | pub fn deinit(self: *LoadCommand, allocator: Allocator) void { | ||
| 1946 | return switch (self.*) { | ||
| 1947 | .segment => |*x| x.deinit(allocator), | ||
| 1948 | .dylinker => |*x| x.deinit(allocator), | ||
| 1949 | .dylib => |*x| x.deinit(allocator), | ||
| 1950 | .rpath => |*x| x.deinit(allocator), | ||
| 1951 | .build_version => |*x| x.deinit(allocator), | ||
| 1952 | .unknown => |*x| x.deinit(allocator), | ||
| 1953 | else => {}, | ||
| 1954 | }; | ||
| 1955 | } | ||
| 1956 | |||
| 1957 | fn writeStruct(command: anytype, writer: anytype) !void { | ||
| 1958 | return writer.writeAll(mem.asBytes(&command)); | ||
| 1959 | } | ||
| 1960 | |||
| 1961 | pub fn eql(self: LoadCommand, other: LoadCommand) bool { | ||
| 1962 | if (@as(meta.Tag(LoadCommand), self) != @as(meta.Tag(LoadCommand), other)) return false; | ||
| 1963 | return switch (self) { | ||
| 1964 | .dyld_info_only => |x| meta.eql(x, other.dyld_info_only), | ||
| 1965 | .symtab => |x| meta.eql(x, other.symtab), | ||
| 1966 | .dysymtab => |x| meta.eql(x, other.dysymtab), | ||
| 1967 | .main => |x| meta.eql(x, other.main), | ||
| 1968 | .version_min => |x| meta.eql(x, other.version_min), | ||
| 1969 | .source_version => |x| meta.eql(x, other.source_version), | ||
| 1970 | .build_version => |x| x.eql(other.build_version), | ||
| 1971 | .uuid => |x| meta.eql(x, other.uuid), | ||
| 1972 | .linkedit_data => |x| meta.eql(x, other.linkedit_data), | ||
| 1973 | .segment => |x| x.eql(other.segment), | ||
| 1974 | .dylinker => |x| x.eql(other.dylinker), | ||
| 1975 | .dylib => |x| x.eql(other.dylib), | ||
| 1976 | .rpath => |x| x.eql(other.rpath), | ||
| 1977 | .unknown => |x| x.eql(other.unknown), | ||
| 1978 | }; | ||
| 1979 | } | ||
| 1980 | }; | ||
| 1981 | |||
| 1982 | /// A Zig wrapper for segment_command_64. | ||
| 1983 | /// Encloses the extern struct together with a list of sections for this segment. | ||
| 1984 | pub const SegmentCommand = struct { | ||
| 1985 | inner: segment_command_64, | ||
| 1986 | sections: std.ArrayListUnmanaged(section_64) = .{}, | ||
| 1987 | |||
| 1988 | pub fn read(allocator: Allocator, reader: anytype) !SegmentCommand { | ||
| 1989 | const inner = try reader.readStruct(segment_command_64); | ||
| 1990 | var segment = SegmentCommand{ | ||
| 1991 | .inner = inner, | ||
| 1992 | }; | ||
| 1993 | try segment.sections.ensureTotalCapacityPrecise(allocator, inner.nsects); | ||
| 1994 | |||
| 1995 | var i: usize = 0; | ||
| 1996 | while (i < inner.nsects) : (i += 1) { | ||
| 1997 | const sect = try reader.readStruct(section_64); | ||
| 1998 | segment.sections.appendAssumeCapacity(sect); | ||
| 1999 | } | ||
| 2000 | |||
| 2001 | return segment; | ||
| 2002 | } | ||
| 2003 | |||
| 2004 | pub fn write(self: SegmentCommand, writer: anytype) !void { | ||
| 2005 | try writer.writeAll(mem.asBytes(&self.inner)); | ||
| 2006 | for (self.sections.items) |sect| { | ||
| 2007 | try writer.writeAll(mem.asBytes(&sect)); | ||
| 2008 | } | ||
| 2009 | } | ||
| 2010 | |||
| 2011 | pub fn deinit(self: *SegmentCommand, allocator: Allocator) void { | ||
| 2012 | self.sections.deinit(allocator); | ||
| 2013 | } | ||
| 2014 | |||
| 2015 | pub fn eql(self: SegmentCommand, other: SegmentCommand) bool { | ||
| 2016 | if (!meta.eql(self.inner, other.inner)) return false; | ||
| 2017 | const lhs = self.sections.items; | ||
| 2018 | const rhs = other.sections.items; | ||
| 2019 | var i: usize = 0; | ||
| 2020 | while (i < self.inner.nsects) : (i += 1) { | ||
| 2021 | if (!meta.eql(lhs[i], rhs[i])) return false; | ||
| 2022 | } | ||
| 2023 | return true; | ||
| 2024 | } | ||
| 2025 | }; | ||
| 2026 | |||
| 2027 | pub fn emptyGenericCommandWithData(cmd: anytype) GenericCommandWithData(@TypeOf(cmd)) { | ||
| 2028 | return .{ .inner = cmd }; | ||
| 2029 | } | ||
| 2030 | |||
| 2031 | /// A Zig wrapper for a generic load command with variable-length data. | ||
| 2032 | pub fn GenericCommandWithData(comptime Cmd: type) type { | ||
| 2033 | return struct { | ||
| 2034 | inner: Cmd, | ||
| 2035 | /// This field remains undefined until `read` is called. | ||
| 2036 | data: []u8 = undefined, | ||
| 2037 | |||
| 2038 | const Self = @This(); | ||
| 2039 | |||
| 2040 | pub fn read(allocator: Allocator, reader: anytype) !Self { | ||
| 2041 | const inner = try reader.readStruct(Cmd); | ||
| 2042 | var data = try allocator.alloc(u8, inner.cmdsize - @sizeOf(Cmd)); | ||
| 2043 | errdefer allocator.free(data); | ||
| 2044 | try reader.readNoEof(data); | ||
| 2045 | return Self{ | ||
| 2046 | .inner = inner, | ||
| 2047 | .data = data, | ||
| 2048 | }; | ||
| 2049 | } | ||
| 2050 | |||
| 2051 | pub fn write(self: Self, writer: anytype) !void { | ||
| 2052 | try writer.writeAll(mem.asBytes(&self.inner)); | ||
| 2053 | try writer.writeAll(self.data); | ||
| 2054 | } | ||
| 2055 | |||
| 2056 | pub fn deinit(self: *Self, allocator: Allocator) void { | ||
| 2057 | allocator.free(self.data); | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | pub fn eql(self: Self, other: Self) bool { | ||
| 2061 | if (!meta.eql(self.inner, other.inner)) return false; | ||
| 2062 | return mem.eql(u8, self.data, other.data); | ||
| 2063 | } | ||
| 2064 | }; | ||
| 2065 | } | ||
| 2066 | |||
| 2067 | pub fn createLoadDylibCommand( | ||
| 2068 | allocator: Allocator, | ||
| 2069 | name: []const u8, | ||
| 2070 | timestamp: u32, | ||
| 2071 | current_version: u32, | ||
| 2072 | compatibility_version: u32, | ||
| 2073 | ) !GenericCommandWithData(dylib_command) { | ||
| 2074 | const cmdsize = @intCast(u32, mem.alignForwardGeneric( | ||
| 2075 | u64, | ||
| 2076 | @sizeOf(dylib_command) + name.len + 1, // +1 for nul | ||
| 2077 | @sizeOf(u64), | ||
| 2078 | )); | ||
| 2079 | |||
| 2080 | var dylib_cmd = emptyGenericCommandWithData(dylib_command{ | ||
| 2081 | .cmd = LC_LOAD_DYLIB, | ||
| 2082 | .cmdsize = cmdsize, | ||
| 2083 | .dylib = .{ | ||
| 2084 | .name = @sizeOf(dylib_command), | ||
| 2085 | .timestamp = timestamp, | ||
| 2086 | .current_version = current_version, | ||
| 2087 | .compatibility_version = compatibility_version, | ||
| 2088 | }, | ||
| 2089 | }); | ||
| 2090 | dylib_cmd.data = try allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); | ||
| 2091 | |||
| 2092 | mem.set(u8, dylib_cmd.data, 0); | ||
| 2093 | mem.copy(u8, dylib_cmd.data, name); | ||
| 2094 | |||
| 2095 | return dylib_cmd; | ||
| 2096 | } | ||
| 2097 | |||
| 2098 | fn testRead(allocator: Allocator, buffer: []const u8, expected: anytype) !void { | ||
| 2099 | var stream = io.fixedBufferStream(buffer); | ||
| 2100 | var given = try LoadCommand.read(allocator, stream.reader()); | ||
| 2101 | defer given.deinit(allocator); | ||
| 2102 | try testing.expect(expected.eql(given)); | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | fn testWrite(buffer: []u8, cmd: LoadCommand, expected: []const u8) !void { | ||
| 2106 | var stream = io.fixedBufferStream(buffer); | ||
| 2107 | try cmd.write(stream.writer()); | ||
| 2108 | try testing.expect(mem.eql(u8, expected, buffer[0..expected.len])); | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | fn makeStaticString(bytes: []const u8) [16]u8 { | ||
| 2112 | var buf = [_]u8{0} ** 16; | ||
| 2113 | assert(bytes.len <= buf.len); | ||
| 2114 | mem.copy(u8, &buf, bytes); | ||
| 2115 | return buf; | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | test "read-write segment command" { | ||
| 2119 | // TODO compiling for macOS from big-endian arch | ||
| 2120 | if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest; | ||
| 2121 | |||
| 2122 | var gpa = testing.allocator; | ||
| 2123 | const in_buffer = &[_]u8{ | ||
| 2124 | 0x19, 0x00, 0x00, 0x00, // cmd | ||
| 2125 | 0x98, 0x00, 0x00, 0x00, // cmdsize | ||
| 2126 | 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname | ||
| 2127 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // vmaddr | ||
| 2128 | 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // vmsize | ||
| 2129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // fileoff | ||
| 2130 | 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // filesize | ||
| 2131 | 0x07, 0x00, 0x00, 0x00, // maxprot | ||
| 2132 | 0x05, 0x00, 0x00, 0x00, // initprot | ||
| 2133 | 0x01, 0x00, 0x00, 0x00, // nsects | ||
| 2134 | 0x00, 0x00, 0x00, 0x00, // flags | ||
| 2135 | 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sectname | ||
| 2136 | 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname | ||
| 2137 | 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // address | ||
| 2138 | 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size | ||
| 2139 | 0x00, 0x40, 0x00, 0x00, // offset | ||
| 2140 | 0x02, 0x00, 0x00, 0x00, // alignment | ||
| 2141 | 0x00, 0x00, 0x00, 0x00, // reloff | ||
| 2142 | 0x00, 0x00, 0x00, 0x00, // nreloc | ||
| 2143 | 0x00, 0x04, 0x00, 0x80, // flags | ||
| 2144 | 0x00, 0x00, 0x00, 0x00, // reserved1 | ||
| 2145 | 0x00, 0x00, 0x00, 0x00, // reserved2 | ||
| 2146 | 0x00, 0x00, 0x00, 0x00, // reserved3 | ||
| 2147 | }; | ||
| 2148 | var cmd = SegmentCommand{ | ||
| 2149 | .inner = .{ | ||
| 2150 | .cmdsize = 152, | ||
| 2151 | .segname = makeStaticString("__TEXT"), | ||
| 2152 | .vmaddr = 4294967296, | ||
| 2153 | .vmsize = 294912, | ||
| 2154 | .filesize = 294912, | ||
| 2155 | .maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, | ||
| 2156 | .initprot = VM_PROT_EXECUTE | VM_PROT_READ, | ||
| 2157 | .nsects = 1, | ||
| 2158 | }, | ||
| 2159 | }; | ||
| 2160 | try cmd.sections.append(gpa, .{ | ||
| 2161 | .sectname = makeStaticString("__text"), | ||
| 2162 | .segname = makeStaticString("__TEXT"), | ||
| 2163 | .addr = 4294983680, | ||
| 2164 | .size = 448, | ||
| 2165 | .offset = 16384, | ||
| 2166 | .@"align" = 2, | ||
| 2167 | .flags = S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS, | ||
| 2168 | }); | ||
| 2169 | defer cmd.deinit(gpa); | ||
| 2170 | try testRead(gpa, in_buffer, LoadCommand{ .segment = cmd }); | ||
| 2171 | |||
| 2172 | var out_buffer: [in_buffer.len]u8 = undefined; | ||
| 2173 | try testWrite(&out_buffer, LoadCommand{ .segment = cmd }, in_buffer); | ||
| 2174 | } | ||
| 2175 | |||
| 2176 | test "read-write generic command with data" { | ||
| 2177 | // TODO compiling for macOS from big-endian arch | ||
| 2178 | if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest; | ||
| 2179 | |||
| 2180 | var gpa = testing.allocator; | ||
| 2181 | const in_buffer = &[_]u8{ | ||
| 2182 | 0x0c, 0x00, 0x00, 0x00, // cmd | ||
| 2183 | 0x20, 0x00, 0x00, 0x00, // cmdsize | ||
| 2184 | 0x18, 0x00, 0x00, 0x00, // name | ||
| 2185 | 0x02, 0x00, 0x00, 0x00, // timestamp | ||
| 2186 | 0x00, 0x00, 0x00, 0x00, // current_version | ||
| 2187 | 0x00, 0x00, 0x00, 0x00, // compatibility_version | ||
| 2188 | 0x2f, 0x75, 0x73, 0x72, 0x00, 0x00, 0x00, 0x00, // data | ||
| 2189 | }; | ||
| 2190 | var cmd = GenericCommandWithData(dylib_command){ | ||
| 2191 | .inner = .{ | ||
| 2192 | .cmd = LC_LOAD_DYLIB, | ||
| 2193 | .cmdsize = 32, | ||
| 2194 | .dylib = .{ | ||
| 2195 | .name = 24, | ||
| 2196 | .timestamp = 2, | ||
| 2197 | .current_version = 0, | ||
| 2198 | .compatibility_version = 0, | ||
| 2199 | }, | ||
| 2200 | }, | ||
| 2201 | }; | ||
| 2202 | cmd.data = try gpa.alloc(u8, 8); | ||
| 2203 | defer gpa.free(cmd.data); | ||
| 2204 | cmd.data[0] = 0x2f; | ||
| 2205 | cmd.data[1] = 0x75; | ||
| 2206 | cmd.data[2] = 0x73; | ||
| 2207 | cmd.data[3] = 0x72; | ||
| 2208 | cmd.data[4] = 0x0; | ||
| 2209 | cmd.data[5] = 0x0; | ||
| 2210 | cmd.data[6] = 0x0; | ||
| 2211 | cmd.data[7] = 0x0; | ||
| 2212 | try testRead(gpa, in_buffer, LoadCommand{ .dylib = cmd }); | ||
| 2213 | |||
| 2214 | var out_buffer: [in_buffer.len]u8 = undefined; | ||
| 2215 | try testWrite(&out_buffer, LoadCommand{ .dylib = cmd }, in_buffer); | ||
| 2216 | } | ||
| 2217 | |||
| 2218 | test "read-write C struct command" { | ||
| 2219 | // TODO compiling for macOS from big-endian arch | ||
| 2220 | if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest; | ||
| 2221 | |||
| 2222 | var gpa = testing.allocator; | ||
| 2223 | const in_buffer = &[_]u8{ | ||
| 2224 | 0x28, 0x00, 0x00, 0x80, // cmd | ||
| 2225 | 0x18, 0x00, 0x00, 0x00, // cmdsize | ||
| 2226 | 0x04, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // entryoff | ||
| 2227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // stacksize | ||
| 2228 | }; | ||
| 2229 | const cmd = .{ | ||
| 2230 | .cmd = LC_MAIN, | ||
| 2231 | .cmdsize = 24, | ||
| 2232 | .entryoff = 16644, | ||
| 2233 | .stacksize = 0, | ||
| 2234 | }; | ||
| 2235 | try testRead(gpa, in_buffer, LoadCommand{ .main = cmd }); | ||
| 2236 | |||
| 2237 | var out_buffer: [in_buffer.len]u8 = undefined; | ||
| 2238 | try testWrite(&out_buffer, LoadCommand{ .main = cmd }, in_buffer); | ||
| 2239 | } |
src/link/MachO.zig+121-131| ... | @@ -15,7 +15,6 @@ const meta = std.meta; | ... | @@ -15,7 +15,6 @@ const meta = std.meta; |
| 15 | const aarch64 = @import("../arch/aarch64/bits.zig"); | 15 | const aarch64 = @import("../arch/aarch64/bits.zig"); |
| 16 | const bind = @import("MachO/bind.zig"); | 16 | const bind = @import("MachO/bind.zig"); |
| 17 | const codegen = @import("../codegen.zig"); | 17 | const codegen = @import("../codegen.zig"); |
| 18 | const commands = @import("MachO/commands.zig"); | ||
| 19 | const link = @import("../link.zig"); | 18 | const link = @import("../link.zig"); |
| 20 | const llvm_backend = @import("../codegen/llvm.zig"); | 19 | const llvm_backend = @import("../codegen/llvm.zig"); |
| 21 | const target_util = @import("../target.zig"); | 20 | const target_util = @import("../target.zig"); |
| ... | @@ -35,9 +34,7 @@ const Object = @import("MachO/Object.zig"); | ... | @@ -35,9 +34,7 @@ const Object = @import("MachO/Object.zig"); |
| 35 | const LibStub = @import("tapi.zig").LibStub; | 34 | const LibStub = @import("tapi.zig").LibStub; |
| 36 | const Liveness = @import("../Liveness.zig"); | 35 | const Liveness = @import("../Liveness.zig"); |
| 37 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 36 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 38 | const LoadCommand = commands.LoadCommand; | ||
| 39 | const Module = @import("../Module.zig"); | 37 | const Module = @import("../Module.zig"); |
| 40 | const SegmentCommand = commands.SegmentCommand; | ||
| 41 | const StringIndexAdapter = std.hash_map.StringIndexAdapter; | 38 | const StringIndexAdapter = std.hash_map.StringIndexAdapter; |
| 42 | const StringIndexContext = std.hash_map.StringIndexContext; | 39 | const StringIndexContext = std.hash_map.StringIndexContext; |
| 43 | const Trie = @import("MachO/Trie.zig"); | 40 | const Trie = @import("MachO/Trie.zig"); |
| ... | @@ -83,7 +80,7 @@ dylibs: std.ArrayListUnmanaged(Dylib) = .{}, | ... | @@ -83,7 +80,7 @@ dylibs: std.ArrayListUnmanaged(Dylib) = .{}, |
| 83 | dylibs_map: std.StringHashMapUnmanaged(u16) = .{}, | 80 | dylibs_map: std.StringHashMapUnmanaged(u16) = .{}, |
| 84 | referenced_dylibs: std.AutoArrayHashMapUnmanaged(u16, void) = .{}, | 81 | referenced_dylibs: std.AutoArrayHashMapUnmanaged(u16, void) = .{}, |
| 85 | 82 | ||
| 86 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 83 | load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{}, |
| 87 | 84 | ||
| 88 | pagezero_segment_cmd_index: ?u16 = null, | 85 | pagezero_segment_cmd_index: ?u16 = null, |
| 89 | text_segment_cmd_index: ?u16 = null, | 86 | text_segment_cmd_index: ?u16 = null, |
| ... | @@ -783,7 +780,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -783,7 +780,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 783 | @sizeOf(macho.rpath_command) + rpath.len + 1, | 780 | @sizeOf(macho.rpath_command) + rpath.len + 1, |
| 784 | @sizeOf(u64), | 781 | @sizeOf(u64), |
| 785 | )); | 782 | )); |
| 786 | var rpath_cmd = commands.emptyGenericCommandWithData(macho.rpath_command{ | 783 | var rpath_cmd = macho.emptyGenericCommandWithData(macho.rpath_command{ |
| 787 | .cmd = macho.LC_RPATH, | 784 | .cmd = macho.LC_RPATH, |
| 788 | .cmdsize = cmdsize, | 785 | .cmdsize = cmdsize, |
| 789 | .path = @sizeOf(macho.rpath_command), | 786 | .path = @sizeOf(macho.rpath_command), |
| ... | @@ -791,7 +788,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -791,7 +788,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 791 | rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path); | 788 | rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path); |
| 792 | mem.set(u8, rpath_cmd.data, 0); | 789 | mem.set(u8, rpath_cmd.data, 0); |
| 793 | mem.copy(u8, rpath_cmd.data, rpath); | 790 | mem.copy(u8, rpath_cmd.data, rpath); |
| 794 | try self.load_commands.append(self.base.allocator, .{ .Rpath = rpath_cmd }); | 791 | try self.load_commands.append(self.base.allocator, .{ .rpath = rpath_cmd }); |
| 795 | try rpath_table.putNoClobber(rpath, {}); | 792 | try rpath_table.putNoClobber(rpath, {}); |
| 796 | self.load_commands_dirty = true; | 793 | self.load_commands_dirty = true; |
| 797 | } | 794 | } |
| ... | @@ -861,12 +858,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -861,12 +858,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 861 | } | 858 | } |
| 862 | 859 | ||
| 863 | if (self.bss_section_index) |idx| { | 860 | if (self.bss_section_index) |idx| { |
| 864 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 861 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 865 | const sect = &seg.sections.items[idx]; | 862 | const sect = &seg.sections.items[idx]; |
| 866 | sect.offset = self.bss_file_offset; | 863 | sect.offset = self.bss_file_offset; |
| 867 | } | 864 | } |
| 868 | if (self.tlv_bss_section_index) |idx| { | 865 | if (self.tlv_bss_section_index) |idx| { |
| 869 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 866 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 870 | const sect = &seg.sections.items[idx]; | 867 | const sect = &seg.sections.items[idx]; |
| 871 | sect.offset = self.tlv_bss_file_offset; | 868 | sect.offset = self.tlv_bss_file_offset; |
| 872 | } | 869 | } |
| ... | @@ -942,13 +939,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -942,13 +939,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 942 | } | 939 | } |
| 943 | 940 | ||
| 944 | if (self.bss_section_index) |idx| { | 941 | if (self.bss_section_index) |idx| { |
| 945 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 942 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 946 | const sect = &seg.sections.items[idx]; | 943 | const sect = &seg.sections.items[idx]; |
| 947 | self.bss_file_offset = sect.offset; | 944 | self.bss_file_offset = sect.offset; |
| 948 | sect.offset = 0; | 945 | sect.offset = 0; |
| 949 | } | 946 | } |
| 950 | if (self.tlv_bss_section_index) |idx| { | 947 | if (self.tlv_bss_section_index) |idx| { |
| 951 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 948 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 952 | const sect = &seg.sections.items[idx]; | 949 | const sect = &seg.sections.items[idx]; |
| 953 | self.tlv_bss_file_offset = sect.offset; | 950 | self.tlv_bss_file_offset = sect.offset; |
| 954 | sect.offset = 0; | 951 | sect.offset = 0; |
| ... | @@ -1324,10 +1321,10 @@ pub const MatchingSection = struct { | ... | @@ -1324,10 +1321,10 @@ pub const MatchingSection = struct { |
| 1324 | }; | 1321 | }; |
| 1325 | 1322 | ||
| 1326 | pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSection { | 1323 | pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSection { |
| 1327 | const segname = commands.segmentName(sect); | 1324 | const segname = sect.segName(); |
| 1328 | const sectname = commands.sectionName(sect); | 1325 | const sectname = sect.sectName(); |
| 1329 | const res: ?MatchingSection = blk: { | 1326 | const res: ?MatchingSection = blk: { |
| 1330 | switch (commands.sectionType(sect)) { | 1327 | switch (sect.type_()) { |
| 1331 | macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { | 1328 | macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { |
| 1332 | if (self.text_const_section_index == null) { | 1329 | if (self.text_const_section_index == null) { |
| 1333 | self.text_const_section_index = try self.initSection( | 1330 | self.text_const_section_index = try self.initSection( |
| ... | @@ -1579,7 +1576,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio | ... | @@ -1579,7 +1576,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1579 | }; | 1576 | }; |
| 1580 | }, | 1577 | }, |
| 1581 | macho.S_REGULAR => { | 1578 | macho.S_REGULAR => { |
| 1582 | if (commands.sectionIsCode(sect)) { | 1579 | if (sect.isCode()) { |
| 1583 | if (self.text_section_index == null) { | 1580 | if (self.text_section_index == null) { |
| 1584 | self.text_section_index = try self.initSection( | 1581 | self.text_section_index = try self.initSection( |
| 1585 | self.text_segment_cmd_index.?, | 1582 | self.text_segment_cmd_index.?, |
| ... | @@ -1599,7 +1596,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio | ... | @@ -1599,7 +1596,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1599 | .sect = self.text_section_index.?, | 1596 | .sect = self.text_section_index.?, |
| 1600 | }; | 1597 | }; |
| 1601 | } | 1598 | } |
| 1602 | if (commands.sectionIsDebug(sect)) { | 1599 | if (sect.isDebug()) { |
| 1603 | // TODO debug attributes | 1600 | // TODO debug attributes |
| 1604 | if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { | 1601 | if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { |
| 1605 | log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{ | 1602 | log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{ |
| ... | @@ -1865,7 +1862,7 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: | ... | @@ -1865,7 +1862,7 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: |
| 1865 | } | 1862 | } |
| 1866 | 1863 | ||
| 1867 | pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void { | 1864 | pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void { |
| 1868 | const seg = self.load_commands.items[match.seg].Segment; | 1865 | const seg = self.load_commands.items[match.seg].segment; |
| 1869 | const sect = seg.sections.items[match.sect]; | 1866 | const sect = seg.sections.items[match.sect]; |
| 1870 | const sym = self.locals.items[atom.local_sym_index]; | 1867 | const sym = self.locals.items[atom.local_sym_index]; |
| 1871 | const file_offset = sect.offset + sym.n_value - sect.addr; | 1868 | const file_offset = sect.offset + sym.n_value - sect.addr; |
| ... | @@ -1885,14 +1882,11 @@ fn allocateLocals(self: *MachO) !void { | ... | @@ -1885,14 +1882,11 @@ fn allocateLocals(self: *MachO) !void { |
| 1885 | } | 1882 | } |
| 1886 | 1883 | ||
| 1887 | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); | 1884 | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 1888 | const seg = self.load_commands.items[match.seg].Segment; | 1885 | const seg = self.load_commands.items[match.seg].segment; |
| 1889 | const sect = seg.sections.items[match.sect]; | 1886 | const sect = seg.sections.items[match.sect]; |
| 1890 | var base_vaddr = sect.addr; | 1887 | var base_vaddr = sect.addr; |
| 1891 | 1888 | ||
| 1892 | log.debug("allocating local symbols in {s},{s}", .{ | 1889 | log.debug("allocating local symbols in {s},{s}", .{ sect.segName(), sect.sectName() }); |
| 1893 | commands.segmentName(sect), | ||
| 1894 | commands.sectionName(sect), | ||
| 1895 | }); | ||
| 1896 | 1890 | ||
| 1897 | while (true) { | 1891 | while (true) { |
| 1898 | const alignment = try math.powi(u32, 2, atom.alignment); | 1892 | const alignment = try math.powi(u32, 2, atom.alignment); |
| ... | @@ -1979,7 +1973,7 @@ fn writeAllAtoms(self: *MachO) !void { | ... | @@ -1979,7 +1973,7 @@ fn writeAllAtoms(self: *MachO) !void { |
| 1979 | var it = self.atoms.iterator(); | 1973 | var it = self.atoms.iterator(); |
| 1980 | while (it.next()) |entry| { | 1974 | while (it.next()) |entry| { |
| 1981 | const match = entry.key_ptr.*; | 1975 | const match = entry.key_ptr.*; |
| 1982 | const seg = self.load_commands.items[match.seg].Segment; | 1976 | const seg = self.load_commands.items[match.seg].segment; |
| 1983 | const sect = seg.sections.items[match.sect]; | 1977 | const sect = seg.sections.items[match.sect]; |
| 1984 | var atom: *Atom = entry.value_ptr.*; | 1978 | var atom: *Atom = entry.value_ptr.*; |
| 1985 | 1979 | ||
| ... | @@ -1987,7 +1981,7 @@ fn writeAllAtoms(self: *MachO) !void { | ... | @@ -1987,7 +1981,7 @@ fn writeAllAtoms(self: *MachO) !void { |
| 1987 | defer buffer.deinit(); | 1981 | defer buffer.deinit(); |
| 1988 | try buffer.ensureTotalCapacity(try math.cast(usize, sect.size)); | 1982 | try buffer.ensureTotalCapacity(try math.cast(usize, sect.size)); |
| 1989 | 1983 | ||
| 1990 | log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) }); | 1984 | log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() }); |
| 1991 | 1985 | ||
| 1992 | while (atom.prev) |prev| { | 1986 | while (atom.prev) |prev| { |
| 1993 | atom = prev; | 1987 | atom = prev; |
| ... | @@ -2031,11 +2025,11 @@ fn writeAtoms(self: *MachO) !void { | ... | @@ -2031,11 +2025,11 @@ fn writeAtoms(self: *MachO) !void { |
| 2031 | var it = self.atoms.iterator(); | 2025 | var it = self.atoms.iterator(); |
| 2032 | while (it.next()) |entry| { | 2026 | while (it.next()) |entry| { |
| 2033 | const match = entry.key_ptr.*; | 2027 | const match = entry.key_ptr.*; |
| 2034 | const seg = self.load_commands.items[match.seg].Segment; | 2028 | const seg = self.load_commands.items[match.seg].segment; |
| 2035 | const sect = seg.sections.items[match.sect]; | 2029 | const sect = seg.sections.items[match.sect]; |
| 2036 | var atom: *Atom = entry.value_ptr.*; | 2030 | var atom: *Atom = entry.value_ptr.*; |
| 2037 | 2031 | ||
| 2038 | log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) }); | 2032 | log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() }); |
| 2039 | 2033 | ||
| 2040 | while (atom.prev) |prev| { | 2034 | while (atom.prev) |prev| { |
| 2041 | atom = prev; | 2035 | atom = prev; |
| ... | @@ -2995,7 +2989,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { | ... | @@ -2995,7 +2989,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2995 | 2989 | ||
| 2996 | const first_atom = atom; | 2990 | const first_atom = atom; |
| 2997 | 2991 | ||
| 2998 | const seg = self.load_commands.items[match.seg].Segment; | 2992 | const seg = self.load_commands.items[match.seg].segment; |
| 2999 | const sect = seg.sections.items[match.sect]; | 2993 | const sect = seg.sections.items[match.sect]; |
| 3000 | const metadata = try section_metadata.getOrPut(match); | 2994 | const metadata = try section_metadata.getOrPut(match); |
| 3001 | if (!metadata.found_existing) { | 2995 | if (!metadata.found_existing) { |
| ... | @@ -3005,7 +2999,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { | ... | @@ -3005,7 +2999,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 3005 | }; | 2999 | }; |
| 3006 | } | 3000 | } |
| 3007 | 3001 | ||
| 3008 | log.debug("{s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) }); | 3002 | log.debug("{s},{s}", .{ sect.segName(), sect.sectName() }); |
| 3009 | 3003 | ||
| 3010 | while (true) { | 3004 | while (true) { |
| 3011 | const alignment = try math.powi(u32, 2, atom.alignment); | 3005 | const alignment = try math.powi(u32, 2, atom.alignment); |
| ... | @@ -3046,11 +3040,11 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { | ... | @@ -3046,11 +3040,11 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 3046 | while (it.next()) |entry| { | 3040 | while (it.next()) |entry| { |
| 3047 | const match = entry.key_ptr.*; | 3041 | const match = entry.key_ptr.*; |
| 3048 | const metadata = entry.value_ptr.*; | 3042 | const metadata = entry.value_ptr.*; |
| 3049 | const seg = &self.load_commands.items[match.seg].Segment; | 3043 | const seg = &self.load_commands.items[match.seg].segment; |
| 3050 | const sect = &seg.sections.items[match.sect]; | 3044 | const sect = &seg.sections.items[match.sect]; |
| 3051 | log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{ | 3045 | log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{ |
| 3052 | commands.segmentName(sect.*), | 3046 | sect.segName(), |
| 3053 | commands.sectionName(sect.*), | 3047 | sect.sectName(), |
| 3054 | metadata.size, | 3048 | metadata.size, |
| 3055 | metadata.alignment, | 3049 | metadata.alignment, |
| 3056 | }); | 3050 | }); |
| ... | @@ -3070,7 +3064,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { | ... | @@ -3070,7 +3064,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 3070 | self.data_segment_cmd_index, | 3064 | self.data_segment_cmd_index, |
| 3071 | }) |maybe_seg_id| { | 3065 | }) |maybe_seg_id| { |
| 3072 | const seg_id = maybe_seg_id orelse continue; | 3066 | const seg_id = maybe_seg_id orelse continue; |
| 3073 | const seg = self.load_commands.items[seg_id].Segment; | 3067 | const seg = self.load_commands.items[seg_id].segment; |
| 3074 | 3068 | ||
| 3075 | for (seg.sections.items) |sect, sect_id| { | 3069 | for (seg.sections.items) |sect, sect_id| { |
| 3076 | const match = MatchingSection{ | 3070 | const match = MatchingSection{ |
| ... | @@ -3140,7 +3134,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { | ... | @@ -3140,7 +3134,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 3140 | fn addLoadDylibLC(self: *MachO, id: u16) !void { | 3134 | fn addLoadDylibLC(self: *MachO, id: u16) !void { |
| 3141 | const dylib = self.dylibs.items[id]; | 3135 | const dylib = self.dylibs.items[id]; |
| 3142 | const dylib_id = dylib.id orelse unreachable; | 3136 | const dylib_id = dylib.id orelse unreachable; |
| 3143 | var dylib_cmd = try commands.createLoadDylibCommand( | 3137 | var dylib_cmd = try macho.createLoadDylibCommand( |
| 3144 | self.base.allocator, | 3138 | self.base.allocator, |
| 3145 | dylib_id.name, | 3139 | dylib_id.name, |
| 3146 | dylib_id.timestamp, | 3140 | dylib_id.timestamp, |
| ... | @@ -3148,7 +3142,7 @@ fn addLoadDylibLC(self: *MachO, id: u16) !void { | ... | @@ -3148,7 +3142,7 @@ fn addLoadDylibLC(self: *MachO, id: u16) !void { |
| 3148 | dylib_id.compatibility_version, | 3142 | dylib_id.compatibility_version, |
| 3149 | ); | 3143 | ); |
| 3150 | errdefer dylib_cmd.deinit(self.base.allocator); | 3144 | errdefer dylib_cmd.deinit(self.base.allocator); |
| 3151 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); | 3145 | try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd }); |
| 3152 | self.load_commands_dirty = true; | 3146 | self.load_commands_dirty = true; |
| 3153 | } | 3147 | } |
| 3154 | 3148 | ||
| ... | @@ -3156,7 +3150,7 @@ fn addCodeSignatureLC(self: *MachO) !void { | ... | @@ -3156,7 +3150,7 @@ fn addCodeSignatureLC(self: *MachO) !void { |
| 3156 | if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return; | 3150 | if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return; |
| 3157 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | 3151 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3158 | try self.load_commands.append(self.base.allocator, .{ | 3152 | try self.load_commands.append(self.base.allocator, .{ |
| 3159 | .LinkeditData = .{ | 3153 | .linkedit_data = .{ |
| 3160 | .cmd = macho.LC_CODE_SIGNATURE, | 3154 | .cmd = macho.LC_CODE_SIGNATURE, |
| 3161 | .cmdsize = @sizeOf(macho.linkedit_data_command), | 3155 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 3162 | .dataoff = 0, | 3156 | .dataoff = 0, |
| ... | @@ -3171,7 +3165,7 @@ fn setEntryPoint(self: *MachO) !void { | ... | @@ -3171,7 +3165,7 @@ fn setEntryPoint(self: *MachO) !void { |
| 3171 | 3165 | ||
| 3172 | // TODO we should respect the -entry flag passed in by the user to set a custom | 3166 | // TODO we should respect the -entry flag passed in by the user to set a custom |
| 3173 | // entrypoint. For now, assume default of `_main`. | 3167 | // entrypoint. For now, assume default of `_main`. |
| 3174 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 3168 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 3175 | const n_strx = self.strtab_dir.getKeyAdapted(@as([]const u8, "_main"), StringIndexAdapter{ | 3169 | const n_strx = self.strtab_dir.getKeyAdapted(@as([]const u8, "_main"), StringIndexAdapter{ |
| 3176 | .bytes = &self.strtab, | 3170 | .bytes = &self.strtab, |
| 3177 | }) orelse { | 3171 | }) orelse { |
| ... | @@ -3181,7 +3175,7 @@ fn setEntryPoint(self: *MachO) !void { | ... | @@ -3181,7 +3175,7 @@ fn setEntryPoint(self: *MachO) !void { |
| 3181 | const resolv = self.symbol_resolver.get(n_strx) orelse unreachable; | 3175 | const resolv = self.symbol_resolver.get(n_strx) orelse unreachable; |
| 3182 | assert(resolv.where == .global); | 3176 | assert(resolv.where == .global); |
| 3183 | const sym = self.globals.items[resolv.where_index]; | 3177 | const sym = self.globals.items[resolv.where_index]; |
| 3184 | const ec = &self.load_commands.items[self.main_cmd_index.?].Main; | 3178 | const ec = &self.load_commands.items[self.main_cmd_index.?].main; |
| 3185 | ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr); | 3179 | ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr); |
| 3186 | ec.stacksize = self.base.options.stack_size_override orelse 0; | 3180 | ec.stacksize = self.base.options.stack_size_override orelse 0; |
| 3187 | self.entry_addr = sym.n_value; | 3181 | self.entry_addr = sym.n_value; |
| ... | @@ -3878,7 +3872,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -3878,7 +3872,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 3878 | if (self.pagezero_segment_cmd_index == null) { | 3872 | if (self.pagezero_segment_cmd_index == null) { |
| 3879 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 3873 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3880 | try self.load_commands.append(self.base.allocator, .{ | 3874 | try self.load_commands.append(self.base.allocator, .{ |
| 3881 | .Segment = .{ | 3875 | .segment = .{ |
| 3882 | .inner = .{ | 3876 | .inner = .{ |
| 3883 | .segname = makeStaticString("__PAGEZERO"), | 3877 | .segname = makeStaticString("__PAGEZERO"), |
| 3884 | .vmsize = pagezero_vmsize, | 3878 | .vmsize = pagezero_vmsize, |
| ... | @@ -3899,7 +3893,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -3899,7 +3893,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 3899 | break :blk needed_size; | 3893 | break :blk needed_size; |
| 3900 | } else 0; | 3894 | } else 0; |
| 3901 | try self.load_commands.append(self.base.allocator, .{ | 3895 | try self.load_commands.append(self.base.allocator, .{ |
| 3902 | .Segment = .{ | 3896 | .segment = .{ |
| 3903 | .inner = .{ | 3897 | .inner = .{ |
| 3904 | .segname = makeStaticString("__TEXT"), | 3898 | .segname = makeStaticString("__TEXT"), |
| 3905 | .vmaddr = pagezero_vmsize, | 3899 | .vmaddr = pagezero_vmsize, |
| ... | @@ -4003,7 +3997,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4003,7 +3997,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4003 | }); | 3997 | }); |
| 4004 | } | 3998 | } |
| 4005 | try self.load_commands.append(self.base.allocator, .{ | 3999 | try self.load_commands.append(self.base.allocator, .{ |
| 4006 | .Segment = .{ | 4000 | .segment = .{ |
| 4007 | .inner = .{ | 4001 | .inner = .{ |
| 4008 | .segname = makeStaticString("__DATA_CONST"), | 4002 | .segname = makeStaticString("__DATA_CONST"), |
| 4009 | .vmaddr = vmaddr, | 4003 | .vmaddr = vmaddr, |
| ... | @@ -4052,7 +4046,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4052,7 +4046,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4052 | }); | 4046 | }); |
| 4053 | } | 4047 | } |
| 4054 | try self.load_commands.append(self.base.allocator, .{ | 4048 | try self.load_commands.append(self.base.allocator, .{ |
| 4055 | .Segment = .{ | 4049 | .segment = .{ |
| 4056 | .inner = .{ | 4050 | .inner = .{ |
| 4057 | .segname = makeStaticString("__DATA"), | 4051 | .segname = makeStaticString("__DATA"), |
| 4058 | .vmaddr = vmaddr, | 4052 | .vmaddr = vmaddr, |
| ... | @@ -4136,7 +4130,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4136,7 +4130,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4136 | .flags = macho.S_THREAD_LOCAL_ZEROFILL, | 4130 | .flags = macho.S_THREAD_LOCAL_ZEROFILL, |
| 4137 | }, | 4131 | }, |
| 4138 | ); | 4132 | ); |
| 4139 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 4133 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 4140 | const sect = seg.sections.items[self.tlv_bss_section_index.?]; | 4134 | const sect = seg.sections.items[self.tlv_bss_section_index.?]; |
| 4141 | self.tlv_bss_file_offset = sect.offset; | 4135 | self.tlv_bss_file_offset = sect.offset; |
| 4142 | } | 4136 | } |
| ... | @@ -4153,7 +4147,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4153,7 +4147,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4153 | .flags = macho.S_ZEROFILL, | 4147 | .flags = macho.S_ZEROFILL, |
| 4154 | }, | 4148 | }, |
| 4155 | ); | 4149 | ); |
| 4156 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 4150 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 4157 | const sect = seg.sections.items[self.bss_section_index.?]; | 4151 | const sect = seg.sections.items[self.bss_section_index.?]; |
| 4158 | self.bss_file_offset = sect.offset; | 4152 | self.bss_file_offset = sect.offset; |
| 4159 | } | 4153 | } |
| ... | @@ -4169,7 +4163,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4169,7 +4163,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4169 | log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff}); | 4163 | log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff}); |
| 4170 | } | 4164 | } |
| 4171 | try self.load_commands.append(self.base.allocator, .{ | 4165 | try self.load_commands.append(self.base.allocator, .{ |
| 4172 | .Segment = .{ | 4166 | .segment = .{ |
| 4173 | .inner = .{ | 4167 | .inner = .{ |
| 4174 | .segname = makeStaticString("__LINKEDIT"), | 4168 | .segname = makeStaticString("__LINKEDIT"), |
| 4175 | .vmaddr = vmaddr, | 4169 | .vmaddr = vmaddr, |
| ... | @@ -4185,7 +4179,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4185,7 +4179,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4185 | if (self.dyld_info_cmd_index == null) { | 4179 | if (self.dyld_info_cmd_index == null) { |
| 4186 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); | 4180 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4187 | try self.load_commands.append(self.base.allocator, .{ | 4181 | try self.load_commands.append(self.base.allocator, .{ |
| 4188 | .DyldInfoOnly = .{ | 4182 | .dyld_info_only = .{ |
| 4189 | .cmd = macho.LC_DYLD_INFO_ONLY, | 4183 | .cmd = macho.LC_DYLD_INFO_ONLY, |
| 4190 | .cmdsize = @sizeOf(macho.dyld_info_command), | 4184 | .cmdsize = @sizeOf(macho.dyld_info_command), |
| 4191 | .rebase_off = 0, | 4185 | .rebase_off = 0, |
| ... | @@ -4206,7 +4200,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4206,7 +4200,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4206 | if (self.symtab_cmd_index == null) { | 4200 | if (self.symtab_cmd_index == null) { |
| 4207 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 4201 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4208 | try self.load_commands.append(self.base.allocator, .{ | 4202 | try self.load_commands.append(self.base.allocator, .{ |
| 4209 | .Symtab = .{ | 4203 | .symtab = .{ |
| 4210 | .cmd = macho.LC_SYMTAB, | 4204 | .cmd = macho.LC_SYMTAB, |
| 4211 | .cmdsize = @sizeOf(macho.symtab_command), | 4205 | .cmdsize = @sizeOf(macho.symtab_command), |
| 4212 | .symoff = 0, | 4206 | .symoff = 0, |
| ... | @@ -4221,7 +4215,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4221,7 +4215,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4221 | if (self.dysymtab_cmd_index == null) { | 4215 | if (self.dysymtab_cmd_index == null) { |
| 4222 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 4216 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4223 | try self.load_commands.append(self.base.allocator, .{ | 4217 | try self.load_commands.append(self.base.allocator, .{ |
| 4224 | .Dysymtab = .{ | 4218 | .dysymtab = .{ |
| 4225 | .cmd = macho.LC_DYSYMTAB, | 4219 | .cmd = macho.LC_DYSYMTAB, |
| 4226 | .cmdsize = @sizeOf(macho.dysymtab_command), | 4220 | .cmdsize = @sizeOf(macho.dysymtab_command), |
| 4227 | .ilocalsym = 0, | 4221 | .ilocalsym = 0, |
| ... | @@ -4254,7 +4248,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4254,7 +4248,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4254 | @sizeOf(macho.dylinker_command) + mem.sliceTo(default_dyld_path, 0).len, | 4248 | @sizeOf(macho.dylinker_command) + mem.sliceTo(default_dyld_path, 0).len, |
| 4255 | @sizeOf(u64), | 4249 | @sizeOf(u64), |
| 4256 | )); | 4250 | )); |
| 4257 | var dylinker_cmd = commands.emptyGenericCommandWithData(macho.dylinker_command{ | 4251 | var dylinker_cmd = macho.emptyGenericCommandWithData(macho.dylinker_command{ |
| 4258 | .cmd = macho.LC_LOAD_DYLINKER, | 4252 | .cmd = macho.LC_LOAD_DYLINKER, |
| 4259 | .cmdsize = cmdsize, | 4253 | .cmdsize = cmdsize, |
| 4260 | .name = @sizeOf(macho.dylinker_command), | 4254 | .name = @sizeOf(macho.dylinker_command), |
| ... | @@ -4262,14 +4256,14 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4262,14 +4256,14 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4262 | dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name); | 4256 | dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name); |
| 4263 | mem.set(u8, dylinker_cmd.data, 0); | 4257 | mem.set(u8, dylinker_cmd.data, 0); |
| 4264 | mem.copy(u8, dylinker_cmd.data, mem.sliceTo(default_dyld_path, 0)); | 4258 | mem.copy(u8, dylinker_cmd.data, mem.sliceTo(default_dyld_path, 0)); |
| 4265 | try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd }); | 4259 | try self.load_commands.append(self.base.allocator, .{ .dylinker = dylinker_cmd }); |
| 4266 | self.load_commands_dirty = true; | 4260 | self.load_commands_dirty = true; |
| 4267 | } | 4261 | } |
| 4268 | 4262 | ||
| 4269 | if (self.main_cmd_index == null and self.base.options.output_mode == .Exe) { | 4263 | if (self.main_cmd_index == null and self.base.options.output_mode == .Exe) { |
| 4270 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); | 4264 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4271 | try self.load_commands.append(self.base.allocator, .{ | 4265 | try self.load_commands.append(self.base.allocator, .{ |
| 4272 | .Main = .{ | 4266 | .main = .{ |
| 4273 | .cmd = macho.LC_MAIN, | 4267 | .cmd = macho.LC_MAIN, |
| 4274 | .cmdsize = @sizeOf(macho.entry_point_command), | 4268 | .cmdsize = @sizeOf(macho.entry_point_command), |
| 4275 | .entryoff = 0x0, | 4269 | .entryoff = 0x0, |
| ... | @@ -4289,7 +4283,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4289,7 +4283,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4289 | std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 }; | 4283 | std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 }; |
| 4290 | const compat_version = self.base.options.compatibility_version orelse | 4284 | const compat_version = self.base.options.compatibility_version orelse |
| 4291 | std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 }; | 4285 | std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 }; |
| 4292 | var dylib_cmd = try commands.createLoadDylibCommand( | 4286 | var dylib_cmd = try macho.createLoadDylibCommand( |
| 4293 | self.base.allocator, | 4287 | self.base.allocator, |
| 4294 | install_name, | 4288 | install_name, |
| 4295 | 2, | 4289 | 2, |
| ... | @@ -4298,14 +4292,14 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4298,14 +4292,14 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4298 | ); | 4292 | ); |
| 4299 | errdefer dylib_cmd.deinit(self.base.allocator); | 4293 | errdefer dylib_cmd.deinit(self.base.allocator); |
| 4300 | dylib_cmd.inner.cmd = macho.LC_ID_DYLIB; | 4294 | dylib_cmd.inner.cmd = macho.LC_ID_DYLIB; |
| 4301 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); | 4295 | try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd }); |
| 4302 | self.load_commands_dirty = true; | 4296 | self.load_commands_dirty = true; |
| 4303 | } | 4297 | } |
| 4304 | 4298 | ||
| 4305 | if (self.source_version_cmd_index == null) { | 4299 | if (self.source_version_cmd_index == null) { |
| 4306 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); | 4300 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4307 | try self.load_commands.append(self.base.allocator, .{ | 4301 | try self.load_commands.append(self.base.allocator, .{ |
| 4308 | .SourceVersion = .{ | 4302 | .source_version = .{ |
| 4309 | .cmd = macho.LC_SOURCE_VERSION, | 4303 | .cmd = macho.LC_SOURCE_VERSION, |
| 4310 | .cmdsize = @sizeOf(macho.source_version_command), | 4304 | .cmdsize = @sizeOf(macho.source_version_command), |
| 4311 | .version = 0x0, | 4305 | .version = 0x0, |
| ... | @@ -4332,7 +4326,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4332,7 +4326,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4332 | break :blk sdk_version; | 4326 | break :blk sdk_version; |
| 4333 | } else platform_version; | 4327 | } else platform_version; |
| 4334 | const is_simulator_abi = self.base.options.target.abi == .simulator; | 4328 | const is_simulator_abi = self.base.options.target.abi == .simulator; |
| 4335 | var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{ | 4329 | var cmd = macho.emptyGenericCommandWithData(macho.build_version_command{ |
| 4336 | .cmd = macho.LC_BUILD_VERSION, | 4330 | .cmd = macho.LC_BUILD_VERSION, |
| 4337 | .cmdsize = cmdsize, | 4331 | .cmdsize = cmdsize, |
| 4338 | .platform = switch (self.base.options.target.os.tag) { | 4332 | .platform = switch (self.base.options.target.os.tag) { |
| ... | @@ -4353,7 +4347,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4353,7 +4347,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4353 | cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command)); | 4347 | cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command)); |
| 4354 | mem.set(u8, cmd.data, 0); | 4348 | mem.set(u8, cmd.data, 0); |
| 4355 | mem.copy(u8, cmd.data, mem.asBytes(&ld_ver)); | 4349 | mem.copy(u8, cmd.data, mem.asBytes(&ld_ver)); |
| 4356 | try self.load_commands.append(self.base.allocator, .{ .BuildVersion = cmd }); | 4350 | try self.load_commands.append(self.base.allocator, .{ .build_version = cmd }); |
| 4357 | self.load_commands_dirty = true; | 4351 | self.load_commands_dirty = true; |
| 4358 | } | 4352 | } |
| 4359 | 4353 | ||
| ... | @@ -4365,14 +4359,14 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4365,14 +4359,14 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4365 | .uuid = undefined, | 4359 | .uuid = undefined, |
| 4366 | }; | 4360 | }; |
| 4367 | std.crypto.random.bytes(&uuid_cmd.uuid); | 4361 | std.crypto.random.bytes(&uuid_cmd.uuid); |
| 4368 | try self.load_commands.append(self.base.allocator, .{ .Uuid = uuid_cmd }); | 4362 | try self.load_commands.append(self.base.allocator, .{ .uuid = uuid_cmd }); |
| 4369 | self.load_commands_dirty = true; | 4363 | self.load_commands_dirty = true; |
| 4370 | } | 4364 | } |
| 4371 | 4365 | ||
| 4372 | if (self.function_starts_cmd_index == null) { | 4366 | if (self.function_starts_cmd_index == null) { |
| 4373 | self.function_starts_cmd_index = @intCast(u16, self.load_commands.items.len); | 4367 | self.function_starts_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4374 | try self.load_commands.append(self.base.allocator, .{ | 4368 | try self.load_commands.append(self.base.allocator, .{ |
| 4375 | .LinkeditData = .{ | 4369 | .linkedit_data = .{ |
| 4376 | .cmd = macho.LC_FUNCTION_STARTS, | 4370 | .cmd = macho.LC_FUNCTION_STARTS, |
| 4377 | .cmdsize = @sizeOf(macho.linkedit_data_command), | 4371 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 4378 | .dataoff = 0, | 4372 | .dataoff = 0, |
| ... | @@ -4385,7 +4379,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4385,7 +4379,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4385 | if (self.data_in_code_cmd_index == null) { | 4379 | if (self.data_in_code_cmd_index == null) { |
| 4386 | self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len); | 4380 | self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4387 | try self.load_commands.append(self.base.allocator, .{ | 4381 | try self.load_commands.append(self.base.allocator, .{ |
| 4388 | .LinkeditData = .{ | 4382 | .linkedit_data = .{ |
| 4389 | .cmd = macho.LC_DATA_IN_CODE, | 4383 | .cmd = macho.LC_DATA_IN_CODE, |
| 4390 | .cmdsize = @sizeOf(macho.linkedit_data_command), | 4384 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 4391 | .dataoff = 0, | 4385 | .dataoff = 0, |
| ... | @@ -4399,8 +4393,8 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4399,8 +4393,8 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4399 | } | 4393 | } |
| 4400 | 4394 | ||
| 4401 | fn allocateTextSegment(self: *MachO) !void { | 4395 | fn allocateTextSegment(self: *MachO) !void { |
| 4402 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 4396 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 4403 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; | 4397 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].segment.inner.vmsize; |
| 4404 | seg.inner.fileoff = 0; | 4398 | seg.inner.fileoff = 0; |
| 4405 | seg.inner.vmaddr = base_vmaddr; | 4399 | seg.inner.vmaddr = base_vmaddr; |
| 4406 | 4400 | ||
| ... | @@ -4436,30 +4430,30 @@ fn allocateTextSegment(self: *MachO) !void { | ... | @@ -4436,30 +4430,30 @@ fn allocateTextSegment(self: *MachO) !void { |
| 4436 | } | 4430 | } |
| 4437 | 4431 | ||
| 4438 | fn allocateDataConstSegment(self: *MachO) !void { | 4432 | fn allocateDataConstSegment(self: *MachO) !void { |
| 4439 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 4433 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 4440 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 4434 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 4441 | seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize; | 4435 | seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize; |
| 4442 | seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize; | 4436 | seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize; |
| 4443 | try self.allocateSegment(self.data_const_segment_cmd_index.?, 0); | 4437 | try self.allocateSegment(self.data_const_segment_cmd_index.?, 0); |
| 4444 | } | 4438 | } |
| 4445 | 4439 | ||
| 4446 | fn allocateDataSegment(self: *MachO) !void { | 4440 | fn allocateDataSegment(self: *MachO) !void { |
| 4447 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 4441 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 4448 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 4442 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 4449 | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; | 4443 | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; |
| 4450 | seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize; | 4444 | seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize; |
| 4451 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); | 4445 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); |
| 4452 | } | 4446 | } |
| 4453 | 4447 | ||
| 4454 | fn allocateLinkeditSegment(self: *MachO) void { | 4448 | fn allocateLinkeditSegment(self: *MachO) void { |
| 4455 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 4449 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 4456 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 4450 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 4457 | seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize; | 4451 | seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize; |
| 4458 | seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize; | 4452 | seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize; |
| 4459 | } | 4453 | } |
| 4460 | 4454 | ||
| 4461 | fn allocateSegment(self: *MachO, index: u16, offset: u64) !void { | 4455 | fn allocateSegment(self: *MachO, index: u16, offset: u64) !void { |
| 4462 | const seg = &self.load_commands.items[index].Segment; | 4456 | const seg = &self.load_commands.items[index].segment; |
| 4463 | 4457 | ||
| 4464 | // Allocate the sections according to their alignment at the beginning of the segment. | 4458 | // Allocate the sections according to their alignment at the beginning of the segment. |
| 4465 | var start: u64 = offset; | 4459 | var start: u64 = offset; |
| ... | @@ -4491,7 +4485,7 @@ fn initSection( | ... | @@ -4491,7 +4485,7 @@ fn initSection( |
| 4491 | alignment: u32, | 4485 | alignment: u32, |
| 4492 | opts: InitSectionOpts, | 4486 | opts: InitSectionOpts, |
| 4493 | ) !u16 { | 4487 | ) !u16 { |
| 4494 | const seg = &self.load_commands.items[segment_id].Segment; | 4488 | const seg = &self.load_commands.items[segment_id].segment; |
| 4495 | var sect = macho.section_64{ | 4489 | var sect = macho.section_64{ |
| 4496 | .sectname = makeStaticString(sectname), | 4490 | .sectname = makeStaticString(sectname), |
| 4497 | .segname = seg.inner.segname, | 4491 | .segname = seg.inner.segname, |
| ... | @@ -4507,8 +4501,8 @@ fn initSection( | ... | @@ -4507,8 +4501,8 @@ fn initSection( |
| 4507 | const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null; | 4501 | const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null; |
| 4508 | const off = self.findFreeSpace(segment_id, alignment_pow_2, padding); | 4502 | const off = self.findFreeSpace(segment_id, alignment_pow_2, padding); |
| 4509 | log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{ | 4503 | log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{ |
| 4510 | commands.segmentName(sect), | 4504 | sect.segName(), |
| 4511 | commands.sectionName(sect), | 4505 | sect.sectName(), |
| 4512 | off, | 4506 | off, |
| 4513 | off + size, | 4507 | off + size, |
| 4514 | }); | 4508 | }); |
| ... | @@ -4535,7 +4529,7 @@ fn initSection( | ... | @@ -4535,7 +4529,7 @@ fn initSection( |
| 4535 | } | 4529 | } |
| 4536 | 4530 | ||
| 4537 | fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64 { | 4531 | fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64 { |
| 4538 | const seg = self.load_commands.items[segment_id].Segment; | 4532 | const seg = self.load_commands.items[segment_id].segment; |
| 4539 | if (seg.sections.items.len == 0) { | 4533 | if (seg.sections.items.len == 0) { |
| 4540 | return if (start) |v| v else seg.inner.fileoff; | 4534 | return if (start) |v| v else seg.inner.fileoff; |
| 4541 | } | 4535 | } |
| ... | @@ -4545,7 +4539,7 @@ fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64 | ... | @@ -4545,7 +4539,7 @@ fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64 |
| 4545 | } | 4539 | } |
| 4546 | 4540 | ||
| 4547 | fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { | 4541 | fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { |
| 4548 | const seg = &self.load_commands.items[seg_id].Segment; | 4542 | const seg = &self.load_commands.items[seg_id].segment; |
| 4549 | const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size); | 4543 | const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size); |
| 4550 | assert(new_seg_size > seg.inner.filesize); | 4544 | assert(new_seg_size > seg.inner.filesize); |
| 4551 | const offset_amt = new_seg_size - seg.inner.filesize; | 4545 | const offset_amt = new_seg_size - seg.inner.filesize; |
| ... | @@ -4567,13 +4561,13 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { | ... | @@ -4567,13 +4561,13 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { |
| 4567 | // TODO We should probably nop the expanded by distance, or put 0s. | 4561 | // TODO We should probably nop the expanded by distance, or put 0s. |
| 4568 | 4562 | ||
| 4569 | // TODO copyRangeAll doesn't automatically extend the file on macOS. | 4563 | // TODO copyRangeAll doesn't automatically extend the file on macOS. |
| 4570 | const ledit_seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 4564 | const ledit_seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 4571 | const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize; | 4565 | const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize; |
| 4572 | try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1); | 4566 | try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1); |
| 4573 | 4567 | ||
| 4574 | var next: usize = seg_id + 1; | 4568 | var next: usize = seg_id + 1; |
| 4575 | while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) { | 4569 | while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) { |
| 4576 | const next_seg = &self.load_commands.items[next].Segment; | 4570 | const next_seg = &self.load_commands.items[next].segment; |
| 4577 | _ = try self.base.file.?.copyRangeAll( | 4571 | _ = try self.base.file.?.copyRangeAll( |
| 4578 | next_seg.inner.fileoff, | 4572 | next_seg.inner.fileoff, |
| 4579 | self.base.file.?, | 4573 | self.base.file.?, |
| ... | @@ -4596,8 +4590,8 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { | ... | @@ -4596,8 +4590,8 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { |
| 4596 | moved_sect.addr += offset_amt; | 4590 | moved_sect.addr += offset_amt; |
| 4597 | 4591 | ||
| 4598 | log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ | 4592 | log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ |
| 4599 | commands.segmentName(moved_sect.*), | 4593 | moved_sect.segName(), |
| 4600 | commands.sectionName(moved_sect.*), | 4594 | moved_sect.sectName(), |
| 4601 | moved_sect.offset, | 4595 | moved_sect.offset, |
| 4602 | moved_sect.offset + moved_sect.size, | 4596 | moved_sect.offset + moved_sect.size, |
| 4603 | moved_sect.addr, | 4597 | moved_sect.addr, |
| ... | @@ -4616,7 +4610,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { | ... | @@ -4616,7 +4610,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { |
| 4616 | const tracy = trace(@src()); | 4610 | const tracy = trace(@src()); |
| 4617 | defer tracy.end(); | 4611 | defer tracy.end(); |
| 4618 | 4612 | ||
| 4619 | const seg = &self.load_commands.items[match.seg].Segment; | 4613 | const seg = &self.load_commands.items[match.seg].segment; |
| 4620 | const sect = &seg.sections.items[match.sect]; | 4614 | const sect = &seg.sections.items[match.sect]; |
| 4621 | 4615 | ||
| 4622 | const alignment = try math.powi(u32, 2, sect.@"align"); | 4616 | const alignment = try math.powi(u32, 2, sect.@"align"); |
| ... | @@ -4670,8 +4664,8 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { | ... | @@ -4670,8 +4664,8 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { |
| 4670 | moved_sect.addr += offset_amt; | 4664 | moved_sect.addr += offset_amt; |
| 4671 | 4665 | ||
| 4672 | log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ | 4666 | log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{ |
| 4673 | commands.segmentName(moved_sect.*), | 4667 | moved_sect.segName(), |
| 4674 | commands.sectionName(moved_sect.*), | 4668 | moved_sect.sectName(), |
| 4675 | moved_sect.offset, | 4669 | moved_sect.offset, |
| 4676 | moved_sect.offset + moved_sect.size, | 4670 | moved_sect.offset + moved_sect.size, |
| 4677 | moved_sect.addr, | 4671 | moved_sect.addr, |
| ... | @@ -4687,7 +4681,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { | ... | @@ -4687,7 +4681,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { |
| 4687 | } | 4681 | } |
| 4688 | 4682 | ||
| 4689 | fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 { | 4683 | fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 { |
| 4690 | const seg = self.load_commands.items[segment_id].Segment; | 4684 | const seg = self.load_commands.items[segment_id].segment; |
| 4691 | assert(start >= seg.inner.fileoff); | 4685 | assert(start >= seg.inner.fileoff); |
| 4692 | var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize; | 4686 | var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize; |
| 4693 | if (start > min_pos) return 0; | 4687 | if (start > min_pos) return 0; |
| ... | @@ -4699,7 +4693,7 @@ fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 { | ... | @@ -4699,7 +4693,7 @@ fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 { |
| 4699 | } | 4693 | } |
| 4700 | 4694 | ||
| 4701 | fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u32 { | 4695 | fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u32 { |
| 4702 | const seg = self.load_commands.items[segment_id].Segment; | 4696 | const seg = self.load_commands.items[segment_id].segment; |
| 4703 | var max_alignment: u32 = 1; | 4697 | var max_alignment: u32 = 1; |
| 4704 | var next = start_sect_id; | 4698 | var next = start_sect_id; |
| 4705 | while (next < seg.sections.items.len) : (next += 1) { | 4699 | while (next < seg.sections.items.len) : (next += 1) { |
| ... | @@ -4714,7 +4708,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m | ... | @@ -4714,7 +4708,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m |
| 4714 | const tracy = trace(@src()); | 4708 | const tracy = trace(@src()); |
| 4715 | defer tracy.end(); | 4709 | defer tracy.end(); |
| 4716 | 4710 | ||
| 4717 | const seg = &self.load_commands.items[match.seg].Segment; | 4711 | const seg = &self.load_commands.items[match.seg].segment; |
| 4718 | const sect = &seg.sections.items[match.sect]; | 4712 | const sect = &seg.sections.items[match.sect]; |
| 4719 | var free_list = self.atom_free_lists.get(match).?; | 4713 | var free_list = self.atom_free_lists.get(match).?; |
| 4720 | const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?; | 4714 | const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?; |
| ... | @@ -4818,7 +4812,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m | ... | @@ -4818,7 +4812,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m |
| 4818 | } | 4812 | } |
| 4819 | 4813 | ||
| 4820 | fn addAtomAndBumpSectionSize(self: *MachO, atom: *Atom, match: MatchingSection) !void { | 4814 | fn addAtomAndBumpSectionSize(self: *MachO, atom: *Atom, match: MatchingSection) !void { |
| 4821 | const seg = &self.load_commands.items[match.seg].Segment; | 4815 | const seg = &self.load_commands.items[match.seg].segment; |
| 4822 | const sect = &seg.sections.items[match.sect]; | 4816 | const sect = &seg.sections.items[match.sect]; |
| 4823 | const alignment = try math.powi(u32, 2, atom.alignment); | 4817 | const alignment = try math.powi(u32, 2, atom.alignment); |
| 4824 | sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size; | 4818 | sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size; |
| ... | @@ -4865,11 +4859,11 @@ const NextSegmentAddressAndOffset = struct { | ... | @@ -4865,11 +4859,11 @@ const NextSegmentAddressAndOffset = struct { |
| 4865 | fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { | 4859 | fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { |
| 4866 | var prev_segment_idx: ?usize = null; // We use optional here for safety. | 4860 | var prev_segment_idx: ?usize = null; // We use optional here for safety. |
| 4867 | for (self.load_commands.items) |cmd, i| { | 4861 | for (self.load_commands.items) |cmd, i| { |
| 4868 | if (cmd == .Segment) { | 4862 | if (cmd == .segment) { |
| 4869 | prev_segment_idx = i; | 4863 | prev_segment_idx = i; |
| 4870 | } | 4864 | } |
| 4871 | } | 4865 | } |
| 4872 | const prev_segment = self.load_commands.items[prev_segment_idx.?].Segment; | 4866 | const prev_segment = self.load_commands.items[prev_segment_idx.?].segment; |
| 4873 | const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize; | 4867 | const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize; |
| 4874 | const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize; | 4868 | const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize; |
| 4875 | return .{ | 4869 | return .{ |
| ... | @@ -4888,7 +4882,7 @@ fn sortSections(self: *MachO) !void { | ... | @@ -4888,7 +4882,7 @@ fn sortSections(self: *MachO) !void { |
| 4888 | 4882 | ||
| 4889 | { | 4883 | { |
| 4890 | // __TEXT segment | 4884 | // __TEXT segment |
| 4891 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 4885 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 4892 | var sections = seg.sections.toOwnedSlice(self.base.allocator); | 4886 | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 4893 | defer self.base.allocator.free(sections); | 4887 | defer self.base.allocator.free(sections); |
| 4894 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); | 4888 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| ... | @@ -4920,7 +4914,7 @@ fn sortSections(self: *MachO) !void { | ... | @@ -4920,7 +4914,7 @@ fn sortSections(self: *MachO) !void { |
| 4920 | 4914 | ||
| 4921 | { | 4915 | { |
| 4922 | // __DATA_CONST segment | 4916 | // __DATA_CONST segment |
| 4923 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 4917 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 4924 | var sections = seg.sections.toOwnedSlice(self.base.allocator); | 4918 | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 4925 | defer self.base.allocator.free(sections); | 4919 | defer self.base.allocator.free(sections); |
| 4926 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); | 4920 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| ... | @@ -4947,7 +4941,7 @@ fn sortSections(self: *MachO) !void { | ... | @@ -4947,7 +4941,7 @@ fn sortSections(self: *MachO) !void { |
| 4947 | 4941 | ||
| 4948 | { | 4942 | { |
| 4949 | // __DATA segment | 4943 | // __DATA segment |
| 4950 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 4944 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 4951 | var sections = seg.sections.toOwnedSlice(self.base.allocator); | 4945 | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 4952 | defer self.base.allocator.free(sections); | 4946 | defer self.base.allocator.free(sections); |
| 4953 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); | 4947 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| ... | @@ -5003,7 +4997,7 @@ fn sortSections(self: *MachO) !void { | ... | @@ -5003,7 +4997,7 @@ fn sortSections(self: *MachO) !void { |
| 5003 | { | 4997 | { |
| 5004 | // Create new section ordinals. | 4998 | // Create new section ordinals. |
| 5005 | self.section_ordinals.clearRetainingCapacity(); | 4999 | self.section_ordinals.clearRetainingCapacity(); |
| 5006 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 5000 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5007 | for (text_seg.sections.items) |_, sect_id| { | 5001 | for (text_seg.sections.items) |_, sect_id| { |
| 5008 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ | 5002 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5009 | .seg = self.text_segment_cmd_index.?, | 5003 | .seg = self.text_segment_cmd_index.?, |
| ... | @@ -5011,7 +5005,7 @@ fn sortSections(self: *MachO) !void { | ... | @@ -5011,7 +5005,7 @@ fn sortSections(self: *MachO) !void { |
| 5011 | }); | 5005 | }); |
| 5012 | assert(!res.found_existing); | 5006 | assert(!res.found_existing); |
| 5013 | } | 5007 | } |
| 5014 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 5008 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 5015 | for (data_const_seg.sections.items) |_, sect_id| { | 5009 | for (data_const_seg.sections.items) |_, sect_id| { |
| 5016 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ | 5010 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5017 | .seg = self.data_const_segment_cmd_index.?, | 5011 | .seg = self.data_const_segment_cmd_index.?, |
| ... | @@ -5019,7 +5013,7 @@ fn sortSections(self: *MachO) !void { | ... | @@ -5019,7 +5013,7 @@ fn sortSections(self: *MachO) !void { |
| 5019 | }); | 5013 | }); |
| 5020 | assert(!res.found_existing); | 5014 | assert(!res.found_existing); |
| 5021 | } | 5015 | } |
| 5022 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 5016 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 5023 | for (data_seg.sections.items) |_, sect_id| { | 5017 | for (data_seg.sections.items) |_, sect_id| { |
| 5024 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ | 5018 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5025 | .seg = self.data_segment_cmd_index.?, | 5019 | .seg = self.data_segment_cmd_index.?, |
| ... | @@ -5044,9 +5038,9 @@ fn updateSectionOrdinals(self: *MachO) !void { | ... | @@ -5044,9 +5038,9 @@ fn updateSectionOrdinals(self: *MachO) !void { |
| 5044 | 5038 | ||
| 5045 | var new_ordinal: u8 = 0; | 5039 | var new_ordinal: u8 = 0; |
| 5046 | for (self.load_commands.items) |lc, lc_id| { | 5040 | for (self.load_commands.items) |lc, lc_id| { |
| 5047 | if (lc != .Segment) break; | 5041 | if (lc != .segment) break; |
| 5048 | 5042 | ||
| 5049 | for (lc.Segment.sections.items) |_, sect_id| { | 5043 | for (lc.segment.sections.items) |_, sect_id| { |
| 5050 | const match = MatchingSection{ | 5044 | const match = MatchingSection{ |
| 5051 | .seg = @intCast(u16, lc_id), | 5045 | .seg = @intCast(u16, lc_id), |
| 5052 | .sect = @intCast(u16, sect_id), | 5046 | .sect = @intCast(u16, sect_id), |
| ... | @@ -5089,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO) !void { | ... | @@ -5089,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5089 | 5083 | ||
| 5090 | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable | 5084 | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable |
| 5091 | 5085 | ||
| 5092 | const seg = self.load_commands.items[match.seg].Segment; | 5086 | const seg = self.load_commands.items[match.seg].segment; |
| 5093 | 5087 | ||
| 5094 | while (true) { | 5088 | while (true) { |
| 5095 | const sym = self.locals.items[atom.local_sym_index]; | 5089 | const sym = self.locals.items[atom.local_sym_index]; |
| ... | @@ -5159,7 +5153,7 @@ fn writeDyldInfoData(self: *MachO) !void { | ... | @@ -5159,7 +5153,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5159 | { | 5153 | { |
| 5160 | // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. | 5154 | // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. |
| 5161 | log.debug("generating export trie", .{}); | 5155 | log.debug("generating export trie", .{}); |
| 5162 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 5156 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5163 | const base_address = text_segment.inner.vmaddr; | 5157 | const base_address = text_segment.inner.vmaddr; |
| 5164 | 5158 | ||
| 5165 | for (self.globals.items) |sym| { | 5159 | for (self.globals.items) |sym| { |
| ... | @@ -5177,8 +5171,8 @@ fn writeDyldInfoData(self: *MachO) !void { | ... | @@ -5177,8 +5171,8 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5177 | try trie.finalize(self.base.allocator); | 5171 | try trie.finalize(self.base.allocator); |
| 5178 | } | 5172 | } |
| 5179 | 5173 | ||
| 5180 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 5174 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 5181 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 5175 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].dyld_info_only; |
| 5182 | const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items); | 5176 | const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items); |
| 5183 | const bind_size = try bind.bindInfoSize(bind_pointers.items); | 5177 | const bind_size = try bind.bindInfoSize(bind_pointers.items); |
| 5184 | const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items); | 5178 | const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items); |
| ... | @@ -5248,7 +5242,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { | ... | @@ -5248,7 +5242,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 5248 | .sect = self.la_symbol_ptr_section_index.?, | 5242 | .sect = self.la_symbol_ptr_section_index.?, |
| 5249 | }).?; | 5243 | }).?; |
| 5250 | const base_addr = blk: { | 5244 | const base_addr = blk: { |
| 5251 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 5245 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 5252 | break :blk seg.inner.vmaddr; | 5246 | break :blk seg.inner.vmaddr; |
| 5253 | }; | 5247 | }; |
| 5254 | 5248 | ||
| ... | @@ -5312,7 +5306,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { | ... | @@ -5312,7 +5306,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 5312 | } | 5306 | } |
| 5313 | 5307 | ||
| 5314 | const sect = blk: { | 5308 | const sect = blk: { |
| 5315 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 5309 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5316 | break :blk seg.sections.items[self.stub_helper_section_index.?]; | 5310 | break :blk seg.sections.items[self.stub_helper_section_index.?]; |
| 5317 | }; | 5311 | }; |
| 5318 | const stub_offset: u4 = switch (self.base.options.target.cpu.arch) { | 5312 | const stub_offset: u4 = switch (self.base.options.target.cpu.arch) { |
| ... | @@ -5353,7 +5347,7 @@ fn writeFunctionStarts(self: *MachO) !void { | ... | @@ -5353,7 +5347,7 @@ fn writeFunctionStarts(self: *MachO) !void { |
| 5353 | var offsets = std.ArrayList(u32).init(self.base.allocator); | 5347 | var offsets = std.ArrayList(u32).init(self.base.allocator); |
| 5354 | defer offsets.deinit(); | 5348 | defer offsets.deinit(); |
| 5355 | 5349 | ||
| 5356 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 5350 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5357 | var last_off: u32 = 0; | 5351 | var last_off: u32 = 0; |
| 5358 | 5352 | ||
| 5359 | while (true) { | 5353 | while (true) { |
| ... | @@ -5410,8 +5404,8 @@ fn writeFunctionStarts(self: *MachO) !void { | ... | @@ -5410,8 +5404,8 @@ fn writeFunctionStarts(self: *MachO) !void { |
| 5410 | } | 5404 | } |
| 5411 | 5405 | ||
| 5412 | const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64))); | 5406 | const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64))); |
| 5413 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 5407 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 5414 | const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].LinkeditData; | 5408 | const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].linkedit_data; |
| 5415 | 5409 | ||
| 5416 | fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); | 5410 | fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 5417 | fn_cmd.datasize = needed_size; | 5411 | fn_cmd.datasize = needed_size; |
| ... | @@ -5444,7 +5438,7 @@ fn writeDices(self: *MachO) !void { | ... | @@ -5444,7 +5438,7 @@ fn writeDices(self: *MachO) !void { |
| 5444 | atom = prev; | 5438 | atom = prev; |
| 5445 | } | 5439 | } |
| 5446 | 5440 | ||
| 5447 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 5441 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5448 | const text_sect = text_seg.sections.items[self.text_section_index.?]; | 5442 | const text_sect = text_seg.sections.items[self.text_section_index.?]; |
| 5449 | 5443 | ||
| 5450 | while (true) { | 5444 | while (true) { |
| ... | @@ -5468,8 +5462,8 @@ fn writeDices(self: *MachO) !void { | ... | @@ -5468,8 +5462,8 @@ fn writeDices(self: *MachO) !void { |
| 5468 | } else break; | 5462 | } else break; |
| 5469 | } | 5463 | } |
| 5470 | 5464 | ||
| 5471 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 5465 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 5472 | const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData; | 5466 | const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data; |
| 5473 | const needed_size = @intCast(u32, buf.items.len); | 5467 | const needed_size = @intCast(u32, buf.items.len); |
| 5474 | 5468 | ||
| 5475 | dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); | 5469 | dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| ... | @@ -5489,8 +5483,8 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -5489,8 +5483,8 @@ fn writeSymbolTable(self: *MachO) !void { |
| 5489 | const tracy = trace(@src()); | 5483 | const tracy = trace(@src()); |
| 5490 | defer tracy.end(); | 5484 | defer tracy.end(); |
| 5491 | 5485 | ||
| 5492 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 5486 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 5493 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 5487 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 5494 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); | 5488 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 5495 | 5489 | ||
| 5496 | var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator); | 5490 | var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator); |
| ... | @@ -5594,18 +5588,18 @@ fn writeSymbolTable(self: *MachO) !void { | ... | @@ -5594,18 +5588,18 @@ fn writeSymbolTable(self: *MachO) !void { |
| 5594 | seg.inner.filesize += locals_size + exports_size + undefs_size; | 5588 | seg.inner.filesize += locals_size + exports_size + undefs_size; |
| 5595 | 5589 | ||
| 5596 | // Update dynamic symbol table. | 5590 | // Update dynamic symbol table. |
| 5597 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | 5591 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].dysymtab; |
| 5598 | dysymtab.nlocalsym = @intCast(u32, nlocals); | 5592 | dysymtab.nlocalsym = @intCast(u32, nlocals); |
| 5599 | dysymtab.iextdefsym = dysymtab.nlocalsym; | 5593 | dysymtab.iextdefsym = dysymtab.nlocalsym; |
| 5600 | dysymtab.nextdefsym = @intCast(u32, nexports); | 5594 | dysymtab.nextdefsym = @intCast(u32, nexports); |
| 5601 | dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym; | 5595 | dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym; |
| 5602 | dysymtab.nundefsym = @intCast(u32, nundefs); | 5596 | dysymtab.nundefsym = @intCast(u32, nundefs); |
| 5603 | 5597 | ||
| 5604 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 5598 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5605 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; | 5599 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; |
| 5606 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 5600 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 5607 | const got = &data_const_segment.sections.items[self.got_section_index.?]; | 5601 | const got = &data_const_segment.sections.items[self.got_section_index.?]; |
| 5608 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 5602 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 5609 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; | 5603 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 5610 | 5604 | ||
| 5611 | const nstubs = @intCast(u32, self.stubs_map.keys().len); | 5605 | const nstubs = @intCast(u32, self.stubs_map.keys().len); |
| ... | @@ -5668,8 +5662,8 @@ fn writeStringTable(self: *MachO) !void { | ... | @@ -5668,8 +5662,8 @@ fn writeStringTable(self: *MachO) !void { |
| 5668 | const tracy = trace(@src()); | 5662 | const tracy = trace(@src()); |
| 5669 | defer tracy.end(); | 5663 | defer tracy.end(); |
| 5670 | 5664 | ||
| 5671 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 5665 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 5672 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 5666 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 5673 | symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); | 5667 | symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 5674 | symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64))); | 5668 | symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64))); |
| 5675 | seg.inner.filesize += symtab.strsize; | 5669 | seg.inner.filesize += symtab.strsize; |
| ... | @@ -5689,7 +5683,7 @@ fn writeLinkeditSegment(self: *MachO) !void { | ... | @@ -5689,7 +5683,7 @@ fn writeLinkeditSegment(self: *MachO) !void { |
| 5689 | const tracy = trace(@src()); | 5683 | const tracy = trace(@src()); |
| 5690 | defer tracy.end(); | 5684 | defer tracy.end(); |
| 5691 | 5685 | ||
| 5692 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 5686 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 5693 | seg.inner.filesize = 0; | 5687 | seg.inner.filesize = 0; |
| 5694 | 5688 | ||
| 5695 | try self.writeDyldInfoData(); | 5689 | try self.writeDyldInfoData(); |
| ... | @@ -5705,8 +5699,8 @@ fn writeCodeSignaturePadding(self: *MachO) !void { | ... | @@ -5705,8 +5699,8 @@ fn writeCodeSignaturePadding(self: *MachO) !void { |
| 5705 | const tracy = trace(@src()); | 5699 | const tracy = trace(@src()); |
| 5706 | defer tracy.end(); | 5700 | defer tracy.end(); |
| 5707 | 5701 | ||
| 5708 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 5702 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 5709 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; | 5703 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data; |
| 5710 | const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize; | 5704 | const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize; |
| 5711 | const needed_size = CodeSignature.calcCodeSignaturePaddingSize( | 5705 | const needed_size = CodeSignature.calcCodeSignaturePaddingSize( |
| 5712 | self.base.options.emit.?.sub_path, | 5706 | self.base.options.emit.?.sub_path, |
| ... | @@ -5732,8 +5726,8 @@ fn writeCodeSignature(self: *MachO) !void { | ... | @@ -5732,8 +5726,8 @@ fn writeCodeSignature(self: *MachO) !void { |
| 5732 | const tracy = trace(@src()); | 5726 | const tracy = trace(@src()); |
| 5733 | defer tracy.end(); | 5727 | defer tracy.end(); |
| 5734 | 5728 | ||
| 5735 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 5729 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5736 | const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; | 5730 | const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data; |
| 5737 | 5731 | ||
| 5738 | var code_sig: CodeSignature = .{}; | 5732 | var code_sig: CodeSignature = .{}; |
| 5739 | defer code_sig.deinit(self.base.allocator); | 5733 | defer code_sig.deinit(self.base.allocator); |
| ... | @@ -5784,9 +5778,8 @@ fn writeLoadCommands(self: *MachO) !void { | ... | @@ -5784,9 +5778,8 @@ fn writeLoadCommands(self: *MachO) !void { |
| 5784 | 5778 | ||
| 5785 | /// Writes Mach-O file header. | 5779 | /// Writes Mach-O file header. |
| 5786 | fn writeHeader(self: *MachO) !void { | 5780 | fn writeHeader(self: *MachO) !void { |
| 5787 | var header = commands.emptyHeader(.{ | 5781 | var header: macho.mach_header_64 = .{}; |
| 5788 | .flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL, | 5782 | header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL; |
| 5789 | }); | ||
| 5790 | 5783 | ||
| 5791 | switch (self.base.options.target.cpu.arch) { | 5784 | switch (self.base.options.target.cpu.arch) { |
| 5792 | .aarch64 => { | 5785 | .aarch64 => { |
| ... | @@ -5959,12 +5952,9 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -5959,12 +5952,9 @@ fn snapshotState(self: *MachO) !void { |
| 5959 | var nodes = std.ArrayList(Snapshot.Node).init(arena); | 5952 | var nodes = std.ArrayList(Snapshot.Node).init(arena); |
| 5960 | 5953 | ||
| 5961 | for (self.section_ordinals.keys()) |key| { | 5954 | for (self.section_ordinals.keys()) |key| { |
| 5962 | const seg = self.load_commands.items[key.seg].Segment; | 5955 | const seg = self.load_commands.items[key.seg].segment; |
| 5963 | const sect = seg.sections.items[key.sect]; | 5956 | const sect = seg.sections.items[key.sect]; |
| 5964 | const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ | 5957 | const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() }); |
| 5965 | commands.segmentName(sect), | ||
| 5966 | commands.sectionName(sect), | ||
| 5967 | }); | ||
| 5968 | try nodes.append(.{ | 5958 | try nodes.append(.{ |
| 5969 | .address = sect.addr, | 5959 | .address = sect.addr, |
| 5970 | .tag = .section_start, | 5960 | .tag = .section_start, |
| ... | @@ -6035,12 +6025,12 @@ fn snapshotState(self: *MachO) !void { | ... | @@ -6035,12 +6025,12 @@ fn snapshotState(self: *MachO) !void { |
| 6035 | const is_tlv = is_tlv: { | 6025 | const is_tlv = is_tlv: { |
| 6036 | const source_sym = self.locals.items[atom.local_sym_index]; | 6026 | const source_sym = self.locals.items[atom.local_sym_index]; |
| 6037 | const match = self.section_ordinals.keys()[source_sym.n_sect - 1]; | 6027 | const match = self.section_ordinals.keys()[source_sym.n_sect - 1]; |
| 6038 | const match_seg = self.load_commands.items[match.seg].Segment; | 6028 | const match_seg = self.load_commands.items[match.seg].segment; |
| 6039 | const match_sect = match_seg.sections.items[match.sect]; | 6029 | const match_sect = match_seg.sections.items[match.sect]; |
| 6040 | break :is_tlv commands.sectionType(match_sect) == macho.S_THREAD_LOCAL_VARIABLES; | 6030 | break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES; |
| 6041 | }; | 6031 | }; |
| 6042 | if (is_tlv) { | 6032 | if (is_tlv) { |
| 6043 | const match_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 6033 | const match_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 6044 | const base_address = inner: { | 6034 | const base_address = inner: { |
| 6045 | if (self.tlv_data_section_index) |i| { | 6035 | if (self.tlv_data_section_index) |i| { |
| 6046 | break :inner match_seg.sections.items[i].addr; | 6036 | break :inner match_seg.sections.items[i].addr; |
| ... | @@ -6200,14 +6190,14 @@ fn logSymtab(self: MachO) void { | ... | @@ -6200,14 +6190,14 @@ fn logSymtab(self: MachO) void { |
| 6200 | 6190 | ||
| 6201 | fn logSectionOrdinals(self: MachO) void { | 6191 | fn logSectionOrdinals(self: MachO) void { |
| 6202 | for (self.section_ordinals.keys()) |match, i| { | 6192 | for (self.section_ordinals.keys()) |match, i| { |
| 6203 | const seg = self.load_commands.items[match.seg].Segment; | 6193 | const seg = self.load_commands.items[match.seg].segment; |
| 6204 | const sect = seg.sections.items[match.sect]; | 6194 | const sect = seg.sections.items[match.sect]; |
| 6205 | log.debug("ord {d}: {d},{d} => {s},{s}", .{ | 6195 | log.debug("ord {d}: {d},{d} => {s},{s}", .{ |
| 6206 | i + 1, | 6196 | i + 1, |
| 6207 | match.seg, | 6197 | match.seg, |
| 6208 | match.sect, | 6198 | match.sect, |
| 6209 | commands.segmentName(sect), | 6199 | sect.segName(), |
| 6210 | commands.sectionName(sect), | 6200 | sect.sectName(), |
| 6211 | }); | 6201 | }); |
| 6212 | } | 6202 | } |
| 6213 | } | 6203 | } |
src/link/MachO/Atom.zig+9-10| ... | @@ -4,7 +4,6 @@ const std = @import("std"); | ... | @@ -4,7 +4,6 @@ const std = @import("std"); |
| 4 | const build_options = @import("build_options"); | 4 | const build_options = @import("build_options"); |
| 5 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | 5 | const aarch64 = @import("../../arch/aarch64/bits.zig"); |
| 6 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 7 | const commands = @import("commands.zig"); | ||
| 8 | const log = std.log.scoped(.link); | 7 | const log = std.log.scoped(.link); |
| 9 | const macho = std.macho; | 8 | const macho = std.macho; |
| 10 | const math = std.math; | 9 | const math = std.math; |
| ... | @@ -342,7 +341,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC | ... | @@ -342,7 +341,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 342 | if (rel.r_extern == 0) { | 341 | if (rel.r_extern == 0) { |
| 343 | const sect_id = @intCast(u16, rel.r_symbolnum - 1); | 342 | const sect_id = @intCast(u16, rel.r_symbolnum - 1); |
| 344 | const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: { | 343 | const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: { |
| 345 | const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment; | 344 | const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].segment; |
| 346 | const sect = seg.sections.items[sect_id]; | 345 | const sect = seg.sections.items[sect_id]; |
| 347 | const match = (try context.macho_file.getMatchingSection(sect)) orelse | 346 | const match = (try context.macho_file.getMatchingSection(sect)) orelse |
| 348 | unreachable; | 347 | unreachable; |
| ... | @@ -398,7 +397,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC | ... | @@ -398,7 +397,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 398 | else | 397 | else |
| 399 | mem.readIntLittle(i32, self.code.items[offset..][0..4]); | 398 | mem.readIntLittle(i32, self.code.items[offset..][0..4]); |
| 400 | if (rel.r_extern == 0) { | 399 | if (rel.r_extern == 0) { |
| 401 | const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment; | 400 | const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].segment; |
| 402 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; | 401 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; |
| 403 | addend -= @intCast(i64, target_sect_base_addr); | 402 | addend -= @intCast(i64, target_sect_base_addr); |
| 404 | } | 403 | } |
| ... | @@ -425,7 +424,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC | ... | @@ -425,7 +424,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 425 | else | 424 | else |
| 426 | mem.readIntLittle(i32, self.code.items[offset..][0..4]); | 425 | mem.readIntLittle(i32, self.code.items[offset..][0..4]); |
| 427 | if (rel.r_extern == 0) { | 426 | if (rel.r_extern == 0) { |
| 428 | const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment; | 427 | const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].segment; |
| 429 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; | 428 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; |
| 430 | addend -= @intCast(i64, target_sect_base_addr); | 429 | addend -= @intCast(i64, target_sect_base_addr); |
| 431 | } | 430 | } |
| ... | @@ -447,7 +446,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC | ... | @@ -447,7 +446,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 447 | if (rel.r_extern == 0) { | 446 | if (rel.r_extern == 0) { |
| 448 | // Note for the future self: when r_extern == 0, we should subtract correction from the | 447 | // Note for the future self: when r_extern == 0, we should subtract correction from the |
| 449 | // addend. | 448 | // addend. |
| 450 | const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment; | 449 | const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].segment; |
| 451 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; | 450 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; |
| 452 | addend += @intCast(i64, context.base_addr + offset + 4) - | 451 | addend += @intCast(i64, context.base_addr + offset + 4) - |
| 453 | @intCast(i64, target_sect_base_addr); | 452 | @intCast(i64, target_sect_base_addr); |
| ... | @@ -490,9 +489,9 @@ fn addPtrBindingOrRebase( | ... | @@ -490,9 +489,9 @@ fn addPtrBindingOrRebase( |
| 490 | .local => { | 489 | .local => { |
| 491 | const source_sym = context.macho_file.locals.items[self.local_sym_index]; | 490 | const source_sym = context.macho_file.locals.items[self.local_sym_index]; |
| 492 | const match = context.macho_file.section_ordinals.keys()[source_sym.n_sect - 1]; | 491 | const match = context.macho_file.section_ordinals.keys()[source_sym.n_sect - 1]; |
| 493 | const seg = context.macho_file.load_commands.items[match.seg].Segment; | 492 | const seg = context.macho_file.load_commands.items[match.seg].segment; |
| 494 | const sect = seg.sections.items[match.sect]; | 493 | const sect = seg.sections.items[match.sect]; |
| 495 | const sect_type = commands.sectionType(sect); | 494 | const sect_type = sect.type_(); |
| 496 | 495 | ||
| 497 | const should_rebase = rebase: { | 496 | const should_rebase = rebase: { |
| 498 | if (rel.r_length != 3) break :rebase false; | 497 | if (rel.r_length != 3) break :rebase false; |
| ... | @@ -705,9 +704,9 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -705,9 +704,9 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 705 | const is_tlv = is_tlv: { | 704 | const is_tlv = is_tlv: { |
| 706 | const source_sym = macho_file.locals.items[self.local_sym_index]; | 705 | const source_sym = macho_file.locals.items[self.local_sym_index]; |
| 707 | const match = macho_file.section_ordinals.keys()[source_sym.n_sect - 1]; | 706 | const match = macho_file.section_ordinals.keys()[source_sym.n_sect - 1]; |
| 708 | const seg = macho_file.load_commands.items[match.seg].Segment; | 707 | const seg = macho_file.load_commands.items[match.seg].segment; |
| 709 | const sect = seg.sections.items[match.sect]; | 708 | const sect = seg.sections.items[match.sect]; |
| 710 | break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES; | 709 | break :is_tlv sect.type_() == macho.S_THREAD_LOCAL_VARIABLES; |
| 711 | }; | 710 | }; |
| 712 | if (is_tlv) { | 711 | if (is_tlv) { |
| 713 | // For TLV relocations, the value specified as a relocation is the displacement from the | 712 | // For TLV relocations, the value specified as a relocation is the displacement from the |
| ... | @@ -715,7 +714,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { | ... | @@ -715,7 +714,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 715 | // defined TLV template init section in the following order: | 714 | // defined TLV template init section in the following order: |
| 716 | // * wrt to __thread_data if defined, then | 715 | // * wrt to __thread_data if defined, then |
| 717 | // * wrt to __thread_bss | 716 | // * wrt to __thread_bss |
| 718 | const seg = macho_file.load_commands.items[macho_file.data_segment_cmd_index.?].Segment; | 717 | const seg = macho_file.load_commands.items[macho_file.data_segment_cmd_index.?].segment; |
| 719 | const base_address = inner: { | 718 | const base_address = inner: { |
| 720 | if (macho_file.tlv_data_section_index) |i| { | 719 | if (macho_file.tlv_data_section_index) |i| { |
| 721 | break :inner seg.sections.items[i].addr; | 720 | break :inner seg.sections.items[i].addr; |
src/link/MachO/DebugSymbols.zig+87-54| ... | @@ -12,15 +12,12 @@ const leb = std.leb; | ... | @@ -12,15 +12,12 @@ const leb = std.leb; |
| 12 | const Allocator = mem.Allocator; | 12 | const Allocator = mem.Allocator; |
| 13 | 13 | ||
| 14 | const build_options = @import("build_options"); | 14 | const build_options = @import("build_options"); |
| 15 | const commands = @import("commands.zig"); | ||
| 16 | const trace = @import("../../tracy.zig").trace; | 15 | const trace = @import("../../tracy.zig").trace; |
| 17 | const LoadCommand = commands.LoadCommand; | ||
| 18 | const Module = @import("../../Module.zig"); | 16 | const Module = @import("../../Module.zig"); |
| 19 | const Type = @import("../../type.zig").Type; | 17 | const Type = @import("../../type.zig").Type; |
| 20 | const link = @import("../../link.zig"); | 18 | const link = @import("../../link.zig"); |
| 21 | const MachO = @import("../MachO.zig"); | 19 | const MachO = @import("../MachO.zig"); |
| 22 | const TextBlock = MachO.TextBlock; | 20 | const TextBlock = MachO.TextBlock; |
| 23 | const SegmentCommand = commands.SegmentCommand; | ||
| 24 | const SrcFn = MachO.SrcFn; | 21 | const SrcFn = MachO.SrcFn; |
| 25 | const makeStaticString = MachO.makeStaticString; | 22 | const makeStaticString = MachO.makeStaticString; |
| 26 | const padToIdeal = MachO.padToIdeal; | 23 | const padToIdeal = MachO.padToIdeal; |
| ... | @@ -31,7 +28,7 @@ base: *MachO, | ... | @@ -31,7 +28,7 @@ base: *MachO, |
| 31 | file: fs.File, | 28 | file: fs.File, |
| 32 | 29 | ||
| 33 | /// Table of all load commands | 30 | /// Table of all load commands |
| 34 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 31 | load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{}, |
| 35 | /// __PAGEZERO segment | 32 | /// __PAGEZERO segment |
| 36 | pagezero_segment_cmd_index: ?u16 = null, | 33 | pagezero_segment_cmd_index: ?u16 = null, |
| 37 | /// __TEXT segment | 34 | /// __TEXT segment |
| ... | @@ -113,7 +110,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -113,7 +110,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 113 | } | 110 | } |
| 114 | if (self.symtab_cmd_index == null) { | 111 | if (self.symtab_cmd_index == null) { |
| 115 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 112 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 116 | const base_cmd = self.base.load_commands.items[self.base.symtab_cmd_index.?].Symtab; | 113 | const base_cmd = self.base.load_commands.items[self.base.symtab_cmd_index.?].symtab; |
| 117 | const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64); | 114 | const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64); |
| 118 | const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64)); | 115 | const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64)); |
| 119 | 116 | ||
| ... | @@ -124,7 +121,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -124,7 +121,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 124 | log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize }); | 121 | log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize }); |
| 125 | 122 | ||
| 126 | try self.load_commands.append(allocator, .{ | 123 | try self.load_commands.append(allocator, .{ |
| 127 | .Symtab = .{ | 124 | .symtab = .{ |
| 128 | .cmd = macho.LC_SYMTAB, | 125 | .cmd = macho.LC_SYMTAB, |
| 129 | .cmdsize = @sizeOf(macho.symtab_command), | 126 | .cmdsize = @sizeOf(macho.symtab_command), |
| 130 | .symoff = @intCast(u32, symtab_off), | 127 | .symoff = @intCast(u32, symtab_off), |
| ... | @@ -138,48 +135,48 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -138,48 +135,48 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 138 | } | 135 | } |
| 139 | if (self.pagezero_segment_cmd_index == null) { | 136 | if (self.pagezero_segment_cmd_index == null) { |
| 140 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 137 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 141 | const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].Segment; | 138 | const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].segment; |
| 142 | const cmd = try self.copySegmentCommand(allocator, base_cmd); | 139 | const cmd = try self.copySegmentCommand(allocator, base_cmd); |
| 143 | try self.load_commands.append(allocator, .{ .Segment = cmd }); | 140 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 144 | self.load_commands_dirty = true; | 141 | self.load_commands_dirty = true; |
| 145 | } | 142 | } |
| 146 | if (self.text_segment_cmd_index == null) { | 143 | if (self.text_segment_cmd_index == null) { |
| 147 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 144 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 148 | const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].Segment; | 145 | const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].segment; |
| 149 | const cmd = try self.copySegmentCommand(allocator, base_cmd); | 146 | const cmd = try self.copySegmentCommand(allocator, base_cmd); |
| 150 | try self.load_commands.append(allocator, .{ .Segment = cmd }); | 147 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 151 | self.load_commands_dirty = true; | 148 | self.load_commands_dirty = true; |
| 152 | } | 149 | } |
| 153 | if (self.data_const_segment_cmd_index == null) outer: { | 150 | if (self.data_const_segment_cmd_index == null) outer: { |
| 154 | if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional | 151 | if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional |
| 155 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 152 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 156 | const base_cmd = self.base.load_commands.items[self.base.data_const_segment_cmd_index.?].Segment; | 153 | const base_cmd = self.base.load_commands.items[self.base.data_const_segment_cmd_index.?].segment; |
| 157 | const cmd = try self.copySegmentCommand(allocator, base_cmd); | 154 | const cmd = try self.copySegmentCommand(allocator, base_cmd); |
| 158 | try self.load_commands.append(allocator, .{ .Segment = cmd }); | 155 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 159 | self.load_commands_dirty = true; | 156 | self.load_commands_dirty = true; |
| 160 | } | 157 | } |
| 161 | if (self.data_segment_cmd_index == null) outer: { | 158 | if (self.data_segment_cmd_index == null) outer: { |
| 162 | if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional | 159 | if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional |
| 163 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 160 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 164 | const base_cmd = self.base.load_commands.items[self.base.data_segment_cmd_index.?].Segment; | 161 | const base_cmd = self.base.load_commands.items[self.base.data_segment_cmd_index.?].segment; |
| 165 | const cmd = try self.copySegmentCommand(allocator, base_cmd); | 162 | const cmd = try self.copySegmentCommand(allocator, base_cmd); |
| 166 | try self.load_commands.append(allocator, .{ .Segment = cmd }); | 163 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 167 | self.load_commands_dirty = true; | 164 | self.load_commands_dirty = true; |
| 168 | } | 165 | } |
| 169 | if (self.linkedit_segment_cmd_index == null) { | 166 | if (self.linkedit_segment_cmd_index == null) { |
| 170 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 167 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 171 | const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].Segment; | 168 | const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].segment; |
| 172 | var cmd = try self.copySegmentCommand(allocator, base_cmd); | 169 | var cmd = try self.copySegmentCommand(allocator, base_cmd); |
| 173 | cmd.inner.vmsize = self.linkedit_size; | 170 | cmd.inner.vmsize = self.linkedit_size; |
| 174 | cmd.inner.fileoff = self.linkedit_off; | 171 | cmd.inner.fileoff = self.linkedit_off; |
| 175 | cmd.inner.filesize = self.linkedit_size; | 172 | cmd.inner.filesize = self.linkedit_size; |
| 176 | try self.load_commands.append(allocator, .{ .Segment = cmd }); | 173 | try self.load_commands.append(allocator, .{ .segment = cmd }); |
| 177 | self.load_commands_dirty = true; | 174 | self.load_commands_dirty = true; |
| 178 | } | 175 | } |
| 179 | if (self.dwarf_segment_cmd_index == null) { | 176 | if (self.dwarf_segment_cmd_index == null) { |
| 180 | self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 177 | self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 181 | 178 | ||
| 182 | const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | 179 | const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 183 | const ideal_size: u16 = 200 + 128 + 160 + 250; | 180 | const ideal_size: u16 = 200 + 128 + 160 + 250; |
| 184 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size); | 181 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size); |
| 185 | const off = linkedit.inner.fileoff + linkedit.inner.filesize; | 182 | const off = linkedit.inner.fileoff + linkedit.inner.filesize; |
| ... | @@ -188,7 +185,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -188,7 +185,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 188 | log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size }); | 185 | log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 189 | 186 | ||
| 190 | try self.load_commands.append(allocator, .{ | 187 | try self.load_commands.append(allocator, .{ |
| 191 | .Segment = .{ | 188 | .segment = .{ |
| 192 | .inner = .{ | 189 | .inner = .{ |
| 193 | .segname = makeStaticString("__DWARF"), | 190 | .segname = makeStaticString("__DWARF"), |
| 194 | .vmaddr = vmaddr, | 191 | .vmaddr = vmaddr, |
| ... | @@ -228,7 +225,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void | ... | @@ -228,7 +225,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 228 | } | 225 | } |
| 229 | 226 | ||
| 230 | fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u16 { | 227 | fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u16 { |
| 231 | const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 228 | const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 232 | var sect = macho.section_64{ | 229 | var sect = macho.section_64{ |
| 233 | .sectname = makeStaticString(sectname), | 230 | .sectname = makeStaticString(sectname), |
| 234 | .segname = seg.inner.segname, | 231 | .segname = seg.inner.segname, |
| ... | @@ -236,13 +233,13 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme | ... | @@ -236,13 +233,13 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme |
| 236 | .@"align" = alignment, | 233 | .@"align" = alignment, |
| 237 | }; | 234 | }; |
| 238 | const alignment_pow_2 = try math.powi(u32, 2, alignment); | 235 | const alignment_pow_2 = try math.powi(u32, 2, alignment); |
| 239 | const off = seg.findFreeSpace(size, alignment_pow_2, null); | 236 | const off = self.findFreeSpace(size, alignment_pow_2); |
| 240 | 237 | ||
| 241 | assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand | 238 | assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand |
| 242 | 239 | ||
| 243 | log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{ | 240 | log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{ |
| 244 | commands.segmentName(sect), | 241 | sect.segName(), |
| 245 | commands.sectionName(sect), | 242 | sect.sectName(), |
| 246 | off, | 243 | off, |
| 247 | off + size, | 244 | off + size, |
| 248 | }); | 245 | }); |
| ... | @@ -268,6 +265,28 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme | ... | @@ -268,6 +265,28 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme |
| 268 | return index; | 265 | return index; |
| 269 | } | 266 | } |
| 270 | 267 | ||
| 268 | fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 { | ||
| 269 | const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; | ||
| 270 | const end = start + padToIdeal(size); | ||
| 271 | for (seg.sections.items) |section| { | ||
| 272 | const increased_size = padToIdeal(section.size); | ||
| 273 | const test_end = section.offset + increased_size; | ||
| 274 | if (end > section.offset and start < test_end) { | ||
| 275 | return test_end; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | return null; | ||
| 279 | } | ||
| 280 | |||
| 281 | fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 { | ||
| 282 | const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; | ||
| 283 | var offset: u64 = seg.inner.fileoff; | ||
| 284 | while (self.detectAllocCollision(offset, object_size)) |item_end| { | ||
| 285 | offset = mem.alignForwardGeneric(u64, item_end, min_alignment); | ||
| 286 | } | ||
| 287 | return offset; | ||
| 288 | } | ||
| 289 | |||
| 271 | pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Options) !void { | 290 | pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Options) !void { |
| 272 | // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the | 291 | // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the |
| 273 | // Zig source code. | 292 | // Zig source code. |
| ... | @@ -275,7 +294,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -275,7 +294,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 275 | const init_len_size: usize = 4; | 294 | const init_len_size: usize = 4; |
| 276 | 295 | ||
| 277 | if (self.debug_abbrev_section_dirty) { | 296 | if (self.debug_abbrev_section_dirty) { |
| 278 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 297 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 279 | const debug_abbrev_sect = &dwarf_segment.sections.items[self.debug_abbrev_section_index.?]; | 298 | const debug_abbrev_sect = &dwarf_segment.sections.items[self.debug_abbrev_section_index.?]; |
| 280 | 299 | ||
| 281 | // These are LEB encoded but since the values are all less than 127 | 300 | // These are LEB encoded but since the values are all less than 127 |
| ... | @@ -320,10 +339,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -320,10 +339,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 320 | }; | 339 | }; |
| 321 | 340 | ||
| 322 | const needed_size = abbrev_buf.len; | 341 | const needed_size = abbrev_buf.len; |
| 323 | const allocated_size = dwarf_segment.allocatedSize(debug_abbrev_sect.offset); | 342 | const allocated_size = self.allocatedSize(debug_abbrev_sect.offset); |
| 324 | if (needed_size > allocated_size) { | 343 | if (needed_size > allocated_size) { |
| 325 | debug_abbrev_sect.size = 0; // free the space | 344 | debug_abbrev_sect.size = 0; // free the space |
| 326 | const offset = dwarf_segment.findFreeSpace(needed_size, 1, null); | 345 | const offset = self.findFreeSpace(needed_size, 1); |
| 327 | debug_abbrev_sect.offset = @intCast(u32, offset); | 346 | debug_abbrev_sect.offset = @intCast(u32, offset); |
| 328 | debug_abbrev_sect.addr = dwarf_segment.inner.vmaddr + offset - dwarf_segment.inner.fileoff; | 347 | debug_abbrev_sect.addr = dwarf_segment.inner.vmaddr + offset - dwarf_segment.inner.fileoff; |
| 329 | } | 348 | } |
| ... | @@ -345,7 +364,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -345,7 +364,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 345 | // leave debug_info_header_dirty=true. | 364 | // leave debug_info_header_dirty=true. |
| 346 | const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info; | 365 | const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info; |
| 347 | const last_dbg_info_decl = self.dbg_info_decl_last.?; | 366 | const last_dbg_info_decl = self.dbg_info_decl_last.?; |
| 348 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 367 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 349 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; | 368 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; |
| 350 | 369 | ||
| 351 | // We have a function to compute the upper bound size, because it's needed | 370 | // We have a function to compute the upper bound size, because it's needed |
| ... | @@ -372,7 +391,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -372,7 +391,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 372 | const producer_strp = try self.makeDebugString(allocator, link.producer_string); | 391 | const producer_strp = try self.makeDebugString(allocator, link.producer_string); |
| 373 | // Currently only one compilation unit is supported, so the address range is simply | 392 | // Currently only one compilation unit is supported, so the address range is simply |
| 374 | // identical to the main program header virtual address and memory size. | 393 | // identical to the main program header virtual address and memory size. |
| 375 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 394 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 376 | const text_section = text_segment.sections.items[self.text_section_index.?]; | 395 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 377 | const low_pc = text_section.addr; | 396 | const low_pc = text_section.addr; |
| 378 | const high_pc = text_section.addr + text_section.size; | 397 | const high_pc = text_section.addr + text_section.size; |
| ... | @@ -399,7 +418,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -399,7 +418,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 399 | } | 418 | } |
| 400 | 419 | ||
| 401 | if (self.debug_aranges_section_dirty) { | 420 | if (self.debug_aranges_section_dirty) { |
| 402 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 421 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 403 | const debug_aranges_sect = &dwarf_segment.sections.items[self.debug_aranges_section_index.?]; | 422 | const debug_aranges_sect = &dwarf_segment.sections.items[self.debug_aranges_section_index.?]; |
| 404 | 423 | ||
| 405 | // Enough for all the data without resizing. When support for more compilation units | 424 | // Enough for all the data without resizing. When support for more compilation units |
| ... | @@ -426,7 +445,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -426,7 +445,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 426 | 445 | ||
| 427 | // Currently only one compilation unit is supported, so the address range is simply | 446 | // Currently only one compilation unit is supported, so the address range is simply |
| 428 | // identical to the main program header virtual address and memory size. | 447 | // identical to the main program header virtual address and memory size. |
| 429 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 448 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 430 | const text_section = text_segment.sections.items[self.text_section_index.?]; | 449 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 431 | mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.addr); | 450 | mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.addr); |
| 432 | mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size); | 451 | mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size); |
| ... | @@ -442,10 +461,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -442,10 +461,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 442 | mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len)); | 461 | mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len)); |
| 443 | 462 | ||
| 444 | const needed_size = di_buf.items.len; | 463 | const needed_size = di_buf.items.len; |
| 445 | const allocated_size = dwarf_segment.allocatedSize(debug_aranges_sect.offset); | 464 | const allocated_size = self.allocatedSize(debug_aranges_sect.offset); |
| 446 | if (needed_size > allocated_size) { | 465 | if (needed_size > allocated_size) { |
| 447 | debug_aranges_sect.size = 0; // free the space | 466 | debug_aranges_sect.size = 0; // free the space |
| 448 | const new_offset = dwarf_segment.findFreeSpace(needed_size, 16, null); | 467 | const new_offset = self.findFreeSpace(needed_size, 16); |
| 449 | debug_aranges_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff; | 468 | debug_aranges_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff; |
| 450 | debug_aranges_sect.offset = @intCast(u32, new_offset); | 469 | debug_aranges_sect.offset = @intCast(u32, new_offset); |
| 451 | } | 470 | } |
| ... | @@ -467,7 +486,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -467,7 +486,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 467 | const dbg_line_prg_end = self.getDebugLineProgramEnd(); | 486 | const dbg_line_prg_end = self.getDebugLineProgramEnd(); |
| 468 | assert(dbg_line_prg_end != 0); | 487 | assert(dbg_line_prg_end != 0); |
| 469 | 488 | ||
| 470 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 489 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 471 | const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?]; | 490 | const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?]; |
| 472 | 491 | ||
| 473 | // The size of this header is variable, depending on the number of directories, | 492 | // The size of this header is variable, depending on the number of directories, |
| ... | @@ -540,15 +559,15 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti | ... | @@ -540,15 +559,15 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 540 | self.debug_line_header_dirty = false; | 559 | self.debug_line_header_dirty = false; |
| 541 | } | 560 | } |
| 542 | { | 561 | { |
| 543 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 562 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 544 | const debug_strtab_sect = &dwarf_segment.sections.items[self.debug_str_section_index.?]; | 563 | const debug_strtab_sect = &dwarf_segment.sections.items[self.debug_str_section_index.?]; |
| 545 | if (self.debug_string_table_dirty or self.debug_string_table.items.len != debug_strtab_sect.size) { | 564 | if (self.debug_string_table_dirty or self.debug_string_table.items.len != debug_strtab_sect.size) { |
| 546 | const allocated_size = dwarf_segment.allocatedSize(debug_strtab_sect.offset); | 565 | const allocated_size = self.allocatedSize(debug_strtab_sect.offset); |
| 547 | const needed_size = self.debug_string_table.items.len; | 566 | const needed_size = self.debug_string_table.items.len; |
| 548 | 567 | ||
| 549 | if (needed_size > allocated_size) { | 568 | if (needed_size > allocated_size) { |
| 550 | debug_strtab_sect.size = 0; // free the space | 569 | debug_strtab_sect.size = 0; // free the space |
| 551 | const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null); | 570 | const new_offset = self.findFreeSpace(needed_size, 1); |
| 552 | debug_strtab_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff; | 571 | debug_strtab_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff; |
| 553 | debug_strtab_sect.offset = @intCast(u32, new_offset); | 572 | debug_strtab_sect.offset = @intCast(u32, new_offset); |
| 554 | } | 573 | } |
| ... | @@ -588,8 +607,12 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void { | ... | @@ -588,8 +607,12 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void { |
| 588 | self.file.close(); | 607 | self.file.close(); |
| 589 | } | 608 | } |
| 590 | 609 | ||
| 591 | fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: SegmentCommand) !SegmentCommand { | 610 | fn copySegmentCommand( |
| 592 | var cmd = SegmentCommand{ | 611 | self: *DebugSymbols, |
| 612 | allocator: Allocator, | ||
| 613 | base_cmd: macho.SegmentCommand, | ||
| 614 | ) !macho.SegmentCommand { | ||
| 615 | var cmd = macho.SegmentCommand{ | ||
| 593 | .inner = .{ | 616 | .inner = .{ |
| 594 | .segname = undefined, | 617 | .segname = undefined, |
| 595 | .cmdsize = base_cmd.inner.cmdsize, | 618 | .cmdsize = base_cmd.inner.cmdsize, |
| ... | @@ -633,7 +656,7 @@ fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: Segme | ... | @@ -633,7 +656,7 @@ fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: Segme |
| 633 | } | 656 | } |
| 634 | 657 | ||
| 635 | fn updateDwarfSegment(self: *DebugSymbols) void { | 658 | fn updateDwarfSegment(self: *DebugSymbols) void { |
| 636 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 659 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 637 | var file_size: u64 = 0; | 660 | var file_size: u64 = 0; |
| 638 | for (dwarf_segment.sections.items) |sect| { | 661 | for (dwarf_segment.sections.items) |sect| { |
| 639 | file_size += sect.size; | 662 | file_size += sect.size; |
| ... | @@ -670,9 +693,8 @@ fn writeLoadCommands(self: *DebugSymbols, allocator: Allocator) !void { | ... | @@ -670,9 +693,8 @@ fn writeLoadCommands(self: *DebugSymbols, allocator: Allocator) !void { |
| 670 | } | 693 | } |
| 671 | 694 | ||
| 672 | fn writeHeader(self: *DebugSymbols) !void { | 695 | fn writeHeader(self: *DebugSymbols) !void { |
| 673 | var header = commands.emptyHeader(.{ | 696 | var header: macho.mach_header_64 = .{}; |
| 674 | .filetype = macho.MH_DSYM, | 697 | header.filetype = macho.MH_DSYM; |
| 675 | }); | ||
| 676 | 698 | ||
| 677 | switch (self.base.base.options.target.cpu.arch) { | 699 | switch (self.base.base.options.target.cpu.arch) { |
| 678 | .aarch64 => { | 700 | .aarch64 => { |
| ... | @@ -703,7 +725,7 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 { | ... | @@ -703,7 +725,7 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 { |
| 703 | var min_pos: u64 = std.math.maxInt(u64); | 725 | var min_pos: u64 = std.math.maxInt(u64); |
| 704 | 726 | ||
| 705 | if (self.symtab_cmd_index) |idx| { | 727 | if (self.symtab_cmd_index) |idx| { |
| 706 | const symtab = self.load_commands.items[idx].Symtab; | 728 | const symtab = self.load_commands.items[idx].symtab; |
| 707 | if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff; | 729 | if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff; |
| 708 | if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff; | 730 | if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff; |
| 709 | } | 731 | } |
| ... | @@ -711,12 +733,23 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 { | ... | @@ -711,12 +733,23 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 { |
| 711 | return min_pos - start; | 733 | return min_pos - start; |
| 712 | } | 734 | } |
| 713 | 735 | ||
| 736 | fn allocatedSize(self: *DebugSymbols, start: u64) u64 { | ||
| 737 | const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; | ||
| 738 | assert(start >= seg.inner.fileoff); | ||
| 739 | var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize; | ||
| 740 | for (seg.sections.items) |section| { | ||
| 741 | if (section.offset <= start) continue; | ||
| 742 | if (section.offset < min_pos) min_pos = section.offset; | ||
| 743 | } | ||
| 744 | return min_pos - start; | ||
| 745 | } | ||
| 746 | |||
| 714 | fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 { | 747 | fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 { |
| 715 | const end = start + padToIdeal(size); | 748 | const end = start + padToIdeal(size); |
| 716 | 749 | ||
| 717 | if (self.symtab_cmd_index) |idx| outer: { | 750 | if (self.symtab_cmd_index) |idx| outer: { |
| 718 | if (self.load_commands.items.len == idx) break :outer; | 751 | if (self.load_commands.items.len == idx) break :outer; |
| 719 | const symtab = self.load_commands.items[idx].Symtab; | 752 | const symtab = self.load_commands.items[idx].symtab; |
| 720 | { | 753 | { |
| 721 | // Symbol table | 754 | // Symbol table |
| 722 | const symsize = symtab.nsyms * @sizeOf(macho.nlist_64); | 755 | const symsize = symtab.nsyms * @sizeOf(macho.nlist_64); |
| ... | @@ -748,7 +781,7 @@ fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u | ... | @@ -748,7 +781,7 @@ fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u |
| 748 | } | 781 | } |
| 749 | 782 | ||
| 750 | fn relocateSymbolTable(self: *DebugSymbols) !void { | 783 | fn relocateSymbolTable(self: *DebugSymbols) !void { |
| 751 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 784 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 752 | const nlocals = self.base.locals.items.len; | 785 | const nlocals = self.base.locals.items.len; |
| 753 | const nglobals = self.base.globals.items.len; | 786 | const nglobals = self.base.globals.items.len; |
| 754 | const nsyms = nlocals + nglobals; | 787 | const nsyms = nlocals + nglobals; |
| ... | @@ -781,7 +814,7 @@ pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void { | ... | @@ -781,7 +814,7 @@ pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void { |
| 781 | const tracy = trace(@src()); | 814 | const tracy = trace(@src()); |
| 782 | defer tracy.end(); | 815 | defer tracy.end(); |
| 783 | try self.relocateSymbolTable(); | 816 | try self.relocateSymbolTable(); |
| 784 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 817 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 785 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; | 818 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; |
| 786 | log.debug("writing local symbol {} at 0x{x}", .{ index, off }); | 819 | log.debug("writing local symbol {} at 0x{x}", .{ index, off }); |
| 787 | try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off); | 820 | try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off); |
| ... | @@ -793,7 +826,7 @@ fn writeStringTable(self: *DebugSymbols) !void { | ... | @@ -793,7 +826,7 @@ fn writeStringTable(self: *DebugSymbols) !void { |
| 793 | const tracy = trace(@src()); | 826 | const tracy = trace(@src()); |
| 794 | defer tracy.end(); | 827 | defer tracy.end(); |
| 795 | 828 | ||
| 796 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 829 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; |
| 797 | const allocated_size = self.allocatedSizeLinkedit(symtab.stroff); | 830 | const allocated_size = self.allocatedSizeLinkedit(symtab.stroff); |
| 798 | const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64)); | 831 | const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64)); |
| 799 | 832 | ||
| ... | @@ -817,7 +850,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M | ... | @@ -817,7 +850,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M |
| 817 | const func = decl.val.castTag(.function).?.data; | 850 | const func = decl.val.castTag(.function).?.data; |
| 818 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); | 851 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); |
| 819 | 852 | ||
| 820 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 853 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 821 | const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?]; | 854 | const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?]; |
| 822 | const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff(); | 855 | const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff(); |
| 823 | var data: [4]u8 = undefined; | 856 | var data: [4]u8 = undefined; |
| ... | @@ -983,7 +1016,7 @@ pub fn commitDeclDebugInfo( | ... | @@ -983,7 +1016,7 @@ pub fn commitDeclDebugInfo( |
| 983 | // `TextBlock` and the .debug_info. If you are editing this logic, you | 1016 | // `TextBlock` and the .debug_info. If you are editing this logic, you |
| 984 | // probably need to edit that logic too. | 1017 | // probably need to edit that logic too. |
| 985 | 1018 | ||
| 986 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 1019 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 987 | const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?]; | 1020 | const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?]; |
| 988 | const src_fn = &decl.fn_link.macho; | 1021 | const src_fn = &decl.fn_link.macho; |
| 989 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); | 1022 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); |
| ... | @@ -1029,8 +1062,8 @@ pub fn commitDeclDebugInfo( | ... | @@ -1029,8 +1062,8 @@ pub fn commitDeclDebugInfo( |
| 1029 | const last_src_fn = self.dbg_line_fn_last.?; | 1062 | const last_src_fn = self.dbg_line_fn_last.?; |
| 1030 | const needed_size = last_src_fn.off + last_src_fn.len; | 1063 | const needed_size = last_src_fn.off + last_src_fn.len; |
| 1031 | if (needed_size != debug_line_sect.size) { | 1064 | if (needed_size != debug_line_sect.size) { |
| 1032 | if (needed_size > dwarf_segment.allocatedSize(debug_line_sect.offset)) { | 1065 | if (needed_size > self.allocatedSize(debug_line_sect.offset)) { |
| 1033 | const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null); | 1066 | const new_offset = self.findFreeSpace(needed_size, 1); |
| 1034 | const existing_size = last_src_fn.off; | 1067 | const existing_size = last_src_fn.off; |
| 1035 | 1068 | ||
| 1036 | log.debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{ | 1069 | log.debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{ |
| ... | @@ -1152,7 +1185,7 @@ fn updateDeclDebugInfoAllocation( | ... | @@ -1152,7 +1185,7 @@ fn updateDeclDebugInfoAllocation( |
| 1152 | // `SrcFn` and the line number programs. If you are editing this logic, you | 1185 | // `SrcFn` and the line number programs. If you are editing this logic, you |
| 1153 | // probably need to edit that logic too. | 1186 | // probably need to edit that logic too. |
| 1154 | 1187 | ||
| 1155 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 1188 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 1156 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; | 1189 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; |
| 1157 | text_block.dbg_info_len = len; | 1190 | text_block.dbg_info_len = len; |
| 1158 | if (self.dbg_info_decl_last) |last| blk: { | 1191 | if (self.dbg_info_decl_last) |last| blk: { |
| ... | @@ -1203,15 +1236,15 @@ fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_buf: | ... | @@ -1203,15 +1236,15 @@ fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_buf: |
| 1203 | // `SrcFn` and the line number programs. If you are editing this logic, you | 1236 | // `SrcFn` and the line number programs. If you are editing this logic, you |
| 1204 | // probably need to edit that logic too. | 1237 | // probably need to edit that logic too. |
| 1205 | 1238 | ||
| 1206 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; | 1239 | const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment; |
| 1207 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; | 1240 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; |
| 1208 | 1241 | ||
| 1209 | const last_decl = self.dbg_info_decl_last.?; | 1242 | const last_decl = self.dbg_info_decl_last.?; |
| 1210 | // +1 for a trailing zero to end the children of the decl tag. | 1243 | // +1 for a trailing zero to end the children of the decl tag. |
| 1211 | const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1; | 1244 | const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1; |
| 1212 | if (needed_size != debug_info_sect.size) { | 1245 | if (needed_size != debug_info_sect.size) { |
| 1213 | if (needed_size > dwarf_segment.allocatedSize(debug_info_sect.offset)) { | 1246 | if (needed_size > self.allocatedSize(debug_info_sect.offset)) { |
| 1214 | const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null); | 1247 | const new_offset = self.findFreeSpace(needed_size, 1); |
| 1215 | const existing_size = last_decl.dbg_info_off; | 1248 | const existing_size = last_decl.dbg_info_off; |
| 1216 | 1249 | ||
| 1217 | log.debug("moving __debug_info section: {} bytes from 0x{x} to 0x{x}", .{ | 1250 | log.debug("moving __debug_info section: {} bytes from 0x{x} to 0x{x}", .{ |
src/link/MachO/Dylib.zig+6-8| ... | @@ -9,11 +9,9 @@ const macho = std.macho; | ... | @@ -9,11 +9,9 @@ const macho = std.macho; |
| 9 | const math = std.math; | 9 | const math = std.math; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | const fat = @import("fat.zig"); | 11 | const fat = @import("fat.zig"); |
| 12 | const commands = @import("commands.zig"); | ||
| 13 | 12 | ||
| 14 | const Allocator = mem.Allocator; | 13 | const Allocator = mem.Allocator; |
| 15 | const LibStub = @import("../tapi.zig").LibStub; | 14 | const LibStub = @import("../tapi.zig").LibStub; |
| 16 | const LoadCommand = commands.LoadCommand; | ||
| 17 | const MachO = @import("../MachO.zig"); | 15 | const MachO = @import("../MachO.zig"); |
| 18 | 16 | ||
| 19 | file: fs.File, | 17 | file: fs.File, |
| ... | @@ -25,7 +23,7 @@ header: ?macho.mach_header_64 = null, | ... | @@ -25,7 +23,7 @@ header: ?macho.mach_header_64 = null, |
| 25 | // an offset within a file if we are linking against a fat lib | 23 | // an offset within a file if we are linking against a fat lib |
| 26 | library_offset: u64 = 0, | 24 | library_offset: u64 = 0, |
| 27 | 25 | ||
| 28 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 26 | load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{}, |
| 29 | 27 | ||
| 30 | symtab_cmd_index: ?u16 = null, | 28 | symtab_cmd_index: ?u16 = null, |
| 31 | dysymtab_cmd_index: ?u16 = null, | 29 | dysymtab_cmd_index: ?u16 = null, |
| ... | @@ -53,7 +51,7 @@ pub const Id = struct { | ... | @@ -53,7 +51,7 @@ pub const Id = struct { |
| 53 | }; | 51 | }; |
| 54 | } | 52 | } |
| 55 | 53 | ||
| 56 | pub fn fromLoadCommand(allocator: Allocator, lc: commands.GenericCommandWithData(macho.dylib_command)) !Id { | 54 | pub fn fromLoadCommand(allocator: Allocator, lc: macho.GenericCommandWithData(macho.dylib_command)) !Id { |
| 57 | const dylib = lc.inner.dylib; | 55 | const dylib = lc.inner.dylib; |
| 58 | const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]); | 56 | const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]); |
| 59 | const name = try allocator.dupe(u8, mem.sliceTo(dylib_name, 0)); | 57 | const name = try allocator.dupe(u8, mem.sliceTo(dylib_name, 0)); |
| ... | @@ -177,7 +175,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende | ... | @@ -177,7 +175,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende |
| 177 | 175 | ||
| 178 | var i: u16 = 0; | 176 | var i: u16 = 0; |
| 179 | while (i < self.header.?.ncmds) : (i += 1) { | 177 | while (i < self.header.?.ncmds) : (i += 1) { |
| 180 | var cmd = try LoadCommand.read(allocator, reader); | 178 | var cmd = try macho.LoadCommand.read(allocator, reader); |
| 181 | switch (cmd.cmd()) { | 179 | switch (cmd.cmd()) { |
| 182 | macho.LC_SYMTAB => { | 180 | macho.LC_SYMTAB => { |
| 183 | self.symtab_cmd_index = i; | 181 | self.symtab_cmd_index = i; |
| ... | @@ -191,7 +189,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende | ... | @@ -191,7 +189,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende |
| 191 | macho.LC_REEXPORT_DYLIB => { | 189 | macho.LC_REEXPORT_DYLIB => { |
| 192 | if (should_lookup_reexports) { | 190 | if (should_lookup_reexports) { |
| 193 | // Parse install_name to dependent dylib. | 191 | // Parse install_name to dependent dylib. |
| 194 | var id = try Id.fromLoadCommand(allocator, cmd.Dylib); | 192 | var id = try Id.fromLoadCommand(allocator, cmd.dylib); |
| 195 | try dependent_libs.writeItem(id); | 193 | try dependent_libs.writeItem(id); |
| 196 | } | 194 | } |
| 197 | }, | 195 | }, |
| ... | @@ -209,12 +207,12 @@ fn parseId(self: *Dylib, allocator: Allocator) !void { | ... | @@ -209,12 +207,12 @@ fn parseId(self: *Dylib, allocator: Allocator) !void { |
| 209 | self.id = try Id.default(allocator, self.name); | 207 | self.id = try Id.default(allocator, self.name); |
| 210 | return; | 208 | return; |
| 211 | }; | 209 | }; |
| 212 | self.id = try Id.fromLoadCommand(allocator, self.load_commands.items[index].Dylib); | 210 | self.id = try Id.fromLoadCommand(allocator, self.load_commands.items[index].dylib); |
| 213 | } | 211 | } |
| 214 | 212 | ||
| 215 | fn parseSymbols(self: *Dylib, allocator: Allocator) !void { | 213 | fn parseSymbols(self: *Dylib, allocator: Allocator) !void { |
| 216 | const index = self.symtab_cmd_index orelse return; | 214 | const index = self.symtab_cmd_index orelse return; |
| 217 | const symtab_cmd = self.load_commands.items[index].Symtab; | 215 | const symtab_cmd = self.load_commands.items[index].symtab; |
| 218 | 216 | ||
| 219 | var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); | 217 | var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); |
| 220 | defer allocator.free(symtab); | 218 | defer allocator.free(symtab); |
src/link/MachO/Object.zig+15-22| ... | @@ -11,14 +11,10 @@ const macho = std.macho; | ... | @@ -11,14 +11,10 @@ const macho = std.macho; |
| 11 | const math = std.math; | 11 | const math = std.math; |
| 12 | const mem = std.mem; | 12 | const mem = std.mem; |
| 13 | const sort = std.sort; | 13 | const sort = std.sort; |
| 14 | const commands = @import("commands.zig"); | ||
| 15 | const segmentName = commands.segmentName; | ||
| 16 | const sectionName = commands.sectionName; | ||
| 17 | const trace = @import("../../tracy.zig").trace; | 14 | const trace = @import("../../tracy.zig").trace; |
| 18 | 15 | ||
| 19 | const Allocator = mem.Allocator; | 16 | const Allocator = mem.Allocator; |
| 20 | const Atom = @import("Atom.zig"); | 17 | const Atom = @import("Atom.zig"); |
| 21 | const LoadCommand = commands.LoadCommand; | ||
| 22 | const MachO = @import("../MachO.zig"); | 18 | const MachO = @import("../MachO.zig"); |
| 23 | 19 | ||
| 24 | file: fs.File, | 20 | file: fs.File, |
| ... | @@ -28,7 +24,7 @@ file_offset: ?u32 = null, | ... | @@ -28,7 +24,7 @@ file_offset: ?u32 = null, |
| 28 | 24 | ||
| 29 | header: ?macho.mach_header_64 = null, | 25 | header: ?macho.mach_header_64 = null, |
| 30 | 26 | ||
| 31 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 27 | load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{}, |
| 32 | 28 | ||
| 33 | segment_cmd_index: ?u16 = null, | 29 | segment_cmd_index: ?u16 = null, |
| 34 | text_section_index: ?u16 = null, | 30 | text_section_index: ?u16 = null, |
| ... | @@ -271,15 +267,15 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v | ... | @@ -271,15 +267,15 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v |
| 271 | 267 | ||
| 272 | var i: u16 = 0; | 268 | var i: u16 = 0; |
| 273 | while (i < header.ncmds) : (i += 1) { | 269 | while (i < header.ncmds) : (i += 1) { |
| 274 | var cmd = try LoadCommand.read(allocator, reader); | 270 | var cmd = try macho.LoadCommand.read(allocator, reader); |
| 275 | switch (cmd.cmd()) { | 271 | switch (cmd.cmd()) { |
| 276 | macho.LC_SEGMENT_64 => { | 272 | macho.LC_SEGMENT_64 => { |
| 277 | self.segment_cmd_index = i; | 273 | self.segment_cmd_index = i; |
| 278 | var seg = cmd.Segment; | 274 | var seg = cmd.segment; |
| 279 | for (seg.sections.items) |*sect, j| { | 275 | for (seg.sections.items) |*sect, j| { |
| 280 | const index = @intCast(u16, j); | 276 | const index = @intCast(u16, j); |
| 281 | const segname = segmentName(sect.*); | 277 | const segname = sect.segName(); |
| 282 | const sectname = sectionName(sect.*); | 278 | const sectname = sect.sectName(); |
| 283 | if (mem.eql(u8, segname, "__DWARF")) { | 279 | if (mem.eql(u8, segname, "__DWARF")) { |
| 284 | if (mem.eql(u8, sectname, "__debug_info")) { | 280 | if (mem.eql(u8, sectname, "__debug_info")) { |
| 285 | self.dwarf_debug_info_index = index; | 281 | self.dwarf_debug_info_index = index; |
| ... | @@ -308,8 +304,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v | ... | @@ -308,8 +304,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v |
| 308 | }, | 304 | }, |
| 309 | macho.LC_SYMTAB => { | 305 | macho.LC_SYMTAB => { |
| 310 | self.symtab_cmd_index = i; | 306 | self.symtab_cmd_index = i; |
| 311 | cmd.Symtab.symoff += offset; | 307 | cmd.symtab.symoff += offset; |
| 312 | cmd.Symtab.stroff += offset; | 308 | cmd.symtab.stroff += offset; |
| 313 | }, | 309 | }, |
| 314 | macho.LC_DYSYMTAB => { | 310 | macho.LC_DYSYMTAB => { |
| 315 | self.dysymtab_cmd_index = i; | 311 | self.dysymtab_cmd_index = i; |
| ... | @@ -319,7 +315,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v | ... | @@ -319,7 +315,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v |
| 319 | }, | 315 | }, |
| 320 | macho.LC_DATA_IN_CODE => { | 316 | macho.LC_DATA_IN_CODE => { |
| 321 | self.data_in_code_cmd_index = i; | 317 | self.data_in_code_cmd_index = i; |
| 322 | cmd.LinkeditData.dataoff += offset; | 318 | cmd.linkedit_data.dataoff += offset; |
| 323 | }, | 319 | }, |
| 324 | else => { | 320 | else => { |
| 325 | log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()}); | 321 | log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()}); |
| ... | @@ -385,7 +381,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! | ... | @@ -385,7 +381,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 385 | const tracy = trace(@src()); | 381 | const tracy = trace(@src()); |
| 386 | defer tracy.end(); | 382 | defer tracy.end(); |
| 387 | 383 | ||
| 388 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | 384 | const seg = self.load_commands.items[self.segment_cmd_index.?].segment; |
| 389 | 385 | ||
| 390 | log.debug("analysing {s}", .{self.name}); | 386 | log.debug("analysing {s}", .{self.name}); |
| 391 | 387 | ||
| ... | @@ -408,7 +404,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! | ... | @@ -408,7 +404,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 408 | // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we | 404 | // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we |
| 409 | // have to infer the start of undef section in the symtab ourselves. | 405 | // have to infer the start of undef section in the symtab ourselves. |
| 410 | const iundefsym = if (self.dysymtab_cmd_index) |cmd_index| blk: { | 406 | const iundefsym = if (self.dysymtab_cmd_index) |cmd_index| blk: { |
| 411 | const dysymtab = self.load_commands.items[cmd_index].Dysymtab; | 407 | const dysymtab = self.load_commands.items[cmd_index].dysymtab; |
| 412 | break :blk dysymtab.iundefsym; | 408 | break :blk dysymtab.iundefsym; |
| 413 | } else blk: { | 409 | } else blk: { |
| 414 | var iundefsym: usize = sorted_all_nlists.items.len; | 410 | var iundefsym: usize = sorted_all_nlists.items.len; |
| ... | @@ -424,10 +420,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! | ... | @@ -424,10 +420,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 424 | 420 | ||
| 425 | for (seg.sections.items) |sect, id| { | 421 | for (seg.sections.items) |sect, id| { |
| 426 | const sect_id = @intCast(u8, id); | 422 | const sect_id = @intCast(u8, id); |
| 427 | log.debug("putting section '{s},{s}' as an Atom", .{ | 423 | log.debug("putting section '{s},{s}' as an Atom", .{ sect.segName(), sect.sectName() }); |
| 428 | segmentName(sect), | ||
| 429 | sectionName(sect), | ||
| 430 | }); | ||
| 431 | 424 | ||
| 432 | // Get matching segment/section in the final artifact. | 425 | // Get matching segment/section in the final artifact. |
| 433 | const match = (try macho_file.getMatchingSection(sect)) orelse { | 426 | const match = (try macho_file.getMatchingSection(sect)) orelse { |
| ... | @@ -479,7 +472,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! | ... | @@ -479,7 +472,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 479 | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align"); | 472 | const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align"); |
| 480 | 473 | ||
| 481 | const is_zerofill = blk: { | 474 | const is_zerofill = blk: { |
| 482 | const section_type = commands.sectionType(sect); | 475 | const section_type = sect.type_(); |
| 483 | break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; | 476 | break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL; |
| 484 | }; | 477 | }; |
| 485 | if (!is_zerofill) { | 478 | if (!is_zerofill) { |
| ... | @@ -559,7 +552,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! | ... | @@ -559,7 +552,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 559 | 552 | ||
| 560 | fn parseSymtab(self: *Object, allocator: Allocator) !void { | 553 | fn parseSymtab(self: *Object, allocator: Allocator) !void { |
| 561 | const index = self.symtab_cmd_index orelse return; | 554 | const index = self.symtab_cmd_index orelse return; |
| 562 | const symtab_cmd = self.load_commands.items[index].Symtab; | 555 | const symtab_cmd = self.load_commands.items[index].symtab; |
| 563 | 556 | ||
| 564 | var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); | 557 | var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); |
| 565 | defer allocator.free(symtab); | 558 | defer allocator.free(symtab); |
| ... | @@ -607,7 +600,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void { | ... | @@ -607,7 +600,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void { |
| 607 | 600 | ||
| 608 | pub fn parseDataInCode(self: *Object, allocator: Allocator) !void { | 601 | pub fn parseDataInCode(self: *Object, allocator: Allocator) !void { |
| 609 | const index = self.data_in_code_cmd_index orelse return; | 602 | const index = self.data_in_code_cmd_index orelse return; |
| 610 | const data_in_code = self.load_commands.items[index].LinkeditData; | 603 | const data_in_code = self.load_commands.items[index].linkedit_data; |
| 611 | 604 | ||
| 612 | var buffer = try allocator.alloc(u8, data_in_code.datasize); | 605 | var buffer = try allocator.alloc(u8, data_in_code.datasize); |
| 613 | defer allocator.free(buffer); | 606 | defer allocator.free(buffer); |
| ... | @@ -626,7 +619,7 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void { | ... | @@ -626,7 +619,7 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void { |
| 626 | } | 619 | } |
| 627 | 620 | ||
| 628 | fn readSection(self: Object, allocator: Allocator, index: u16) ![]u8 { | 621 | fn readSection(self: Object, allocator: Allocator, index: u16) ![]u8 { |
| 629 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | 622 | const seg = self.load_commands.items[self.segment_cmd_index.?].segment; |
| 630 | const sect = seg.sections.items[index]; | 623 | const sect = seg.sections.items[index]; |
| 631 | var buffer = try allocator.alloc(u8, @intCast(usize, sect.size)); | 624 | var buffer = try allocator.alloc(u8, @intCast(usize, sect.size)); |
| 632 | _ = try self.file.preadAll(buffer, sect.offset); | 625 | _ = try self.file.preadAll(buffer, sect.offset); |
src/link/MachO/commands.zig deleted-523| ... | @@ -1,523 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const fs = std.fs; | ||
| 3 | const io = std.io; | ||
| 4 | const mem = std.mem; | ||
| 5 | const meta = std.meta; | ||
| 6 | const macho = std.macho; | ||
| 7 | const testing = std.testing; | ||
| 8 | const assert = std.debug.assert; | ||
| 9 | |||
| 10 | const Allocator = std.mem.Allocator; | ||
| 11 | const MachO = @import("../MachO.zig"); | ||
| 12 | const makeStaticString = MachO.makeStaticString; | ||
| 13 | const padToIdeal = MachO.padToIdeal; | ||
| 14 | |||
| 15 | pub const HeaderArgs = struct { | ||
| 16 | magic: u32 = macho.MH_MAGIC_64, | ||
| 17 | cputype: macho.cpu_type_t = 0, | ||
| 18 | cpusubtype: macho.cpu_subtype_t = 0, | ||
| 19 | filetype: u32 = 0, | ||
| 20 | flags: u32 = 0, | ||
| 21 | reserved: u32 = 0, | ||
| 22 | }; | ||
| 23 | |||
| 24 | pub fn emptyHeader(args: HeaderArgs) macho.mach_header_64 { | ||
| 25 | return .{ | ||
| 26 | .magic = args.magic, | ||
| 27 | .cputype = args.cputype, | ||
| 28 | .cpusubtype = args.cpusubtype, | ||
| 29 | .filetype = args.filetype, | ||
| 30 | .ncmds = 0, | ||
| 31 | .sizeofcmds = 0, | ||
| 32 | .flags = args.flags, | ||
| 33 | .reserved = args.reserved, | ||
| 34 | }; | ||
| 35 | } | ||
| 36 | |||
| 37 | pub const LoadCommand = union(enum) { | ||
| 38 | Segment: SegmentCommand, | ||
| 39 | DyldInfoOnly: macho.dyld_info_command, | ||
| 40 | Symtab: macho.symtab_command, | ||
| 41 | Dysymtab: macho.dysymtab_command, | ||
| 42 | Dylinker: GenericCommandWithData(macho.dylinker_command), | ||
| 43 | Dylib: GenericCommandWithData(macho.dylib_command), | ||
| 44 | Main: macho.entry_point_command, | ||
| 45 | VersionMin: macho.version_min_command, | ||
| 46 | SourceVersion: macho.source_version_command, | ||
| 47 | BuildVersion: GenericCommandWithData(macho.build_version_command), | ||
| 48 | Uuid: macho.uuid_command, | ||
| 49 | LinkeditData: macho.linkedit_data_command, | ||
| 50 | Rpath: GenericCommandWithData(macho.rpath_command), | ||
| 51 | Unknown: GenericCommandWithData(macho.load_command), | ||
| 52 | |||
| 53 | pub fn read(allocator: Allocator, reader: anytype) !LoadCommand { | ||
| 54 | const header = try reader.readStruct(macho.load_command); | ||
| 55 | var buffer = try allocator.alloc(u8, header.cmdsize); | ||
| 56 | defer allocator.free(buffer); | ||
| 57 | mem.copy(u8, buffer, mem.asBytes(&header)); | ||
| 58 | try reader.readNoEof(buffer[@sizeOf(macho.load_command)..]); | ||
| 59 | var stream = io.fixedBufferStream(buffer); | ||
| 60 | |||
| 61 | return switch (header.cmd) { | ||
| 62 | macho.LC_SEGMENT_64 => LoadCommand{ | ||
| 63 | .Segment = try SegmentCommand.read(allocator, stream.reader()), | ||
| 64 | }, | ||
| 65 | macho.LC_DYLD_INFO, | ||
| 66 | macho.LC_DYLD_INFO_ONLY, | ||
| 67 | => LoadCommand{ | ||
| 68 | .DyldInfoOnly = try stream.reader().readStruct(macho.dyld_info_command), | ||
| 69 | }, | ||
| 70 | macho.LC_SYMTAB => LoadCommand{ | ||
| 71 | .Symtab = try stream.reader().readStruct(macho.symtab_command), | ||
| 72 | }, | ||
| 73 | macho.LC_DYSYMTAB => LoadCommand{ | ||
| 74 | .Dysymtab = try stream.reader().readStruct(macho.dysymtab_command), | ||
| 75 | }, | ||
| 76 | macho.LC_ID_DYLINKER, | ||
| 77 | macho.LC_LOAD_DYLINKER, | ||
| 78 | macho.LC_DYLD_ENVIRONMENT, | ||
| 79 | => LoadCommand{ | ||
| 80 | .Dylinker = try GenericCommandWithData(macho.dylinker_command).read(allocator, stream.reader()), | ||
| 81 | }, | ||
| 82 | macho.LC_ID_DYLIB, | ||
| 83 | macho.LC_LOAD_WEAK_DYLIB, | ||
| 84 | macho.LC_LOAD_DYLIB, | ||
| 85 | macho.LC_REEXPORT_DYLIB, | ||
| 86 | => LoadCommand{ | ||
| 87 | .Dylib = try GenericCommandWithData(macho.dylib_command).read(allocator, stream.reader()), | ||
| 88 | }, | ||
| 89 | macho.LC_MAIN => LoadCommand{ | ||
| 90 | .Main = try stream.reader().readStruct(macho.entry_point_command), | ||
| 91 | }, | ||
| 92 | macho.LC_VERSION_MIN_MACOSX, | ||
| 93 | macho.LC_VERSION_MIN_IPHONEOS, | ||
| 94 | macho.LC_VERSION_MIN_WATCHOS, | ||
| 95 | macho.LC_VERSION_MIN_TVOS, | ||
| 96 | => LoadCommand{ | ||
| 97 | .VersionMin = try stream.reader().readStruct(macho.version_min_command), | ||
| 98 | }, | ||
| 99 | macho.LC_SOURCE_VERSION => LoadCommand{ | ||
| 100 | .SourceVersion = try stream.reader().readStruct(macho.source_version_command), | ||
| 101 | }, | ||
| 102 | macho.LC_BUILD_VERSION => LoadCommand{ | ||
| 103 | .BuildVersion = try GenericCommandWithData(macho.build_version_command).read(allocator, stream.reader()), | ||
| 104 | }, | ||
| 105 | macho.LC_UUID => LoadCommand{ | ||
| 106 | .Uuid = try stream.reader().readStruct(macho.uuid_command), | ||
| 107 | }, | ||
| 108 | macho.LC_FUNCTION_STARTS, | ||
| 109 | macho.LC_DATA_IN_CODE, | ||
| 110 | macho.LC_CODE_SIGNATURE, | ||
| 111 | => LoadCommand{ | ||
| 112 | .LinkeditData = try stream.reader().readStruct(macho.linkedit_data_command), | ||
| 113 | }, | ||
| 114 | macho.LC_RPATH => LoadCommand{ | ||
| 115 | .Rpath = try GenericCommandWithData(macho.rpath_command).read(allocator, stream.reader()), | ||
| 116 | }, | ||
| 117 | else => LoadCommand{ | ||
| 118 | .Unknown = try GenericCommandWithData(macho.load_command).read(allocator, stream.reader()), | ||
| 119 | }, | ||
| 120 | }; | ||
| 121 | } | ||
| 122 | |||
| 123 | pub fn write(self: LoadCommand, writer: anytype) !void { | ||
| 124 | return switch (self) { | ||
| 125 | .DyldInfoOnly => |x| writeStruct(x, writer), | ||
| 126 | .Symtab => |x| writeStruct(x, writer), | ||
| 127 | .Dysymtab => |x| writeStruct(x, writer), | ||
| 128 | .Main => |x| writeStruct(x, writer), | ||
| 129 | .VersionMin => |x| writeStruct(x, writer), | ||
| 130 | .SourceVersion => |x| writeStruct(x, writer), | ||
| 131 | .Uuid => |x| writeStruct(x, writer), | ||
| 132 | .LinkeditData => |x| writeStruct(x, writer), | ||
| 133 | .Segment => |x| x.write(writer), | ||
| 134 | .Dylinker => |x| x.write(writer), | ||
| 135 | .Dylib => |x| x.write(writer), | ||
| 136 | .Rpath => |x| x.write(writer), | ||
| 137 | .BuildVersion => |x| x.write(writer), | ||
| 138 | .Unknown => |x| x.write(writer), | ||
| 139 | }; | ||
| 140 | } | ||
| 141 | |||
| 142 | pub fn cmd(self: LoadCommand) u32 { | ||
| 143 | return switch (self) { | ||
| 144 | .DyldInfoOnly => |x| x.cmd, | ||
| 145 | .Symtab => |x| x.cmd, | ||
| 146 | .Dysymtab => |x| x.cmd, | ||
| 147 | .Main => |x| x.cmd, | ||
| 148 | .VersionMin => |x| x.cmd, | ||
| 149 | .SourceVersion => |x| x.cmd, | ||
| 150 | .Uuid => |x| x.cmd, | ||
| 151 | .LinkeditData => |x| x.cmd, | ||
| 152 | .Segment => |x| x.inner.cmd, | ||
| 153 | .Dylinker => |x| x.inner.cmd, | ||
| 154 | .Dylib => |x| x.inner.cmd, | ||
| 155 | .Rpath => |x| x.inner.cmd, | ||
| 156 | .BuildVersion => |x| x.inner.cmd, | ||
| 157 | .Unknown => |x| x.inner.cmd, | ||
| 158 | }; | ||
| 159 | } | ||
| 160 | |||
| 161 | pub fn cmdsize(self: LoadCommand) u32 { | ||
| 162 | return switch (self) { | ||
| 163 | .DyldInfoOnly => |x| x.cmdsize, | ||
| 164 | .Symtab => |x| x.cmdsize, | ||
| 165 | .Dysymtab => |x| x.cmdsize, | ||
| 166 | .Main => |x| x.cmdsize, | ||
| 167 | .VersionMin => |x| x.cmdsize, | ||
| 168 | .SourceVersion => |x| x.cmdsize, | ||
| 169 | .LinkeditData => |x| x.cmdsize, | ||
| 170 | .Uuid => |x| x.cmdsize, | ||
| 171 | .Segment => |x| x.inner.cmdsize, | ||
| 172 | .Dylinker => |x| x.inner.cmdsize, | ||
| 173 | .Dylib => |x| x.inner.cmdsize, | ||
| 174 | .Rpath => |x| x.inner.cmdsize, | ||
| 175 | .BuildVersion => |x| x.inner.cmdsize, | ||
| 176 | .Unknown => |x| x.inner.cmdsize, | ||
| 177 | }; | ||
| 178 | } | ||
| 179 | |||
| 180 | pub fn deinit(self: *LoadCommand, allocator: Allocator) void { | ||
| 181 | return switch (self.*) { | ||
| 182 | .Segment => |*x| x.deinit(allocator), | ||
| 183 | .Dylinker => |*x| x.deinit(allocator), | ||
| 184 | .Dylib => |*x| x.deinit(allocator), | ||
| 185 | .Rpath => |*x| x.deinit(allocator), | ||
| 186 | .BuildVersion => |*x| x.deinit(allocator), | ||
| 187 | .Unknown => |*x| x.deinit(allocator), | ||
| 188 | else => {}, | ||
| 189 | }; | ||
| 190 | } | ||
| 191 | |||
| 192 | fn writeStruct(command: anytype, writer: anytype) !void { | ||
| 193 | return writer.writeAll(mem.asBytes(&command)); | ||
| 194 | } | ||
| 195 | |||
| 196 | fn eql(self: LoadCommand, other: LoadCommand) bool { | ||
| 197 | if (@as(meta.Tag(LoadCommand), self) != @as(meta.Tag(LoadCommand), other)) return false; | ||
| 198 | return switch (self) { | ||
| 199 | .DyldInfoOnly => |x| meta.eql(x, other.DyldInfoOnly), | ||
| 200 | .Symtab => |x| meta.eql(x, other.Symtab), | ||
| 201 | .Dysymtab => |x| meta.eql(x, other.Dysymtab), | ||
| 202 | .Main => |x| meta.eql(x, other.Main), | ||
| 203 | .VersionMin => |x| meta.eql(x, other.VersionMin), | ||
| 204 | .SourceVersion => |x| meta.eql(x, other.SourceVersion), | ||
| 205 | .BuildVersion => |x| x.eql(other.BuildVersion), | ||
| 206 | .Uuid => |x| meta.eql(x, other.Uuid), | ||
| 207 | .LinkeditData => |x| meta.eql(x, other.LinkeditData), | ||
| 208 | .Segment => |x| x.eql(other.Segment), | ||
| 209 | .Dylinker => |x| x.eql(other.Dylinker), | ||
| 210 | .Dylib => |x| x.eql(other.Dylib), | ||
| 211 | .Rpath => |x| x.eql(other.Rpath), | ||
| 212 | .Unknown => |x| x.eql(other.Unknown), | ||
| 213 | }; | ||
| 214 | } | ||
| 215 | }; | ||
| 216 | |||
| 217 | pub const SegmentCommand = struct { | ||
| 218 | inner: macho.segment_command_64, | ||
| 219 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, | ||
| 220 | |||
| 221 | pub fn read(alloc: Allocator, reader: anytype) !SegmentCommand { | ||
| 222 | const inner = try reader.readStruct(macho.segment_command_64); | ||
| 223 | var segment = SegmentCommand{ | ||
| 224 | .inner = inner, | ||
| 225 | }; | ||
| 226 | try segment.sections.ensureTotalCapacityPrecise(alloc, inner.nsects); | ||
| 227 | |||
| 228 | var i: usize = 0; | ||
| 229 | while (i < inner.nsects) : (i += 1) { | ||
| 230 | const section = try reader.readStruct(macho.section_64); | ||
| 231 | segment.sections.appendAssumeCapacity(section); | ||
| 232 | } | ||
| 233 | |||
| 234 | return segment; | ||
| 235 | } | ||
| 236 | |||
| 237 | pub fn write(self: SegmentCommand, writer: anytype) !void { | ||
| 238 | try writer.writeAll(mem.asBytes(&self.inner)); | ||
| 239 | for (self.sections.items) |sect| { | ||
| 240 | try writer.writeAll(mem.asBytes(&sect)); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | pub fn deinit(self: *SegmentCommand, alloc: Allocator) void { | ||
| 245 | self.sections.deinit(alloc); | ||
| 246 | } | ||
| 247 | |||
| 248 | pub fn allocatedSize(self: SegmentCommand, start: u64) u64 { | ||
| 249 | assert(start >= self.inner.fileoff); | ||
| 250 | var min_pos: u64 = self.inner.fileoff + self.inner.filesize; | ||
| 251 | for (self.sections.items) |section| { | ||
| 252 | if (section.offset <= start) continue; | ||
| 253 | if (section.offset < min_pos) min_pos = section.offset; | ||
| 254 | } | ||
| 255 | return min_pos - start; | ||
| 256 | } | ||
| 257 | |||
| 258 | fn detectAllocCollision(self: SegmentCommand, start: u64, size: u64) ?u64 { | ||
| 259 | const end = start + padToIdeal(size); | ||
| 260 | for (self.sections.items) |section| { | ||
| 261 | const increased_size = padToIdeal(section.size); | ||
| 262 | const test_end = section.offset + increased_size; | ||
| 263 | if (end > section.offset and start < test_end) { | ||
| 264 | return test_end; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | return null; | ||
| 268 | } | ||
| 269 | |||
| 270 | pub fn findFreeSpace(self: SegmentCommand, object_size: u64, min_alignment: u64, start: ?u64) u64 { | ||
| 271 | var offset: u64 = if (start) |v| v else self.inner.fileoff; | ||
| 272 | while (self.detectAllocCollision(offset, object_size)) |item_end| { | ||
| 273 | offset = mem.alignForwardGeneric(u64, item_end, min_alignment); | ||
| 274 | } | ||
| 275 | return offset; | ||
| 276 | } | ||
| 277 | |||
| 278 | fn eql(self: SegmentCommand, other: SegmentCommand) bool { | ||
| 279 | if (!meta.eql(self.inner, other.inner)) return false; | ||
| 280 | const lhs = self.sections.items; | ||
| 281 | const rhs = other.sections.items; | ||
| 282 | var i: usize = 0; | ||
| 283 | while (i < self.inner.nsects) : (i += 1) { | ||
| 284 | if (!meta.eql(lhs[i], rhs[i])) return false; | ||
| 285 | } | ||
| 286 | return true; | ||
| 287 | } | ||
| 288 | }; | ||
| 289 | |||
| 290 | pub fn emptyGenericCommandWithData(cmd: anytype) GenericCommandWithData(@TypeOf(cmd)) { | ||
| 291 | return .{ .inner = cmd }; | ||
| 292 | } | ||
| 293 | |||
| 294 | pub fn GenericCommandWithData(comptime Cmd: type) type { | ||
| 295 | return struct { | ||
| 296 | inner: Cmd, | ||
| 297 | /// This field remains undefined until `read` is called. | ||
| 298 | data: []u8 = undefined, | ||
| 299 | |||
| 300 | const Self = @This(); | ||
| 301 | |||
| 302 | pub fn read(allocator: Allocator, reader: anytype) !Self { | ||
| 303 | const inner = try reader.readStruct(Cmd); | ||
| 304 | var data = try allocator.alloc(u8, inner.cmdsize - @sizeOf(Cmd)); | ||
| 305 | errdefer allocator.free(data); | ||
| 306 | try reader.readNoEof(data); | ||
| 307 | return Self{ | ||
| 308 | .inner = inner, | ||
| 309 | .data = data, | ||
| 310 | }; | ||
| 311 | } | ||
| 312 | |||
| 313 | pub fn write(self: Self, writer: anytype) !void { | ||
| 314 | try writer.writeAll(mem.asBytes(&self.inner)); | ||
| 315 | try writer.writeAll(self.data); | ||
| 316 | } | ||
| 317 | |||
| 318 | pub fn deinit(self: *Self, allocator: Allocator) void { | ||
| 319 | allocator.free(self.data); | ||
| 320 | } | ||
| 321 | |||
| 322 | fn eql(self: Self, other: Self) bool { | ||
| 323 | if (!meta.eql(self.inner, other.inner)) return false; | ||
| 324 | return mem.eql(u8, self.data, other.data); | ||
| 325 | } | ||
| 326 | }; | ||
| 327 | } | ||
| 328 | |||
| 329 | pub fn createLoadDylibCommand( | ||
| 330 | allocator: Allocator, | ||
| 331 | name: []const u8, | ||
| 332 | timestamp: u32, | ||
| 333 | current_version: u32, | ||
| 334 | compatibility_version: u32, | ||
| 335 | ) !GenericCommandWithData(macho.dylib_command) { | ||
| 336 | const cmdsize = @intCast(u32, mem.alignForwardGeneric( | ||
| 337 | u64, | ||
| 338 | @sizeOf(macho.dylib_command) + name.len + 1, // +1 for nul | ||
| 339 | @sizeOf(u64), | ||
| 340 | )); | ||
| 341 | |||
| 342 | var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ | ||
| 343 | .cmd = macho.LC_LOAD_DYLIB, | ||
| 344 | .cmdsize = cmdsize, | ||
| 345 | .dylib = .{ | ||
| 346 | .name = @sizeOf(macho.dylib_command), | ||
| 347 | .timestamp = timestamp, | ||
| 348 | .current_version = current_version, | ||
| 349 | .compatibility_version = compatibility_version, | ||
| 350 | }, | ||
| 351 | }); | ||
| 352 | dylib_cmd.data = try allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); | ||
| 353 | |||
| 354 | mem.set(u8, dylib_cmd.data, 0); | ||
| 355 | mem.copy(u8, dylib_cmd.data, name); | ||
| 356 | |||
| 357 | return dylib_cmd; | ||
| 358 | } | ||
| 359 | |||
| 360 | fn parseName(name: *const [16]u8) []const u8 { | ||
| 361 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; | ||
| 362 | return name[0..len]; | ||
| 363 | } | ||
| 364 | |||
| 365 | pub fn segmentName(sect: macho.section_64) []const u8 { | ||
| 366 | return parseName(&sect.segname); | ||
| 367 | } | ||
| 368 | |||
| 369 | pub fn sectionName(sect: macho.section_64) []const u8 { | ||
| 370 | return parseName(&sect.sectname); | ||
| 371 | } | ||
| 372 | |||
| 373 | pub fn sectionType(sect: macho.section_64) u8 { | ||
| 374 | return @truncate(u8, sect.flags & 0xff); | ||
| 375 | } | ||
| 376 | |||
| 377 | pub fn sectionAttrs(sect: macho.section_64) u32 { | ||
| 378 | return sect.flags & 0xffffff00; | ||
| 379 | } | ||
| 380 | |||
| 381 | pub fn sectionIsCode(sect: macho.section_64) bool { | ||
| 382 | const attr = sectionAttrs(sect); | ||
| 383 | return attr & macho.S_ATTR_PURE_INSTRUCTIONS != 0 or attr & macho.S_ATTR_SOME_INSTRUCTIONS != 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | pub fn sectionIsDebug(sect: macho.section_64) bool { | ||
| 387 | return sectionAttrs(sect) & macho.S_ATTR_DEBUG != 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | pub fn sectionIsDontDeadStrip(sect: macho.section_64) bool { | ||
| 391 | return sectionAttrs(sect) & macho.S_ATTR_NO_DEAD_STRIP != 0; | ||
| 392 | } | ||
| 393 | |||
| 394 | pub fn sectionIsDontDeadStripIfReferencesLive(sect: macho.section_64) bool { | ||
| 395 | return sectionAttrs(sect) & macho.S_ATTR_LIVE_SUPPORT != 0; | ||
| 396 | } | ||
| 397 | |||
| 398 | fn testRead(allocator: Allocator, buffer: []const u8, expected: anytype) !void { | ||
| 399 | var stream = io.fixedBufferStream(buffer); | ||
| 400 | var given = try LoadCommand.read(allocator, stream.reader()); | ||
| 401 | defer given.deinit(allocator); | ||
| 402 | try testing.expect(expected.eql(given)); | ||
| 403 | } | ||
| 404 | |||
| 405 | fn testWrite(buffer: []u8, cmd: LoadCommand, expected: []const u8) !void { | ||
| 406 | var stream = io.fixedBufferStream(buffer); | ||
| 407 | try cmd.write(stream.writer()); | ||
| 408 | try testing.expect(mem.eql(u8, expected, buffer[0..expected.len])); | ||
| 409 | } | ||
| 410 | |||
| 411 | test "read-write segment command" { | ||
| 412 | var gpa = testing.allocator; | ||
| 413 | const in_buffer = &[_]u8{ | ||
| 414 | 0x19, 0x00, 0x00, 0x00, // cmd | ||
| 415 | 0x98, 0x00, 0x00, 0x00, // cmdsize | ||
| 416 | 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname | ||
| 417 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // vmaddr | ||
| 418 | 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // vmsize | ||
| 419 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // fileoff | ||
| 420 | 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // filesize | ||
| 421 | 0x07, 0x00, 0x00, 0x00, // maxprot | ||
| 422 | 0x05, 0x00, 0x00, 0x00, // initprot | ||
| 423 | 0x01, 0x00, 0x00, 0x00, // nsects | ||
| 424 | 0x00, 0x00, 0x00, 0x00, // flags | ||
| 425 | 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sectname | ||
| 426 | 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname | ||
| 427 | 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // address | ||
| 428 | 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size | ||
| 429 | 0x00, 0x40, 0x00, 0x00, // offset | ||
| 430 | 0x02, 0x00, 0x00, 0x00, // alignment | ||
| 431 | 0x00, 0x00, 0x00, 0x00, // reloff | ||
| 432 | 0x00, 0x00, 0x00, 0x00, // nreloc | ||
| 433 | 0x00, 0x04, 0x00, 0x80, // flags | ||
| 434 | 0x00, 0x00, 0x00, 0x00, // reserved1 | ||
| 435 | 0x00, 0x00, 0x00, 0x00, // reserved2 | ||
| 436 | 0x00, 0x00, 0x00, 0x00, // reserved3 | ||
| 437 | }; | ||
| 438 | var cmd = SegmentCommand{ | ||
| 439 | .inner = .{ | ||
| 440 | .cmdsize = 152, | ||
| 441 | .segname = makeStaticString("__TEXT"), | ||
| 442 | .vmaddr = 4294967296, | ||
| 443 | .vmsize = 294912, | ||
| 444 | .filesize = 294912, | ||
| 445 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE, | ||
| 446 | .initprot = macho.VM_PROT_EXECUTE | macho.VM_PROT_READ, | ||
| 447 | .nsects = 1, | ||
| 448 | }, | ||
| 449 | }; | ||
| 450 | try cmd.sections.append(gpa, .{ | ||
| 451 | .sectname = makeStaticString("__text"), | ||
| 452 | .segname = makeStaticString("__TEXT"), | ||
| 453 | .addr = 4294983680, | ||
| 454 | .size = 448, | ||
| 455 | .offset = 16384, | ||
| 456 | .@"align" = 2, | ||
| 457 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | ||
| 458 | }); | ||
| 459 | defer cmd.deinit(gpa); | ||
| 460 | try testRead(gpa, in_buffer, LoadCommand{ .Segment = cmd }); | ||
| 461 | |||
| 462 | var out_buffer: [in_buffer.len]u8 = undefined; | ||
| 463 | try testWrite(&out_buffer, LoadCommand{ .Segment = cmd }, in_buffer); | ||
| 464 | } | ||
| 465 | |||
| 466 | test "read-write generic command with data" { | ||
| 467 | var gpa = testing.allocator; | ||
| 468 | const in_buffer = &[_]u8{ | ||
| 469 | 0x0c, 0x00, 0x00, 0x00, // cmd | ||
| 470 | 0x20, 0x00, 0x00, 0x00, // cmdsize | ||
| 471 | 0x18, 0x00, 0x00, 0x00, // name | ||
| 472 | 0x02, 0x00, 0x00, 0x00, // timestamp | ||
| 473 | 0x00, 0x00, 0x00, 0x00, // current_version | ||
| 474 | 0x00, 0x00, 0x00, 0x00, // compatibility_version | ||
| 475 | 0x2f, 0x75, 0x73, 0x72, 0x00, 0x00, 0x00, 0x00, // data | ||
| 476 | }; | ||
| 477 | var cmd = GenericCommandWithData(macho.dylib_command){ | ||
| 478 | .inner = .{ | ||
| 479 | .cmd = macho.LC_LOAD_DYLIB, | ||
| 480 | .cmdsize = 32, | ||
| 481 | .dylib = .{ | ||
| 482 | .name = 24, | ||
| 483 | .timestamp = 2, | ||
| 484 | .current_version = 0, | ||
| 485 | .compatibility_version = 0, | ||
| 486 | }, | ||
| 487 | }, | ||
| 488 | }; | ||
| 489 | cmd.data = try gpa.alloc(u8, 8); | ||
| 490 | defer gpa.free(cmd.data); | ||
| 491 | cmd.data[0] = 0x2f; | ||
| 492 | cmd.data[1] = 0x75; | ||
| 493 | cmd.data[2] = 0x73; | ||
| 494 | cmd.data[3] = 0x72; | ||
| 495 | cmd.data[4] = 0x0; | ||
| 496 | cmd.data[5] = 0x0; | ||
| 497 | cmd.data[6] = 0x0; | ||
| 498 | cmd.data[7] = 0x0; | ||
| 499 | try testRead(gpa, in_buffer, LoadCommand{ .Dylib = cmd }); | ||
| 500 | |||
| 501 | var out_buffer: [in_buffer.len]u8 = undefined; | ||
| 502 | try testWrite(&out_buffer, LoadCommand{ .Dylib = cmd }, in_buffer); | ||
| 503 | } | ||
| 504 | |||
| 505 | test "read-write C struct command" { | ||
| 506 | var gpa = testing.allocator; | ||
| 507 | const in_buffer = &[_]u8{ | ||
| 508 | 0x28, 0x00, 0x00, 0x80, // cmd | ||
| 509 | 0x18, 0x00, 0x00, 0x00, // cmdsize | ||
| 510 | 0x04, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // entryoff | ||
| 511 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // stacksize | ||
| 512 | }; | ||
| 513 | const cmd = .{ | ||
| 514 | .cmd = macho.LC_MAIN, | ||
| 515 | .cmdsize = 24, | ||
| 516 | .entryoff = 16644, | ||
| 517 | .stacksize = 0, | ||
| 518 | }; | ||
| 519 | try testRead(gpa, in_buffer, LoadCommand{ .Main = cmd }); | ||
| 520 | |||
| 521 | var out_buffer: [in_buffer.len]u8 = undefined; | ||
| 522 | try testWrite(&out_buffer, LoadCommand{ .Main = cmd }, in_buffer); | ||
| 523 | } | ||