authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-10 14:13:43+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-10 18:18:28+01:00
log828f61e8dfcf17e0f7c42552311e6589bb187880
tree6972d08f0c0292d27ebb1e8a74bc7c9a3087feae
parent81e7d8505c086a93accb74e9f1a84abb8ff7cf24

macho: move all helpers from commands.zig into std.macho

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,7 +590,6 @@ set(ZIG_STAGE2_SOURCES
590 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"590 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
591 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"591 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
592 "${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig"592 "${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig"
593 "${CMAKE_SOURCE_DIR}/src/link/MachO/commands.zig"
594 "${CMAKE_SOURCE_DIR}/src/link/Plan9.zig"593 "${CMAKE_SOURCE_DIR}/src/link/Plan9.zig"
595 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"594 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
596 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"595 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
lib/std/macho.zig+434-1
...@@ -1,4 +1,12 @@...@@ -1,4 +1,12 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const io = std.io;
5const mem = std.mem;
6const meta = std.meta;
7const testing = std.testing;
8
9const Allocator = mem.Allocator;
210
3pub const mach_header = extern struct {11pub const mach_header = extern struct {
4 magic: u32,12 magic: u32,
...@@ -770,7 +778,7 @@ pub const section_64 = extern struct {...@@ -770,7 +778,7 @@ pub const section_64 = extern struct {
770};778};
771779
772fn parseName(name: *const [16]u8) []const u8 {780fn 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 return name[0..len];782 return name[0..len];
775}783}
776784
...@@ -1804,3 +1812,428 @@ pub const data_in_code_entry = extern struct {...@@ -1804,3 +1812,428 @@ pub const data_in_code_entry = extern struct {
1804 /// A DICE_KIND value.1812 /// A DICE_KIND value.
1805 kind: u16,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.
1818pub 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.
1984pub 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
2027pub 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.
2032pub 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
2067pub 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
2098fn 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
2105fn 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
2111fn 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
2118test "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
2176test "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
2218test "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,7 +15,6 @@ const meta = std.meta;
15const aarch64 = @import("../arch/aarch64/bits.zig");15const aarch64 = @import("../arch/aarch64/bits.zig");
16const bind = @import("MachO/bind.zig");16const bind = @import("MachO/bind.zig");
17const codegen = @import("../codegen.zig");17const codegen = @import("../codegen.zig");
18const commands = @import("MachO/commands.zig");
19const link = @import("../link.zig");18const link = @import("../link.zig");
20const llvm_backend = @import("../codegen/llvm.zig");19const llvm_backend = @import("../codegen/llvm.zig");
21const target_util = @import("../target.zig");20const target_util = @import("../target.zig");
...@@ -35,9 +34,7 @@ const Object = @import("MachO/Object.zig");...@@ -35,9 +34,7 @@ const Object = @import("MachO/Object.zig");
35const LibStub = @import("tapi.zig").LibStub;34const LibStub = @import("tapi.zig").LibStub;
36const Liveness = @import("../Liveness.zig");35const Liveness = @import("../Liveness.zig");
37const LlvmObject = @import("../codegen/llvm.zig").Object;36const LlvmObject = @import("../codegen/llvm.zig").Object;
38const LoadCommand = commands.LoadCommand;
39const Module = @import("../Module.zig");37const Module = @import("../Module.zig");
40const SegmentCommand = commands.SegmentCommand;
41const StringIndexAdapter = std.hash_map.StringIndexAdapter;38const StringIndexAdapter = std.hash_map.StringIndexAdapter;
42const StringIndexContext = std.hash_map.StringIndexContext;39const StringIndexContext = std.hash_map.StringIndexContext;
43const Trie = @import("MachO/Trie.zig");40const Trie = @import("MachO/Trie.zig");
...@@ -83,7 +80,7 @@ dylibs: std.ArrayListUnmanaged(Dylib) = .{},...@@ -83,7 +80,7 @@ dylibs: std.ArrayListUnmanaged(Dylib) = .{},
83dylibs_map: std.StringHashMapUnmanaged(u16) = .{},80dylibs_map: std.StringHashMapUnmanaged(u16) = .{},
84referenced_dylibs: std.AutoArrayHashMapUnmanaged(u16, void) = .{},81referenced_dylibs: std.AutoArrayHashMapUnmanaged(u16, void) = .{},
8582
86load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},83load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
8784
88pagezero_segment_cmd_index: ?u16 = null,85pagezero_segment_cmd_index: ?u16 = null,
89text_segment_cmd_index: ?u16 = null,86text_segment_cmd_index: ?u16 = null,
...@@ -783,7 +780,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -783,7 +780,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
783 @sizeOf(macho.rpath_command) + rpath.len + 1,780 @sizeOf(macho.rpath_command) + rpath.len + 1,
784 @sizeOf(u64),781 @sizeOf(u64),
785 ));782 ));
786 var rpath_cmd = commands.emptyGenericCommandWithData(macho.rpath_command{783 var rpath_cmd = macho.emptyGenericCommandWithData(macho.rpath_command{
787 .cmd = macho.LC_RPATH,784 .cmd = macho.LC_RPATH,
788 .cmdsize = cmdsize,785 .cmdsize = cmdsize,
789 .path = @sizeOf(macho.rpath_command),786 .path = @sizeOf(macho.rpath_command),
...@@ -791,7 +788,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -791,7 +788,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
791 rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path);788 rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path);
792 mem.set(u8, rpath_cmd.data, 0);789 mem.set(u8, rpath_cmd.data, 0);
793 mem.copy(u8, rpath_cmd.data, rpath);790 mem.copy(u8, rpath_cmd.data, rpath);
794 try self.load_commands.append(self.base.allocator, .{ .Rpath = rpath_cmd });791 try self.load_commands.append(self.base.allocator, .{ .rpath = rpath_cmd });
795 try rpath_table.putNoClobber(rpath, {});792 try rpath_table.putNoClobber(rpath, {});
796 self.load_commands_dirty = true;793 self.load_commands_dirty = true;
797 }794 }
...@@ -861,12 +858,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -861,12 +858,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
861 }858 }
862859
863 if (self.bss_section_index) |idx| {860 if (self.bss_section_index) |idx| {
864 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;861 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
865 const sect = &seg.sections.items[idx];862 const sect = &seg.sections.items[idx];
866 sect.offset = self.bss_file_offset;863 sect.offset = self.bss_file_offset;
867 }864 }
868 if (self.tlv_bss_section_index) |idx| {865 if (self.tlv_bss_section_index) |idx| {
869 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;866 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
870 const sect = &seg.sections.items[idx];867 const sect = &seg.sections.items[idx];
871 sect.offset = self.tlv_bss_file_offset;868 sect.offset = self.tlv_bss_file_offset;
872 }869 }
...@@ -942,13 +939,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -942,13 +939,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
942 }939 }
943940
944 if (self.bss_section_index) |idx| {941 if (self.bss_section_index) |idx| {
945 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;942 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
946 const sect = &seg.sections.items[idx];943 const sect = &seg.sections.items[idx];
947 self.bss_file_offset = sect.offset;944 self.bss_file_offset = sect.offset;
948 sect.offset = 0;945 sect.offset = 0;
949 }946 }
950 if (self.tlv_bss_section_index) |idx| {947 if (self.tlv_bss_section_index) |idx| {
951 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;948 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
952 const sect = &seg.sections.items[idx];949 const sect = &seg.sections.items[idx];
953 self.tlv_bss_file_offset = sect.offset;950 self.tlv_bss_file_offset = sect.offset;
954 sect.offset = 0;951 sect.offset = 0;
...@@ -1865,7 +1862,7 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment:...@@ -1865,7 +1862,7 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment:
1865}1862}
18661863
1867pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {1864pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {
1868 const seg = self.load_commands.items[match.seg].Segment;1865 const seg = self.load_commands.items[match.seg].segment;
1869 const sect = seg.sections.items[match.sect];1866 const sect = seg.sections.items[match.sect];
1870 const sym = self.locals.items[atom.local_sym_index];1867 const sym = self.locals.items[atom.local_sym_index];
1871 const file_offset = sect.offset + sym.n_value - sect.addr;1868 const file_offset = sect.offset + sym.n_value - sect.addr;
...@@ -1885,7 +1882,7 @@ fn allocateLocals(self: *MachO) !void {...@@ -1885,7 +1882,7 @@ fn allocateLocals(self: *MachO) !void {
1885 }1882 }
18861883
1887 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);1884 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1888 const seg = self.load_commands.items[match.seg].Segment;1885 const seg = self.load_commands.items[match.seg].segment;
1889 const sect = seg.sections.items[match.sect];1886 const sect = seg.sections.items[match.sect];
1890 var base_vaddr = sect.addr;1887 var base_vaddr = sect.addr;
18911888
...@@ -1976,7 +1973,7 @@ fn writeAllAtoms(self: *MachO) !void {...@@ -1976,7 +1973,7 @@ fn writeAllAtoms(self: *MachO) !void {
1976 var it = self.atoms.iterator();1973 var it = self.atoms.iterator();
1977 while (it.next()) |entry| {1974 while (it.next()) |entry| {
1978 const match = entry.key_ptr.*;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 const sect = seg.sections.items[match.sect];1977 const sect = seg.sections.items[match.sect];
1981 var atom: *Atom = entry.value_ptr.*;1978 var atom: *Atom = entry.value_ptr.*;
19821979
...@@ -2028,7 +2025,7 @@ fn writeAtoms(self: *MachO) !void {...@@ -2028,7 +2025,7 @@ fn writeAtoms(self: *MachO) !void {
2028 var it = self.atoms.iterator();2025 var it = self.atoms.iterator();
2029 while (it.next()) |entry| {2026 while (it.next()) |entry| {
2030 const match = entry.key_ptr.*;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 const sect = seg.sections.items[match.sect];2029 const sect = seg.sections.items[match.sect];
2033 var atom: *Atom = entry.value_ptr.*;2030 var atom: *Atom = entry.value_ptr.*;
20342031
...@@ -2992,7 +2989,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {...@@ -2992,7 +2989,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
29922989
2993 const first_atom = atom;2990 const first_atom = atom;
29942991
2995 const seg = self.load_commands.items[match.seg].Segment;2992 const seg = self.load_commands.items[match.seg].segment;
2996 const sect = seg.sections.items[match.sect];2993 const sect = seg.sections.items[match.sect];
2997 const metadata = try section_metadata.getOrPut(match);2994 const metadata = try section_metadata.getOrPut(match);
2998 if (!metadata.found_existing) {2995 if (!metadata.found_existing) {
...@@ -3043,7 +3040,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {...@@ -3043,7 +3040,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
3043 while (it.next()) |entry| {3040 while (it.next()) |entry| {
3044 const match = entry.key_ptr.*;3041 const match = entry.key_ptr.*;
3045 const metadata = entry.value_ptr.*;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 const sect = &seg.sections.items[match.sect];3044 const sect = &seg.sections.items[match.sect];
3048 log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{3045 log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{
3049 sect.segName(),3046 sect.segName(),
...@@ -3067,7 +3064,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {...@@ -3067,7 +3064,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
3067 self.data_segment_cmd_index,3064 self.data_segment_cmd_index,
3068 }) |maybe_seg_id| {3065 }) |maybe_seg_id| {
3069 const seg_id = maybe_seg_id orelse continue;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;
30713068
3072 for (seg.sections.items) |sect, sect_id| {3069 for (seg.sections.items) |sect, sect_id| {
3073 const match = MatchingSection{3070 const match = MatchingSection{
...@@ -3137,7 +3134,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {...@@ -3137,7 +3134,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
3137fn addLoadDylibLC(self: *MachO, id: u16) !void {3134fn addLoadDylibLC(self: *MachO, id: u16) !void {
3138 const dylib = self.dylibs.items[id];3135 const dylib = self.dylibs.items[id];
3139 const dylib_id = dylib.id orelse unreachable;3136 const dylib_id = dylib.id orelse unreachable;
3140 var dylib_cmd = try commands.createLoadDylibCommand(3137 var dylib_cmd = try macho.createLoadDylibCommand(
3141 self.base.allocator,3138 self.base.allocator,
3142 dylib_id.name,3139 dylib_id.name,
3143 dylib_id.timestamp,3140 dylib_id.timestamp,
...@@ -3145,7 +3142,7 @@ fn addLoadDylibLC(self: *MachO, id: u16) !void {...@@ -3145,7 +3142,7 @@ fn addLoadDylibLC(self: *MachO, id: u16) !void {
3145 dylib_id.compatibility_version,3142 dylib_id.compatibility_version,
3146 );3143 );
3147 errdefer dylib_cmd.deinit(self.base.allocator);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 self.load_commands_dirty = true;3146 self.load_commands_dirty = true;
3150}3147}
31513148
...@@ -3153,7 +3150,7 @@ fn addCodeSignatureLC(self: *MachO) !void {...@@ -3153,7 +3150,7 @@ fn addCodeSignatureLC(self: *MachO) !void {
3153 if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return;3150 if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return;
3154 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);3151 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
3155 try self.load_commands.append(self.base.allocator, .{3152 try self.load_commands.append(self.base.allocator, .{
3156 .LinkeditData = .{3153 .linkedit_data = .{
3157 .cmd = macho.LC_CODE_SIGNATURE,3154 .cmd = macho.LC_CODE_SIGNATURE,
3158 .cmdsize = @sizeOf(macho.linkedit_data_command),3155 .cmdsize = @sizeOf(macho.linkedit_data_command),
3159 .dataoff = 0,3156 .dataoff = 0,
...@@ -3168,7 +3165,7 @@ fn setEntryPoint(self: *MachO) !void {...@@ -3168,7 +3165,7 @@ fn setEntryPoint(self: *MachO) !void {
31683165
3169 // TODO we should respect the -entry flag passed in by the user to set a custom3166 // TODO we should respect the -entry flag passed in by the user to set a custom
3170 // entrypoint. For now, assume default of `_main`.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 const n_strx = self.strtab_dir.getKeyAdapted(@as([]const u8, "_main"), StringIndexAdapter{3169 const n_strx = self.strtab_dir.getKeyAdapted(@as([]const u8, "_main"), StringIndexAdapter{
3173 .bytes = &self.strtab,3170 .bytes = &self.strtab,
3174 }) orelse {3171 }) orelse {
...@@ -3178,7 +3175,7 @@ fn setEntryPoint(self: *MachO) !void {...@@ -3178,7 +3175,7 @@ fn setEntryPoint(self: *MachO) !void {
3178 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;3175 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
3179 assert(resolv.where == .global);3176 assert(resolv.where == .global);
3180 const sym = self.globals.items[resolv.where_index];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 ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr);3179 ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr);
3183 ec.stacksize = self.base.options.stack_size_override orelse 0;3180 ec.stacksize = self.base.options.stack_size_override orelse 0;
3184 self.entry_addr = sym.n_value;3181 self.entry_addr = sym.n_value;
...@@ -3875,7 +3872,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -3875,7 +3872,7 @@ fn populateMissingMetadata(self: *MachO) !void {
3875 if (self.pagezero_segment_cmd_index == null) {3872 if (self.pagezero_segment_cmd_index == null) {
3876 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);3873 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3877 try self.load_commands.append(self.base.allocator, .{3874 try self.load_commands.append(self.base.allocator, .{
3878 .Segment = .{3875 .segment = .{
3879 .inner = .{3876 .inner = .{
3880 .segname = makeStaticString("__PAGEZERO"),3877 .segname = makeStaticString("__PAGEZERO"),
3881 .vmsize = pagezero_vmsize,3878 .vmsize = pagezero_vmsize,
...@@ -3896,7 +3893,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -3896,7 +3893,7 @@ fn populateMissingMetadata(self: *MachO) !void {
3896 break :blk needed_size;3893 break :blk needed_size;
3897 } else 0;3894 } else 0;
3898 try self.load_commands.append(self.base.allocator, .{3895 try self.load_commands.append(self.base.allocator, .{
3899 .Segment = .{3896 .segment = .{
3900 .inner = .{3897 .inner = .{
3901 .segname = makeStaticString("__TEXT"),3898 .segname = makeStaticString("__TEXT"),
3902 .vmaddr = pagezero_vmsize,3899 .vmaddr = pagezero_vmsize,
...@@ -4000,7 +3997,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4000,7 +3997,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4000 });3997 });
4001 }3998 }
4002 try self.load_commands.append(self.base.allocator, .{3999 try self.load_commands.append(self.base.allocator, .{
4003 .Segment = .{4000 .segment = .{
4004 .inner = .{4001 .inner = .{
4005 .segname = makeStaticString("__DATA_CONST"),4002 .segname = makeStaticString("__DATA_CONST"),
4006 .vmaddr = vmaddr,4003 .vmaddr = vmaddr,
...@@ -4049,7 +4046,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4049,7 +4046,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4049 });4046 });
4050 }4047 }
4051 try self.load_commands.append(self.base.allocator, .{4048 try self.load_commands.append(self.base.allocator, .{
4052 .Segment = .{4049 .segment = .{
4053 .inner = .{4050 .inner = .{
4054 .segname = makeStaticString("__DATA"),4051 .segname = makeStaticString("__DATA"),
4055 .vmaddr = vmaddr,4052 .vmaddr = vmaddr,
...@@ -4133,7 +4130,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4133,7 +4130,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4133 .flags = macho.S_THREAD_LOCAL_ZEROFILL,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 const sect = seg.sections.items[self.tlv_bss_section_index.?];4134 const sect = seg.sections.items[self.tlv_bss_section_index.?];
4138 self.tlv_bss_file_offset = sect.offset;4135 self.tlv_bss_file_offset = sect.offset;
4139 }4136 }
...@@ -4150,7 +4147,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4150,7 +4147,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4150 .flags = macho.S_ZEROFILL,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 const sect = seg.sections.items[self.bss_section_index.?];4151 const sect = seg.sections.items[self.bss_section_index.?];
4155 self.bss_file_offset = sect.offset;4152 self.bss_file_offset = sect.offset;
4156 }4153 }
...@@ -4166,7 +4163,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4166,7 +4163,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4166 log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});4163 log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});
4167 }4164 }
4168 try self.load_commands.append(self.base.allocator, .{4165 try self.load_commands.append(self.base.allocator, .{
4169 .Segment = .{4166 .segment = .{
4170 .inner = .{4167 .inner = .{
4171 .segname = makeStaticString("__LINKEDIT"),4168 .segname = makeStaticString("__LINKEDIT"),
4172 .vmaddr = vmaddr,4169 .vmaddr = vmaddr,
...@@ -4182,7 +4179,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4182,7 +4179,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4182 if (self.dyld_info_cmd_index == null) {4179 if (self.dyld_info_cmd_index == null) {
4183 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);4180 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
4184 try self.load_commands.append(self.base.allocator, .{4181 try self.load_commands.append(self.base.allocator, .{
4185 .DyldInfoOnly = .{4182 .dyld_info_only = .{
4186 .cmd = macho.LC_DYLD_INFO_ONLY,4183 .cmd = macho.LC_DYLD_INFO_ONLY,
4187 .cmdsize = @sizeOf(macho.dyld_info_command),4184 .cmdsize = @sizeOf(macho.dyld_info_command),
4188 .rebase_off = 0,4185 .rebase_off = 0,
...@@ -4203,7 +4200,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4203,7 +4200,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4203 if (self.symtab_cmd_index == null) {4200 if (self.symtab_cmd_index == null) {
4204 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);4201 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
4205 try self.load_commands.append(self.base.allocator, .{4202 try self.load_commands.append(self.base.allocator, .{
4206 .Symtab = .{4203 .symtab = .{
4207 .cmd = macho.LC_SYMTAB,4204 .cmd = macho.LC_SYMTAB,
4208 .cmdsize = @sizeOf(macho.symtab_command),4205 .cmdsize = @sizeOf(macho.symtab_command),
4209 .symoff = 0,4206 .symoff = 0,
...@@ -4218,7 +4215,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4218,7 +4215,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4218 if (self.dysymtab_cmd_index == null) {4215 if (self.dysymtab_cmd_index == null) {
4219 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);4216 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
4220 try self.load_commands.append(self.base.allocator, .{4217 try self.load_commands.append(self.base.allocator, .{
4221 .Dysymtab = .{4218 .dysymtab = .{
4222 .cmd = macho.LC_DYSYMTAB,4219 .cmd = macho.LC_DYSYMTAB,
4223 .cmdsize = @sizeOf(macho.dysymtab_command),4220 .cmdsize = @sizeOf(macho.dysymtab_command),
4224 .ilocalsym = 0,4221 .ilocalsym = 0,
...@@ -4251,7 +4248,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4251,7 +4248,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4251 @sizeOf(macho.dylinker_command) + mem.sliceTo(default_dyld_path, 0).len,4248 @sizeOf(macho.dylinker_command) + mem.sliceTo(default_dyld_path, 0).len,
4252 @sizeOf(u64),4249 @sizeOf(u64),
4253 ));4250 ));
4254 var dylinker_cmd = commands.emptyGenericCommandWithData(macho.dylinker_command{4251 var dylinker_cmd = macho.emptyGenericCommandWithData(macho.dylinker_command{
4255 .cmd = macho.LC_LOAD_DYLINKER,4252 .cmd = macho.LC_LOAD_DYLINKER,
4256 .cmdsize = cmdsize,4253 .cmdsize = cmdsize,
4257 .name = @sizeOf(macho.dylinker_command),4254 .name = @sizeOf(macho.dylinker_command),
...@@ -4259,14 +4256,14 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4259,14 +4256,14 @@ fn populateMissingMetadata(self: *MachO) !void {
4259 dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name);4256 dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name);
4260 mem.set(u8, dylinker_cmd.data, 0);4257 mem.set(u8, dylinker_cmd.data, 0);
4261 mem.copy(u8, dylinker_cmd.data, mem.sliceTo(default_dyld_path, 0));4258 mem.copy(u8, dylinker_cmd.data, mem.sliceTo(default_dyld_path, 0));
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 self.load_commands_dirty = true;4260 self.load_commands_dirty = true;
4264 }4261 }
42654262
4266 if (self.main_cmd_index == null and self.base.options.output_mode == .Exe) {4263 if (self.main_cmd_index == null and self.base.options.output_mode == .Exe) {
4267 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);4264 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
4268 try self.load_commands.append(self.base.allocator, .{4265 try self.load_commands.append(self.base.allocator, .{
4269 .Main = .{4266 .main = .{
4270 .cmd = macho.LC_MAIN,4267 .cmd = macho.LC_MAIN,
4271 .cmdsize = @sizeOf(macho.entry_point_command),4268 .cmdsize = @sizeOf(macho.entry_point_command),
4272 .entryoff = 0x0,4269 .entryoff = 0x0,
...@@ -4286,7 +4283,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4286,7 +4283,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4286 std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };4283 std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };
4287 const compat_version = self.base.options.compatibility_version orelse4284 const compat_version = self.base.options.compatibility_version orelse
4288 std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };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 self.base.allocator,4287 self.base.allocator,
4291 install_name,4288 install_name,
4292 2,4289 2,
...@@ -4295,14 +4292,14 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4295,14 +4292,14 @@ fn populateMissingMetadata(self: *MachO) !void {
4295 );4292 );
4296 errdefer dylib_cmd.deinit(self.base.allocator);4293 errdefer dylib_cmd.deinit(self.base.allocator);
4297 dylib_cmd.inner.cmd = macho.LC_ID_DYLIB;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 self.load_commands_dirty = true;4296 self.load_commands_dirty = true;
4300 }4297 }
43014298
4302 if (self.source_version_cmd_index == null) {4299 if (self.source_version_cmd_index == null) {
4303 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);4300 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
4304 try self.load_commands.append(self.base.allocator, .{4301 try self.load_commands.append(self.base.allocator, .{
4305 .SourceVersion = .{4302 .source_version = .{
4306 .cmd = macho.LC_SOURCE_VERSION,4303 .cmd = macho.LC_SOURCE_VERSION,
4307 .cmdsize = @sizeOf(macho.source_version_command),4304 .cmdsize = @sizeOf(macho.source_version_command),
4308 .version = 0x0,4305 .version = 0x0,
...@@ -4329,7 +4326,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4329,7 +4326,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4329 break :blk sdk_version;4326 break :blk sdk_version;
4330 } else platform_version;4327 } else platform_version;
4331 const is_simulator_abi = self.base.options.target.abi == .simulator;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 .cmd = macho.LC_BUILD_VERSION,4330 .cmd = macho.LC_BUILD_VERSION,
4334 .cmdsize = cmdsize,4331 .cmdsize = cmdsize,
4335 .platform = switch (self.base.options.target.os.tag) {4332 .platform = switch (self.base.options.target.os.tag) {
...@@ -4350,7 +4347,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4350,7 +4347,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4350 cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command));4347 cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command));
4351 mem.set(u8, cmd.data, 0);4348 mem.set(u8, cmd.data, 0);
4352 mem.copy(u8, cmd.data, mem.asBytes(&ld_ver));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 self.load_commands_dirty = true;4351 self.load_commands_dirty = true;
4355 }4352 }
43564353
...@@ -4362,14 +4359,14 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4362,14 +4359,14 @@ fn populateMissingMetadata(self: *MachO) !void {
4362 .uuid = undefined,4359 .uuid = undefined,
4363 };4360 };
4364 std.crypto.random.bytes(&uuid_cmd.uuid);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 self.load_commands_dirty = true;4363 self.load_commands_dirty = true;
4367 }4364 }
43684365
4369 if (self.function_starts_cmd_index == null) {4366 if (self.function_starts_cmd_index == null) {
4370 self.function_starts_cmd_index = @intCast(u16, self.load_commands.items.len);4367 self.function_starts_cmd_index = @intCast(u16, self.load_commands.items.len);
4371 try self.load_commands.append(self.base.allocator, .{4368 try self.load_commands.append(self.base.allocator, .{
4372 .LinkeditData = .{4369 .linkedit_data = .{
4373 .cmd = macho.LC_FUNCTION_STARTS,4370 .cmd = macho.LC_FUNCTION_STARTS,
4374 .cmdsize = @sizeOf(macho.linkedit_data_command),4371 .cmdsize = @sizeOf(macho.linkedit_data_command),
4375 .dataoff = 0,4372 .dataoff = 0,
...@@ -4382,7 +4379,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4382,7 +4379,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4382 if (self.data_in_code_cmd_index == null) {4379 if (self.data_in_code_cmd_index == null) {
4383 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);4380 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
4384 try self.load_commands.append(self.base.allocator, .{4381 try self.load_commands.append(self.base.allocator, .{
4385 .LinkeditData = .{4382 .linkedit_data = .{
4386 .cmd = macho.LC_DATA_IN_CODE,4383 .cmd = macho.LC_DATA_IN_CODE,
4387 .cmdsize = @sizeOf(macho.linkedit_data_command),4384 .cmdsize = @sizeOf(macho.linkedit_data_command),
4388 .dataoff = 0,4385 .dataoff = 0,
...@@ -4396,8 +4393,8 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4396,8 +4393,8 @@ fn populateMissingMetadata(self: *MachO) !void {
4396}4393}
43974394
4398fn allocateTextSegment(self: *MachO) !void {4395fn allocateTextSegment(self: *MachO) !void {
4399 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;4396 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment;
4400 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;4397 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].segment.inner.vmsize;
4401 seg.inner.fileoff = 0;4398 seg.inner.fileoff = 0;
4402 seg.inner.vmaddr = base_vmaddr;4399 seg.inner.vmaddr = base_vmaddr;
44034400
...@@ -4433,30 +4430,30 @@ fn allocateTextSegment(self: *MachO) !void {...@@ -4433,30 +4430,30 @@ fn allocateTextSegment(self: *MachO) !void {
4433}4430}
44344431
4435fn allocateDataConstSegment(self: *MachO) !void {4432fn allocateDataConstSegment(self: *MachO) !void {
4436 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;4433 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
4437 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;4434 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;
4438 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;4435 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
4439 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;4436 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
4440 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);4437 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
4441}4438}
44424439
4443fn allocateDataSegment(self: *MachO) !void {4440fn allocateDataSegment(self: *MachO) !void {
4444 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;4441 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
4445 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;4442 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
4446 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;4443 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
4447 seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;4444 seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;
4448 try self.allocateSegment(self.data_segment_cmd_index.?, 0);4445 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
4449}4446}
44504447
4451fn allocateLinkeditSegment(self: *MachO) void {4448fn allocateLinkeditSegment(self: *MachO) void {
4452 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;4449 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
4453 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;4450 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;
4454 seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;4451 seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;
4455 seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;4452 seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;
4456}4453}
44574454
4458fn allocateSegment(self: *MachO, index: u16, offset: u64) !void {4455fn 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;
44604457
4461 // Allocate the sections according to their alignment at the beginning of the segment.4458 // Allocate the sections according to their alignment at the beginning of the segment.
4462 var start: u64 = offset;4459 var start: u64 = offset;
...@@ -4488,7 +4485,7 @@ fn initSection(...@@ -4488,7 +4485,7 @@ fn initSection(
4488 alignment: u32,4485 alignment: u32,
4489 opts: InitSectionOpts,4486 opts: InitSectionOpts,
4490) !u16 {4487) !u16 {
4491 const seg = &self.load_commands.items[segment_id].Segment;4488 const seg = &self.load_commands.items[segment_id].segment;
4492 var sect = macho.section_64{4489 var sect = macho.section_64{
4493 .sectname = makeStaticString(sectname),4490 .sectname = makeStaticString(sectname),
4494 .segname = seg.inner.segname,4491 .segname = seg.inner.segname,
...@@ -4532,7 +4529,7 @@ fn initSection(...@@ -4532,7 +4529,7 @@ fn initSection(
4532}4529}
45334530
4534fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64 {4531fn 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 if (seg.sections.items.len == 0) {4533 if (seg.sections.items.len == 0) {
4537 return if (start) |v| v else seg.inner.fileoff;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,7 +4539,7 @@ fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64
4542}4539}
45434540
4544fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {4541fn 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 const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);4543 const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);
4547 assert(new_seg_size > seg.inner.filesize);4544 assert(new_seg_size > seg.inner.filesize);
4548 const offset_amt = new_seg_size - seg.inner.filesize;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,13 +4561,13 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
4564 // TODO We should probably nop the expanded by distance, or put 0s.4561 // TODO We should probably nop the expanded by distance, or put 0s.
45654562
4566 // TODO copyRangeAll doesn't automatically extend the file on macOS.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 const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize;4565 const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize;
4569 try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1);4566 try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1);
45704567
4571 var next: usize = seg_id + 1;4568 var next: usize = seg_id + 1;
4572 while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) {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 _ = try self.base.file.?.copyRangeAll(4571 _ = try self.base.file.?.copyRangeAll(
4575 next_seg.inner.fileoff,4572 next_seg.inner.fileoff,
4576 self.base.file.?,4573 self.base.file.?,
...@@ -4613,7 +4610,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {...@@ -4613,7 +4610,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
4613 const tracy = trace(@src());4610 const tracy = trace(@src());
4614 defer tracy.end();4611 defer tracy.end();
46154612
4616 const seg = &self.load_commands.items[match.seg].Segment;4613 const seg = &self.load_commands.items[match.seg].segment;
4617 const sect = &seg.sections.items[match.sect];4614 const sect = &seg.sections.items[match.sect];
46184615
4619 const alignment = try math.powi(u32, 2, sect.@"align");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,7 +4681,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
4684}4681}
46854682
4686fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 {4683fn 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 assert(start >= seg.inner.fileoff);4685 assert(start >= seg.inner.fileoff);
4689 var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize;4686 var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize;
4690 if (start > min_pos) return 0;4687 if (start > min_pos) return 0;
...@@ -4696,7 +4693,7 @@ fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 {...@@ -4696,7 +4693,7 @@ fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 {
4696}4693}
46974694
4698fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u32 {4695fn 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 var max_alignment: u32 = 1;4697 var max_alignment: u32 = 1;
4701 var next = start_sect_id;4698 var next = start_sect_id;
4702 while (next < seg.sections.items.len) : (next += 1) {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,7 +4708,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
4711 const tracy = trace(@src());4708 const tracy = trace(@src());
4712 defer tracy.end();4709 defer tracy.end();
47134710
4714 const seg = &self.load_commands.items[match.seg].Segment;4711 const seg = &self.load_commands.items[match.seg].segment;
4715 const sect = &seg.sections.items[match.sect];4712 const sect = &seg.sections.items[match.sect];
4716 var free_list = self.atom_free_lists.get(match).?;4713 var free_list = self.atom_free_lists.get(match).?;
4717 const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;4714 const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;
...@@ -4815,7 +4812,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m...@@ -4815,7 +4812,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
4815}4812}
48164813
4817fn addAtomAndBumpSectionSize(self: *MachO, atom: *Atom, match: MatchingSection) !void {4814fn 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 const sect = &seg.sections.items[match.sect];4816 const sect = &seg.sections.items[match.sect];
4820 const alignment = try math.powi(u32, 2, atom.alignment);4817 const alignment = try math.powi(u32, 2, atom.alignment);
4821 sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size;4818 sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size;
...@@ -4862,11 +4859,11 @@ const NextSegmentAddressAndOffset = struct {...@@ -4862,11 +4859,11 @@ const NextSegmentAddressAndOffset = struct {
4862fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {4859fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
4863 var prev_segment_idx: ?usize = null; // We use optional here for safety.4860 var prev_segment_idx: ?usize = null; // We use optional here for safety.
4864 for (self.load_commands.items) |cmd, i| {4861 for (self.load_commands.items) |cmd, i| {
4865 if (cmd == .Segment) {4862 if (cmd == .segment) {
4866 prev_segment_idx = i;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 const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize;4867 const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize;
4871 const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize;4868 const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize;
4872 return .{4869 return .{
...@@ -4885,7 +4882,7 @@ fn sortSections(self: *MachO) !void {...@@ -4885,7 +4882,7 @@ fn sortSections(self: *MachO) !void {
48854882
4886 {4883 {
4887 // __TEXT segment4884 // __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 var sections = seg.sections.toOwnedSlice(self.base.allocator);4886 var sections = seg.sections.toOwnedSlice(self.base.allocator);
4890 defer self.base.allocator.free(sections);4887 defer self.base.allocator.free(sections);
4891 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);4888 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
...@@ -4917,7 +4914,7 @@ fn sortSections(self: *MachO) !void {...@@ -4917,7 +4914,7 @@ fn sortSections(self: *MachO) !void {
49174914
4918 {4915 {
4919 // __DATA_CONST segment4916 // __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 var sections = seg.sections.toOwnedSlice(self.base.allocator);4918 var sections = seg.sections.toOwnedSlice(self.base.allocator);
4922 defer self.base.allocator.free(sections);4919 defer self.base.allocator.free(sections);
4923 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);4920 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
...@@ -4944,7 +4941,7 @@ fn sortSections(self: *MachO) !void {...@@ -4944,7 +4941,7 @@ fn sortSections(self: *MachO) !void {
49444941
4945 {4942 {
4946 // __DATA segment4943 // __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 var sections = seg.sections.toOwnedSlice(self.base.allocator);4945 var sections = seg.sections.toOwnedSlice(self.base.allocator);
4949 defer self.base.allocator.free(sections);4946 defer self.base.allocator.free(sections);
4950 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);4947 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
...@@ -5000,7 +4997,7 @@ fn sortSections(self: *MachO) !void {...@@ -5000,7 +4997,7 @@ fn sortSections(self: *MachO) !void {
5000 {4997 {
5001 // Create new section ordinals.4998 // Create new section ordinals.
5002 self.section_ordinals.clearRetainingCapacity();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 for (text_seg.sections.items) |_, sect_id| {5001 for (text_seg.sections.items) |_, sect_id| {
5005 const res = self.section_ordinals.getOrPutAssumeCapacity(.{5002 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
5006 .seg = self.text_segment_cmd_index.?,5003 .seg = self.text_segment_cmd_index.?,
...@@ -5008,7 +5005,7 @@ fn sortSections(self: *MachO) !void {...@@ -5008,7 +5005,7 @@ fn sortSections(self: *MachO) !void {
5008 });5005 });
5009 assert(!res.found_existing);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 for (data_const_seg.sections.items) |_, sect_id| {5009 for (data_const_seg.sections.items) |_, sect_id| {
5013 const res = self.section_ordinals.getOrPutAssumeCapacity(.{5010 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
5014 .seg = self.data_const_segment_cmd_index.?,5011 .seg = self.data_const_segment_cmd_index.?,
...@@ -5016,7 +5013,7 @@ fn sortSections(self: *MachO) !void {...@@ -5016,7 +5013,7 @@ fn sortSections(self: *MachO) !void {
5016 });5013 });
5017 assert(!res.found_existing);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 for (data_seg.sections.items) |_, sect_id| {5017 for (data_seg.sections.items) |_, sect_id| {
5021 const res = self.section_ordinals.getOrPutAssumeCapacity(.{5018 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
5022 .seg = self.data_segment_cmd_index.?,5019 .seg = self.data_segment_cmd_index.?,
...@@ -5041,9 +5038,9 @@ fn updateSectionOrdinals(self: *MachO) !void {...@@ -5041,9 +5038,9 @@ fn updateSectionOrdinals(self: *MachO) !void {
50415038
5042 var new_ordinal: u8 = 0;5039 var new_ordinal: u8 = 0;
5043 for (self.load_commands.items) |lc, lc_id| {5040 for (self.load_commands.items) |lc, lc_id| {
5044 if (lc != .Segment) break;5041 if (lc != .segment) break;
50455042
5046 for (lc.Segment.sections.items) |_, sect_id| {5043 for (lc.segment.sections.items) |_, sect_id| {
5047 const match = MatchingSection{5044 const match = MatchingSection{
5048 .seg = @intCast(u16, lc_id),5045 .seg = @intCast(u16, lc_id),
5049 .sect = @intCast(u16, sect_id),5046 .sect = @intCast(u16, sect_id),
...@@ -5086,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5086,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO) !void {
50865083
5087 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable5084 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
50885085
5089 const seg = self.load_commands.items[match.seg].Segment;5086 const seg = self.load_commands.items[match.seg].segment;
50905087
5091 while (true) {5088 while (true) {
5092 const sym = self.locals.items[atom.local_sym_index];5089 const sym = self.locals.items[atom.local_sym_index];
...@@ -5156,7 +5153,7 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5156,7 +5153,7 @@ fn writeDyldInfoData(self: *MachO) !void {
5156 {5153 {
5157 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.5154 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
5158 log.debug("generating export trie", .{});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 const base_address = text_segment.inner.vmaddr;5157 const base_address = text_segment.inner.vmaddr;
51615158
5162 for (self.globals.items) |sym| {5159 for (self.globals.items) |sym| {
...@@ -5174,8 +5171,8 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5174,8 +5171,8 @@ fn writeDyldInfoData(self: *MachO) !void {
5174 try trie.finalize(self.base.allocator);5171 try trie.finalize(self.base.allocator);
5175 }5172 }
51765173
5177 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;5174 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5178 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;5175 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].dyld_info_only;
5179 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);5176 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
5180 const bind_size = try bind.bindInfoSize(bind_pointers.items);5177 const bind_size = try bind.bindInfoSize(bind_pointers.items);
5181 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);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,7 +5242,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
5245 .sect = self.la_symbol_ptr_section_index.?,5242 .sect = self.la_symbol_ptr_section_index.?,
5246 }).?;5243 }).?;
5247 const base_addr = blk: {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 break :blk seg.inner.vmaddr;5246 break :blk seg.inner.vmaddr;
5250 };5247 };
52515248
...@@ -5309,7 +5306,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -5309,7 +5306,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
5309 }5306 }
53105307
5311 const sect = blk: {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 break :blk seg.sections.items[self.stub_helper_section_index.?];5310 break :blk seg.sections.items[self.stub_helper_section_index.?];
5314 };5311 };
5315 const stub_offset: u4 = switch (self.base.options.target.cpu.arch) {5312 const stub_offset: u4 = switch (self.base.options.target.cpu.arch) {
...@@ -5350,7 +5347,7 @@ fn writeFunctionStarts(self: *MachO) !void {...@@ -5350,7 +5347,7 @@ fn writeFunctionStarts(self: *MachO) !void {
5350 var offsets = std.ArrayList(u32).init(self.base.allocator);5347 var offsets = std.ArrayList(u32).init(self.base.allocator);
5351 defer offsets.deinit();5348 defer offsets.deinit();
53525349
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 var last_off: u32 = 0;5351 var last_off: u32 = 0;
53555352
5356 while (true) {5353 while (true) {
...@@ -5407,8 +5404,8 @@ fn writeFunctionStarts(self: *MachO) !void {...@@ -5407,8 +5404,8 @@ fn writeFunctionStarts(self: *MachO) !void {
5407 }5404 }
54085405
5409 const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64)));5406 const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64)));
5410 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;5407 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5411 const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].LinkeditData;5408 const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].linkedit_data;
54125409
5413 fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);5410 fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
5414 fn_cmd.datasize = needed_size;5411 fn_cmd.datasize = needed_size;
...@@ -5441,7 +5438,7 @@ fn writeDices(self: *MachO) !void {...@@ -5441,7 +5438,7 @@ fn writeDices(self: *MachO) !void {
5441 atom = prev;5438 atom = prev;
5442 }5439 }
54435440
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 const text_sect = text_seg.sections.items[self.text_section_index.?];5442 const text_sect = text_seg.sections.items[self.text_section_index.?];
54465443
5447 while (true) {5444 while (true) {
...@@ -5465,8 +5462,8 @@ fn writeDices(self: *MachO) !void {...@@ -5465,8 +5462,8 @@ fn writeDices(self: *MachO) !void {
5465 } else break;5462 } else break;
5466 }5463 }
54675464
5468 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;5465 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5469 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;5466 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data;
5470 const needed_size = @intCast(u32, buf.items.len);5467 const needed_size = @intCast(u32, buf.items.len);
54715468
5472 dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);5469 dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
...@@ -5486,8 +5483,8 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -5486,8 +5483,8 @@ fn writeSymbolTable(self: *MachO) !void {
5486 const tracy = trace(@src());5483 const tracy = trace(@src());
5487 defer tracy.end();5484 defer tracy.end();
54885485
5489 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;5486 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5490 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;5487 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
5491 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);5488 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
54925489
5493 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);5490 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
...@@ -5591,18 +5588,18 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -5591,18 +5588,18 @@ fn writeSymbolTable(self: *MachO) !void {
5591 seg.inner.filesize += locals_size + exports_size + undefs_size;5588 seg.inner.filesize += locals_size + exports_size + undefs_size;
55925589
5593 // Update dynamic symbol table.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 dysymtab.nlocalsym = @intCast(u32, nlocals);5592 dysymtab.nlocalsym = @intCast(u32, nlocals);
5596 dysymtab.iextdefsym = dysymtab.nlocalsym;5593 dysymtab.iextdefsym = dysymtab.nlocalsym;
5597 dysymtab.nextdefsym = @intCast(u32, nexports);5594 dysymtab.nextdefsym = @intCast(u32, nexports);
5598 dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;5595 dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;
5599 dysymtab.nundefsym = @intCast(u32, nundefs);5596 dysymtab.nundefsym = @intCast(u32, nundefs);
56005597
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 const stubs = &text_segment.sections.items[self.stubs_section_index.?];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 const got = &data_const_segment.sections.items[self.got_section_index.?];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 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];5603 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
56075604
5608 const nstubs = @intCast(u32, self.stubs_map.keys().len);5605 const nstubs = @intCast(u32, self.stubs_map.keys().len);
...@@ -5665,8 +5662,8 @@ fn writeStringTable(self: *MachO) !void {...@@ -5665,8 +5662,8 @@ fn writeStringTable(self: *MachO) !void {
5665 const tracy = trace(@src());5662 const tracy = trace(@src());
5666 defer tracy.end();5663 defer tracy.end();
56675664
5668 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;5665 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5669 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;5666 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
5670 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);5667 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
5671 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));5668 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
5672 seg.inner.filesize += symtab.strsize;5669 seg.inner.filesize += symtab.strsize;
...@@ -5686,7 +5683,7 @@ fn writeLinkeditSegment(self: *MachO) !void {...@@ -5686,7 +5683,7 @@ fn writeLinkeditSegment(self: *MachO) !void {
5686 const tracy = trace(@src());5683 const tracy = trace(@src());
5687 defer tracy.end();5684 defer tracy.end();
56885685
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 seg.inner.filesize = 0;5687 seg.inner.filesize = 0;
56915688
5692 try self.writeDyldInfoData();5689 try self.writeDyldInfoData();
...@@ -5702,8 +5699,8 @@ fn writeCodeSignaturePadding(self: *MachO) !void {...@@ -5702,8 +5699,8 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
5702 const tracy = trace(@src());5699 const tracy = trace(@src());
5703 defer tracy.end();5700 defer tracy.end();
57045701
5705 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;5702 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5706 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;5703 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
5707 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;5704 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
5708 const needed_size = CodeSignature.calcCodeSignaturePaddingSize(5705 const needed_size = CodeSignature.calcCodeSignaturePaddingSize(
5709 self.base.options.emit.?.sub_path,5706 self.base.options.emit.?.sub_path,
...@@ -5729,8 +5726,8 @@ fn writeCodeSignature(self: *MachO) !void {...@@ -5729,8 +5726,8 @@ fn writeCodeSignature(self: *MachO) !void {
5729 const tracy = trace(@src());5726 const tracy = trace(@src());
5730 defer tracy.end();5727 defer tracy.end();
57315728
5732 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;5729 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;
5733 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;5730 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
57345731
5735 var code_sig: CodeSignature = .{};5732 var code_sig: CodeSignature = .{};
5736 defer code_sig.deinit(self.base.allocator);5733 defer code_sig.deinit(self.base.allocator);
...@@ -5955,7 +5952,7 @@ fn snapshotState(self: *MachO) !void {...@@ -5955,7 +5952,7 @@ fn snapshotState(self: *MachO) !void {
5955 var nodes = std.ArrayList(Snapshot.Node).init(arena);5952 var nodes = std.ArrayList(Snapshot.Node).init(arena);
59565953
5957 for (self.section_ordinals.keys()) |key| {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 const sect = seg.sections.items[key.sect];5956 const sect = seg.sections.items[key.sect];
5960 const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() });5957 const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() });
5961 try nodes.append(.{5958 try nodes.append(.{
...@@ -6028,12 +6025,12 @@ fn snapshotState(self: *MachO) !void {...@@ -6028,12 +6025,12 @@ fn snapshotState(self: *MachO) !void {
6028 const is_tlv = is_tlv: {6025 const is_tlv = is_tlv: {
6029 const source_sym = self.locals.items[atom.local_sym_index];6026 const source_sym = self.locals.items[atom.local_sym_index];
6030 const match = self.section_ordinals.keys()[source_sym.n_sect - 1];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 const match_sect = match_seg.sections.items[match.sect];6029 const match_sect = match_seg.sections.items[match.sect];
6033 break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;6030 break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
6034 };6031 };
6035 if (is_tlv) {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 const base_address = inner: {6034 const base_address = inner: {
6038 if (self.tlv_data_section_index) |i| {6035 if (self.tlv_data_section_index) |i| {
6039 break :inner match_seg.sections.items[i].addr;6036 break :inner match_seg.sections.items[i].addr;
...@@ -6193,7 +6190,7 @@ fn logSymtab(self: MachO) void {...@@ -6193,7 +6190,7 @@ fn logSymtab(self: MachO) void {
61936190
6194fn logSectionOrdinals(self: MachO) void {6191fn logSectionOrdinals(self: MachO) void {
6195 for (self.section_ordinals.keys()) |match, i| {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 const sect = seg.sections.items[match.sect];6194 const sect = seg.sections.items[match.sect];
6198 log.debug("ord {d}: {d},{d} => {s},{s}", .{6195 log.debug("ord {d}: {d},{d} => {s},{s}", .{
6199 i + 1,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,7 +341,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
341 if (rel.r_extern == 0) {341 if (rel.r_extern == 0) {
342 const sect_id = @intCast(u16, rel.r_symbolnum - 1);342 const sect_id = @intCast(u16, rel.r_symbolnum - 1);
343 const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: {343 const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: {
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 const sect = seg.sections.items[sect_id];345 const sect = seg.sections.items[sect_id];
346 const match = (try context.macho_file.getMatchingSection(sect)) orelse346 const match = (try context.macho_file.getMatchingSection(sect)) orelse
347 unreachable;347 unreachable;
...@@ -397,7 +397,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC...@@ -397,7 +397,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
397 else397 else
398 mem.readIntLittle(i32, self.code.items[offset..][0..4]);398 mem.readIntLittle(i32, self.code.items[offset..][0..4]);
399 if (rel.r_extern == 0) {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 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;401 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
402 addend -= @intCast(i64, target_sect_base_addr);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,7 +424,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
424 else424 else
425 mem.readIntLittle(i32, self.code.items[offset..][0..4]);425 mem.readIntLittle(i32, self.code.items[offset..][0..4]);
426 if (rel.r_extern == 0) {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 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;428 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
429 addend -= @intCast(i64, target_sect_base_addr);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,7 +446,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
446 if (rel.r_extern == 0) {446 if (rel.r_extern == 0) {
447 // Note for the future self: when r_extern == 0, we should subtract correction from the447 // Note for the future self: when r_extern == 0, we should subtract correction from the
448 // addend.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 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;450 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
451 addend += @intCast(i64, context.base_addr + offset + 4) -451 addend += @intCast(i64, context.base_addr + offset + 4) -
452 @intCast(i64, target_sect_base_addr);452 @intCast(i64, target_sect_base_addr);
...@@ -489,7 +489,7 @@ fn addPtrBindingOrRebase(...@@ -489,7 +489,7 @@ fn addPtrBindingOrRebase(
489 .local => {489 .local => {
490 const source_sym = context.macho_file.locals.items[self.local_sym_index];490 const source_sym = context.macho_file.locals.items[self.local_sym_index];
491 const match = context.macho_file.section_ordinals.keys()[source_sym.n_sect - 1];491 const match = context.macho_file.section_ordinals.keys()[source_sym.n_sect - 1];
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 const sect = seg.sections.items[match.sect];493 const sect = seg.sections.items[match.sect];
494 const sect_type = sect.type_();494 const sect_type = sect.type_();
495495
...@@ -704,7 +704,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {...@@ -704,7 +704,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
704 const is_tlv = is_tlv: {704 const is_tlv = is_tlv: {
705 const source_sym = macho_file.locals.items[self.local_sym_index];705 const source_sym = macho_file.locals.items[self.local_sym_index];
706 const match = macho_file.section_ordinals.keys()[source_sym.n_sect - 1];706 const match = macho_file.section_ordinals.keys()[source_sym.n_sect - 1];
707 const seg = macho_file.load_commands.items[match.seg].Segment;707 const seg = macho_file.load_commands.items[match.seg].segment;
708 const sect = seg.sections.items[match.sect];708 const sect = seg.sections.items[match.sect];
709 break :is_tlv sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;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,7 +714,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
714 // defined TLV template init section in the following order:714 // defined TLV template init section in the following order:
715 // * wrt to __thread_data if defined, then715 // * wrt to __thread_data if defined, then
716 // * wrt to __thread_bss716 // * 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 const base_address = inner: {718 const base_address = inner: {
719 if (macho_file.tlv_data_section_index) |i| {719 if (macho_file.tlv_data_section_index) |i| {
720 break :inner seg.sections.items[i].addr;720 break :inner seg.sections.items[i].addr;
src/link/MachO/DebugSymbols.zig+83-49
...@@ -12,15 +12,12 @@ const leb = std.leb;...@@ -12,15 +12,12 @@ const leb = std.leb;
12const Allocator = mem.Allocator;12const Allocator = mem.Allocator;
1313
14const build_options = @import("build_options");14const build_options = @import("build_options");
15const commands = @import("commands.zig");
16const trace = @import("../../tracy.zig").trace;15const trace = @import("../../tracy.zig").trace;
17const LoadCommand = commands.LoadCommand;
18const Module = @import("../../Module.zig");16const Module = @import("../../Module.zig");
19const Type = @import("../../type.zig").Type;17const Type = @import("../../type.zig").Type;
20const link = @import("../../link.zig");18const link = @import("../../link.zig");
21const MachO = @import("../MachO.zig");19const MachO = @import("../MachO.zig");
22const TextBlock = MachO.TextBlock;20const TextBlock = MachO.TextBlock;
23const SegmentCommand = commands.SegmentCommand;
24const SrcFn = MachO.SrcFn;21const SrcFn = MachO.SrcFn;
25const makeStaticString = MachO.makeStaticString;22const makeStaticString = MachO.makeStaticString;
26const padToIdeal = MachO.padToIdeal;23const padToIdeal = MachO.padToIdeal;
...@@ -31,7 +28,7 @@ base: *MachO,...@@ -31,7 +28,7 @@ base: *MachO,
31file: fs.File,28file: fs.File,
3229
33/// Table of all load commands30/// Table of all load commands
34load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},31load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
35/// __PAGEZERO segment32/// __PAGEZERO segment
36pagezero_segment_cmd_index: ?u16 = null,33pagezero_segment_cmd_index: ?u16 = null,
37/// __TEXT segment34/// __TEXT segment
...@@ -113,7 +110,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -113,7 +110,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
113 }110 }
114 if (self.symtab_cmd_index == null) {111 if (self.symtab_cmd_index == null) {
115 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);112 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
116 const base_cmd = self.base.load_commands.items[self.base.symtab_cmd_index.?].Symtab;113 const base_cmd = self.base.load_commands.items[self.base.symtab_cmd_index.?].symtab;
117 const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64);114 const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64);
118 const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64));115 const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64));
119116
...@@ -124,7 +121,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -124,7 +121,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
124 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize });121 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize });
125122
126 try self.load_commands.append(allocator, .{123 try self.load_commands.append(allocator, .{
127 .Symtab = .{124 .symtab = .{
128 .cmd = macho.LC_SYMTAB,125 .cmd = macho.LC_SYMTAB,
129 .cmdsize = @sizeOf(macho.symtab_command),126 .cmdsize = @sizeOf(macho.symtab_command),
130 .symoff = @intCast(u32, symtab_off),127 .symoff = @intCast(u32, symtab_off),
...@@ -138,48 +135,48 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -138,48 +135,48 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
138 }135 }
139 if (self.pagezero_segment_cmd_index == null) {136 if (self.pagezero_segment_cmd_index == null) {
140 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);137 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
141 const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].Segment;138 const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].segment;
142 const cmd = try self.copySegmentCommand(allocator, base_cmd);139 const cmd = try self.copySegmentCommand(allocator, base_cmd);
143 try self.load_commands.append(allocator, .{ .Segment = cmd });140 try self.load_commands.append(allocator, .{ .segment = cmd });
144 self.load_commands_dirty = true;141 self.load_commands_dirty = true;
145 }142 }
146 if (self.text_segment_cmd_index == null) {143 if (self.text_segment_cmd_index == null) {
147 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);144 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
148 const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].Segment;145 const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].segment;
149 const cmd = try self.copySegmentCommand(allocator, base_cmd);146 const cmd = try self.copySegmentCommand(allocator, base_cmd);
150 try self.load_commands.append(allocator, .{ .Segment = cmd });147 try self.load_commands.append(allocator, .{ .segment = cmd });
151 self.load_commands_dirty = true;148 self.load_commands_dirty = true;
152 }149 }
153 if (self.data_const_segment_cmd_index == null) outer: {150 if (self.data_const_segment_cmd_index == null) outer: {
154 if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional151 if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional
155 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);152 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
156 const base_cmd = self.base.load_commands.items[self.base.data_const_segment_cmd_index.?].Segment;153 const base_cmd = self.base.load_commands.items[self.base.data_const_segment_cmd_index.?].segment;
157 const cmd = try self.copySegmentCommand(allocator, base_cmd);154 const cmd = try self.copySegmentCommand(allocator, base_cmd);
158 try self.load_commands.append(allocator, .{ .Segment = cmd });155 try self.load_commands.append(allocator, .{ .segment = cmd });
159 self.load_commands_dirty = true;156 self.load_commands_dirty = true;
160 }157 }
161 if (self.data_segment_cmd_index == null) outer: {158 if (self.data_segment_cmd_index == null) outer: {
162 if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional159 if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional
163 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);160 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
164 const base_cmd = self.base.load_commands.items[self.base.data_segment_cmd_index.?].Segment;161 const base_cmd = self.base.load_commands.items[self.base.data_segment_cmd_index.?].segment;
165 const cmd = try self.copySegmentCommand(allocator, base_cmd);162 const cmd = try self.copySegmentCommand(allocator, base_cmd);
166 try self.load_commands.append(allocator, .{ .Segment = cmd });163 try self.load_commands.append(allocator, .{ .segment = cmd });
167 self.load_commands_dirty = true;164 self.load_commands_dirty = true;
168 }165 }
169 if (self.linkedit_segment_cmd_index == null) {166 if (self.linkedit_segment_cmd_index == null) {
170 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);167 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
171 const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].Segment;168 const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].segment;
172 var cmd = try self.copySegmentCommand(allocator, base_cmd);169 var cmd = try self.copySegmentCommand(allocator, base_cmd);
173 cmd.inner.vmsize = self.linkedit_size;170 cmd.inner.vmsize = self.linkedit_size;
174 cmd.inner.fileoff = self.linkedit_off;171 cmd.inner.fileoff = self.linkedit_off;
175 cmd.inner.filesize = self.linkedit_size;172 cmd.inner.filesize = self.linkedit_size;
176 try self.load_commands.append(allocator, .{ .Segment = cmd });173 try self.load_commands.append(allocator, .{ .segment = cmd });
177 self.load_commands_dirty = true;174 self.load_commands_dirty = true;
178 }175 }
179 if (self.dwarf_segment_cmd_index == null) {176 if (self.dwarf_segment_cmd_index == null) {
180 self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len);177 self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
181178
182 const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;179 const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
183 const ideal_size: u16 = 200 + 128 + 160 + 250;180 const ideal_size: u16 = 200 + 128 + 160 + 250;
184 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size);181 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size);
185 const off = linkedit.inner.fileoff + linkedit.inner.filesize;182 const off = linkedit.inner.fileoff + linkedit.inner.filesize;
...@@ -188,7 +185,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -188,7 +185,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
188 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });185 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });
189186
190 try self.load_commands.append(allocator, .{187 try self.load_commands.append(allocator, .{
191 .Segment = .{188 .segment = .{
192 .inner = .{189 .inner = .{
193 .segname = makeStaticString("__DWARF"),190 .segname = makeStaticString("__DWARF"),
194 .vmaddr = vmaddr,191 .vmaddr = vmaddr,
...@@ -228,7 +225,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -228,7 +225,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
228}225}
229226
230fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u16 {227fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u16 {
231 const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;228 const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
232 var sect = macho.section_64{229 var sect = macho.section_64{
233 .sectname = makeStaticString(sectname),230 .sectname = makeStaticString(sectname),
234 .segname = seg.inner.segname,231 .segname = seg.inner.segname,
...@@ -236,7 +233,7 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme...@@ -236,7 +233,7 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
236 .@"align" = alignment,233 .@"align" = alignment,
237 };234 };
238 const alignment_pow_2 = try math.powi(u32, 2, alignment);235 const alignment_pow_2 = try math.powi(u32, 2, alignment);
239 const off = seg.findFreeSpace(size, alignment_pow_2, null);236 const off = self.findFreeSpace(size, alignment_pow_2);
240237
241 assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand238 assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand
242239
...@@ -268,6 +265,28 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme...@@ -268,6 +265,28 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
268 return index;265 return index;
269}266}
270267
268fn 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
281fn 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
271pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Options) !void {290pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Options) !void {
272 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the291 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the
273 // Zig source code.292 // Zig source code.
...@@ -275,7 +294,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -275,7 +294,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
275 const init_len_size: usize = 4;294 const init_len_size: usize = 4;
276295
277 if (self.debug_abbrev_section_dirty) {296 if (self.debug_abbrev_section_dirty) {
278 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;297 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
279 const debug_abbrev_sect = &dwarf_segment.sections.items[self.debug_abbrev_section_index.?];298 const debug_abbrev_sect = &dwarf_segment.sections.items[self.debug_abbrev_section_index.?];
280299
281 // These are LEB encoded but since the values are all less than 127300 // These are LEB encoded but since the values are all less than 127
...@@ -320,10 +339,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -320,10 +339,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
320 };339 };
321340
322 const needed_size = abbrev_buf.len;341 const needed_size = abbrev_buf.len;
323 const allocated_size = dwarf_segment.allocatedSize(debug_abbrev_sect.offset);342 const allocated_size = self.allocatedSize(debug_abbrev_sect.offset);
324 if (needed_size > allocated_size) {343 if (needed_size > allocated_size) {
325 debug_abbrev_sect.size = 0; // free the space344 debug_abbrev_sect.size = 0; // free the space
326 const offset = dwarf_segment.findFreeSpace(needed_size, 1, null);345 const offset = self.findFreeSpace(needed_size, 1);
327 debug_abbrev_sect.offset = @intCast(u32, offset);346 debug_abbrev_sect.offset = @intCast(u32, offset);
328 debug_abbrev_sect.addr = dwarf_segment.inner.vmaddr + offset - dwarf_segment.inner.fileoff;347 debug_abbrev_sect.addr = dwarf_segment.inner.vmaddr + offset - dwarf_segment.inner.fileoff;
329 }348 }
...@@ -345,7 +364,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -345,7 +364,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
345 // leave debug_info_header_dirty=true.364 // leave debug_info_header_dirty=true.
346 const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info;365 const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info;
347 const last_dbg_info_decl = self.dbg_info_decl_last.?;366 const last_dbg_info_decl = self.dbg_info_decl_last.?;
348 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;367 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
349 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];368 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
350369
351 // We have a function to compute the upper bound size, because it's needed370 // We have a function to compute the upper bound size, because it's needed
...@@ -372,7 +391,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -372,7 +391,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
372 const producer_strp = try self.makeDebugString(allocator, link.producer_string);391 const producer_strp = try self.makeDebugString(allocator, link.producer_string);
373 // Currently only one compilation unit is supported, so the address range is simply392 // Currently only one compilation unit is supported, so the address range is simply
374 // identical to the main program header virtual address and memory size.393 // identical to the main program header virtual address and memory size.
375 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;394 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;
376 const text_section = text_segment.sections.items[self.text_section_index.?];395 const text_section = text_segment.sections.items[self.text_section_index.?];
377 const low_pc = text_section.addr;396 const low_pc = text_section.addr;
378 const high_pc = text_section.addr + text_section.size;397 const high_pc = text_section.addr + text_section.size;
...@@ -399,7 +418,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -399,7 +418,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
399 }418 }
400419
401 if (self.debug_aranges_section_dirty) {420 if (self.debug_aranges_section_dirty) {
402 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;421 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
403 const debug_aranges_sect = &dwarf_segment.sections.items[self.debug_aranges_section_index.?];422 const debug_aranges_sect = &dwarf_segment.sections.items[self.debug_aranges_section_index.?];
404423
405 // Enough for all the data without resizing. When support for more compilation units424 // Enough for all the data without resizing. When support for more compilation units
...@@ -426,7 +445,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -426,7 +445,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
426445
427 // Currently only one compilation unit is supported, so the address range is simply446 // Currently only one compilation unit is supported, so the address range is simply
428 // identical to the main program header virtual address and memory size.447 // identical to the main program header virtual address and memory size.
429 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;448 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;
430 const text_section = text_segment.sections.items[self.text_section_index.?];449 const text_section = text_segment.sections.items[self.text_section_index.?];
431 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.addr);450 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.addr);
432 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size);451 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size);
...@@ -442,10 +461,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -442,10 +461,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
442 mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len));461 mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len));
443462
444 const needed_size = di_buf.items.len;463 const needed_size = di_buf.items.len;
445 const allocated_size = dwarf_segment.allocatedSize(debug_aranges_sect.offset);464 const allocated_size = self.allocatedSize(debug_aranges_sect.offset);
446 if (needed_size > allocated_size) {465 if (needed_size > allocated_size) {
447 debug_aranges_sect.size = 0; // free the space466 debug_aranges_sect.size = 0; // free the space
448 const new_offset = dwarf_segment.findFreeSpace(needed_size, 16, null);467 const new_offset = self.findFreeSpace(needed_size, 16);
449 debug_aranges_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;468 debug_aranges_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;
450 debug_aranges_sect.offset = @intCast(u32, new_offset);469 debug_aranges_sect.offset = @intCast(u32, new_offset);
451 }470 }
...@@ -467,7 +486,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -467,7 +486,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
467 const dbg_line_prg_end = self.getDebugLineProgramEnd();486 const dbg_line_prg_end = self.getDebugLineProgramEnd();
468 assert(dbg_line_prg_end != 0);487 assert(dbg_line_prg_end != 0);
469488
470 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;489 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
471 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];490 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];
472491
473 // The size of this header is variable, depending on the number of directories,492 // The size of this header is variable, depending on the number of directories,
...@@ -540,15 +559,15 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -540,15 +559,15 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
540 self.debug_line_header_dirty = false;559 self.debug_line_header_dirty = false;
541 }560 }
542 {561 {
543 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;562 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
544 const debug_strtab_sect = &dwarf_segment.sections.items[self.debug_str_section_index.?];563 const debug_strtab_sect = &dwarf_segment.sections.items[self.debug_str_section_index.?];
545 if (self.debug_string_table_dirty or self.debug_string_table.items.len != debug_strtab_sect.size) {564 if (self.debug_string_table_dirty or self.debug_string_table.items.len != debug_strtab_sect.size) {
546 const allocated_size = dwarf_segment.allocatedSize(debug_strtab_sect.offset);565 const allocated_size = self.allocatedSize(debug_strtab_sect.offset);
547 const needed_size = self.debug_string_table.items.len;566 const needed_size = self.debug_string_table.items.len;
548567
549 if (needed_size > allocated_size) {568 if (needed_size > allocated_size) {
550 debug_strtab_sect.size = 0; // free the space569 debug_strtab_sect.size = 0; // free the space
551 const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null);570 const new_offset = self.findFreeSpace(needed_size, 1);
552 debug_strtab_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;571 debug_strtab_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;
553 debug_strtab_sect.offset = @intCast(u32, new_offset);572 debug_strtab_sect.offset = @intCast(u32, new_offset);
554 }573 }
...@@ -588,8 +607,12 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {...@@ -588,8 +607,12 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {
588 self.file.close();607 self.file.close();
589}608}
590609
591fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: SegmentCommand) !SegmentCommand {610fn copySegmentCommand(
592 var cmd = SegmentCommand{611 self: *DebugSymbols,
612 allocator: Allocator,
613 base_cmd: macho.SegmentCommand,
614) !macho.SegmentCommand {
615 var cmd = macho.SegmentCommand{
593 .inner = .{616 .inner = .{
594 .segname = undefined,617 .segname = undefined,
595 .cmdsize = base_cmd.inner.cmdsize,618 .cmdsize = base_cmd.inner.cmdsize,
...@@ -633,7 +656,7 @@ fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: Segme...@@ -633,7 +656,7 @@ fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: Segme
633}656}
634657
635fn updateDwarfSegment(self: *DebugSymbols) void {658fn updateDwarfSegment(self: *DebugSymbols) void {
636 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;659 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
637 var file_size: u64 = 0;660 var file_size: u64 = 0;
638 for (dwarf_segment.sections.items) |sect| {661 for (dwarf_segment.sections.items) |sect| {
639 file_size += sect.size;662 file_size += sect.size;
...@@ -702,7 +725,7 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {...@@ -702,7 +725,7 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {
702 var min_pos: u64 = std.math.maxInt(u64);725 var min_pos: u64 = std.math.maxInt(u64);
703726
704 if (self.symtab_cmd_index) |idx| {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 if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff;729 if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff;
707 if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff;730 if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff;
708 }731 }
...@@ -710,12 +733,23 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {...@@ -710,12 +733,23 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {
710 return min_pos - start;733 return min_pos - start;
711}734}
712735
736fn 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
713fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 {747fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 {
714 const end = start + padToIdeal(size);748 const end = start + padToIdeal(size);
715749
716 if (self.symtab_cmd_index) |idx| outer: {750 if (self.symtab_cmd_index) |idx| outer: {
717 if (self.load_commands.items.len == idx) break :outer;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 // Symbol table754 // Symbol table
721 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);755 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
...@@ -747,7 +781,7 @@ fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u...@@ -747,7 +781,7 @@ fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u
747}781}
748782
749fn relocateSymbolTable(self: *DebugSymbols) !void {783fn 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 const nlocals = self.base.locals.items.len;785 const nlocals = self.base.locals.items.len;
752 const nglobals = self.base.globals.items.len;786 const nglobals = self.base.globals.items.len;
753 const nsyms = nlocals + nglobals;787 const nsyms = nlocals + nglobals;
...@@ -780,7 +814,7 @@ pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void {...@@ -780,7 +814,7 @@ pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void {
780 const tracy = trace(@src());814 const tracy = trace(@src());
781 defer tracy.end();815 defer tracy.end();
782 try self.relocateSymbolTable();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 const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;818 const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;
785 log.debug("writing local symbol {} at 0x{x}", .{ index, off });819 log.debug("writing local symbol {} at 0x{x}", .{ index, off });
786 try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off);820 try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off);
...@@ -792,7 +826,7 @@ fn writeStringTable(self: *DebugSymbols) !void {...@@ -792,7 +826,7 @@ fn writeStringTable(self: *DebugSymbols) !void {
792 const tracy = trace(@src());826 const tracy = trace(@src());
793 defer tracy.end();827 defer tracy.end();
794828
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 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);830 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);
797 const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64));831 const needed_size = mem.alignForwardGeneric(u64, self.base.strtab.items.len, @alignOf(u64));
798832
...@@ -816,7 +850,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M...@@ -816,7 +850,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
816 const func = decl.val.castTag(.function).?.data;850 const func = decl.val.castTag(.function).?.data;
817 const line_off = @intCast(u28, decl.src_line + func.lbrace_line);851 const line_off = @intCast(u28, decl.src_line + func.lbrace_line);
818852
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 const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?];854 const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?];
821 const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff();855 const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff();
822 var data: [4]u8 = undefined;856 var data: [4]u8 = undefined;
...@@ -982,7 +1016,7 @@ pub fn commitDeclDebugInfo(...@@ -982,7 +1016,7 @@ pub fn commitDeclDebugInfo(
982 // `TextBlock` and the .debug_info. If you are editing this logic, you1016 // `TextBlock` and the .debug_info. If you are editing this logic, you
983 // probably need to edit that logic too.1017 // probably need to edit that logic too.
9841018
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 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];1020 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];
987 const src_fn = &decl.fn_link.macho;1021 const src_fn = &decl.fn_link.macho;
988 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);1022 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
...@@ -1028,8 +1062,8 @@ pub fn commitDeclDebugInfo(...@@ -1028,8 +1062,8 @@ pub fn commitDeclDebugInfo(
1028 const last_src_fn = self.dbg_line_fn_last.?;1062 const last_src_fn = self.dbg_line_fn_last.?;
1029 const needed_size = last_src_fn.off + last_src_fn.len;1063 const needed_size = last_src_fn.off + last_src_fn.len;
1030 if (needed_size != debug_line_sect.size) {1064 if (needed_size != debug_line_sect.size) {
1031 if (needed_size > dwarf_segment.allocatedSize(debug_line_sect.offset)) {1065 if (needed_size > self.allocatedSize(debug_line_sect.offset)) {
1032 const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null);1066 const new_offset = self.findFreeSpace(needed_size, 1);
1033 const existing_size = last_src_fn.off;1067 const existing_size = last_src_fn.off;
10341068
1035 log.debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{1069 log.debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{
...@@ -1151,7 +1185,7 @@ fn updateDeclDebugInfoAllocation(...@@ -1151,7 +1185,7 @@ fn updateDeclDebugInfoAllocation(
1151 // `SrcFn` and the line number programs. If you are editing this logic, you1185 // `SrcFn` and the line number programs. If you are editing this logic, you
1152 // probably need to edit that logic too.1186 // probably need to edit that logic too.
11531187
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 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];1189 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
1156 text_block.dbg_info_len = len;1190 text_block.dbg_info_len = len;
1157 if (self.dbg_info_decl_last) |last| blk: {1191 if (self.dbg_info_decl_last) |last| blk: {
...@@ -1202,15 +1236,15 @@ fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_buf:...@@ -1202,15 +1236,15 @@ fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_buf:
1202 // `SrcFn` and the line number programs. If you are editing this logic, you1236 // `SrcFn` and the line number programs. If you are editing this logic, you
1203 // probably need to edit that logic too.1237 // probably need to edit that logic too.
12041238
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 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];1240 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
12071241
1208 const last_decl = self.dbg_info_decl_last.?;1242 const last_decl = self.dbg_info_decl_last.?;
1209 // +1 for a trailing zero to end the children of the decl tag.1243 // +1 for a trailing zero to end the children of the decl tag.
1210 const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1;1244 const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1;
1211 if (needed_size != debug_info_sect.size) {1245 if (needed_size != debug_info_sect.size) {
1212 if (needed_size > dwarf_segment.allocatedSize(debug_info_sect.offset)) {1246 if (needed_size > self.allocatedSize(debug_info_sect.offset)) {
1213 const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null);1247 const new_offset = self.findFreeSpace(needed_size, 1);
1214 const existing_size = last_decl.dbg_info_off;1248 const existing_size = last_decl.dbg_info_off;
12151249
1216 log.debug("moving __debug_info section: {} bytes from 0x{x} to 0x{x}", .{1250 log.debug("moving __debug_info section: {} bytes from 0x{x} to 0x{x}", .{
src/link/MachO/Dylib.zig+6-8
...@@ -9,11 +9,9 @@ const macho = std.macho;...@@ -9,11 +9,9 @@ const macho = std.macho;
9const math = std.math;9const math = std.math;
10const mem = std.mem;10const mem = std.mem;
11const fat = @import("fat.zig");11const fat = @import("fat.zig");
12const commands = @import("commands.zig");
1312
14const Allocator = mem.Allocator;13const Allocator = mem.Allocator;
15const LibStub = @import("../tapi.zig").LibStub;14const LibStub = @import("../tapi.zig").LibStub;
16const LoadCommand = commands.LoadCommand;
17const MachO = @import("../MachO.zig");15const MachO = @import("../MachO.zig");
1816
19file: fs.File,17file: fs.File,
...@@ -25,7 +23,7 @@ header: ?macho.mach_header_64 = null,...@@ -25,7 +23,7 @@ header: ?macho.mach_header_64 = null,
25// an offset within a file if we are linking against a fat lib23// an offset within a file if we are linking against a fat lib
26library_offset: u64 = 0,24library_offset: u64 = 0,
2725
28load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},26load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
2927
30symtab_cmd_index: ?u16 = null,28symtab_cmd_index: ?u16 = null,
31dysymtab_cmd_index: ?u16 = null,29dysymtab_cmd_index: ?u16 = null,
...@@ -53,7 +51,7 @@ pub const Id = struct {...@@ -53,7 +51,7 @@ pub const Id = struct {
53 };51 };
54 }52 }
5553
56 pub fn fromLoadCommand(allocator: Allocator, lc: commands.GenericCommandWithData(macho.dylib_command)) !Id {54 pub fn fromLoadCommand(allocator: Allocator, lc: macho.GenericCommandWithData(macho.dylib_command)) !Id {
57 const dylib = lc.inner.dylib;55 const dylib = lc.inner.dylib;
58 const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]);56 const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]);
59 const name = try allocator.dupe(u8, mem.sliceTo(dylib_name, 0));57 const name = try allocator.dupe(u8, mem.sliceTo(dylib_name, 0));
...@@ -177,7 +175,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende...@@ -177,7 +175,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende
177175
178 var i: u16 = 0;176 var i: u16 = 0;
179 while (i < self.header.?.ncmds) : (i += 1) {177 while (i < self.header.?.ncmds) : (i += 1) {
180 var cmd = try LoadCommand.read(allocator, reader);178 var cmd = try macho.LoadCommand.read(allocator, reader);
181 switch (cmd.cmd()) {179 switch (cmd.cmd()) {
182 macho.LC_SYMTAB => {180 macho.LC_SYMTAB => {
183 self.symtab_cmd_index = i;181 self.symtab_cmd_index = i;
...@@ -191,7 +189,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende...@@ -191,7 +189,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende
191 macho.LC_REEXPORT_DYLIB => {189 macho.LC_REEXPORT_DYLIB => {
192 if (should_lookup_reexports) {190 if (should_lookup_reexports) {
193 // Parse install_name to dependent dylib.191 // Parse install_name to dependent dylib.
194 var id = try Id.fromLoadCommand(allocator, cmd.Dylib);192 var id = try Id.fromLoadCommand(allocator, cmd.dylib);
195 try dependent_libs.writeItem(id);193 try dependent_libs.writeItem(id);
196 }194 }
197 },195 },
...@@ -209,12 +207,12 @@ fn parseId(self: *Dylib, allocator: Allocator) !void {...@@ -209,12 +207,12 @@ fn parseId(self: *Dylib, allocator: Allocator) !void {
209 self.id = try Id.default(allocator, self.name);207 self.id = try Id.default(allocator, self.name);
210 return;208 return;
211 };209 };
212 self.id = try Id.fromLoadCommand(allocator, self.load_commands.items[index].Dylib);210 self.id = try Id.fromLoadCommand(allocator, self.load_commands.items[index].dylib);
213}211}
214212
215fn parseSymbols(self: *Dylib, allocator: Allocator) !void {213fn parseSymbols(self: *Dylib, allocator: Allocator) !void {
216 const index = self.symtab_cmd_index orelse return;214 const index = self.symtab_cmd_index orelse return;
217 const symtab_cmd = self.load_commands.items[index].Symtab;215 const symtab_cmd = self.load_commands.items[index].symtab;
218216
219 var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);217 var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
220 defer allocator.free(symtab);218 defer allocator.free(symtab);
src/link/MachO/Object.zig+11-12
...@@ -15,7 +15,6 @@ const trace = @import("../../tracy.zig").trace;...@@ -15,7 +15,6 @@ const trace = @import("../../tracy.zig").trace;
1515
16const Allocator = mem.Allocator;16const Allocator = mem.Allocator;
17const Atom = @import("Atom.zig");17const Atom = @import("Atom.zig");
18const LoadCommand = @import("commands.zig").LoadCommand;
19const MachO = @import("../MachO.zig");18const MachO = @import("../MachO.zig");
2019
21file: fs.File,20file: fs.File,
...@@ -25,7 +24,7 @@ file_offset: ?u32 = null,...@@ -25,7 +24,7 @@ file_offset: ?u32 = null,
2524
26header: ?macho.mach_header_64 = null,25header: ?macho.mach_header_64 = null,
2726
28load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},27load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
2928
30segment_cmd_index: ?u16 = null,29segment_cmd_index: ?u16 = null,
31text_section_index: ?u16 = null,30text_section_index: ?u16 = null,
...@@ -268,11 +267,11 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v...@@ -268,11 +267,11 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
268267
269 var i: u16 = 0;268 var i: u16 = 0;
270 while (i < header.ncmds) : (i += 1) {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 switch (cmd.cmd()) {271 switch (cmd.cmd()) {
273 macho.LC_SEGMENT_64 => {272 macho.LC_SEGMENT_64 => {
274 self.segment_cmd_index = i;273 self.segment_cmd_index = i;
275 var seg = cmd.Segment;274 var seg = cmd.segment;
276 for (seg.sections.items) |*sect, j| {275 for (seg.sections.items) |*sect, j| {
277 const index = @intCast(u16, j);276 const index = @intCast(u16, j);
278 const segname = sect.segName();277 const segname = sect.segName();
...@@ -305,8 +304,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v...@@ -305,8 +304,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
305 },304 },
306 macho.LC_SYMTAB => {305 macho.LC_SYMTAB => {
307 self.symtab_cmd_index = i;306 self.symtab_cmd_index = i;
308 cmd.Symtab.symoff += offset;307 cmd.symtab.symoff += offset;
309 cmd.Symtab.stroff += offset;308 cmd.symtab.stroff += offset;
310 },309 },
311 macho.LC_DYSYMTAB => {310 macho.LC_DYSYMTAB => {
312 self.dysymtab_cmd_index = i;311 self.dysymtab_cmd_index = i;
...@@ -316,7 +315,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v...@@ -316,7 +315,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
316 },315 },
317 macho.LC_DATA_IN_CODE => {316 macho.LC_DATA_IN_CODE => {
318 self.data_in_code_cmd_index = i;317 self.data_in_code_cmd_index = i;
319 cmd.LinkeditData.dataoff += offset;318 cmd.linkedit_data.dataoff += offset;
320 },319 },
321 else => {320 else => {
322 log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()});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,7 +381,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
382 const tracy = trace(@src());381 const tracy = trace(@src());
383 defer tracy.end();382 defer tracy.end();
384383
385 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;384 const seg = self.load_commands.items[self.segment_cmd_index.?].segment;
386385
387 log.debug("analysing {s}", .{self.name});386 log.debug("analysing {s}", .{self.name});
388387
...@@ -405,7 +404,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -405,7 +404,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
405 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we404 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
406 // have to infer the start of undef section in the symtab ourselves.405 // have to infer the start of undef section in the symtab ourselves.
407 const iundefsym = if (self.dysymtab_cmd_index) |cmd_index| blk: {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 break :blk dysymtab.iundefsym;408 break :blk dysymtab.iundefsym;
410 } else blk: {409 } else blk: {
411 var iundefsym: usize = sorted_all_nlists.items.len;410 var iundefsym: usize = sorted_all_nlists.items.len;
...@@ -553,7 +552,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -553,7 +552,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
553552
554fn parseSymtab(self: *Object, allocator: Allocator) !void {553fn parseSymtab(self: *Object, allocator: Allocator) !void {
555 const index = self.symtab_cmd_index orelse return;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;
557556
558 var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);557 var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
559 defer allocator.free(symtab);558 defer allocator.free(symtab);
...@@ -601,7 +600,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {...@@ -601,7 +600,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {
601600
602pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {601pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {
603 const index = self.data_in_code_cmd_index orelse return;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;
605604
606 var buffer = try allocator.alloc(u8, data_in_code.datasize);605 var buffer = try allocator.alloc(u8, data_in_code.datasize);
607 defer allocator.free(buffer);606 defer allocator.free(buffer);
...@@ -620,7 +619,7 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {...@@ -620,7 +619,7 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {
620}619}
621620
622fn readSection(self: Object, allocator: Allocator, index: u16) ![]u8 {621fn 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 const sect = seg.sections.items[index];623 const sect = seg.sections.items[index];
625 var buffer = try allocator.alloc(u8, @intCast(usize, sect.size));624 var buffer = try allocator.alloc(u8, @intCast(usize, sect.size));
626 _ = try self.file.preadAll(buffer, sect.offset);625 _ = try self.file.preadAll(buffer, sect.offset);
src/link/MachO/commands.zig deleted-463
...@@ -1,463 +0,0 @@
1const std = @import("std");
2const fs = std.fs;
3const io = std.io;
4const mem = std.mem;
5const meta = std.meta;
6const macho = std.macho;
7const testing = std.testing;
8const assert = std.debug.assert;
9
10const Allocator = std.mem.Allocator;
11const MachO = @import("../MachO.zig");
12const makeStaticString = MachO.makeStaticString;
13const padToIdeal = MachO.padToIdeal;
14
15pub 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
195pub 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
268pub fn emptyGenericCommandWithData(cmd: anytype) GenericCommandWithData(@TypeOf(cmd)) {
269 return .{ .inner = cmd };
270}
271
272pub 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
307pub 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
338fn 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
345fn 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
351test "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
406test "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
445test "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}