| author | |
| committer | |
| log | 828f61e8dfcf17e0f7c42552311e6589bb187880 |
| tree | 6972d08f0c0292d27ebb1e8a74bc7c9a3087feae |
| parent | 81e7d8505c086a93accb74e9f1a84abb8ff7cf24 |
This way we will finally be able to share common parsing logic
between different Zig components and 3rd party packages.8 files changed, 639 insertions(+), 642 deletions(-)
CMakeLists.txt-1| ... | ... | @@ -590,7 +590,6 @@ set(ZIG_STAGE2_SOURCES |
| 590 | 590 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig" |
| 591 | 591 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig" |
| 592 | 592 | "${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig" |
| 593 | "${CMAKE_SOURCE_DIR}/src/link/MachO/commands.zig" | |
| 594 | 593 | "${CMAKE_SOURCE_DIR}/src/link/Plan9.zig" |
| 595 | 594 | "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig" |
| 596 | 595 | "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig" |
lib/std/macho.zig+434-1| ... | ... | @@ -1,4 +1,12 @@ |
| 1 | 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; | |
| 2 | 10 | |
| 3 | 11 | pub const mach_header = extern struct { |
| 4 | 12 | magic: u32, |
| ... | ... | @@ -770,7 +778,7 @@ pub const section_64 = extern struct { |
| 770 | 778 | }; |
| 771 | 779 | |
| 772 | 780 | fn parseName(name: *const [16]u8) []const u8 { |
| 773 | const len = std.mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; | |
| 781 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; | |
| 774 | 782 | return name[0..len]; |
| 775 | 783 | } |
| 776 | 784 | |
| ... | ... | @@ -1804,3 +1812,428 @@ pub const data_in_code_entry = extern struct { |
| 1804 | 1812 | /// A DICE_KIND value. |
| 1805 | 1813 | kind: u16, |
| 1806 | 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+98-101| ... | ... | @@ -15,7 +15,6 @@ const meta = std.meta; |
| 15 | 15 | const aarch64 = @import("../arch/aarch64/bits.zig"); |
| 16 | 16 | const bind = @import("MachO/bind.zig"); |
| 17 | 17 | const codegen = @import("../codegen.zig"); |
| 18 | const commands = @import("MachO/commands.zig"); | |
| 19 | 18 | const link = @import("../link.zig"); |
| 20 | 19 | const llvm_backend = @import("../codegen/llvm.zig"); |
| 21 | 20 | const target_util = @import("../target.zig"); |
| ... | ... | @@ -35,9 +34,7 @@ const Object = @import("MachO/Object.zig"); |
| 35 | 34 | const LibStub = @import("tapi.zig").LibStub; |
| 36 | 35 | const Liveness = @import("../Liveness.zig"); |
| 37 | 36 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 38 | const LoadCommand = commands.LoadCommand; | |
| 39 | 37 | const Module = @import("../Module.zig"); |
| 40 | const SegmentCommand = commands.SegmentCommand; | |
| 41 | 38 | const StringIndexAdapter = std.hash_map.StringIndexAdapter; |
| 42 | 39 | const StringIndexContext = std.hash_map.StringIndexContext; |
| 43 | 40 | const Trie = @import("MachO/Trie.zig"); |
| ... | ... | @@ -83,7 +80,7 @@ dylibs: std.ArrayListUnmanaged(Dylib) = .{}, |
| 83 | 80 | dylibs_map: std.StringHashMapUnmanaged(u16) = .{}, |
| 84 | 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 | 85 | pagezero_segment_cmd_index: ?u16 = null, |
| 89 | 86 | text_segment_cmd_index: ?u16 = null, |
| ... | ... | @@ -783,7 +780,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 783 | 780 | @sizeOf(macho.rpath_command) + rpath.len + 1, |
| 784 | 781 | @sizeOf(u64), |
| 785 | 782 | )); |
| 786 | var rpath_cmd = commands.emptyGenericCommandWithData(macho.rpath_command{ | |
| 783 | var rpath_cmd = macho.emptyGenericCommandWithData(macho.rpath_command{ | |
| 787 | 784 | .cmd = macho.LC_RPATH, |
| 788 | 785 | .cmdsize = cmdsize, |
| 789 | 786 | .path = @sizeOf(macho.rpath_command), |
| ... | ... | @@ -791,7 +788,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 791 | 788 | rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path); |
| 792 | 789 | mem.set(u8, rpath_cmd.data, 0); |
| 793 | 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 | 792 | try rpath_table.putNoClobber(rpath, {}); |
| 796 | 793 | self.load_commands_dirty = true; |
| 797 | 794 | } |
| ... | ... | @@ -861,12 +858,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 861 | 858 | } |
| 862 | 859 | |
| 863 | 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 | 862 | const sect = &seg.sections.items[idx]; |
| 866 | 863 | sect.offset = self.bss_file_offset; |
| 867 | 864 | } |
| 868 | 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 | 867 | const sect = &seg.sections.items[idx]; |
| 871 | 868 | sect.offset = self.tlv_bss_file_offset; |
| 872 | 869 | } |
| ... | ... | @@ -942,13 +939,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 942 | 939 | } |
| 943 | 940 | |
| 944 | 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 | 943 | const sect = &seg.sections.items[idx]; |
| 947 | 944 | self.bss_file_offset = sect.offset; |
| 948 | 945 | sect.offset = 0; |
| 949 | 946 | } |
| 950 | 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 | 949 | const sect = &seg.sections.items[idx]; |
| 953 | 950 | self.tlv_bss_file_offset = sect.offset; |
| 954 | 951 | sect.offset = 0; |
| ... | ... | @@ -1865,7 +1862,7 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: |
| 1865 | 1862 | } |
| 1866 | 1863 | |
| 1867 | 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 | 1866 | const sect = seg.sections.items[match.sect]; |
| 1870 | 1867 | const sym = self.locals.items[atom.local_sym_index]; |
| 1871 | 1868 | const file_offset = sect.offset + sym.n_value - sect.addr; |
| ... | ... | @@ -1885,7 +1882,7 @@ fn allocateLocals(self: *MachO) !void { |
| 1885 | 1882 | } |
| 1886 | 1883 | |
| 1887 | 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 | 1886 | const sect = seg.sections.items[match.sect]; |
| 1890 | 1887 | var base_vaddr = sect.addr; |
| 1891 | 1888 | |
| ... | ... | @@ -1976,7 +1973,7 @@ fn writeAllAtoms(self: *MachO) !void { |
| 1976 | 1973 | var it = self.atoms.iterator(); |
| 1977 | 1974 | while (it.next()) |entry| { |
| 1978 | 1975 | const match = entry.key_ptr.*; |
| 1979 | const seg = self.load_commands.items[match.seg].Segment; | |
| 1976 | const seg = self.load_commands.items[match.seg].segment; | |
| 1980 | 1977 | const sect = seg.sections.items[match.sect]; |
| 1981 | 1978 | var atom: *Atom = entry.value_ptr.*; |
| 1982 | 1979 | |
| ... | ... | @@ -2028,7 +2025,7 @@ fn writeAtoms(self: *MachO) !void { |
| 2028 | 2025 | var it = self.atoms.iterator(); |
| 2029 | 2026 | while (it.next()) |entry| { |
| 2030 | 2027 | const match = entry.key_ptr.*; |
| 2031 | const seg = self.load_commands.items[match.seg].Segment; | |
| 2028 | const seg = self.load_commands.items[match.seg].segment; | |
| 2032 | 2029 | const sect = seg.sections.items[match.sect]; |
| 2033 | 2030 | var atom: *Atom = entry.value_ptr.*; |
| 2034 | 2031 | |
| ... | ... | @@ -2992,7 +2989,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2992 | 2989 | |
| 2993 | 2990 | const first_atom = atom; |
| 2994 | 2991 | |
| 2995 | const seg = self.load_commands.items[match.seg].Segment; | |
| 2992 | const seg = self.load_commands.items[match.seg].segment; | |
| 2996 | 2993 | const sect = seg.sections.items[match.sect]; |
| 2997 | 2994 | const metadata = try section_metadata.getOrPut(match); |
| 2998 | 2995 | if (!metadata.found_existing) { |
| ... | ... | @@ -3043,7 +3040,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 3043 | 3040 | while (it.next()) |entry| { |
| 3044 | 3041 | const match = entry.key_ptr.*; |
| 3045 | 3042 | const metadata = entry.value_ptr.*; |
| 3046 | const seg = &self.load_commands.items[match.seg].Segment; | |
| 3043 | const seg = &self.load_commands.items[match.seg].segment; | |
| 3047 | 3044 | const sect = &seg.sections.items[match.sect]; |
| 3048 | 3045 | log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{ |
| 3049 | 3046 | sect.segName(), |
| ... | ... | @@ -3067,7 +3064,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 3067 | 3064 | self.data_segment_cmd_index, |
| 3068 | 3065 | }) |maybe_seg_id| { |
| 3069 | 3066 | const seg_id = maybe_seg_id orelse continue; |
| 3070 | const seg = self.load_commands.items[seg_id].Segment; | |
| 3067 | const seg = self.load_commands.items[seg_id].segment; | |
| 3071 | 3068 | |
| 3072 | 3069 | for (seg.sections.items) |sect, sect_id| { |
| 3073 | 3070 | const match = MatchingSection{ |
| ... | ... | @@ -3137,7 +3134,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 3137 | 3134 | fn addLoadDylibLC(self: *MachO, id: u16) !void { |
| 3138 | 3135 | const dylib = self.dylibs.items[id]; |
| 3139 | 3136 | const dylib_id = dylib.id orelse unreachable; |
| 3140 | var dylib_cmd = try commands.createLoadDylibCommand( | |
| 3137 | var dylib_cmd = try macho.createLoadDylibCommand( | |
| 3141 | 3138 | self.base.allocator, |
| 3142 | 3139 | dylib_id.name, |
| 3143 | 3140 | dylib_id.timestamp, |
| ... | ... | @@ -3145,7 +3142,7 @@ fn addLoadDylibLC(self: *MachO, id: u16) !void { |
| 3145 | 3142 | dylib_id.compatibility_version, |
| 3146 | 3143 | ); |
| 3147 | 3144 | errdefer dylib_cmd.deinit(self.base.allocator); |
| 3148 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); | |
| 3145 | try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd }); | |
| 3149 | 3146 | self.load_commands_dirty = true; |
| 3150 | 3147 | } |
| 3151 | 3148 | |
| ... | ... | @@ -3153,7 +3150,7 @@ fn addCodeSignatureLC(self: *MachO) !void { |
| 3153 | 3150 | if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return; |
| 3154 | 3151 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3155 | 3152 | try self.load_commands.append(self.base.allocator, .{ |
| 3156 | .LinkeditData = .{ | |
| 3153 | .linkedit_data = .{ | |
| 3157 | 3154 | .cmd = macho.LC_CODE_SIGNATURE, |
| 3158 | 3155 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 3159 | 3156 | .dataoff = 0, |
| ... | ... | @@ -3168,7 +3165,7 @@ fn setEntryPoint(self: *MachO) !void { |
| 3168 | 3165 | |
| 3169 | 3166 | // TODO we should respect the -entry flag passed in by the user to set a custom |
| 3170 | 3167 | // entrypoint. For now, assume default of `_main`. |
| 3171 | 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; | |
| 3172 | 3169 | const n_strx = self.strtab_dir.getKeyAdapted(@as([]const u8, "_main"), StringIndexAdapter{ |
| 3173 | 3170 | .bytes = &self.strtab, |
| 3174 | 3171 | }) orelse { |
| ... | ... | @@ -3178,7 +3175,7 @@ fn setEntryPoint(self: *MachO) !void { |
| 3178 | 3175 | const resolv = self.symbol_resolver.get(n_strx) orelse unreachable; |
| 3179 | 3176 | assert(resolv.where == .global); |
| 3180 | 3177 | const sym = self.globals.items[resolv.where_index]; |
| 3181 | const ec = &self.load_commands.items[self.main_cmd_index.?].Main; | |
| 3178 | const ec = &self.load_commands.items[self.main_cmd_index.?].main; | |
| 3182 | 3179 | ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr); |
| 3183 | 3180 | ec.stacksize = self.base.options.stack_size_override orelse 0; |
| 3184 | 3181 | self.entry_addr = sym.n_value; |
| ... | ... | @@ -3875,7 +3872,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 3875 | 3872 | if (self.pagezero_segment_cmd_index == null) { |
| 3876 | 3873 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3877 | 3874 | try self.load_commands.append(self.base.allocator, .{ |
| 3878 | .Segment = .{ | |
| 3875 | .segment = .{ | |
| 3879 | 3876 | .inner = .{ |
| 3880 | 3877 | .segname = makeStaticString("__PAGEZERO"), |
| 3881 | 3878 | .vmsize = pagezero_vmsize, |
| ... | ... | @@ -3896,7 +3893,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 3896 | 3893 | break :blk needed_size; |
| 3897 | 3894 | } else 0; |
| 3898 | 3895 | try self.load_commands.append(self.base.allocator, .{ |
| 3899 | .Segment = .{ | |
| 3896 | .segment = .{ | |
| 3900 | 3897 | .inner = .{ |
| 3901 | 3898 | .segname = makeStaticString("__TEXT"), |
| 3902 | 3899 | .vmaddr = pagezero_vmsize, |
| ... | ... | @@ -4000,7 +3997,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4000 | 3997 | }); |
| 4001 | 3998 | } |
| 4002 | 3999 | try self.load_commands.append(self.base.allocator, .{ |
| 4003 | .Segment = .{ | |
| 4000 | .segment = .{ | |
| 4004 | 4001 | .inner = .{ |
| 4005 | 4002 | .segname = makeStaticString("__DATA_CONST"), |
| 4006 | 4003 | .vmaddr = vmaddr, |
| ... | ... | @@ -4049,7 +4046,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4049 | 4046 | }); |
| 4050 | 4047 | } |
| 4051 | 4048 | try self.load_commands.append(self.base.allocator, .{ |
| 4052 | .Segment = .{ | |
| 4049 | .segment = .{ | |
| 4053 | 4050 | .inner = .{ |
| 4054 | 4051 | .segname = makeStaticString("__DATA"), |
| 4055 | 4052 | .vmaddr = vmaddr, |
| ... | ... | @@ -4133,7 +4130,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4133 | 4130 | .flags = macho.S_THREAD_LOCAL_ZEROFILL, |
| 4134 | 4131 | }, |
| 4135 | 4132 | ); |
| 4136 | 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; | |
| 4137 | 4134 | const sect = seg.sections.items[self.tlv_bss_section_index.?]; |
| 4138 | 4135 | self.tlv_bss_file_offset = sect.offset; |
| 4139 | 4136 | } |
| ... | ... | @@ -4150,7 +4147,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4150 | 4147 | .flags = macho.S_ZEROFILL, |
| 4151 | 4148 | }, |
| 4152 | 4149 | ); |
| 4153 | 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; | |
| 4154 | 4151 | const sect = seg.sections.items[self.bss_section_index.?]; |
| 4155 | 4152 | self.bss_file_offset = sect.offset; |
| 4156 | 4153 | } |
| ... | ... | @@ -4166,7 +4163,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4166 | 4163 | log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff}); |
| 4167 | 4164 | } |
| 4168 | 4165 | try self.load_commands.append(self.base.allocator, .{ |
| 4169 | .Segment = .{ | |
| 4166 | .segment = .{ | |
| 4170 | 4167 | .inner = .{ |
| 4171 | 4168 | .segname = makeStaticString("__LINKEDIT"), |
| 4172 | 4169 | .vmaddr = vmaddr, |
| ... | ... | @@ -4182,7 +4179,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4182 | 4179 | if (self.dyld_info_cmd_index == null) { |
| 4183 | 4180 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4184 | 4181 | try self.load_commands.append(self.base.allocator, .{ |
| 4185 | .DyldInfoOnly = .{ | |
| 4182 | .dyld_info_only = .{ | |
| 4186 | 4183 | .cmd = macho.LC_DYLD_INFO_ONLY, |
| 4187 | 4184 | .cmdsize = @sizeOf(macho.dyld_info_command), |
| 4188 | 4185 | .rebase_off = 0, |
| ... | ... | @@ -4203,7 +4200,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4203 | 4200 | if (self.symtab_cmd_index == null) { |
| 4204 | 4201 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4205 | 4202 | try self.load_commands.append(self.base.allocator, .{ |
| 4206 | .Symtab = .{ | |
| 4203 | .symtab = .{ | |
| 4207 | 4204 | .cmd = macho.LC_SYMTAB, |
| 4208 | 4205 | .cmdsize = @sizeOf(macho.symtab_command), |
| 4209 | 4206 | .symoff = 0, |
| ... | ... | @@ -4218,7 +4215,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4218 | 4215 | if (self.dysymtab_cmd_index == null) { |
| 4219 | 4216 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4220 | 4217 | try self.load_commands.append(self.base.allocator, .{ |
| 4221 | .Dysymtab = .{ | |
| 4218 | .dysymtab = .{ | |
| 4222 | 4219 | .cmd = macho.LC_DYSYMTAB, |
| 4223 | 4220 | .cmdsize = @sizeOf(macho.dysymtab_command), |
| 4224 | 4221 | .ilocalsym = 0, |
| ... | ... | @@ -4251,7 +4248,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4251 | 4248 | @sizeOf(macho.dylinker_command) + mem.sliceTo(default_dyld_path, 0).len, |
| 4252 | 4249 | @sizeOf(u64), |
| 4253 | 4250 | )); |
| 4254 | var dylinker_cmd = commands.emptyGenericCommandWithData(macho.dylinker_command{ | |
| 4251 | var dylinker_cmd = macho.emptyGenericCommandWithData(macho.dylinker_command{ | |
| 4255 | 4252 | .cmd = macho.LC_LOAD_DYLINKER, |
| 4256 | 4253 | .cmdsize = cmdsize, |
| 4257 | 4254 | .name = @sizeOf(macho.dylinker_command), |
| ... | ... | @@ -4259,14 +4256,14 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4259 | 4256 | dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name); |
| 4260 | 4257 | mem.set(u8, dylinker_cmd.data, 0); |
| 4261 | 4258 | mem.copy(u8, dylinker_cmd.data, mem.sliceTo(default_dyld_path, 0)); |
| 4262 | try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd }); | |
| 4259 | try self.load_commands.append(self.base.allocator, .{ .dylinker = dylinker_cmd }); | |
| 4263 | 4260 | self.load_commands_dirty = true; |
| 4264 | 4261 | } |
| 4265 | 4262 | |
| 4266 | 4263 | if (self.main_cmd_index == null and self.base.options.output_mode == .Exe) { |
| 4267 | 4264 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4268 | 4265 | try self.load_commands.append(self.base.allocator, .{ |
| 4269 | .Main = .{ | |
| 4266 | .main = .{ | |
| 4270 | 4267 | .cmd = macho.LC_MAIN, |
| 4271 | 4268 | .cmdsize = @sizeOf(macho.entry_point_command), |
| 4272 | 4269 | .entryoff = 0x0, |
| ... | ... | @@ -4286,7 +4283,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4286 | 4283 | std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 }; |
| 4287 | 4284 | const compat_version = self.base.options.compatibility_version orelse |
| 4288 | 4285 | std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 }; |
| 4289 | var dylib_cmd = try commands.createLoadDylibCommand( | |
| 4286 | var dylib_cmd = try macho.createLoadDylibCommand( | |
| 4290 | 4287 | self.base.allocator, |
| 4291 | 4288 | install_name, |
| 4292 | 4289 | 2, |
| ... | ... | @@ -4295,14 +4292,14 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4295 | 4292 | ); |
| 4296 | 4293 | errdefer dylib_cmd.deinit(self.base.allocator); |
| 4297 | 4294 | dylib_cmd.inner.cmd = macho.LC_ID_DYLIB; |
| 4298 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); | |
| 4295 | try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd }); | |
| 4299 | 4296 | self.load_commands_dirty = true; |
| 4300 | 4297 | } |
| 4301 | 4298 | |
| 4302 | 4299 | if (self.source_version_cmd_index == null) { |
| 4303 | 4300 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4304 | 4301 | try self.load_commands.append(self.base.allocator, .{ |
| 4305 | .SourceVersion = .{ | |
| 4302 | .source_version = .{ | |
| 4306 | 4303 | .cmd = macho.LC_SOURCE_VERSION, |
| 4307 | 4304 | .cmdsize = @sizeOf(macho.source_version_command), |
| 4308 | 4305 | .version = 0x0, |
| ... | ... | @@ -4329,7 +4326,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4329 | 4326 | break :blk sdk_version; |
| 4330 | 4327 | } else platform_version; |
| 4331 | 4328 | const is_simulator_abi = self.base.options.target.abi == .simulator; |
| 4332 | var cmd = commands.emptyGenericCommandWithData(macho.build_version_command{ | |
| 4329 | var cmd = macho.emptyGenericCommandWithData(macho.build_version_command{ | |
| 4333 | 4330 | .cmd = macho.LC_BUILD_VERSION, |
| 4334 | 4331 | .cmdsize = cmdsize, |
| 4335 | 4332 | .platform = switch (self.base.options.target.os.tag) { |
| ... | ... | @@ -4350,7 +4347,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4350 | 4347 | cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command)); |
| 4351 | 4348 | mem.set(u8, cmd.data, 0); |
| 4352 | 4349 | mem.copy(u8, cmd.data, mem.asBytes(&ld_ver)); |
| 4353 | try self.load_commands.append(self.base.allocator, .{ .BuildVersion = cmd }); | |
| 4350 | try self.load_commands.append(self.base.allocator, .{ .build_version = cmd }); | |
| 4354 | 4351 | self.load_commands_dirty = true; |
| 4355 | 4352 | } |
| 4356 | 4353 | |
| ... | ... | @@ -4362,14 +4359,14 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4362 | 4359 | .uuid = undefined, |
| 4363 | 4360 | }; |
| 4364 | 4361 | std.crypto.random.bytes(&uuid_cmd.uuid); |
| 4365 | try self.load_commands.append(self.base.allocator, .{ .Uuid = uuid_cmd }); | |
| 4362 | try self.load_commands.append(self.base.allocator, .{ .uuid = uuid_cmd }); | |
| 4366 | 4363 | self.load_commands_dirty = true; |
| 4367 | 4364 | } |
| 4368 | 4365 | |
| 4369 | 4366 | if (self.function_starts_cmd_index == null) { |
| 4370 | 4367 | self.function_starts_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4371 | 4368 | try self.load_commands.append(self.base.allocator, .{ |
| 4372 | .LinkeditData = .{ | |
| 4369 | .linkedit_data = .{ | |
| 4373 | 4370 | .cmd = macho.LC_FUNCTION_STARTS, |
| 4374 | 4371 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 4375 | 4372 | .dataoff = 0, |
| ... | ... | @@ -4382,7 +4379,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4382 | 4379 | if (self.data_in_code_cmd_index == null) { |
| 4383 | 4380 | self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 4384 | 4381 | try self.load_commands.append(self.base.allocator, .{ |
| 4385 | .LinkeditData = .{ | |
| 4382 | .linkedit_data = .{ | |
| 4386 | 4383 | .cmd = macho.LC_DATA_IN_CODE, |
| 4387 | 4384 | .cmdsize = @sizeOf(macho.linkedit_data_command), |
| 4388 | 4385 | .dataoff = 0, |
| ... | ... | @@ -4396,8 +4393,8 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4396 | 4393 | } |
| 4397 | 4394 | |
| 4398 | 4395 | fn allocateTextSegment(self: *MachO) !void { |
| 4399 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | |
| 4400 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; | |
| 4396 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment; | |
| 4397 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].segment.inner.vmsize; | |
| 4401 | 4398 | seg.inner.fileoff = 0; |
| 4402 | 4399 | seg.inner.vmaddr = base_vmaddr; |
| 4403 | 4400 | |
| ... | ... | @@ -4433,30 +4430,30 @@ fn allocateTextSegment(self: *MachO) !void { |
| 4433 | 4430 | } |
| 4434 | 4431 | |
| 4435 | 4432 | fn allocateDataConstSegment(self: *MachO) !void { |
| 4436 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | |
| 4437 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | |
| 4433 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; | |
| 4434 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; | |
| 4438 | 4435 | seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize; |
| 4439 | 4436 | seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize; |
| 4440 | 4437 | try self.allocateSegment(self.data_const_segment_cmd_index.?, 0); |
| 4441 | 4438 | } |
| 4442 | 4439 | |
| 4443 | 4440 | fn allocateDataSegment(self: *MachO) !void { |
| 4444 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | |
| 4445 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | |
| 4441 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; | |
| 4442 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment; | |
| 4446 | 4443 | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; |
| 4447 | 4444 | seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize; |
| 4448 | 4445 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); |
| 4449 | 4446 | } |
| 4450 | 4447 | |
| 4451 | 4448 | fn allocateLinkeditSegment(self: *MachO) void { |
| 4452 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 4453 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | |
| 4449 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; | |
| 4450 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; | |
| 4454 | 4451 | seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize; |
| 4455 | 4452 | seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize; |
| 4456 | 4453 | } |
| 4457 | 4454 | |
| 4458 | 4455 | fn allocateSegment(self: *MachO, index: u16, offset: u64) !void { |
| 4459 | const seg = &self.load_commands.items[index].Segment; | |
| 4456 | const seg = &self.load_commands.items[index].segment; | |
| 4460 | 4457 | |
| 4461 | 4458 | // Allocate the sections according to their alignment at the beginning of the segment. |
| 4462 | 4459 | var start: u64 = offset; |
| ... | ... | @@ -4488,7 +4485,7 @@ fn initSection( |
| 4488 | 4485 | alignment: u32, |
| 4489 | 4486 | opts: InitSectionOpts, |
| 4490 | 4487 | ) !u16 { |
| 4491 | const seg = &self.load_commands.items[segment_id].Segment; | |
| 4488 | const seg = &self.load_commands.items[segment_id].segment; | |
| 4492 | 4489 | var sect = macho.section_64{ |
| 4493 | 4490 | .sectname = makeStaticString(sectname), |
| 4494 | 4491 | .segname = seg.inner.segname, |
| ... | ... | @@ -4532,7 +4529,7 @@ fn initSection( |
| 4532 | 4529 | } |
| 4533 | 4530 | |
| 4534 | 4531 | fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64 { |
| 4535 | const seg = self.load_commands.items[segment_id].Segment; | |
| 4532 | const seg = self.load_commands.items[segment_id].segment; | |
| 4536 | 4533 | if (seg.sections.items.len == 0) { |
| 4537 | 4534 | return if (start) |v| v else seg.inner.fileoff; |
| 4538 | 4535 | } |
| ... | ... | @@ -4542,7 +4539,7 @@ fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64 |
| 4542 | 4539 | } |
| 4543 | 4540 | |
| 4544 | 4541 | fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { |
| 4545 | const seg = &self.load_commands.items[seg_id].Segment; | |
| 4542 | const seg = &self.load_commands.items[seg_id].segment; | |
| 4546 | 4543 | const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size); |
| 4547 | 4544 | assert(new_seg_size > seg.inner.filesize); |
| 4548 | 4545 | const offset_amt = new_seg_size - seg.inner.filesize; |
| ... | ... | @@ -4564,13 +4561,13 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { |
| 4564 | 4561 | // TODO We should probably nop the expanded by distance, or put 0s. |
| 4565 | 4562 | |
| 4566 | 4563 | // TODO copyRangeAll doesn't automatically extend the file on macOS. |
| 4567 | 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; | |
| 4568 | 4565 | const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize; |
| 4569 | 4566 | try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1); |
| 4570 | 4567 | |
| 4571 | 4568 | var next: usize = seg_id + 1; |
| 4572 | 4569 | while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) { |
| 4573 | const next_seg = &self.load_commands.items[next].Segment; | |
| 4570 | const next_seg = &self.load_commands.items[next].segment; | |
| 4574 | 4571 | _ = try self.base.file.?.copyRangeAll( |
| 4575 | 4572 | next_seg.inner.fileoff, |
| 4576 | 4573 | self.base.file.?, |
| ... | ... | @@ -4613,7 +4610,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { |
| 4613 | 4610 | const tracy = trace(@src()); |
| 4614 | 4611 | defer tracy.end(); |
| 4615 | 4612 | |
| 4616 | const seg = &self.load_commands.items[match.seg].Segment; | |
| 4613 | const seg = &self.load_commands.items[match.seg].segment; | |
| 4617 | 4614 | const sect = &seg.sections.items[match.sect]; |
| 4618 | 4615 | |
| 4619 | 4616 | const alignment = try math.powi(u32, 2, sect.@"align"); |
| ... | ... | @@ -4684,7 +4681,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { |
| 4684 | 4681 | } |
| 4685 | 4682 | |
| 4686 | 4683 | fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 { |
| 4687 | const seg = self.load_commands.items[segment_id].Segment; | |
| 4684 | const seg = self.load_commands.items[segment_id].segment; | |
| 4688 | 4685 | assert(start >= seg.inner.fileoff); |
| 4689 | 4686 | var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize; |
| 4690 | 4687 | if (start > min_pos) return 0; |
| ... | ... | @@ -4696,7 +4693,7 @@ fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 { |
| 4696 | 4693 | } |
| 4697 | 4694 | |
| 4698 | 4695 | fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u32 { |
| 4699 | const seg = self.load_commands.items[segment_id].Segment; | |
| 4696 | const seg = self.load_commands.items[segment_id].segment; | |
| 4700 | 4697 | var max_alignment: u32 = 1; |
| 4701 | 4698 | var next = start_sect_id; |
| 4702 | 4699 | while (next < seg.sections.items.len) : (next += 1) { |
| ... | ... | @@ -4711,7 +4708,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m |
| 4711 | 4708 | const tracy = trace(@src()); |
| 4712 | 4709 | defer tracy.end(); |
| 4713 | 4710 | |
| 4714 | const seg = &self.load_commands.items[match.seg].Segment; | |
| 4711 | const seg = &self.load_commands.items[match.seg].segment; | |
| 4715 | 4712 | const sect = &seg.sections.items[match.sect]; |
| 4716 | 4713 | var free_list = self.atom_free_lists.get(match).?; |
| 4717 | 4714 | const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?; |
| ... | ... | @@ -4815,7 +4812,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m |
| 4815 | 4812 | } |
| 4816 | 4813 | |
| 4817 | 4814 | fn addAtomAndBumpSectionSize(self: *MachO, atom: *Atom, match: MatchingSection) !void { |
| 4818 | const seg = &self.load_commands.items[match.seg].Segment; | |
| 4815 | const seg = &self.load_commands.items[match.seg].segment; | |
| 4819 | 4816 | const sect = &seg.sections.items[match.sect]; |
| 4820 | 4817 | const alignment = try math.powi(u32, 2, atom.alignment); |
| 4821 | 4818 | sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size; |
| ... | ... | @@ -4862,11 +4859,11 @@ const NextSegmentAddressAndOffset = struct { |
| 4862 | 4859 | fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { |
| 4863 | 4860 | var prev_segment_idx: ?usize = null; // We use optional here for safety. |
| 4864 | 4861 | for (self.load_commands.items) |cmd, i| { |
| 4865 | if (cmd == .Segment) { | |
| 4862 | if (cmd == .segment) { | |
| 4866 | 4863 | prev_segment_idx = i; |
| 4867 | 4864 | } |
| 4868 | 4865 | } |
| 4869 | const prev_segment = self.load_commands.items[prev_segment_idx.?].Segment; | |
| 4866 | const prev_segment = self.load_commands.items[prev_segment_idx.?].segment; | |
| 4870 | 4867 | const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize; |
| 4871 | 4868 | const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize; |
| 4872 | 4869 | return .{ |
| ... | ... | @@ -4885,7 +4882,7 @@ fn sortSections(self: *MachO) !void { |
| 4885 | 4882 | |
| 4886 | 4883 | { |
| 4887 | 4884 | // __TEXT segment |
| 4888 | 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; | |
| 4889 | 4886 | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 4890 | 4887 | defer self.base.allocator.free(sections); |
| 4891 | 4888 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| ... | ... | @@ -4917,7 +4914,7 @@ fn sortSections(self: *MachO) !void { |
| 4917 | 4914 | |
| 4918 | 4915 | { |
| 4919 | 4916 | // __DATA_CONST segment |
| 4920 | 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; | |
| 4921 | 4918 | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 4922 | 4919 | defer self.base.allocator.free(sections); |
| 4923 | 4920 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| ... | ... | @@ -4944,7 +4941,7 @@ fn sortSections(self: *MachO) !void { |
| 4944 | 4941 | |
| 4945 | 4942 | { |
| 4946 | 4943 | // __DATA segment |
| 4947 | 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; | |
| 4948 | 4945 | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 4949 | 4946 | defer self.base.allocator.free(sections); |
| 4950 | 4947 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| ... | ... | @@ -5000,7 +4997,7 @@ fn sortSections(self: *MachO) !void { |
| 5000 | 4997 | { |
| 5001 | 4998 | // Create new section ordinals. |
| 5002 | 4999 | self.section_ordinals.clearRetainingCapacity(); |
| 5003 | 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; | |
| 5004 | 5001 | for (text_seg.sections.items) |_, sect_id| { |
| 5005 | 5002 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5006 | 5003 | .seg = self.text_segment_cmd_index.?, |
| ... | ... | @@ -5008,7 +5005,7 @@ fn sortSections(self: *MachO) !void { |
| 5008 | 5005 | }); |
| 5009 | 5006 | assert(!res.found_existing); |
| 5010 | 5007 | } |
| 5011 | 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; | |
| 5012 | 5009 | for (data_const_seg.sections.items) |_, sect_id| { |
| 5013 | 5010 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5014 | 5011 | .seg = self.data_const_segment_cmd_index.?, |
| ... | ... | @@ -5016,7 +5013,7 @@ fn sortSections(self: *MachO) !void { |
| 5016 | 5013 | }); |
| 5017 | 5014 | assert(!res.found_existing); |
| 5018 | 5015 | } |
| 5019 | 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; | |
| 5020 | 5017 | for (data_seg.sections.items) |_, sect_id| { |
| 5021 | 5018 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5022 | 5019 | .seg = self.data_segment_cmd_index.?, |
| ... | ... | @@ -5041,9 +5038,9 @@ fn updateSectionOrdinals(self: *MachO) !void { |
| 5041 | 5038 | |
| 5042 | 5039 | var new_ordinal: u8 = 0; |
| 5043 | 5040 | for (self.load_commands.items) |lc, lc_id| { |
| 5044 | if (lc != .Segment) break; | |
| 5041 | if (lc != .segment) break; | |
| 5045 | 5042 | |
| 5046 | for (lc.Segment.sections.items) |_, sect_id| { | |
| 5043 | for (lc.segment.sections.items) |_, sect_id| { | |
| 5047 | 5044 | const match = MatchingSection{ |
| 5048 | 5045 | .seg = @intCast(u16, lc_id), |
| 5049 | 5046 | .sect = @intCast(u16, sect_id), |
| ... | ... | @@ -5086,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5086 | 5083 | |
| 5087 | 5084 | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable |
| 5088 | 5085 | |
| 5089 | const seg = self.load_commands.items[match.seg].Segment; | |
| 5086 | const seg = self.load_commands.items[match.seg].segment; | |
| 5090 | 5087 | |
| 5091 | 5088 | while (true) { |
| 5092 | 5089 | const sym = self.locals.items[atom.local_sym_index]; |
| ... | ... | @@ -5156,7 +5153,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5156 | 5153 | { |
| 5157 | 5154 | // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. |
| 5158 | 5155 | log.debug("generating export trie", .{}); |
| 5159 | 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; | |
| 5160 | 5157 | const base_address = text_segment.inner.vmaddr; |
| 5161 | 5158 | |
| 5162 | 5159 | for (self.globals.items) |sym| { |
| ... | ... | @@ -5174,8 +5171,8 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5174 | 5171 | try trie.finalize(self.base.allocator); |
| 5175 | 5172 | } |
| 5176 | 5173 | |
| 5177 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 5178 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | |
| 5174 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; | |
| 5175 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].dyld_info_only; | |
| 5179 | 5176 | const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items); |
| 5180 | 5177 | const bind_size = try bind.bindInfoSize(bind_pointers.items); |
| 5181 | 5178 | const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items); |
| ... | ... | @@ -5245,7 +5242,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 5245 | 5242 | .sect = self.la_symbol_ptr_section_index.?, |
| 5246 | 5243 | }).?; |
| 5247 | 5244 | const base_addr = blk: { |
| 5248 | 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; | |
| 5249 | 5246 | break :blk seg.inner.vmaddr; |
| 5250 | 5247 | }; |
| 5251 | 5248 | |
| ... | ... | @@ -5309,7 +5306,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 5309 | 5306 | } |
| 5310 | 5307 | |
| 5311 | 5308 | const sect = blk: { |
| 5312 | 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; | |
| 5313 | 5310 | break :blk seg.sections.items[self.stub_helper_section_index.?]; |
| 5314 | 5311 | }; |
| 5315 | 5312 | const stub_offset: u4 = switch (self.base.options.target.cpu.arch) { |
| ... | ... | @@ -5350,7 +5347,7 @@ fn writeFunctionStarts(self: *MachO) !void { |
| 5350 | 5347 | var offsets = std.ArrayList(u32).init(self.base.allocator); |
| 5351 | 5348 | defer offsets.deinit(); |
| 5352 | 5349 | |
| 5353 | 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; | |
| 5354 | 5351 | var last_off: u32 = 0; |
| 5355 | 5352 | |
| 5356 | 5353 | while (true) { |
| ... | ... | @@ -5407,8 +5404,8 @@ fn writeFunctionStarts(self: *MachO) !void { |
| 5407 | 5404 | } |
| 5408 | 5405 | |
| 5409 | 5406 | const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64))); |
| 5410 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 5411 | const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].LinkeditData; | |
| 5407 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; | |
| 5408 | const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].linkedit_data; | |
| 5412 | 5409 | |
| 5413 | 5410 | fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 5414 | 5411 | fn_cmd.datasize = needed_size; |
| ... | ... | @@ -5441,7 +5438,7 @@ fn writeDices(self: *MachO) !void { |
| 5441 | 5438 | atom = prev; |
| 5442 | 5439 | } |
| 5443 | 5440 | |
| 5444 | 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; | |
| 5445 | 5442 | const text_sect = text_seg.sections.items[self.text_section_index.?]; |
| 5446 | 5443 | |
| 5447 | 5444 | while (true) { |
| ... | ... | @@ -5465,8 +5462,8 @@ fn writeDices(self: *MachO) !void { |
| 5465 | 5462 | } else break; |
| 5466 | 5463 | } |
| 5467 | 5464 | |
| 5468 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 5469 | const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData; | |
| 5465 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; | |
| 5466 | const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data; | |
| 5470 | 5467 | const needed_size = @intCast(u32, buf.items.len); |
| 5471 | 5468 | |
| 5472 | 5469 | dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| ... | ... | @@ -5486,8 +5483,8 @@ fn writeSymbolTable(self: *MachO) !void { |
| 5486 | 5483 | const tracy = trace(@src()); |
| 5487 | 5484 | defer tracy.end(); |
| 5488 | 5485 | |
| 5489 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 5490 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | |
| 5486 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; | |
| 5487 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; | |
| 5491 | 5488 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 5492 | 5489 | |
| 5493 | 5490 | var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator); |
| ... | ... | @@ -5591,18 +5588,18 @@ fn writeSymbolTable(self: *MachO) !void { |
| 5591 | 5588 | seg.inner.filesize += locals_size + exports_size + undefs_size; |
| 5592 | 5589 | |
| 5593 | 5590 | // Update dynamic symbol table. |
| 5594 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | |
| 5591 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].dysymtab; | |
| 5595 | 5592 | dysymtab.nlocalsym = @intCast(u32, nlocals); |
| 5596 | 5593 | dysymtab.iextdefsym = dysymtab.nlocalsym; |
| 5597 | 5594 | dysymtab.nextdefsym = @intCast(u32, nexports); |
| 5598 | 5595 | dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym; |
| 5599 | 5596 | dysymtab.nundefsym = @intCast(u32, nundefs); |
| 5600 | 5597 | |
| 5601 | 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; | |
| 5602 | 5599 | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; |
| 5603 | 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; | |
| 5604 | 5601 | const got = &data_const_segment.sections.items[self.got_section_index.?]; |
| 5605 | 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; | |
| 5606 | 5603 | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 5607 | 5604 | |
| 5608 | 5605 | const nstubs = @intCast(u32, self.stubs_map.keys().len); |
| ... | ... | @@ -5665,8 +5662,8 @@ fn writeStringTable(self: *MachO) !void { |
| 5665 | 5662 | const tracy = trace(@src()); |
| 5666 | 5663 | defer tracy.end(); |
| 5667 | 5664 | |
| 5668 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 5669 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | |
| 5665 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; | |
| 5666 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; | |
| 5670 | 5667 | symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 5671 | 5668 | symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64))); |
| 5672 | 5669 | seg.inner.filesize += symtab.strsize; |
| ... | ... | @@ -5686,7 +5683,7 @@ fn writeLinkeditSegment(self: *MachO) !void { |
| 5686 | 5683 | const tracy = trace(@src()); |
| 5687 | 5684 | defer tracy.end(); |
| 5688 | 5685 | |
| 5689 | 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; | |
| 5690 | 5687 | seg.inner.filesize = 0; |
| 5691 | 5688 | |
| 5692 | 5689 | try self.writeDyldInfoData(); |
| ... | ... | @@ -5702,8 +5699,8 @@ fn writeCodeSignaturePadding(self: *MachO) !void { |
| 5702 | 5699 | const tracy = trace(@src()); |
| 5703 | 5700 | defer tracy.end(); |
| 5704 | 5701 | |
| 5705 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; | |
| 5706 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; | |
| 5702 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; | |
| 5703 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data; | |
| 5707 | 5704 | const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize; |
| 5708 | 5705 | const needed_size = CodeSignature.calcCodeSignaturePaddingSize( |
| 5709 | 5706 | self.base.options.emit.?.sub_path, |
| ... | ... | @@ -5729,8 +5726,8 @@ fn writeCodeSignature(self: *MachO) !void { |
| 5729 | 5726 | const tracy = trace(@src()); |
| 5730 | 5727 | defer tracy.end(); |
| 5731 | 5728 | |
| 5732 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | |
| 5733 | const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; | |
| 5729 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment; | |
| 5730 | const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data; | |
| 5734 | 5731 | |
| 5735 | 5732 | var code_sig: CodeSignature = .{}; |
| 5736 | 5733 | defer code_sig.deinit(self.base.allocator); |
| ... | ... | @@ -5955,7 +5952,7 @@ fn snapshotState(self: *MachO) !void { |
| 5955 | 5952 | var nodes = std.ArrayList(Snapshot.Node).init(arena); |
| 5956 | 5953 | |
| 5957 | 5954 | for (self.section_ordinals.keys()) |key| { |
| 5958 | const seg = self.load_commands.items[key.seg].Segment; | |
| 5955 | const seg = self.load_commands.items[key.seg].segment; | |
| 5959 | 5956 | const sect = seg.sections.items[key.sect]; |
| 5960 | 5957 | const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() }); |
| 5961 | 5958 | try nodes.append(.{ |
| ... | ... | @@ -6028,12 +6025,12 @@ fn snapshotState(self: *MachO) !void { |
| 6028 | 6025 | const is_tlv = is_tlv: { |
| 6029 | 6026 | const source_sym = self.locals.items[atom.local_sym_index]; |
| 6030 | 6027 | const match = self.section_ordinals.keys()[source_sym.n_sect - 1]; |
| 6031 | const match_seg = self.load_commands.items[match.seg].Segment; | |
| 6028 | const match_seg = self.load_commands.items[match.seg].segment; | |
| 6032 | 6029 | const match_sect = match_seg.sections.items[match.sect]; |
| 6033 | 6030 | break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES; |
| 6034 | 6031 | }; |
| 6035 | 6032 | if (is_tlv) { |
| 6036 | 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; | |
| 6037 | 6034 | const base_address = inner: { |
| 6038 | 6035 | if (self.tlv_data_section_index) |i| { |
| 6039 | 6036 | break :inner match_seg.sections.items[i].addr; |
| ... | ... | @@ -6193,7 +6190,7 @@ fn logSymtab(self: MachO) void { |
| 6193 | 6190 | |
| 6194 | 6191 | fn logSectionOrdinals(self: MachO) void { |
| 6195 | 6192 | for (self.section_ordinals.keys()) |match, i| { |
| 6196 | const seg = self.load_commands.items[match.seg].Segment; | |
| 6193 | const seg = self.load_commands.items[match.seg].segment; | |
| 6197 | 6194 | const sect = seg.sections.items[match.sect]; |
| 6198 | 6195 | log.debug("ord {d}: {d},{d} => {s},{s}", .{ |
| 6199 | 6196 | i + 1, |
src/link/MachO/Atom.zig+7-7| ... | ... | @@ -341,7 +341,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 341 | 341 | if (rel.r_extern == 0) { |
| 342 | 342 | const sect_id = @intCast(u16, rel.r_symbolnum - 1); |
| 343 | 343 | const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: { |
| 344 | 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; | |
| 345 | 345 | const sect = seg.sections.items[sect_id]; |
| 346 | 346 | const match = (try context.macho_file.getMatchingSection(sect)) orelse |
| 347 | 347 | unreachable; |
| ... | ... | @@ -397,7 +397,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 397 | 397 | else |
| 398 | 398 | mem.readIntLittle(i32, self.code.items[offset..][0..4]); |
| 399 | 399 | if (rel.r_extern == 0) { |
| 400 | 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; | |
| 401 | 401 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; |
| 402 | 402 | addend -= @intCast(i64, target_sect_base_addr); |
| 403 | 403 | } |
| ... | ... | @@ -424,7 +424,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 424 | 424 | else |
| 425 | 425 | mem.readIntLittle(i32, self.code.items[offset..][0..4]); |
| 426 | 426 | if (rel.r_extern == 0) { |
| 427 | 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; | |
| 428 | 428 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; |
| 429 | 429 | addend -= @intCast(i64, target_sect_base_addr); |
| 430 | 430 | } |
| ... | ... | @@ -446,7 +446,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC |
| 446 | 446 | if (rel.r_extern == 0) { |
| 447 | 447 | // Note for the future self: when r_extern == 0, we should subtract correction from the |
| 448 | 448 | // addend. |
| 449 | 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; | |
| 450 | 450 | const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr; |
| 451 | 451 | addend += @intCast(i64, context.base_addr + offset + 4) - |
| 452 | 452 | @intCast(i64, target_sect_base_addr); |
| ... | ... | @@ -489,7 +489,7 @@ fn addPtrBindingOrRebase( |
| 489 | 489 | .local => { |
| 490 | 490 | const source_sym = context.macho_file.locals.items[self.local_sym_index]; |
| 491 | 491 | const match = context.macho_file.section_ordinals.keys()[source_sym.n_sect - 1]; |
| 492 | const seg = context.macho_file.load_commands.items[match.seg].Segment; | |
| 492 | const seg = context.macho_file.load_commands.items[match.seg].segment; | |
| 493 | 493 | const sect = seg.sections.items[match.sect]; |
| 494 | 494 | const sect_type = sect.type_(); |
| 495 | 495 | |
| ... | ... | @@ -704,7 +704,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 704 | 704 | const is_tlv = is_tlv: { |
| 705 | 705 | const source_sym = macho_file.locals.items[self.local_sym_index]; |
| 706 | 706 | const match = macho_file.section_ordinals.keys()[source_sym.n_sect - 1]; |
| 707 | const seg = macho_file.load_commands.items[match.seg].Segment; | |
| 707 | const seg = macho_file.load_commands.items[match.seg].segment; | |
| 708 | 708 | const sect = seg.sections.items[match.sect]; |
| 709 | 709 | break :is_tlv sect.type_() == macho.S_THREAD_LOCAL_VARIABLES; |
| 710 | 710 | }; |
| ... | ... | @@ -714,7 +714,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void { |
| 714 | 714 | // defined TLV template init section in the following order: |
| 715 | 715 | // * wrt to __thread_data if defined, then |
| 716 | 716 | // * wrt to __thread_bss |
| 717 | 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; | |
| 718 | 718 | const base_address = inner: { |
| 719 | 719 | if (macho_file.tlv_data_section_index) |i| { |
| 720 | 720 | break :inner seg.sections.items[i].addr; |
src/link/MachO/DebugSymbols.zig+83-49| ... | ... | @@ -12,15 +12,12 @@ const leb = std.leb; |
| 12 | 12 | const Allocator = mem.Allocator; |
| 13 | 13 | |
| 14 | 14 | const build_options = @import("build_options"); |
| 15 | const commands = @import("commands.zig"); | |
| 16 | 15 | const trace = @import("../../tracy.zig").trace; |
| 17 | const LoadCommand = commands.LoadCommand; | |
| 18 | 16 | const Module = @import("../../Module.zig"); |
| 19 | 17 | const Type = @import("../../type.zig").Type; |
| 20 | 18 | const link = @import("../../link.zig"); |
| 21 | 19 | const MachO = @import("../MachO.zig"); |
| 22 | 20 | const TextBlock = MachO.TextBlock; |
| 23 | const SegmentCommand = commands.SegmentCommand; | |
| 24 | 21 | const SrcFn = MachO.SrcFn; |
| 25 | 22 | const makeStaticString = MachO.makeStaticString; |
| 26 | 23 | const padToIdeal = MachO.padToIdeal; |
| ... | ... | @@ -31,7 +28,7 @@ base: *MachO, |
| 31 | 28 | file: fs.File, |
| 32 | 29 | |
| 33 | 30 | /// Table of all load commands |
| 34 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | |
| 31 | load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{}, | |
| 35 | 32 | /// __PAGEZERO segment |
| 36 | 33 | pagezero_segment_cmd_index: ?u16 = null, |
| 37 | 34 | /// __TEXT segment |
| ... | ... | @@ -113,7 +110,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 113 | 110 | } |
| 114 | 111 | if (self.symtab_cmd_index == null) { |
| 115 | 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 | 114 | const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64); |
| 118 | 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 | 121 | log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize }); |
| 125 | 122 | |
| 126 | 123 | try self.load_commands.append(allocator, .{ |
| 127 | .Symtab = .{ | |
| 124 | .symtab = .{ | |
| 128 | 125 | .cmd = macho.LC_SYMTAB, |
| 129 | 126 | .cmdsize = @sizeOf(macho.symtab_command), |
| 130 | 127 | .symoff = @intCast(u32, symtab_off), |
| ... | ... | @@ -138,48 +135,48 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 138 | 135 | } |
| 139 | 136 | if (self.pagezero_segment_cmd_index == null) { |
| 140 | 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 | 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 | 141 | self.load_commands_dirty = true; |
| 145 | 142 | } |
| 146 | 143 | if (self.text_segment_cmd_index == null) { |
| 147 | 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 | 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 | 148 | self.load_commands_dirty = true; |
| 152 | 149 | } |
| 153 | 150 | if (self.data_const_segment_cmd_index == null) outer: { |
| 154 | 151 | if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional |
| 155 | 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 | 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 | 156 | self.load_commands_dirty = true; |
| 160 | 157 | } |
| 161 | 158 | if (self.data_segment_cmd_index == null) outer: { |
| 162 | 159 | if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional |
| 163 | 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 | 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 | 164 | self.load_commands_dirty = true; |
| 168 | 165 | } |
| 169 | 166 | if (self.linkedit_segment_cmd_index == null) { |
| 170 | 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 | 169 | var cmd = try self.copySegmentCommand(allocator, base_cmd); |
| 173 | 170 | cmd.inner.vmsize = self.linkedit_size; |
| 174 | 171 | cmd.inner.fileoff = self.linkedit_off; |
| 175 | 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 | 174 | self.load_commands_dirty = true; |
| 178 | 175 | } |
| 179 | 176 | if (self.dwarf_segment_cmd_index == null) { |
| 180 | 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 | 180 | const ideal_size: u16 = 200 + 128 + 160 + 250; |
| 184 | 181 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size); |
| 185 | 182 | const off = linkedit.inner.fileoff + linkedit.inner.filesize; |
| ... | ... | @@ -188,7 +185,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 188 | 185 | log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size }); |
| 189 | 186 | |
| 190 | 187 | try self.load_commands.append(allocator, .{ |
| 191 | .Segment = .{ | |
| 188 | .segment = .{ | |
| 192 | 189 | .inner = .{ |
| 193 | 190 | .segname = makeStaticString("__DWARF"), |
| 194 | 191 | .vmaddr = vmaddr, |
| ... | ... | @@ -228,7 +225,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void |
| 228 | 225 | } |
| 229 | 226 | |
| 230 | 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 | 229 | var sect = macho.section_64{ |
| 233 | 230 | .sectname = makeStaticString(sectname), |
| 234 | 231 | .segname = seg.inner.segname, |
| ... | ... | @@ -236,7 +233,7 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme |
| 236 | 233 | .@"align" = alignment, |
| 237 | 234 | }; |
| 238 | 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 | 238 | assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand |
| 242 | 239 | |
| ... | ... | @@ -268,6 +265,28 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme |
| 268 | 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 | 290 | pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Options) !void { |
| 272 | 291 | // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the |
| 273 | 292 | // Zig source code. |
| ... | ... | @@ -275,7 +294,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti |
| 275 | 294 | const init_len_size: usize = 4; |
| 276 | 295 | |
| 277 | 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 | 298 | const debug_abbrev_sect = &dwarf_segment.sections.items[self.debug_abbrev_section_index.?]; |
| 280 | 299 | |
| 281 | 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 | 339 | }; |
| 321 | 340 | |
| 322 | 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 | 343 | if (needed_size > allocated_size) { |
| 325 | 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 | 346 | debug_abbrev_sect.offset = @intCast(u32, offset); |
| 328 | 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 | 364 | // leave debug_info_header_dirty=true. |
| 346 | 365 | const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info; |
| 347 | 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 | 368 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; |
| 350 | 369 | |
| 351 | 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 | 391 | const producer_strp = try self.makeDebugString(allocator, link.producer_string); |
| 373 | 392 | // Currently only one compilation unit is supported, so the address range is simply |
| 374 | 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 | 395 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 377 | 396 | const low_pc = text_section.addr; |
| 378 | 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 | 418 | } |
| 400 | 419 | |
| 401 | 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 | 422 | const debug_aranges_sect = &dwarf_segment.sections.items[self.debug_aranges_section_index.?]; |
| 404 | 423 | |
| 405 | 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 | 445 | |
| 427 | 446 | // Currently only one compilation unit is supported, so the address range is simply |
| 428 | 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 | 449 | const text_section = text_segment.sections.items[self.text_section_index.?]; |
| 431 | 450 | mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.addr); |
| 432 | 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 | 461 | mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len)); |
| 443 | 462 | |
| 444 | 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 | 465 | if (needed_size > allocated_size) { |
| 447 | 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 | 468 | debug_aranges_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff; |
| 450 | 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 | 486 | const dbg_line_prg_end = self.getDebugLineProgramEnd(); |
| 468 | 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 | 490 | const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?]; |
| 472 | 491 | |
| 473 | 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 | 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 | 563 | const debug_strtab_sect = &dwarf_segment.sections.items[self.debug_str_section_index.?]; |
| 545 | 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 | 566 | const needed_size = self.debug_string_table.items.len; |
| 548 | 567 | |
| 549 | 568 | if (needed_size > allocated_size) { |
| 550 | 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 | 571 | debug_strtab_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff; |
| 553 | 572 | debug_strtab_sect.offset = @intCast(u32, new_offset); |
| 554 | 573 | } |
| ... | ... | @@ -588,8 +607,12 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void { |
| 588 | 607 | self.file.close(); |
| 589 | 608 | } |
| 590 | 609 | |
| 591 | fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: SegmentCommand) !SegmentCommand { | |
| 592 | var cmd = SegmentCommand{ | |
| 610 | fn copySegmentCommand( | |
| 611 | self: *DebugSymbols, | |
| 612 | allocator: Allocator, | |
| 613 | base_cmd: macho.SegmentCommand, | |
| 614 | ) !macho.SegmentCommand { | |
| 615 | var cmd = macho.SegmentCommand{ | |
| 593 | 616 | .inner = .{ |
| 594 | 617 | .segname = undefined, |
| 595 | 618 | .cmdsize = base_cmd.inner.cmdsize, |
| ... | ... | @@ -633,7 +656,7 @@ fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: Segme |
| 633 | 656 | } |
| 634 | 657 | |
| 635 | 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 | 660 | var file_size: u64 = 0; |
| 638 | 661 | for (dwarf_segment.sections.items) |sect| { |
| 639 | 662 | file_size += sect.size; |
| ... | ... | @@ -702,7 +725,7 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 { |
| 702 | 725 | var min_pos: u64 = std.math.maxInt(u64); |
| 703 | 726 | |
| 704 | 727 | if (self.symtab_cmd_index) |idx| { |
| 705 | const symtab = self.load_commands.items[idx].Symtab; | |
| 728 | const symtab = self.load_commands.items[idx].symtab; | |
| 706 | 729 | if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff; |
| 707 | 730 | if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff; |
| 708 | 731 | } |
| ... | ... | @@ -710,12 +733,23 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 { |
| 710 | 733 | return min_pos - start; |
| 711 | 734 | } |
| 712 | 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 | ||
| 713 | 747 | fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 { |
| 714 | 748 | const end = start + padToIdeal(size); |
| 715 | 749 | |
| 716 | 750 | if (self.symtab_cmd_index) |idx| outer: { |
| 717 | 751 | if (self.load_commands.items.len == idx) break :outer; |
| 718 | const symtab = self.load_commands.items[idx].Symtab; | |
| 752 | const symtab = self.load_commands.items[idx].symtab; | |
| 719 | 753 | { |
| 720 | 754 | // Symbol table |
| 721 | 755 | const symsize = symtab.nsyms * @sizeOf(macho.nlist_64); |
| ... | ... | @@ -747,7 +781,7 @@ fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u |
| 747 | 781 | } |
| 748 | 782 | |
| 749 | 783 | fn relocateSymbolTable(self: *DebugSymbols) !void { |
| 750 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | |
| 784 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; | |
| 751 | 785 | const nlocals = self.base.locals.items.len; |
| 752 | 786 | const nglobals = self.base.globals.items.len; |
| 753 | 787 | const nsyms = nlocals + nglobals; |
| ... | ... | @@ -780,7 +814,7 @@ pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void { |
| 780 | 814 | const tracy = trace(@src()); |
| 781 | 815 | defer tracy.end(); |
| 782 | 816 | try self.relocateSymbolTable(); |
| 783 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | |
| 817 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; | |
| 784 | 818 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; |
| 785 | 819 | log.debug("writing local symbol {} at 0x{x}", .{ index, off }); |
| 786 | 820 | try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off); |
| ... | ... | @@ -792,7 +826,7 @@ fn writeStringTable(self: *DebugSymbols) !void { |
| 792 | 826 | const tracy = trace(@src()); |
| 793 | 827 | defer tracy.end(); |
| 794 | 828 | |
| 795 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | |
| 829 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab; | |
| 796 | 830 | const allocated_size = self.allocatedSizeLinkedit(symtab.stroff); |
| 797 | 831 | const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64)); |
| 798 | 832 | |
| ... | ... | @@ -816,7 +850,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M |
| 816 | 850 | const func = decl.val.castTag(.function).?.data; |
| 817 | 851 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); |
| 818 | 852 | |
| 819 | 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; | |
| 820 | 854 | const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?]; |
| 821 | 855 | const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff(); |
| 822 | 856 | var data: [4]u8 = undefined; |
| ... | ... | @@ -982,7 +1016,7 @@ pub fn commitDeclDebugInfo( |
| 982 | 1016 | // `TextBlock` and the .debug_info. If you are editing this logic, you |
| 983 | 1017 | // probably need to edit that logic too. |
| 984 | 1018 | |
| 985 | 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; | |
| 986 | 1020 | const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?]; |
| 987 | 1021 | const src_fn = &decl.fn_link.macho; |
| 988 | 1022 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); |
| ... | ... | @@ -1028,8 +1062,8 @@ pub fn commitDeclDebugInfo( |
| 1028 | 1062 | const last_src_fn = self.dbg_line_fn_last.?; |
| 1029 | 1063 | const needed_size = last_src_fn.off + last_src_fn.len; |
| 1030 | 1064 | if (needed_size != debug_line_sect.size) { |
| 1031 | if (needed_size > dwarf_segment.allocatedSize(debug_line_sect.offset)) { | |
| 1032 | const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null); | |
| 1065 | if (needed_size > self.allocatedSize(debug_line_sect.offset)) { | |
| 1066 | const new_offset = self.findFreeSpace(needed_size, 1); | |
| 1033 | 1067 | const existing_size = last_src_fn.off; |
| 1034 | 1068 | |
| 1035 | 1069 | log.debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{ |
| ... | ... | @@ -1151,7 +1185,7 @@ fn updateDeclDebugInfoAllocation( |
| 1151 | 1185 | // `SrcFn` and the line number programs. If you are editing this logic, you |
| 1152 | 1186 | // probably need to edit that logic too. |
| 1153 | 1187 | |
| 1154 | 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; | |
| 1155 | 1189 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; |
| 1156 | 1190 | text_block.dbg_info_len = len; |
| 1157 | 1191 | if (self.dbg_info_decl_last) |last| blk: { |
| ... | ... | @@ -1202,15 +1236,15 @@ fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_buf: |
| 1202 | 1236 | // `SrcFn` and the line number programs. If you are editing this logic, you |
| 1203 | 1237 | // probably need to edit that logic too. |
| 1204 | 1238 | |
| 1205 | 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; | |
| 1206 | 1240 | const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; |
| 1207 | 1241 | |
| 1208 | 1242 | const last_decl = self.dbg_info_decl_last.?; |
| 1209 | 1243 | // +1 for a trailing zero to end the children of the decl tag. |
| 1210 | 1244 | const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1; |
| 1211 | 1245 | if (needed_size != debug_info_sect.size) { |
| 1212 | if (needed_size > dwarf_segment.allocatedSize(debug_info_sect.offset)) { | |
| 1213 | const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null); | |
| 1246 | if (needed_size > self.allocatedSize(debug_info_sect.offset)) { | |
| 1247 | const new_offset = self.findFreeSpace(needed_size, 1); | |
| 1214 | 1248 | const existing_size = last_decl.dbg_info_off; |
| 1215 | 1249 | |
| 1216 | 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 | 9 | const math = std.math; |
| 10 | 10 | const mem = std.mem; |
| 11 | 11 | const fat = @import("fat.zig"); |
| 12 | const commands = @import("commands.zig"); | |
| 13 | 12 | |
| 14 | 13 | const Allocator = mem.Allocator; |
| 15 | 14 | const LibStub = @import("../tapi.zig").LibStub; |
| 16 | const LoadCommand = commands.LoadCommand; | |
| 17 | 15 | const MachO = @import("../MachO.zig"); |
| 18 | 16 | |
| 19 | 17 | file: fs.File, |
| ... | ... | @@ -25,7 +23,7 @@ header: ?macho.mach_header_64 = null, |
| 25 | 23 | // an offset within a file if we are linking against a fat lib |
| 26 | 24 | library_offset: u64 = 0, |
| 27 | 25 | |
| 28 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | |
| 26 | load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{}, | |
| 29 | 27 | |
| 30 | 28 | symtab_cmd_index: ?u16 = null, |
| 31 | 29 | dysymtab_cmd_index: ?u16 = null, |
| ... | ... | @@ -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 | 55 | const dylib = lc.inner.dylib; |
| 58 | 56 | const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]); |
| 59 | 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 | 175 | |
| 178 | 176 | var i: u16 = 0; |
| 179 | 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 | 179 | switch (cmd.cmd()) { |
| 182 | 180 | macho.LC_SYMTAB => { |
| 183 | 181 | self.symtab_cmd_index = i; |
| ... | ... | @@ -191,7 +189,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende |
| 191 | 189 | macho.LC_REEXPORT_DYLIB => { |
| 192 | 190 | if (should_lookup_reexports) { |
| 193 | 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 | 193 | try dependent_libs.writeItem(id); |
| 196 | 194 | } |
| 197 | 195 | }, |
| ... | ... | @@ -209,12 +207,12 @@ fn parseId(self: *Dylib, allocator: Allocator) !void { |
| 209 | 207 | self.id = try Id.default(allocator, self.name); |
| 210 | 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 | 213 | fn parseSymbols(self: *Dylib, allocator: Allocator) !void { |
| 216 | 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 | 217 | var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); |
| 220 | 218 | defer allocator.free(symtab); |
src/link/MachO/Object.zig+11-12| ... | ... | @@ -15,7 +15,6 @@ const trace = @import("../../tracy.zig").trace; |
| 15 | 15 | |
| 16 | 16 | const Allocator = mem.Allocator; |
| 17 | 17 | const Atom = @import("Atom.zig"); |
| 18 | const LoadCommand = @import("commands.zig").LoadCommand; | |
| 19 | 18 | const MachO = @import("../MachO.zig"); |
| 20 | 19 | |
| 21 | 20 | file: fs.File, |
| ... | ... | @@ -25,7 +24,7 @@ file_offset: ?u32 = null, |
| 25 | 24 | |
| 26 | 25 | header: ?macho.mach_header_64 = null, |
| 27 | 26 | |
| 28 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | |
| 27 | load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{}, | |
| 29 | 28 | |
| 30 | 29 | segment_cmd_index: ?u16 = null, |
| 31 | 30 | text_section_index: ?u16 = null, |
| ... | ... | @@ -268,11 +267,11 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v |
| 268 | 267 | |
| 269 | 268 | var i: u16 = 0; |
| 270 | 269 | while (i < header.ncmds) : (i += 1) { |
| 271 | var cmd = try LoadCommand.read(allocator, reader); | |
| 270 | var cmd = try macho.LoadCommand.read(allocator, reader); | |
| 272 | 271 | switch (cmd.cmd()) { |
| 273 | 272 | macho.LC_SEGMENT_64 => { |
| 274 | 273 | self.segment_cmd_index = i; |
| 275 | var seg = cmd.Segment; | |
| 274 | var seg = cmd.segment; | |
| 276 | 275 | for (seg.sections.items) |*sect, j| { |
| 277 | 276 | const index = @intCast(u16, j); |
| 278 | 277 | const segname = sect.segName(); |
| ... | ... | @@ -305,8 +304,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v |
| 305 | 304 | }, |
| 306 | 305 | macho.LC_SYMTAB => { |
| 307 | 306 | self.symtab_cmd_index = i; |
| 308 | cmd.Symtab.symoff += offset; | |
| 309 | cmd.Symtab.stroff += offset; | |
| 307 | cmd.symtab.symoff += offset; | |
| 308 | cmd.symtab.stroff += offset; | |
| 310 | 309 | }, |
| 311 | 310 | macho.LC_DYSYMTAB => { |
| 312 | 311 | self.dysymtab_cmd_index = i; |
| ... | ... | @@ -316,7 +315,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v |
| 316 | 315 | }, |
| 317 | 316 | macho.LC_DATA_IN_CODE => { |
| 318 | 317 | self.data_in_code_cmd_index = i; |
| 319 | cmd.LinkeditData.dataoff += offset; | |
| 318 | cmd.linkedit_data.dataoff += offset; | |
| 320 | 319 | }, |
| 321 | 320 | else => { |
| 322 | 321 | log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()}); |
| ... | ... | @@ -382,7 +381,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 382 | 381 | const tracy = trace(@src()); |
| 383 | 382 | defer tracy.end(); |
| 384 | 383 | |
| 385 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | |
| 384 | const seg = self.load_commands.items[self.segment_cmd_index.?].segment; | |
| 386 | 385 | |
| 387 | 386 | log.debug("analysing {s}", .{self.name}); |
| 388 | 387 | |
| ... | ... | @@ -405,7 +404,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 405 | 404 | // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we |
| 406 | 405 | // have to infer the start of undef section in the symtab ourselves. |
| 407 | 406 | const iundefsym = if (self.dysymtab_cmd_index) |cmd_index| blk: { |
| 408 | const dysymtab = self.load_commands.items[cmd_index].Dysymtab; | |
| 407 | const dysymtab = self.load_commands.items[cmd_index].dysymtab; | |
| 409 | 408 | break :blk dysymtab.iundefsym; |
| 410 | 409 | } else blk: { |
| 411 | 410 | var iundefsym: usize = sorted_all_nlists.items.len; |
| ... | ... | @@ -553,7 +552,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) ! |
| 553 | 552 | |
| 554 | 553 | fn parseSymtab(self: *Object, allocator: Allocator) !void { |
| 555 | 554 | const index = self.symtab_cmd_index orelse return; |
| 556 | const symtab_cmd = self.load_commands.items[index].Symtab; | |
| 555 | const symtab_cmd = self.load_commands.items[index].symtab; | |
| 557 | 556 | |
| 558 | 557 | var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms); |
| 559 | 558 | defer allocator.free(symtab); |
| ... | ... | @@ -601,7 +600,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void { |
| 601 | 600 | |
| 602 | 601 | pub fn parseDataInCode(self: *Object, allocator: Allocator) !void { |
| 603 | 602 | const index = self.data_in_code_cmd_index orelse return; |
| 604 | const data_in_code = self.load_commands.items[index].LinkeditData; | |
| 603 | const data_in_code = self.load_commands.items[index].linkedit_data; | |
| 605 | 604 | |
| 606 | 605 | var buffer = try allocator.alloc(u8, data_in_code.datasize); |
| 607 | 606 | defer allocator.free(buffer); |
| ... | ... | @@ -620,7 +619,7 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void { |
| 620 | 619 | } |
| 621 | 620 | |
| 622 | 621 | fn readSection(self: Object, allocator: Allocator, index: u16) ![]u8 { |
| 623 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | |
| 622 | const seg = self.load_commands.items[self.segment_cmd_index.?].segment; | |
| 624 | 623 | const sect = seg.sections.items[index]; |
| 625 | 624 | var buffer = try allocator.alloc(u8, @intCast(usize, sect.size)); |
| 626 | 625 | _ = try self.file.preadAll(buffer, sect.offset); |
src/link/MachO/commands.zig deleted-463| ... | ... | @@ -1,463 +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 LoadCommand = union(enum) { | |
| 16 | Segment: SegmentCommand, | |
| 17 | DyldInfoOnly: macho.dyld_info_command, | |
| 18 | Symtab: macho.symtab_command, | |
| 19 | Dysymtab: macho.dysymtab_command, | |
| 20 | Dylinker: GenericCommandWithData(macho.dylinker_command), | |
| 21 | Dylib: GenericCommandWithData(macho.dylib_command), | |
| 22 | Main: macho.entry_point_command, | |
| 23 | VersionMin: macho.version_min_command, | |
| 24 | SourceVersion: macho.source_version_command, | |
| 25 | BuildVersion: GenericCommandWithData(macho.build_version_command), | |
| 26 | Uuid: macho.uuid_command, | |
| 27 | LinkeditData: macho.linkedit_data_command, | |
| 28 | Rpath: GenericCommandWithData(macho.rpath_command), | |
| 29 | Unknown: GenericCommandWithData(macho.load_command), | |
| 30 | ||
| 31 | pub fn read(allocator: Allocator, reader: anytype) !LoadCommand { | |
| 32 | const header = try reader.readStruct(macho.load_command); | |
| 33 | var buffer = try allocator.alloc(u8, header.cmdsize); | |
| 34 | defer allocator.free(buffer); | |
| 35 | mem.copy(u8, buffer, mem.asBytes(&header)); | |
| 36 | try reader.readNoEof(buffer[@sizeOf(macho.load_command)..]); | |
| 37 | var stream = io.fixedBufferStream(buffer); | |
| 38 | ||
| 39 | return switch (header.cmd) { | |
| 40 | macho.LC_SEGMENT_64 => LoadCommand{ | |
| 41 | .Segment = try SegmentCommand.read(allocator, stream.reader()), | |
| 42 | }, | |
| 43 | macho.LC_DYLD_INFO, | |
| 44 | macho.LC_DYLD_INFO_ONLY, | |
| 45 | => LoadCommand{ | |
| 46 | .DyldInfoOnly = try stream.reader().readStruct(macho.dyld_info_command), | |
| 47 | }, | |
| 48 | macho.LC_SYMTAB => LoadCommand{ | |
| 49 | .Symtab = try stream.reader().readStruct(macho.symtab_command), | |
| 50 | }, | |
| 51 | macho.LC_DYSYMTAB => LoadCommand{ | |
| 52 | .Dysymtab = try stream.reader().readStruct(macho.dysymtab_command), | |
| 53 | }, | |
| 54 | macho.LC_ID_DYLINKER, | |
| 55 | macho.LC_LOAD_DYLINKER, | |
| 56 | macho.LC_DYLD_ENVIRONMENT, | |
| 57 | => LoadCommand{ | |
| 58 | .Dylinker = try GenericCommandWithData(macho.dylinker_command).read(allocator, stream.reader()), | |
| 59 | }, | |
| 60 | macho.LC_ID_DYLIB, | |
| 61 | macho.LC_LOAD_WEAK_DYLIB, | |
| 62 | macho.LC_LOAD_DYLIB, | |
| 63 | macho.LC_REEXPORT_DYLIB, | |
| 64 | => LoadCommand{ | |
| 65 | .Dylib = try GenericCommandWithData(macho.dylib_command).read(allocator, stream.reader()), | |
| 66 | }, | |
| 67 | macho.LC_MAIN => LoadCommand{ | |
| 68 | .Main = try stream.reader().readStruct(macho.entry_point_command), | |
| 69 | }, | |
| 70 | macho.LC_VERSION_MIN_MACOSX, | |
| 71 | macho.LC_VERSION_MIN_IPHONEOS, | |
| 72 | macho.LC_VERSION_MIN_WATCHOS, | |
| 73 | macho.LC_VERSION_MIN_TVOS, | |
| 74 | => LoadCommand{ | |
| 75 | .VersionMin = try stream.reader().readStruct(macho.version_min_command), | |
| 76 | }, | |
| 77 | macho.LC_SOURCE_VERSION => LoadCommand{ | |
| 78 | .SourceVersion = try stream.reader().readStruct(macho.source_version_command), | |
| 79 | }, | |
| 80 | macho.LC_BUILD_VERSION => LoadCommand{ | |
| 81 | .BuildVersion = try GenericCommandWithData(macho.build_version_command).read(allocator, stream.reader()), | |
| 82 | }, | |
| 83 | macho.LC_UUID => LoadCommand{ | |
| 84 | .Uuid = try stream.reader().readStruct(macho.uuid_command), | |
| 85 | }, | |
| 86 | macho.LC_FUNCTION_STARTS, | |
| 87 | macho.LC_DATA_IN_CODE, | |
| 88 | macho.LC_CODE_SIGNATURE, | |
| 89 | => LoadCommand{ | |
| 90 | .LinkeditData = try stream.reader().readStruct(macho.linkedit_data_command), | |
| 91 | }, | |
| 92 | macho.LC_RPATH => LoadCommand{ | |
| 93 | .Rpath = try GenericCommandWithData(macho.rpath_command).read(allocator, stream.reader()), | |
| 94 | }, | |
| 95 | else => LoadCommand{ | |
| 96 | .Unknown = try GenericCommandWithData(macho.load_command).read(allocator, stream.reader()), | |
| 97 | }, | |
| 98 | }; | |
| 99 | } | |
| 100 | ||
| 101 | pub fn write(self: LoadCommand, writer: anytype) !void { | |
| 102 | return switch (self) { | |
| 103 | .DyldInfoOnly => |x| writeStruct(x, writer), | |
| 104 | .Symtab => |x| writeStruct(x, writer), | |
| 105 | .Dysymtab => |x| writeStruct(x, writer), | |
| 106 | .Main => |x| writeStruct(x, writer), | |
| 107 | .VersionMin => |x| writeStruct(x, writer), | |
| 108 | .SourceVersion => |x| writeStruct(x, writer), | |
| 109 | .Uuid => |x| writeStruct(x, writer), | |
| 110 | .LinkeditData => |x| writeStruct(x, writer), | |
| 111 | .Segment => |x| x.write(writer), | |
| 112 | .Dylinker => |x| x.write(writer), | |
| 113 | .Dylib => |x| x.write(writer), | |
| 114 | .Rpath => |x| x.write(writer), | |
| 115 | .BuildVersion => |x| x.write(writer), | |
| 116 | .Unknown => |x| x.write(writer), | |
| 117 | }; | |
| 118 | } | |
| 119 | ||
| 120 | pub fn cmd(self: LoadCommand) u32 { | |
| 121 | return switch (self) { | |
| 122 | .DyldInfoOnly => |x| x.cmd, | |
| 123 | .Symtab => |x| x.cmd, | |
| 124 | .Dysymtab => |x| x.cmd, | |
| 125 | .Main => |x| x.cmd, | |
| 126 | .VersionMin => |x| x.cmd, | |
| 127 | .SourceVersion => |x| x.cmd, | |
| 128 | .Uuid => |x| x.cmd, | |
| 129 | .LinkeditData => |x| x.cmd, | |
| 130 | .Segment => |x| x.inner.cmd, | |
| 131 | .Dylinker => |x| x.inner.cmd, | |
| 132 | .Dylib => |x| x.inner.cmd, | |
| 133 | .Rpath => |x| x.inner.cmd, | |
| 134 | .BuildVersion => |x| x.inner.cmd, | |
| 135 | .Unknown => |x| x.inner.cmd, | |
| 136 | }; | |
| 137 | } | |
| 138 | ||
| 139 | pub fn cmdsize(self: LoadCommand) u32 { | |
| 140 | return switch (self) { | |
| 141 | .DyldInfoOnly => |x| x.cmdsize, | |
| 142 | .Symtab => |x| x.cmdsize, | |
| 143 | .Dysymtab => |x| x.cmdsize, | |
| 144 | .Main => |x| x.cmdsize, | |
| 145 | .VersionMin => |x| x.cmdsize, | |
| 146 | .SourceVersion => |x| x.cmdsize, | |
| 147 | .LinkeditData => |x| x.cmdsize, | |
| 148 | .Uuid => |x| x.cmdsize, | |
| 149 | .Segment => |x| x.inner.cmdsize, | |
| 150 | .Dylinker => |x| x.inner.cmdsize, | |
| 151 | .Dylib => |x| x.inner.cmdsize, | |
| 152 | .Rpath => |x| x.inner.cmdsize, | |
| 153 | .BuildVersion => |x| x.inner.cmdsize, | |
| 154 | .Unknown => |x| x.inner.cmdsize, | |
| 155 | }; | |
| 156 | } | |
| 157 | ||
| 158 | pub fn deinit(self: *LoadCommand, allocator: Allocator) void { | |
| 159 | return switch (self.*) { | |
| 160 | .Segment => |*x| x.deinit(allocator), | |
| 161 | .Dylinker => |*x| x.deinit(allocator), | |
| 162 | .Dylib => |*x| x.deinit(allocator), | |
| 163 | .Rpath => |*x| x.deinit(allocator), | |
| 164 | .BuildVersion => |*x| x.deinit(allocator), | |
| 165 | .Unknown => |*x| x.deinit(allocator), | |
| 166 | else => {}, | |
| 167 | }; | |
| 168 | } | |
| 169 | ||
| 170 | fn writeStruct(command: anytype, writer: anytype) !void { | |
| 171 | return writer.writeAll(mem.asBytes(&command)); | |
| 172 | } | |
| 173 | ||
| 174 | fn eql(self: LoadCommand, other: LoadCommand) bool { | |
| 175 | if (@as(meta.Tag(LoadCommand), self) != @as(meta.Tag(LoadCommand), other)) return false; | |
| 176 | return switch (self) { | |
| 177 | .DyldInfoOnly => |x| meta.eql(x, other.DyldInfoOnly), | |
| 178 | .Symtab => |x| meta.eql(x, other.Symtab), | |
| 179 | .Dysymtab => |x| meta.eql(x, other.Dysymtab), | |
| 180 | .Main => |x| meta.eql(x, other.Main), | |
| 181 | .VersionMin => |x| meta.eql(x, other.VersionMin), | |
| 182 | .SourceVersion => |x| meta.eql(x, other.SourceVersion), | |
| 183 | .BuildVersion => |x| x.eql(other.BuildVersion), | |
| 184 | .Uuid => |x| meta.eql(x, other.Uuid), | |
| 185 | .LinkeditData => |x| meta.eql(x, other.LinkeditData), | |
| 186 | .Segment => |x| x.eql(other.Segment), | |
| 187 | .Dylinker => |x| x.eql(other.Dylinker), | |
| 188 | .Dylib => |x| x.eql(other.Dylib), | |
| 189 | .Rpath => |x| x.eql(other.Rpath), | |
| 190 | .Unknown => |x| x.eql(other.Unknown), | |
| 191 | }; | |
| 192 | } | |
| 193 | }; | |
| 194 | ||
| 195 | pub const SegmentCommand = struct { | |
| 196 | inner: macho.segment_command_64, | |
| 197 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, | |
| 198 | ||
| 199 | pub fn read(alloc: Allocator, reader: anytype) !SegmentCommand { | |
| 200 | const inner = try reader.readStruct(macho.segment_command_64); | |
| 201 | var segment = SegmentCommand{ | |
| 202 | .inner = inner, | |
| 203 | }; | |
| 204 | try segment.sections.ensureTotalCapacityPrecise(alloc, inner.nsects); | |
| 205 | ||
| 206 | var i: usize = 0; | |
| 207 | while (i < inner.nsects) : (i += 1) { | |
| 208 | const section = try reader.readStruct(macho.section_64); | |
| 209 | segment.sections.appendAssumeCapacity(section); | |
| 210 | } | |
| 211 | ||
| 212 | return segment; | |
| 213 | } | |
| 214 | ||
| 215 | pub fn write(self: SegmentCommand, writer: anytype) !void { | |
| 216 | try writer.writeAll(mem.asBytes(&self.inner)); | |
| 217 | for (self.sections.items) |sect| { | |
| 218 | try writer.writeAll(mem.asBytes(&sect)); | |
| 219 | } | |
| 220 | } | |
| 221 | ||
| 222 | pub fn deinit(self: *SegmentCommand, alloc: Allocator) void { | |
| 223 | self.sections.deinit(alloc); | |
| 224 | } | |
| 225 | ||
| 226 | pub fn allocatedSize(self: SegmentCommand, start: u64) u64 { | |
| 227 | assert(start >= self.inner.fileoff); | |
| 228 | var min_pos: u64 = self.inner.fileoff + self.inner.filesize; | |
| 229 | for (self.sections.items) |section| { | |
| 230 | if (section.offset <= start) continue; | |
| 231 | if (section.offset < min_pos) min_pos = section.offset; | |
| 232 | } | |
| 233 | return min_pos - start; | |
| 234 | } | |
| 235 | ||
| 236 | fn detectAllocCollision(self: SegmentCommand, start: u64, size: u64) ?u64 { | |
| 237 | const end = start + padToIdeal(size); | |
| 238 | for (self.sections.items) |section| { | |
| 239 | const increased_size = padToIdeal(section.size); | |
| 240 | const test_end = section.offset + increased_size; | |
| 241 | if (end > section.offset and start < test_end) { | |
| 242 | return test_end; | |
| 243 | } | |
| 244 | } | |
| 245 | return null; | |
| 246 | } | |
| 247 | ||
| 248 | pub fn findFreeSpace(self: SegmentCommand, object_size: u64, min_alignment: u64, start: ?u64) u64 { | |
| 249 | var offset: u64 = if (start) |v| v else self.inner.fileoff; | |
| 250 | while (self.detectAllocCollision(offset, object_size)) |item_end| { | |
| 251 | offset = mem.alignForwardGeneric(u64, item_end, min_alignment); | |
| 252 | } | |
| 253 | return offset; | |
| 254 | } | |
| 255 | ||
| 256 | fn eql(self: SegmentCommand, other: SegmentCommand) bool { | |
| 257 | if (!meta.eql(self.inner, other.inner)) return false; | |
| 258 | const lhs = self.sections.items; | |
| 259 | const rhs = other.sections.items; | |
| 260 | var i: usize = 0; | |
| 261 | while (i < self.inner.nsects) : (i += 1) { | |
| 262 | if (!meta.eql(lhs[i], rhs[i])) return false; | |
| 263 | } | |
| 264 | return true; | |
| 265 | } | |
| 266 | }; | |
| 267 | ||
| 268 | pub fn emptyGenericCommandWithData(cmd: anytype) GenericCommandWithData(@TypeOf(cmd)) { | |
| 269 | return .{ .inner = cmd }; | |
| 270 | } | |
| 271 | ||
| 272 | pub fn GenericCommandWithData(comptime Cmd: type) type { | |
| 273 | return struct { | |
| 274 | inner: Cmd, | |
| 275 | /// This field remains undefined until `read` is called. | |
| 276 | data: []u8 = undefined, | |
| 277 | ||
| 278 | const Self = @This(); | |
| 279 | ||
| 280 | pub fn read(allocator: Allocator, reader: anytype) !Self { | |
| 281 | const inner = try reader.readStruct(Cmd); | |
| 282 | var data = try allocator.alloc(u8, inner.cmdsize - @sizeOf(Cmd)); | |
| 283 | errdefer allocator.free(data); | |
| 284 | try reader.readNoEof(data); | |
| 285 | return Self{ | |
| 286 | .inner = inner, | |
| 287 | .data = data, | |
| 288 | }; | |
| 289 | } | |
| 290 | ||
| 291 | pub fn write(self: Self, writer: anytype) !void { | |
| 292 | try writer.writeAll(mem.asBytes(&self.inner)); | |
| 293 | try writer.writeAll(self.data); | |
| 294 | } | |
| 295 | ||
| 296 | pub fn deinit(self: *Self, allocator: Allocator) void { | |
| 297 | allocator.free(self.data); | |
| 298 | } | |
| 299 | ||
| 300 | fn eql(self: Self, other: Self) bool { | |
| 301 | if (!meta.eql(self.inner, other.inner)) return false; | |
| 302 | return mem.eql(u8, self.data, other.data); | |
| 303 | } | |
| 304 | }; | |
| 305 | } | |
| 306 | ||
| 307 | pub fn createLoadDylibCommand( | |
| 308 | allocator: Allocator, | |
| 309 | name: []const u8, | |
| 310 | timestamp: u32, | |
| 311 | current_version: u32, | |
| 312 | compatibility_version: u32, | |
| 313 | ) !GenericCommandWithData(macho.dylib_command) { | |
| 314 | const cmdsize = @intCast(u32, mem.alignForwardGeneric( | |
| 315 | u64, | |
| 316 | @sizeOf(macho.dylib_command) + name.len + 1, // +1 for nul | |
| 317 | @sizeOf(u64), | |
| 318 | )); | |
| 319 | ||
| 320 | var dylib_cmd = emptyGenericCommandWithData(macho.dylib_command{ | |
| 321 | .cmd = macho.LC_LOAD_DYLIB, | |
| 322 | .cmdsize = cmdsize, | |
| 323 | .dylib = .{ | |
| 324 | .name = @sizeOf(macho.dylib_command), | |
| 325 | .timestamp = timestamp, | |
| 326 | .current_version = current_version, | |
| 327 | .compatibility_version = compatibility_version, | |
| 328 | }, | |
| 329 | }); | |
| 330 | dylib_cmd.data = try allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name); | |
| 331 | ||
| 332 | mem.set(u8, dylib_cmd.data, 0); | |
| 333 | mem.copy(u8, dylib_cmd.data, name); | |
| 334 | ||
| 335 | return dylib_cmd; | |
| 336 | } | |
| 337 | ||
| 338 | fn testRead(allocator: Allocator, buffer: []const u8, expected: anytype) !void { | |
| 339 | var stream = io.fixedBufferStream(buffer); | |
| 340 | var given = try LoadCommand.read(allocator, stream.reader()); | |
| 341 | defer given.deinit(allocator); | |
| 342 | try testing.expect(expected.eql(given)); | |
| 343 | } | |
| 344 | ||
| 345 | fn testWrite(buffer: []u8, cmd: LoadCommand, expected: []const u8) !void { | |
| 346 | var stream = io.fixedBufferStream(buffer); | |
| 347 | try cmd.write(stream.writer()); | |
| 348 | try testing.expect(mem.eql(u8, expected, buffer[0..expected.len])); | |
| 349 | } | |
| 350 | ||
| 351 | test "read-write segment command" { | |
| 352 | var gpa = testing.allocator; | |
| 353 | const in_buffer = &[_]u8{ | |
| 354 | 0x19, 0x00, 0x00, 0x00, // cmd | |
| 355 | 0x98, 0x00, 0x00, 0x00, // cmdsize | |
| 356 | 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname | |
| 357 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // vmaddr | |
| 358 | 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // vmsize | |
| 359 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // fileoff | |
| 360 | 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // filesize | |
| 361 | 0x07, 0x00, 0x00, 0x00, // maxprot | |
| 362 | 0x05, 0x00, 0x00, 0x00, // initprot | |
| 363 | 0x01, 0x00, 0x00, 0x00, // nsects | |
| 364 | 0x00, 0x00, 0x00, 0x00, // flags | |
| 365 | 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sectname | |
| 366 | 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname | |
| 367 | 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // address | |
| 368 | 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size | |
| 369 | 0x00, 0x40, 0x00, 0x00, // offset | |
| 370 | 0x02, 0x00, 0x00, 0x00, // alignment | |
| 371 | 0x00, 0x00, 0x00, 0x00, // reloff | |
| 372 | 0x00, 0x00, 0x00, 0x00, // nreloc | |
| 373 | 0x00, 0x04, 0x00, 0x80, // flags | |
| 374 | 0x00, 0x00, 0x00, 0x00, // reserved1 | |
| 375 | 0x00, 0x00, 0x00, 0x00, // reserved2 | |
| 376 | 0x00, 0x00, 0x00, 0x00, // reserved3 | |
| 377 | }; | |
| 378 | var cmd = SegmentCommand{ | |
| 379 | .inner = .{ | |
| 380 | .cmdsize = 152, | |
| 381 | .segname = makeStaticString("__TEXT"), | |
| 382 | .vmaddr = 4294967296, | |
| 383 | .vmsize = 294912, | |
| 384 | .filesize = 294912, | |
| 385 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE, | |
| 386 | .initprot = macho.VM_PROT_EXECUTE | macho.VM_PROT_READ, | |
| 387 | .nsects = 1, | |
| 388 | }, | |
| 389 | }; | |
| 390 | try cmd.sections.append(gpa, .{ | |
| 391 | .sectname = makeStaticString("__text"), | |
| 392 | .segname = makeStaticString("__TEXT"), | |
| 393 | .addr = 4294983680, | |
| 394 | .size = 448, | |
| 395 | .offset = 16384, | |
| 396 | .@"align" = 2, | |
| 397 | .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, | |
| 398 | }); | |
| 399 | defer cmd.deinit(gpa); | |
| 400 | try testRead(gpa, in_buffer, LoadCommand{ .Segment = cmd }); | |
| 401 | ||
| 402 | var out_buffer: [in_buffer.len]u8 = undefined; | |
| 403 | try testWrite(&out_buffer, LoadCommand{ .Segment = cmd }, in_buffer); | |
| 404 | } | |
| 405 | ||
| 406 | test "read-write generic command with data" { | |
| 407 | var gpa = testing.allocator; | |
| 408 | const in_buffer = &[_]u8{ | |
| 409 | 0x0c, 0x00, 0x00, 0x00, // cmd | |
| 410 | 0x20, 0x00, 0x00, 0x00, // cmdsize | |
| 411 | 0x18, 0x00, 0x00, 0x00, // name | |
| 412 | 0x02, 0x00, 0x00, 0x00, // timestamp | |
| 413 | 0x00, 0x00, 0x00, 0x00, // current_version | |
| 414 | 0x00, 0x00, 0x00, 0x00, // compatibility_version | |
| 415 | 0x2f, 0x75, 0x73, 0x72, 0x00, 0x00, 0x00, 0x00, // data | |
| 416 | }; | |
| 417 | var cmd = GenericCommandWithData(macho.dylib_command){ | |
| 418 | .inner = .{ | |
| 419 | .cmd = macho.LC_LOAD_DYLIB, | |
| 420 | .cmdsize = 32, | |
| 421 | .dylib = .{ | |
| 422 | .name = 24, | |
| 423 | .timestamp = 2, | |
| 424 | .current_version = 0, | |
| 425 | .compatibility_version = 0, | |
| 426 | }, | |
| 427 | }, | |
| 428 | }; | |
| 429 | cmd.data = try gpa.alloc(u8, 8); | |
| 430 | defer gpa.free(cmd.data); | |
| 431 | cmd.data[0] = 0x2f; | |
| 432 | cmd.data[1] = 0x75; | |
| 433 | cmd.data[2] = 0x73; | |
| 434 | cmd.data[3] = 0x72; | |
| 435 | cmd.data[4] = 0x0; | |
| 436 | cmd.data[5] = 0x0; | |
| 437 | cmd.data[6] = 0x0; | |
| 438 | cmd.data[7] = 0x0; | |
| 439 | try testRead(gpa, in_buffer, LoadCommand{ .Dylib = cmd }); | |
| 440 | ||
| 441 | var out_buffer: [in_buffer.len]u8 = undefined; | |
| 442 | try testWrite(&out_buffer, LoadCommand{ .Dylib = cmd }, in_buffer); | |
| 443 | } | |
| 444 | ||
| 445 | test "read-write C struct command" { | |
| 446 | var gpa = testing.allocator; | |
| 447 | const in_buffer = &[_]u8{ | |
| 448 | 0x28, 0x00, 0x00, 0x80, // cmd | |
| 449 | 0x18, 0x00, 0x00, 0x00, // cmdsize | |
| 450 | 0x04, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // entryoff | |
| 451 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // stacksize | |
| 452 | }; | |
| 453 | const cmd = .{ | |
| 454 | .cmd = macho.LC_MAIN, | |
| 455 | .cmdsize = 24, | |
| 456 | .entryoff = 16644, | |
| 457 | .stacksize = 0, | |
| 458 | }; | |
| 459 | try testRead(gpa, in_buffer, LoadCommand{ .Main = cmd }); | |
| 460 | ||
| 461 | var out_buffer: [in_buffer.len]u8 = undefined; | |
| 462 | try testWrite(&out_buffer, LoadCommand{ .Main = cmd }, in_buffer); | |
| 463 | } |