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
590590 "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig"
591591 "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig"
592592 "${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig"
593 "${CMAKE_SOURCE_DIR}/src/link/MachO/commands.zig"
594593 "${CMAKE_SOURCE_DIR}/src/link/Plan9.zig"
595594 "${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
596595 "${CMAKE_SOURCE_DIR}/src/link/Wasm.zig"
lib/std/macho.zig+434-1
......@@ -1,4 +1,12 @@
11const 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
311pub const mach_header = extern struct {
412 magic: u32,
......@@ -770,7 +778,7 @@ pub const section_64 = extern struct {
770778};
771779
772780fn 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;
774782 return name[0..len];
775783}
776784
......@@ -1804,3 +1812,428 @@ pub const data_in_code_entry = extern struct {
18041812 /// A DICE_KIND value.
18051813 kind: u16,
18061814};
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;
1515const aarch64 = @import("../arch/aarch64/bits.zig");
1616const bind = @import("MachO/bind.zig");
1717const codegen = @import("../codegen.zig");
18const commands = @import("MachO/commands.zig");
1918const link = @import("../link.zig");
2019const llvm_backend = @import("../codegen/llvm.zig");
2120const target_util = @import("../target.zig");
......@@ -35,9 +34,7 @@ const Object = @import("MachO/Object.zig");
3534const LibStub = @import("tapi.zig").LibStub;
3635const Liveness = @import("../Liveness.zig");
3736const LlvmObject = @import("../codegen/llvm.zig").Object;
38const LoadCommand = commands.LoadCommand;
3937const Module = @import("../Module.zig");
40const SegmentCommand = commands.SegmentCommand;
4138const StringIndexAdapter = std.hash_map.StringIndexAdapter;
4239const StringIndexContext = std.hash_map.StringIndexContext;
4340const Trie = @import("MachO/Trie.zig");
......@@ -83,7 +80,7 @@ dylibs: std.ArrayListUnmanaged(Dylib) = .{},
8380dylibs_map: std.StringHashMapUnmanaged(u16) = .{},
8481referenced_dylibs: std.AutoArrayHashMapUnmanaged(u16, void) = .{},
8582
86load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
83load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
8784
8885pagezero_segment_cmd_index: ?u16 = null,
8986text_segment_cmd_index: ?u16 = null,
......@@ -783,7 +780,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
783780 @sizeOf(macho.rpath_command) + rpath.len + 1,
784781 @sizeOf(u64),
785782 ));
786 var rpath_cmd = commands.emptyGenericCommandWithData(macho.rpath_command{
783 var rpath_cmd = macho.emptyGenericCommandWithData(macho.rpath_command{
787784 .cmd = macho.LC_RPATH,
788785 .cmdsize = cmdsize,
789786 .path = @sizeOf(macho.rpath_command),
......@@ -791,7 +788,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
791788 rpath_cmd.data = try self.base.allocator.alloc(u8, cmdsize - rpath_cmd.inner.path);
792789 mem.set(u8, rpath_cmd.data, 0);
793790 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 });
795792 try rpath_table.putNoClobber(rpath, {});
796793 self.load_commands_dirty = true;
797794 }
......@@ -861,12 +858,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
861858 }
862859
863860 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;
865862 const sect = &seg.sections.items[idx];
866863 sect.offset = self.bss_file_offset;
867864 }
868865 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;
870867 const sect = &seg.sections.items[idx];
871868 sect.offset = self.tlv_bss_file_offset;
872869 }
......@@ -942,13 +939,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
942939 }
943940
944941 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;
946943 const sect = &seg.sections.items[idx];
947944 self.bss_file_offset = sect.offset;
948945 sect.offset = 0;
949946 }
950947 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;
952949 const sect = &seg.sections.items[idx];
953950 self.tlv_bss_file_offset = sect.offset;
954951 sect.offset = 0;
......@@ -1865,7 +1862,7 @@ pub fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment:
18651862}
18661863
18671864pub 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;
18691866 const sect = seg.sections.items[match.sect];
18701867 const sym = self.locals.items[atom.local_sym_index];
18711868 const file_offset = sect.offset + sym.n_value - sect.addr;
......@@ -1885,7 +1882,7 @@ fn allocateLocals(self: *MachO) !void {
18851882 }
18861883
18871884 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;
18891886 const sect = seg.sections.items[match.sect];
18901887 var base_vaddr = sect.addr;
18911888
......@@ -1976,7 +1973,7 @@ fn writeAllAtoms(self: *MachO) !void {
19761973 var it = self.atoms.iterator();
19771974 while (it.next()) |entry| {
19781975 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;
19801977 const sect = seg.sections.items[match.sect];
19811978 var atom: *Atom = entry.value_ptr.*;
19821979
......@@ -2028,7 +2025,7 @@ fn writeAtoms(self: *MachO) !void {
20282025 var it = self.atoms.iterator();
20292026 while (it.next()) |entry| {
20302027 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;
20322029 const sect = seg.sections.items[match.sect];
20332030 var atom: *Atom = entry.value_ptr.*;
20342031
......@@ -2992,7 +2989,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
29922989
29932990 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;
29962993 const sect = seg.sections.items[match.sect];
29972994 const metadata = try section_metadata.getOrPut(match);
29982995 if (!metadata.found_existing) {
......@@ -3043,7 +3040,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
30433040 while (it.next()) |entry| {
30443041 const match = entry.key_ptr.*;
30453042 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;
30473044 const sect = &seg.sections.items[match.sect];
30483045 log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{
30493046 sect.segName(),
......@@ -3067,7 +3064,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
30673064 self.data_segment_cmd_index,
30683065 }) |maybe_seg_id| {
30693066 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
30723069 for (seg.sections.items) |sect, sect_id| {
30733070 const match = MatchingSection{
......@@ -3137,7 +3134,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
31373134fn addLoadDylibLC(self: *MachO, id: u16) !void {
31383135 const dylib = self.dylibs.items[id];
31393136 const dylib_id = dylib.id orelse unreachable;
3140 var dylib_cmd = try commands.createLoadDylibCommand(
3137 var dylib_cmd = try macho.createLoadDylibCommand(
31413138 self.base.allocator,
31423139 dylib_id.name,
31433140 dylib_id.timestamp,
......@@ -3145,7 +3142,7 @@ fn addLoadDylibLC(self: *MachO, id: u16) !void {
31453142 dylib_id.compatibility_version,
31463143 );
31473144 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 });
31493146 self.load_commands_dirty = true;
31503147}
31513148
......@@ -3153,7 +3150,7 @@ fn addCodeSignatureLC(self: *MachO) !void {
31533150 if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return;
31543151 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
31553152 try self.load_commands.append(self.base.allocator, .{
3156 .LinkeditData = .{
3153 .linkedit_data = .{
31573154 .cmd = macho.LC_CODE_SIGNATURE,
31583155 .cmdsize = @sizeOf(macho.linkedit_data_command),
31593156 .dataoff = 0,
......@@ -3168,7 +3165,7 @@ fn setEntryPoint(self: *MachO) !void {
31683165
31693166 // TODO we should respect the -entry flag passed in by the user to set a custom
31703167 // 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;
31723169 const n_strx = self.strtab_dir.getKeyAdapted(@as([]const u8, "_main"), StringIndexAdapter{
31733170 .bytes = &self.strtab,
31743171 }) orelse {
......@@ -3178,7 +3175,7 @@ fn setEntryPoint(self: *MachO) !void {
31783175 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
31793176 assert(resolv.where == .global);
31803177 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;
31823179 ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr);
31833180 ec.stacksize = self.base.options.stack_size_override orelse 0;
31843181 self.entry_addr = sym.n_value;
......@@ -3875,7 +3872,7 @@ fn populateMissingMetadata(self: *MachO) !void {
38753872 if (self.pagezero_segment_cmd_index == null) {
38763873 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
38773874 try self.load_commands.append(self.base.allocator, .{
3878 .Segment = .{
3875 .segment = .{
38793876 .inner = .{
38803877 .segname = makeStaticString("__PAGEZERO"),
38813878 .vmsize = pagezero_vmsize,
......@@ -3896,7 +3893,7 @@ fn populateMissingMetadata(self: *MachO) !void {
38963893 break :blk needed_size;
38973894 } else 0;
38983895 try self.load_commands.append(self.base.allocator, .{
3899 .Segment = .{
3896 .segment = .{
39003897 .inner = .{
39013898 .segname = makeStaticString("__TEXT"),
39023899 .vmaddr = pagezero_vmsize,
......@@ -4000,7 +3997,7 @@ fn populateMissingMetadata(self: *MachO) !void {
40003997 });
40013998 }
40023999 try self.load_commands.append(self.base.allocator, .{
4003 .Segment = .{
4000 .segment = .{
40044001 .inner = .{
40054002 .segname = makeStaticString("__DATA_CONST"),
40064003 .vmaddr = vmaddr,
......@@ -4049,7 +4046,7 @@ fn populateMissingMetadata(self: *MachO) !void {
40494046 });
40504047 }
40514048 try self.load_commands.append(self.base.allocator, .{
4052 .Segment = .{
4049 .segment = .{
40534050 .inner = .{
40544051 .segname = makeStaticString("__DATA"),
40554052 .vmaddr = vmaddr,
......@@ -4133,7 +4130,7 @@ fn populateMissingMetadata(self: *MachO) !void {
41334130 .flags = macho.S_THREAD_LOCAL_ZEROFILL,
41344131 },
41354132 );
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;
41374134 const sect = seg.sections.items[self.tlv_bss_section_index.?];
41384135 self.tlv_bss_file_offset = sect.offset;
41394136 }
......@@ -4150,7 +4147,7 @@ fn populateMissingMetadata(self: *MachO) !void {
41504147 .flags = macho.S_ZEROFILL,
41514148 },
41524149 );
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;
41544151 const sect = seg.sections.items[self.bss_section_index.?];
41554152 self.bss_file_offset = sect.offset;
41564153 }
......@@ -4166,7 +4163,7 @@ fn populateMissingMetadata(self: *MachO) !void {
41664163 log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});
41674164 }
41684165 try self.load_commands.append(self.base.allocator, .{
4169 .Segment = .{
4166 .segment = .{
41704167 .inner = .{
41714168 .segname = makeStaticString("__LINKEDIT"),
41724169 .vmaddr = vmaddr,
......@@ -4182,7 +4179,7 @@ fn populateMissingMetadata(self: *MachO) !void {
41824179 if (self.dyld_info_cmd_index == null) {
41834180 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
41844181 try self.load_commands.append(self.base.allocator, .{
4185 .DyldInfoOnly = .{
4182 .dyld_info_only = .{
41864183 .cmd = macho.LC_DYLD_INFO_ONLY,
41874184 .cmdsize = @sizeOf(macho.dyld_info_command),
41884185 .rebase_off = 0,
......@@ -4203,7 +4200,7 @@ fn populateMissingMetadata(self: *MachO) !void {
42034200 if (self.symtab_cmd_index == null) {
42044201 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
42054202 try self.load_commands.append(self.base.allocator, .{
4206 .Symtab = .{
4203 .symtab = .{
42074204 .cmd = macho.LC_SYMTAB,
42084205 .cmdsize = @sizeOf(macho.symtab_command),
42094206 .symoff = 0,
......@@ -4218,7 +4215,7 @@ fn populateMissingMetadata(self: *MachO) !void {
42184215 if (self.dysymtab_cmd_index == null) {
42194216 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
42204217 try self.load_commands.append(self.base.allocator, .{
4221 .Dysymtab = .{
4218 .dysymtab = .{
42224219 .cmd = macho.LC_DYSYMTAB,
42234220 .cmdsize = @sizeOf(macho.dysymtab_command),
42244221 .ilocalsym = 0,
......@@ -4251,7 +4248,7 @@ fn populateMissingMetadata(self: *MachO) !void {
42514248 @sizeOf(macho.dylinker_command) + mem.sliceTo(default_dyld_path, 0).len,
42524249 @sizeOf(u64),
42534250 ));
4254 var dylinker_cmd = commands.emptyGenericCommandWithData(macho.dylinker_command{
4251 var dylinker_cmd = macho.emptyGenericCommandWithData(macho.dylinker_command{
42554252 .cmd = macho.LC_LOAD_DYLINKER,
42564253 .cmdsize = cmdsize,
42574254 .name = @sizeOf(macho.dylinker_command),
......@@ -4259,14 +4256,14 @@ fn populateMissingMetadata(self: *MachO) !void {
42594256 dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name);
42604257 mem.set(u8, dylinker_cmd.data, 0);
42614258 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 });
42634260 self.load_commands_dirty = true;
42644261 }
42654262
42664263 if (self.main_cmd_index == null and self.base.options.output_mode == .Exe) {
42674264 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
42684265 try self.load_commands.append(self.base.allocator, .{
4269 .Main = .{
4266 .main = .{
42704267 .cmd = macho.LC_MAIN,
42714268 .cmdsize = @sizeOf(macho.entry_point_command),
42724269 .entryoff = 0x0,
......@@ -4286,7 +4283,7 @@ fn populateMissingMetadata(self: *MachO) !void {
42864283 std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };
42874284 const compat_version = self.base.options.compatibility_version orelse
42884285 std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };
4289 var dylib_cmd = try commands.createLoadDylibCommand(
4286 var dylib_cmd = try macho.createLoadDylibCommand(
42904287 self.base.allocator,
42914288 install_name,
42924289 2,
......@@ -4295,14 +4292,14 @@ fn populateMissingMetadata(self: *MachO) !void {
42954292 );
42964293 errdefer dylib_cmd.deinit(self.base.allocator);
42974294 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 });
42994296 self.load_commands_dirty = true;
43004297 }
43014298
43024299 if (self.source_version_cmd_index == null) {
43034300 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
43044301 try self.load_commands.append(self.base.allocator, .{
4305 .SourceVersion = .{
4302 .source_version = .{
43064303 .cmd = macho.LC_SOURCE_VERSION,
43074304 .cmdsize = @sizeOf(macho.source_version_command),
43084305 .version = 0x0,
......@@ -4329,7 +4326,7 @@ fn populateMissingMetadata(self: *MachO) !void {
43294326 break :blk sdk_version;
43304327 } else platform_version;
43314328 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{
43334330 .cmd = macho.LC_BUILD_VERSION,
43344331 .cmdsize = cmdsize,
43354332 .platform = switch (self.base.options.target.os.tag) {
......@@ -4350,7 +4347,7 @@ fn populateMissingMetadata(self: *MachO) !void {
43504347 cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command));
43514348 mem.set(u8, cmd.data, 0);
43524349 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 });
43544351 self.load_commands_dirty = true;
43554352 }
43564353
......@@ -4362,14 +4359,14 @@ fn populateMissingMetadata(self: *MachO) !void {
43624359 .uuid = undefined,
43634360 };
43644361 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 });
43664363 self.load_commands_dirty = true;
43674364 }
43684365
43694366 if (self.function_starts_cmd_index == null) {
43704367 self.function_starts_cmd_index = @intCast(u16, self.load_commands.items.len);
43714368 try self.load_commands.append(self.base.allocator, .{
4372 .LinkeditData = .{
4369 .linkedit_data = .{
43734370 .cmd = macho.LC_FUNCTION_STARTS,
43744371 .cmdsize = @sizeOf(macho.linkedit_data_command),
43754372 .dataoff = 0,
......@@ -4382,7 +4379,7 @@ fn populateMissingMetadata(self: *MachO) !void {
43824379 if (self.data_in_code_cmd_index == null) {
43834380 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
43844381 try self.load_commands.append(self.base.allocator, .{
4385 .LinkeditData = .{
4382 .linkedit_data = .{
43864383 .cmd = macho.LC_DATA_IN_CODE,
43874384 .cmdsize = @sizeOf(macho.linkedit_data_command),
43884385 .dataoff = 0,
......@@ -4396,8 +4393,8 @@ fn populateMissingMetadata(self: *MachO) !void {
43964393}
43974394
43984395fn allocateTextSegment(self: *MachO) !void {
4399 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4400 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
4396 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment;
4397 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].segment.inner.vmsize;
44014398 seg.inner.fileoff = 0;
44024399 seg.inner.vmaddr = base_vmaddr;
44034400
......@@ -4433,30 +4430,30 @@ fn allocateTextSegment(self: *MachO) !void {
44334430}
44344431
44354432fn allocateDataConstSegment(self: *MachO) !void {
4436 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4437 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4433 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
4434 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;
44384435 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
44394436 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
44404437 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
44414438}
44424439
44434440fn allocateDataSegment(self: *MachO) !void {
4444 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4445 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4441 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment;
4442 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment;
44464443 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
44474444 seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;
44484445 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
44494446}
44504447
44514448fn allocateLinkeditSegment(self: *MachO) void {
4452 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4453 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4449 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
4450 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;
44544451 seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;
44554452 seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;
44564453}
44574454
44584455fn 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
44614458 // Allocate the sections according to their alignment at the beginning of the segment.
44624459 var start: u64 = offset;
......@@ -4488,7 +4485,7 @@ fn initSection(
44884485 alignment: u32,
44894486 opts: InitSectionOpts,
44904487) !u16 {
4491 const seg = &self.load_commands.items[segment_id].Segment;
4488 const seg = &self.load_commands.items[segment_id].segment;
44924489 var sect = macho.section_64{
44934490 .sectname = makeStaticString(sectname),
44944491 .segname = seg.inner.segname,
......@@ -4532,7 +4529,7 @@ fn initSection(
45324529}
45334530
45344531fn 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;
45364533 if (seg.sections.items.len == 0) {
45374534 return if (start) |v| v else seg.inner.fileoff;
45384535 }
......@@ -4542,7 +4539,7 @@ fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u64) u64
45424539}
45434540
45444541fn 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;
45464543 const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);
45474544 assert(new_seg_size > seg.inner.filesize);
45484545 const offset_amt = new_seg_size - seg.inner.filesize;
......@@ -4564,13 +4561,13 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
45644561 // TODO We should probably nop the expanded by distance, or put 0s.
45654562
45664563 // 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;
45684565 const new_filesize = offset_amt + ledit_seg.inner.fileoff + ledit_seg.inner.filesize;
45694566 try self.base.file.?.pwriteAll(&[_]u8{0}, new_filesize - 1);
45704567
45714568 var next: usize = seg_id + 1;
45724569 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;
45744571 _ = try self.base.file.?.copyRangeAll(
45754572 next_seg.inner.fileoff,
45764573 self.base.file.?,
......@@ -4613,7 +4610,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
46134610 const tracy = trace(@src());
46144611 defer tracy.end();
46154612
4616 const seg = &self.load_commands.items[match.seg].Segment;
4613 const seg = &self.load_commands.items[match.seg].segment;
46174614 const sect = &seg.sections.items[match.sect];
46184615
46194616 const alignment = try math.powi(u32, 2, sect.@"align");
......@@ -4684,7 +4681,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
46844681}
46854682
46864683fn 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;
46884685 assert(start >= seg.inner.fileoff);
46894686 var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize;
46904687 if (start > min_pos) return 0;
......@@ -4696,7 +4693,7 @@ fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 {
46964693}
46974694
46984695fn 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;
47004697 var max_alignment: u32 = 1;
47014698 var next = start_sect_id;
47024699 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
47114708 const tracy = trace(@src());
47124709 defer tracy.end();
47134710
4714 const seg = &self.load_commands.items[match.seg].Segment;
4711 const seg = &self.load_commands.items[match.seg].segment;
47154712 const sect = &seg.sections.items[match.sect];
47164713 var free_list = self.atom_free_lists.get(match).?;
47174714 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
48154812}
48164813
48174814fn 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;
48194816 const sect = &seg.sections.items[match.sect];
48204817 const alignment = try math.powi(u32, 2, atom.alignment);
48214818 sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size;
......@@ -4862,11 +4859,11 @@ const NextSegmentAddressAndOffset = struct {
48624859fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
48634860 var prev_segment_idx: ?usize = null; // We use optional here for safety.
48644861 for (self.load_commands.items) |cmd, i| {
4865 if (cmd == .Segment) {
4862 if (cmd == .segment) {
48664863 prev_segment_idx = i;
48674864 }
48684865 }
4869 const prev_segment = self.load_commands.items[prev_segment_idx.?].Segment;
4866 const prev_segment = self.load_commands.items[prev_segment_idx.?].segment;
48704867 const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize;
48714868 const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize;
48724869 return .{
......@@ -4885,7 +4882,7 @@ fn sortSections(self: *MachO) !void {
48854882
48864883 {
48874884 // __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;
48894886 var sections = seg.sections.toOwnedSlice(self.base.allocator);
48904887 defer self.base.allocator.free(sections);
48914888 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
......@@ -4917,7 +4914,7 @@ fn sortSections(self: *MachO) !void {
49174914
49184915 {
49194916 // __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;
49214918 var sections = seg.sections.toOwnedSlice(self.base.allocator);
49224919 defer self.base.allocator.free(sections);
49234920 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
......@@ -4944,7 +4941,7 @@ fn sortSections(self: *MachO) !void {
49444941
49454942 {
49464943 // __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;
49484945 var sections = seg.sections.toOwnedSlice(self.base.allocator);
49494946 defer self.base.allocator.free(sections);
49504947 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
......@@ -5000,7 +4997,7 @@ fn sortSections(self: *MachO) !void {
50004997 {
50014998 // Create new section ordinals.
50024999 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;
50045001 for (text_seg.sections.items) |_, sect_id| {
50055002 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
50065003 .seg = self.text_segment_cmd_index.?,
......@@ -5008,7 +5005,7 @@ fn sortSections(self: *MachO) !void {
50085005 });
50095006 assert(!res.found_existing);
50105007 }
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;
50125009 for (data_const_seg.sections.items) |_, sect_id| {
50135010 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
50145011 .seg = self.data_const_segment_cmd_index.?,
......@@ -5016,7 +5013,7 @@ fn sortSections(self: *MachO) !void {
50165013 });
50175014 assert(!res.found_existing);
50185015 }
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;
50205017 for (data_seg.sections.items) |_, sect_id| {
50215018 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
50225019 .seg = self.data_segment_cmd_index.?,
......@@ -5041,9 +5038,9 @@ fn updateSectionOrdinals(self: *MachO) !void {
50415038
50425039 var new_ordinal: u8 = 0;
50435040 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| {
50475044 const match = MatchingSection{
50485045 .seg = @intCast(u16, lc_id),
50495046 .sect = @intCast(u16, sect_id),
......@@ -5086,7 +5083,7 @@ fn writeDyldInfoData(self: *MachO) !void {
50865083
50875084 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
50915088 while (true) {
50925089 const sym = self.locals.items[atom.local_sym_index];
......@@ -5156,7 +5153,7 @@ fn writeDyldInfoData(self: *MachO) !void {
51565153 {
51575154 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
51585155 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;
51605157 const base_address = text_segment.inner.vmaddr;
51615158
51625159 for (self.globals.items) |sym| {
......@@ -5174,8 +5171,8 @@ fn writeDyldInfoData(self: *MachO) !void {
51745171 try trie.finalize(self.base.allocator);
51755172 }
51765173
5177 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5178 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
5174 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5175 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].dyld_info_only;
51795176 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
51805177 const bind_size = try bind.bindInfoSize(bind_pointers.items);
51815178 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
......@@ -5245,7 +5242,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
52455242 .sect = self.la_symbol_ptr_section_index.?,
52465243 }).?;
52475244 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;
52495246 break :blk seg.inner.vmaddr;
52505247 };
52515248
......@@ -5309,7 +5306,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
53095306 }
53105307
53115308 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;
53135310 break :blk seg.sections.items[self.stub_helper_section_index.?];
53145311 };
53155312 const stub_offset: u4 = switch (self.base.options.target.cpu.arch) {
......@@ -5350,7 +5347,7 @@ fn writeFunctionStarts(self: *MachO) !void {
53505347 var offsets = std.ArrayList(u32).init(self.base.allocator);
53515348 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;
53545351 var last_off: u32 = 0;
53555352
53565353 while (true) {
......@@ -5407,8 +5404,8 @@ fn writeFunctionStarts(self: *MachO) !void {
54075404 }
54085405
54095406 const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64)));
5410 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5411 const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].LinkeditData;
5407 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5408 const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].linkedit_data;
54125409
54135410 fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
54145411 fn_cmd.datasize = needed_size;
......@@ -5441,7 +5438,7 @@ fn writeDices(self: *MachO) !void {
54415438 atom = prev;
54425439 }
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;
54455442 const text_sect = text_seg.sections.items[self.text_section_index.?];
54465443
54475444 while (true) {
......@@ -5465,8 +5462,8 @@ fn writeDices(self: *MachO) !void {
54655462 } else break;
54665463 }
54675464
5468 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5469 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
5465 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5466 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data;
54705467 const needed_size = @intCast(u32, buf.items.len);
54715468
54725469 dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
......@@ -5486,8 +5483,8 @@ fn writeSymbolTable(self: *MachO) !void {
54865483 const tracy = trace(@src());
54875484 defer tracy.end();
54885485
5489 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5490 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
5486 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5487 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
54915488 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
54925489
54935490 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
......@@ -5591,18 +5588,18 @@ fn writeSymbolTable(self: *MachO) !void {
55915588 seg.inner.filesize += locals_size + exports_size + undefs_size;
55925589
55935590 // 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;
55955592 dysymtab.nlocalsym = @intCast(u32, nlocals);
55965593 dysymtab.iextdefsym = dysymtab.nlocalsym;
55975594 dysymtab.nextdefsym = @intCast(u32, nexports);
55985595 dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;
55995596 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;
56025599 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;
56045601 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;
56065603 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
56075604
56085605 const nstubs = @intCast(u32, self.stubs_map.keys().len);
......@@ -5665,8 +5662,8 @@ fn writeStringTable(self: *MachO) !void {
56655662 const tracy = trace(@src());
56665663 defer tracy.end();
56675664
5668 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5669 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
5665 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5666 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
56705667 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
56715668 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
56725669 seg.inner.filesize += symtab.strsize;
......@@ -5686,7 +5683,7 @@ fn writeLinkeditSegment(self: *MachO) !void {
56865683 const tracy = trace(@src());
56875684 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;
56905687 seg.inner.filesize = 0;
56915688
56925689 try self.writeDyldInfoData();
......@@ -5702,8 +5699,8 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
57025699 const tracy = trace(@src());
57035700 defer tracy.end();
57045701
5705 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
5706 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
5702 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5703 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
57075704 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
57085705 const needed_size = CodeSignature.calcCodeSignaturePaddingSize(
57095706 self.base.options.emit.?.sub_path,
......@@ -5729,8 +5726,8 @@ fn writeCodeSignature(self: *MachO) !void {
57295726 const tracy = trace(@src());
57305727 defer tracy.end();
57315728
5732 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
5733 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
5729 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;
5730 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
57345731
57355732 var code_sig: CodeSignature = .{};
57365733 defer code_sig.deinit(self.base.allocator);
......@@ -5955,7 +5952,7 @@ fn snapshotState(self: *MachO) !void {
59555952 var nodes = std.ArrayList(Snapshot.Node).init(arena);
59565953
59575954 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;
59595956 const sect = seg.sections.items[key.sect];
59605957 const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() });
59615958 try nodes.append(.{
......@@ -6028,12 +6025,12 @@ fn snapshotState(self: *MachO) !void {
60286025 const is_tlv = is_tlv: {
60296026 const source_sym = self.locals.items[atom.local_sym_index];
60306027 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;
60326029 const match_sect = match_seg.sections.items[match.sect];
60336030 break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
60346031 };
60356032 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;
60376034 const base_address = inner: {
60386035 if (self.tlv_data_section_index) |i| {
60396036 break :inner match_seg.sections.items[i].addr;
......@@ -6193,7 +6190,7 @@ fn logSymtab(self: MachO) void {
61936190
61946191fn logSectionOrdinals(self: MachO) void {
61956192 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;
61976194 const sect = seg.sections.items[match.sect];
61986195 log.debug("ord {d}: {d},{d} => {s},{s}", .{
61996196 i + 1,
src/link/MachO/Atom.zig+7-7
......@@ -341,7 +341,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
341341 if (rel.r_extern == 0) {
342342 const sect_id = @intCast(u16, rel.r_symbolnum - 1);
343343 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;
345345 const sect = seg.sections.items[sect_id];
346346 const match = (try context.macho_file.getMatchingSection(sect)) orelse
347347 unreachable;
......@@ -397,7 +397,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
397397 else
398398 mem.readIntLittle(i32, self.code.items[offset..][0..4]);
399399 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;
401401 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
402402 addend -= @intCast(i64, target_sect_base_addr);
403403 }
......@@ -424,7 +424,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
424424 else
425425 mem.readIntLittle(i32, self.code.items[offset..][0..4]);
426426 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;
428428 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
429429 addend -= @intCast(i64, target_sect_base_addr);
430430 }
......@@ -446,7 +446,7 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
446446 if (rel.r_extern == 0) {
447447 // Note for the future self: when r_extern == 0, we should subtract correction from the
448448 // 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;
450450 const target_sect_base_addr = seg.sections.items[rel.r_symbolnum - 1].addr;
451451 addend += @intCast(i64, context.base_addr + offset + 4) -
452452 @intCast(i64, target_sect_base_addr);
......@@ -489,7 +489,7 @@ fn addPtrBindingOrRebase(
489489 .local => {
490490 const source_sym = context.macho_file.locals.items[self.local_sym_index];
491491 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;
493493 const sect = seg.sections.items[match.sect];
494494 const sect_type = sect.type_();
495495
......@@ -704,7 +704,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
704704 const is_tlv = is_tlv: {
705705 const source_sym = macho_file.locals.items[self.local_sym_index];
706706 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;
708708 const sect = seg.sections.items[match.sect];
709709 break :is_tlv sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
710710 };
......@@ -714,7 +714,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
714714 // defined TLV template init section in the following order:
715715 // * wrt to __thread_data if defined, then
716716 // * 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;
718718 const base_address = inner: {
719719 if (macho_file.tlv_data_section_index) |i| {
720720 break :inner seg.sections.items[i].addr;
src/link/MachO/DebugSymbols.zig+83-49
......@@ -12,15 +12,12 @@ const leb = std.leb;
1212const Allocator = mem.Allocator;
1313
1414const build_options = @import("build_options");
15const commands = @import("commands.zig");
1615const trace = @import("../../tracy.zig").trace;
17const LoadCommand = commands.LoadCommand;
1816const Module = @import("../../Module.zig");
1917const Type = @import("../../type.zig").Type;
2018const link = @import("../../link.zig");
2119const MachO = @import("../MachO.zig");
2220const TextBlock = MachO.TextBlock;
23const SegmentCommand = commands.SegmentCommand;
2421const SrcFn = MachO.SrcFn;
2522const makeStaticString = MachO.makeStaticString;
2623const padToIdeal = MachO.padToIdeal;
......@@ -31,7 +28,7 @@ base: *MachO,
3128file: fs.File,
3229
3330/// Table of all load commands
34load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
31load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
3532/// __PAGEZERO segment
3633pagezero_segment_cmd_index: ?u16 = null,
3734/// __TEXT segment
......@@ -113,7 +110,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
113110 }
114111 if (self.symtab_cmd_index == null) {
115112 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;
117114 const symtab_size = base_cmd.nsyms * @sizeOf(macho.nlist_64);
118115 const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64));
119116
......@@ -124,7 +121,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
124121 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + base_cmd.strsize });
125122
126123 try self.load_commands.append(allocator, .{
127 .Symtab = .{
124 .symtab = .{
128125 .cmd = macho.LC_SYMTAB,
129126 .cmdsize = @sizeOf(macho.symtab_command),
130127 .symoff = @intCast(u32, symtab_off),
......@@ -138,48 +135,48 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
138135 }
139136 if (self.pagezero_segment_cmd_index == null) {
140137 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;
142139 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 });
144141 self.load_commands_dirty = true;
145142 }
146143 if (self.text_segment_cmd_index == null) {
147144 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;
149146 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 });
151148 self.load_commands_dirty = true;
152149 }
153150 if (self.data_const_segment_cmd_index == null) outer: {
154151 if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional
155152 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;
157154 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 });
159156 self.load_commands_dirty = true;
160157 }
161158 if (self.data_segment_cmd_index == null) outer: {
162159 if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional
163160 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;
165162 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 });
167164 self.load_commands_dirty = true;
168165 }
169166 if (self.linkedit_segment_cmd_index == null) {
170167 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;
172169 var cmd = try self.copySegmentCommand(allocator, base_cmd);
173170 cmd.inner.vmsize = self.linkedit_size;
174171 cmd.inner.fileoff = self.linkedit_off;
175172 cmd.inner.filesize = self.linkedit_size;
176 try self.load_commands.append(allocator, .{ .Segment = cmd });
173 try self.load_commands.append(allocator, .{ .segment = cmd });
177174 self.load_commands_dirty = true;
178175 }
179176 if (self.dwarf_segment_cmd_index == null) {
180177 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;
183180 const ideal_size: u16 = 200 + 128 + 160 + 250;
184181 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), page_size);
185182 const off = linkedit.inner.fileoff + linkedit.inner.filesize;
......@@ -188,7 +185,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
188185 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ off, off + needed_size });
189186
190187 try self.load_commands.append(allocator, .{
191 .Segment = .{
188 .segment = .{
192189 .inner = .{
193190 .segname = makeStaticString("__DWARF"),
194191 .vmaddr = vmaddr,
......@@ -228,7 +225,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
228225}
229226
230227fn 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;
232229 var sect = macho.section_64{
233230 .sectname = makeStaticString(sectname),
234231 .segname = seg.inner.segname,
......@@ -236,7 +233,7 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
236233 .@"align" = alignment,
237234 };
238235 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
241238 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
268265 return index;
269266}
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
271290pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Options) !void {
272291 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the
273292 // Zig source code.
......@@ -275,7 +294,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
275294 const init_len_size: usize = 4;
276295
277296 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;
279298 const debug_abbrev_sect = &dwarf_segment.sections.items[self.debug_abbrev_section_index.?];
280299
281300 // 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
320339 };
321340
322341 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);
324343 if (needed_size > allocated_size) {
325344 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);
327346 debug_abbrev_sect.offset = @intCast(u32, offset);
328347 debug_abbrev_sect.addr = dwarf_segment.inner.vmaddr + offset - dwarf_segment.inner.fileoff;
329348 }
......@@ -345,7 +364,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
345364 // leave debug_info_header_dirty=true.
346365 const first_dbg_info_decl = self.dbg_info_decl_first orelse break :debug_info;
347366 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;
349368 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
350369
351370 // 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
372391 const producer_strp = try self.makeDebugString(allocator, link.producer_string);
373392 // Currently only one compilation unit is supported, so the address range is simply
374393 // 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;
376395 const text_section = text_segment.sections.items[self.text_section_index.?];
377396 const low_pc = text_section.addr;
378397 const high_pc = text_section.addr + text_section.size;
......@@ -399,7 +418,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
399418 }
400419
401420 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;
403422 const debug_aranges_sect = &dwarf_segment.sections.items[self.debug_aranges_section_index.?];
404423
405424 // 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
426445
427446 // Currently only one compilation unit is supported, so the address range is simply
428447 // 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;
430449 const text_section = text_segment.sections.items[self.text_section_index.?];
431450 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.addr);
432451 mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), text_section.size);
......@@ -442,10 +461,10 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
442461 mem.writeIntLittle(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len));
443462
444463 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);
446465 if (needed_size > allocated_size) {
447466 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);
449468 debug_aranges_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;
450469 debug_aranges_sect.offset = @intCast(u32, new_offset);
451470 }
......@@ -467,7 +486,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
467486 const dbg_line_prg_end = self.getDebugLineProgramEnd();
468487 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;
471490 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];
472491
473492 // 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
540559 self.debug_line_header_dirty = false;
541560 }
542561 {
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;
544563 const debug_strtab_sect = &dwarf_segment.sections.items[self.debug_str_section_index.?];
545564 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);
547566 const needed_size = self.debug_string_table.items.len;
548567
549568 if (needed_size > allocated_size) {
550569 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);
552571 debug_strtab_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;
553572 debug_strtab_sect.offset = @intCast(u32, new_offset);
554573 }
......@@ -588,8 +607,12 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {
588607 self.file.close();
589608}
590609
591fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: SegmentCommand) !SegmentCommand {
592 var cmd = SegmentCommand{
610fn copySegmentCommand(
611 self: *DebugSymbols,
612 allocator: Allocator,
613 base_cmd: macho.SegmentCommand,
614) !macho.SegmentCommand {
615 var cmd = macho.SegmentCommand{
593616 .inner = .{
594617 .segname = undefined,
595618 .cmdsize = base_cmd.inner.cmdsize,
......@@ -633,7 +656,7 @@ fn copySegmentCommand(self: *DebugSymbols, allocator: Allocator, base_cmd: Segme
633656}
634657
635658fn 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;
637660 var file_size: u64 = 0;
638661 for (dwarf_segment.sections.items) |sect| {
639662 file_size += sect.size;
......@@ -702,7 +725,7 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {
702725 var min_pos: u64 = std.math.maxInt(u64);
703726
704727 if (self.symtab_cmd_index) |idx| {
705 const symtab = self.load_commands.items[idx].Symtab;
728 const symtab = self.load_commands.items[idx].symtab;
706729 if (symtab.symoff >= start and symtab.symoff < min_pos) min_pos = symtab.symoff;
707730 if (symtab.stroff >= start and symtab.stroff < min_pos) min_pos = symtab.stroff;
708731 }
......@@ -710,12 +733,23 @@ fn allocatedSizeLinkedit(self: *DebugSymbols, start: u64) u64 {
710733 return min_pos - start;
711734}
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
713747fn detectAllocCollisionLinkedit(self: *DebugSymbols, start: u64, size: u64) ?u64 {
714748 const end = start + padToIdeal(size);
715749
716750 if (self.symtab_cmd_index) |idx| outer: {
717751 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;
719753 {
720754 // Symbol table
721755 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
......@@ -747,7 +781,7 @@ fn findFreeSpaceLinkedit(self: *DebugSymbols, object_size: u64, min_alignment: u
747781}
748782
749783fn 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;
751785 const nlocals = self.base.locals.items.len;
752786 const nglobals = self.base.globals.items.len;
753787 const nsyms = nlocals + nglobals;
......@@ -780,7 +814,7 @@ pub fn writeLocalSymbol(self: *DebugSymbols, index: usize) !void {
780814 const tracy = trace(@src());
781815 defer tracy.end();
782816 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;
784818 const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;
785819 log.debug("writing local symbol {} at 0x{x}", .{ index, off });
786820 try self.file.pwriteAll(mem.asBytes(&self.base.locals.items[index]), off);
......@@ -792,7 +826,7 @@ fn writeStringTable(self: *DebugSymbols) !void {
792826 const tracy = trace(@src());
793827 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;
796830 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);
797831 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
816850 const func = decl.val.castTag(.function).?.data;
817851 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;
820854 const shdr = &dwarf_segment.sections.items[self.debug_line_section_index.?];
821855 const file_pos = shdr.offset + decl.fn_link.macho.off + getRelocDbgLineOff();
822856 var data: [4]u8 = undefined;
......@@ -982,7 +1016,7 @@ pub fn commitDeclDebugInfo(
9821016 // `TextBlock` and the .debug_info. If you are editing this logic, you
9831017 // 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;
9861020 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];
9871021 const src_fn = &decl.fn_link.macho;
9881022 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
......@@ -1028,8 +1062,8 @@ pub fn commitDeclDebugInfo(
10281062 const last_src_fn = self.dbg_line_fn_last.?;
10291063 const needed_size = last_src_fn.off + last_src_fn.len;
10301064 if (needed_size != debug_line_sect.size) {
1031 if (needed_size > dwarf_segment.allocatedSize(debug_line_sect.offset)) {
1032 const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null);
1065 if (needed_size > self.allocatedSize(debug_line_sect.offset)) {
1066 const new_offset = self.findFreeSpace(needed_size, 1);
10331067 const existing_size = last_src_fn.off;
10341068
10351069 log.debug("moving __debug_line section: {} bytes from 0x{x} to 0x{x}", .{
......@@ -1151,7 +1185,7 @@ fn updateDeclDebugInfoAllocation(
11511185 // `SrcFn` and the line number programs. If you are editing this logic, you
11521186 // 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;
11551189 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
11561190 text_block.dbg_info_len = len;
11571191 if (self.dbg_info_decl_last) |last| blk: {
......@@ -1202,15 +1236,15 @@ fn writeDeclDebugInfo(self: *DebugSymbols, text_block: *TextBlock, dbg_info_buf:
12021236 // `SrcFn` and the line number programs. If you are editing this logic, you
12031237 // 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;
12061240 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
12071241
12081242 const last_decl = self.dbg_info_decl_last.?;
12091243 // +1 for a trailing zero to end the children of the decl tag.
12101244 const needed_size = last_decl.dbg_info_off + last_decl.dbg_info_len + 1;
12111245 if (needed_size != debug_info_sect.size) {
1212 if (needed_size > dwarf_segment.allocatedSize(debug_info_sect.offset)) {
1213 const new_offset = dwarf_segment.findFreeSpace(needed_size, 1, null);
1246 if (needed_size > self.allocatedSize(debug_info_sect.offset)) {
1247 const new_offset = self.findFreeSpace(needed_size, 1);
12141248 const existing_size = last_decl.dbg_info_off;
12151249
12161250 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;
99const math = std.math;
1010const mem = std.mem;
1111const fat = @import("fat.zig");
12const commands = @import("commands.zig");
1312
1413const Allocator = mem.Allocator;
1514const LibStub = @import("../tapi.zig").LibStub;
16const LoadCommand = commands.LoadCommand;
1715const MachO = @import("../MachO.zig");
1816
1917file: fs.File,
......@@ -25,7 +23,7 @@ header: ?macho.mach_header_64 = null,
2523// an offset within a file if we are linking against a fat lib
2624library_offset: u64 = 0,
2725
28load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
26load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
2927
3028symtab_cmd_index: ?u16 = null,
3129dysymtab_cmd_index: ?u16 = null,
......@@ -53,7 +51,7 @@ pub const Id = struct {
5351 };
5452 }
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 {
5755 const dylib = lc.inner.dylib;
5856 const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]);
5957 const name = try allocator.dupe(u8, mem.sliceTo(dylib_name, 0));
......@@ -177,7 +175,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende
177175
178176 var i: u16 = 0;
179177 while (i < self.header.?.ncmds) : (i += 1) {
180 var cmd = try LoadCommand.read(allocator, reader);
178 var cmd = try macho.LoadCommand.read(allocator, reader);
181179 switch (cmd.cmd()) {
182180 macho.LC_SYMTAB => {
183181 self.symtab_cmd_index = i;
......@@ -191,7 +189,7 @@ fn readLoadCommands(self: *Dylib, allocator: Allocator, reader: anytype, depende
191189 macho.LC_REEXPORT_DYLIB => {
192190 if (should_lookup_reexports) {
193191 // Parse install_name to dependent dylib.
194 var id = try Id.fromLoadCommand(allocator, cmd.Dylib);
192 var id = try Id.fromLoadCommand(allocator, cmd.dylib);
195193 try dependent_libs.writeItem(id);
196194 }
197195 },
......@@ -209,12 +207,12 @@ fn parseId(self: *Dylib, allocator: Allocator) !void {
209207 self.id = try Id.default(allocator, self.name);
210208 return;
211209 };
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);
213211}
214212
215213fn parseSymbols(self: *Dylib, allocator: Allocator) !void {
216214 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
219217 var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
220218 defer allocator.free(symtab);
src/link/MachO/Object.zig+11-12
......@@ -15,7 +15,6 @@ const trace = @import("../../tracy.zig").trace;
1515
1616const Allocator = mem.Allocator;
1717const Atom = @import("Atom.zig");
18const LoadCommand = @import("commands.zig").LoadCommand;
1918const MachO = @import("../MachO.zig");
2019
2120file: fs.File,
......@@ -25,7 +24,7 @@ file_offset: ?u32 = null,
2524
2625header: ?macho.mach_header_64 = null,
2726
28load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
27load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
2928
3029segment_cmd_index: ?u16 = null,
3130text_section_index: ?u16 = null,
......@@ -268,11 +267,11 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
268267
269268 var i: u16 = 0;
270269 while (i < header.ncmds) : (i += 1) {
271 var cmd = try LoadCommand.read(allocator, reader);
270 var cmd = try macho.LoadCommand.read(allocator, reader);
272271 switch (cmd.cmd()) {
273272 macho.LC_SEGMENT_64 => {
274273 self.segment_cmd_index = i;
275 var seg = cmd.Segment;
274 var seg = cmd.segment;
276275 for (seg.sections.items) |*sect, j| {
277276 const index = @intCast(u16, j);
278277 const segname = sect.segName();
......@@ -305,8 +304,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
305304 },
306305 macho.LC_SYMTAB => {
307306 self.symtab_cmd_index = i;
308 cmd.Symtab.symoff += offset;
309 cmd.Symtab.stroff += offset;
307 cmd.symtab.symoff += offset;
308 cmd.symtab.stroff += offset;
310309 },
311310 macho.LC_DYSYMTAB => {
312311 self.dysymtab_cmd_index = i;
......@@ -316,7 +315,7 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
316315 },
317316 macho.LC_DATA_IN_CODE => {
318317 self.data_in_code_cmd_index = i;
319 cmd.LinkeditData.dataoff += offset;
318 cmd.linkedit_data.dataoff += offset;
320319 },
321320 else => {
322321 log.debug("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
......@@ -382,7 +381,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
382381 const tracy = trace(@src());
383382 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
387386 log.debug("analysing {s}", .{self.name});
388387
......@@ -405,7 +404,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
405404 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
406405 // have to infer the start of undef section in the symtab ourselves.
407406 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;
409408 break :blk dysymtab.iundefsym;
410409 } else blk: {
411410 var iundefsym: usize = sorted_all_nlists.items.len;
......@@ -553,7 +552,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
553552
554553fn parseSymtab(self: *Object, allocator: Allocator) !void {
555554 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
558557 var symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
559558 defer allocator.free(symtab);
......@@ -601,7 +600,7 @@ pub fn parseDebugInfo(self: *Object, allocator: Allocator) !void {
601600
602601pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {
603602 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
606605 var buffer = try allocator.alloc(u8, data_in_code.datasize);
607606 defer allocator.free(buffer);
......@@ -620,7 +619,7 @@ pub fn parseDataInCode(self: *Object, allocator: Allocator) !void {
620619}
621620
622621fn 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;
624623 const sect = seg.sections.items[index];
625624 var buffer = try allocator.alloc(u8, @intCast(usize, sect.size));
626625 _ = 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}