authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-31 18:19:17+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-03 21:19:41+02:00
logf26d5ee7ea97c8fd6e5b2655f845be7e4293930e
treefab17016b079fcd7aaef84672feb469136dcc646
parent4c750016eb9b1c0831cbb0398a4d6ee9dbdc932e

macho: sync with zld

gitrev a2c32e972f8c5adfcda8ed2d99379ae868f59c24 https://github.com/kubkon/zld/commit/a2c32e972f8c5adfcda8ed2d99379ae868f59c24

12 files changed, 2124 insertions(+), 3073 deletions(-)

lib/std/build/CheckObjectStep.zig+47-42
...@@ -283,7 +283,14 @@ fn make(step: *Step) !void {...@@ -283,7 +283,14 @@ fn make(step: *Step) !void {
283283
284 const gpa = self.builder.allocator;284 const gpa = self.builder.allocator;
285 const src_path = self.source.getPath(self.builder);285 const src_path = self.source.getPath(self.builder);
286 const contents = try fs.cwd().readFileAlloc(gpa, src_path, self.max_bytes);286 const contents = try fs.cwd().readFileAllocOptions(
287 gpa,
288 src_path,
289 self.max_bytes,
290 null,
291 @alignOf(u64),
292 null,
293 );
287294
288 const output = switch (self.obj_format) {295 const output = switch (self.obj_format) {
289 .macho => try MachODumper.parseAndDump(contents, .{296 .macho => try MachODumper.parseAndDump(contents, .{
...@@ -370,9 +377,10 @@ const Opts = struct {...@@ -370,9 +377,10 @@ const Opts = struct {
370};377};
371378
372const MachODumper = struct {379const MachODumper = struct {
380 const LoadCommandIterator = macho.LoadCommandIterator;
373 const symtab_label = "symtab";381 const symtab_label = "symtab";
374382
375 fn parseAndDump(bytes: []const u8, opts: Opts) ![]const u8 {383 fn parseAndDump(bytes: []align(@alignOf(u64)) const u8, opts: Opts) ![]const u8 {
376 const gpa = opts.gpa orelse unreachable; // MachO dumper requires an allocator384 const gpa = opts.gpa orelse unreachable; // MachO dumper requires an allocator
377 var stream = std.io.fixedBufferStream(bytes);385 var stream = std.io.fixedBufferStream(bytes);
378 const reader = stream.reader();386 const reader = stream.reader();
...@@ -385,55 +393,54 @@ const MachODumper = struct {...@@ -385,55 +393,54 @@ const MachODumper = struct {
385 var output = std.ArrayList(u8).init(gpa);393 var output = std.ArrayList(u8).init(gpa);
386 const writer = output.writer();394 const writer = output.writer();
387395
388 var load_commands = std.ArrayList(macho.LoadCommand).init(gpa);396 var symtab: []const macho.nlist_64 = undefined;
389 try load_commands.ensureTotalCapacity(hdr.ncmds);397 var strtab: []const u8 = undefined;
390398 var sections = std.ArrayList(macho.section_64).init(gpa);
391 var sections = std.ArrayList(struct { seg: u16, sect: u16 }).init(gpa);399 var imports = std.ArrayList([]const u8).init(gpa);
392 var imports = std.ArrayList(u16).init(gpa);
393
394 var symtab_cmd: ?u16 = null;
395 var i: u16 = 0;
396 while (i < hdr.ncmds) : (i += 1) {
397 var cmd = try macho.LoadCommand.read(gpa, reader);
398 load_commands.appendAssumeCapacity(cmd);
399400
401 var it = LoadCommandIterator{
402 .ncmds = hdr.ncmds,
403 .buffer = bytes[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
404 };
405 var i: usize = 0;
406 while (it.next()) |cmd| {
400 switch (cmd.cmd()) {407 switch (cmd.cmd()) {
401 .SEGMENT_64 => {408 .SEGMENT_64 => {
402 const seg = cmd.segment;409 const seg = cmd.cast(macho.segment_command_64).?;
403 for (seg.sections.items) |_, j| {410 try sections.ensureUnusedCapacity(seg.nsects);
404 try sections.append(.{ .seg = i, .sect = @intCast(u16, j) });411 for (cmd.getSections()) |sect| {
412 sections.appendAssumeCapacity(sect);
405 }413 }
406 },414 },
407 .SYMTAB => {415 .SYMTAB => if (opts.dump_symtab) {
408 symtab_cmd = i;416 const lc = cmd.cast(macho.symtab_command).?;
417 symtab = @ptrCast(
418 [*]const macho.nlist_64,
419 @alignCast(@alignOf(macho.nlist_64), &bytes[lc.symoff]),
420 )[0..lc.nsyms];
421 strtab = bytes[lc.stroff..][0..lc.strsize];
409 },422 },
410 .LOAD_DYLIB,423 .LOAD_DYLIB,
411 .LOAD_WEAK_DYLIB,424 .LOAD_WEAK_DYLIB,
412 .REEXPORT_DYLIB,425 .REEXPORT_DYLIB,
413 => {426 => {
414 try imports.append(i);427 try imports.append(cmd.getDylibPathName());
415 },428 },
416 else => {},429 else => {},
417 }430 }
418431
419 try dumpLoadCommand(cmd, i, writer);432 try dumpLoadCommand(cmd, i, writer);
420 try writer.writeByte('\n');433 try writer.writeByte('\n');
434
435 i += 1;
421 }436 }
422437
423 if (opts.dump_symtab) {438 if (opts.dump_symtab) {
424 const cmd = load_commands.items[symtab_cmd.?].symtab;
425 try writer.writeAll(symtab_label ++ "\n");
426 const strtab = bytes[cmd.stroff..][0..cmd.strsize];
427 const raw_symtab = bytes[cmd.symoff..][0 .. cmd.nsyms * @sizeOf(macho.nlist_64)];
428 const symtab = mem.bytesAsSlice(macho.nlist_64, raw_symtab);
429
430 for (symtab) |sym| {439 for (symtab) |sym| {
431 if (sym.stab()) continue;440 if (sym.stab()) continue;
432 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);441 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);
433 if (sym.sect()) {442 if (sym.sect()) {
434 const map = sections.items[sym.n_sect - 1];443 const sect = sections.items[sym.n_sect - 1];
435 const seg = load_commands.items[map.seg].segment;
436 const sect = seg.sections.items[map.sect];
437 try writer.print("{x} ({s},{s})", .{444 try writer.print("{x} ({s},{s})", .{
438 sym.n_value,445 sym.n_value,
439 sect.segName(),446 sect.segName(),
...@@ -455,9 +462,7 @@ const MachODumper = struct {...@@ -455,9 +462,7 @@ const MachODumper = struct {
455 break :blk "flat lookup";462 break :blk "flat lookup";
456 unreachable;463 unreachable;
457 }464 }
458 const import_id = imports.items[@bitCast(u16, ordinal) - 1];465 const full_path = imports.items[@bitCast(u16, ordinal) - 1];
459 const import = load_commands.items[import_id].dylib;
460 const full_path = mem.sliceTo(import.data, 0);
461 const basename = fs.path.basename(full_path);466 const basename = fs.path.basename(full_path);
462 assert(basename.len > 0);467 assert(basename.len > 0);
463 const ext = mem.lastIndexOfScalar(u8, basename, '.') orelse basename.len;468 const ext = mem.lastIndexOfScalar(u8, basename, '.') orelse basename.len;
...@@ -481,7 +486,7 @@ const MachODumper = struct {...@@ -481,7 +486,7 @@ const MachODumper = struct {
481 return output.toOwnedSlice();486 return output.toOwnedSlice();
482 }487 }
483488
484 fn dumpLoadCommand(lc: macho.LoadCommand, index: u16, writer: anytype) !void {489 fn dumpLoadCommand(lc: macho.LoadCommandIterator.LoadCommand, index: usize, writer: anytype) !void {
485 // print header first490 // print header first
486 try writer.print(491 try writer.print(
487 \\LC {d}492 \\LC {d}
...@@ -491,8 +496,7 @@ const MachODumper = struct {...@@ -491,8 +496,7 @@ const MachODumper = struct {
491496
492 switch (lc.cmd()) {497 switch (lc.cmd()) {
493 .SEGMENT_64 => {498 .SEGMENT_64 => {
494 // TODO dump section headers499 const seg = lc.cast(macho.segment_command_64).?;
495 const seg = lc.segment.inner;
496 try writer.writeByte('\n');500 try writer.writeByte('\n');
497 try writer.print(501 try writer.print(
498 \\segname {s}502 \\segname {s}
...@@ -508,7 +512,7 @@ const MachODumper = struct {...@@ -508,7 +512,7 @@ const MachODumper = struct {
508 seg.filesize,512 seg.filesize,
509 });513 });
510514
511 for (lc.segment.sections.items) |sect| {515 for (lc.getSections()) |sect| {
512 try writer.writeByte('\n');516 try writer.writeByte('\n');
513 try writer.print(517 try writer.print(
514 \\sectname {s}518 \\sectname {s}
...@@ -531,7 +535,7 @@ const MachODumper = struct {...@@ -531,7 +535,7 @@ const MachODumper = struct {
531 .LOAD_WEAK_DYLIB,535 .LOAD_WEAK_DYLIB,
532 .REEXPORT_DYLIB,536 .REEXPORT_DYLIB,
533 => {537 => {
534 const dylib = lc.dylib.inner.dylib;538 const dylib = lc.cast(macho.dylib_command).?;
535 try writer.writeByte('\n');539 try writer.writeByte('\n');
536 try writer.print(540 try writer.print(
537 \\name {s}541 \\name {s}
...@@ -539,19 +543,20 @@ const MachODumper = struct {...@@ -539,19 +543,20 @@ const MachODumper = struct {
539 \\current version {x}543 \\current version {x}
540 \\compatibility version {x}544 \\compatibility version {x}
541 , .{545 , .{
542 mem.sliceTo(lc.dylib.data, 0),546 lc.getDylibPathName(),
543 dylib.timestamp,547 dylib.dylib.timestamp,
544 dylib.current_version,548 dylib.dylib.current_version,
545 dylib.compatibility_version,549 dylib.dylib.compatibility_version,
546 });550 });
547 },551 },
548552
549 .MAIN => {553 .MAIN => {
554 const main = lc.cast(macho.entry_point_command).?;
550 try writer.writeByte('\n');555 try writer.writeByte('\n');
551 try writer.print(556 try writer.print(
552 \\entryoff {x}557 \\entryoff {x}
553 \\stacksize {x}558 \\stacksize {x}
554 , .{ lc.main.entryoff, lc.main.stacksize });559 , .{ main.entryoff, main.stacksize });
555 },560 },
556561
557 .RPATH => {562 .RPATH => {
...@@ -559,7 +564,7 @@ const MachODumper = struct {...@@ -559,7 +564,7 @@ const MachODumper = struct {
559 try writer.print(564 try writer.print(
560 \\path {s}565 \\path {s}
561 , .{566 , .{
562 mem.sliceTo(lc.rpath.data, 0),567 lc.getRpathPathName(),
563 });568 });
564 },569 },
565570
lib/std/macho.zig+49-408
...@@ -1835,429 +1835,70 @@ pub const data_in_code_entry = extern struct {...@@ -1835,429 +1835,70 @@ pub const data_in_code_entry = extern struct {
1835 kind: u16,1835 kind: u16,
1836};1836};
18371837
1838/// A Zig wrapper for all known MachO load commands.1838pub const LoadCommandIterator = struct {
1839/// Provides interface to read and write the load command data to a buffer.1839 ncmds: usize,
1840pub const LoadCommand = union(enum) {1840 buffer: []align(@alignOf(u64)) const u8,
1841 segment: SegmentCommand,1841 index: usize = 0,
1842 dyld_info_only: dyld_info_command,
1843 symtab: symtab_command,
1844 dysymtab: dysymtab_command,
1845 dylinker: GenericCommandWithData(dylinker_command),
1846 dylib: GenericCommandWithData(dylib_command),
1847 main: entry_point_command,
1848 version_min: version_min_command,
1849 source_version: source_version_command,
1850 build_version: GenericCommandWithData(build_version_command),
1851 uuid: uuid_command,
1852 linkedit_data: linkedit_data_command,
1853 rpath: GenericCommandWithData(rpath_command),
1854 unknown: GenericCommandWithData(load_command),
1855
1856 pub fn read(allocator: Allocator, reader: anytype) !LoadCommand {
1857 const header = try reader.readStruct(load_command);
1858 var buffer = try allocator.alloc(u8, header.cmdsize);
1859 defer allocator.free(buffer);
1860 mem.copy(u8, buffer, mem.asBytes(&header));
1861 try reader.readNoEof(buffer[@sizeOf(load_command)..]);
1862 var stream = io.fixedBufferStream(buffer);
1863
1864 return switch (header.cmd) {
1865 .SEGMENT_64 => LoadCommand{
1866 .segment = try SegmentCommand.read(allocator, stream.reader()),
1867 },
1868 .DYLD_INFO, .DYLD_INFO_ONLY => LoadCommand{
1869 .dyld_info_only = try stream.reader().readStruct(dyld_info_command),
1870 },
1871 .SYMTAB => LoadCommand{
1872 .symtab = try stream.reader().readStruct(symtab_command),
1873 },
1874 .DYSYMTAB => LoadCommand{
1875 .dysymtab = try stream.reader().readStruct(dysymtab_command),
1876 },
1877 .ID_DYLINKER, .LOAD_DYLINKER, .DYLD_ENVIRONMENT => LoadCommand{
1878 .dylinker = try GenericCommandWithData(dylinker_command).read(allocator, stream.reader()),
1879 },
1880 .ID_DYLIB, .LOAD_WEAK_DYLIB, .LOAD_DYLIB, .REEXPORT_DYLIB => LoadCommand{
1881 .dylib = try GenericCommandWithData(dylib_command).read(allocator, stream.reader()),
1882 },
1883 .MAIN => LoadCommand{
1884 .main = try stream.reader().readStruct(entry_point_command),
1885 },
1886 .VERSION_MIN_MACOSX, .VERSION_MIN_IPHONEOS, .VERSION_MIN_WATCHOS, .VERSION_MIN_TVOS => LoadCommand{
1887 .version_min = try stream.reader().readStruct(version_min_command),
1888 },
1889 .SOURCE_VERSION => LoadCommand{
1890 .source_version = try stream.reader().readStruct(source_version_command),
1891 },
1892 .BUILD_VERSION => LoadCommand{
1893 .build_version = try GenericCommandWithData(build_version_command).read(allocator, stream.reader()),
1894 },
1895 .UUID => LoadCommand{
1896 .uuid = try stream.reader().readStruct(uuid_command),
1897 },
1898 .FUNCTION_STARTS, .DATA_IN_CODE, .CODE_SIGNATURE => LoadCommand{
1899 .linkedit_data = try stream.reader().readStruct(linkedit_data_command),
1900 },
1901 .RPATH => LoadCommand{
1902 .rpath = try GenericCommandWithData(rpath_command).read(allocator, stream.reader()),
1903 },
1904 else => LoadCommand{
1905 .unknown = try GenericCommandWithData(load_command).read(allocator, stream.reader()),
1906 },
1907 };
1908 }
1909
1910 pub fn write(self: LoadCommand, writer: anytype) !void {
1911 return switch (self) {
1912 .dyld_info_only => |x| writeStruct(x, writer),
1913 .symtab => |x| writeStruct(x, writer),
1914 .dysymtab => |x| writeStruct(x, writer),
1915 .main => |x| writeStruct(x, writer),
1916 .version_min => |x| writeStruct(x, writer),
1917 .source_version => |x| writeStruct(x, writer),
1918 .uuid => |x| writeStruct(x, writer),
1919 .linkedit_data => |x| writeStruct(x, writer),
1920 .segment => |x| x.write(writer),
1921 .dylinker => |x| x.write(writer),
1922 .dylib => |x| x.write(writer),
1923 .rpath => |x| x.write(writer),
1924 .build_version => |x| x.write(writer),
1925 .unknown => |x| x.write(writer),
1926 };
1927 }
1928
1929 pub fn cmd(self: LoadCommand) LC {
1930 return switch (self) {
1931 .dyld_info_only => |x| x.cmd,
1932 .symtab => |x| x.cmd,
1933 .dysymtab => |x| x.cmd,
1934 .main => |x| x.cmd,
1935 .version_min => |x| x.cmd,
1936 .source_version => |x| x.cmd,
1937 .uuid => |x| x.cmd,
1938 .linkedit_data => |x| x.cmd,
1939 .segment => |x| x.inner.cmd,
1940 .dylinker => |x| x.inner.cmd,
1941 .dylib => |x| x.inner.cmd,
1942 .rpath => |x| x.inner.cmd,
1943 .build_version => |x| x.inner.cmd,
1944 .unknown => |x| x.inner.cmd,
1945 };
1946 }
19471842
1948 pub fn cmdsize(self: LoadCommand) u32 {1843 pub const LoadCommand = struct {
1949 return switch (self) {1844 hdr: load_command,
1950 .dyld_info_only => |x| x.cmdsize,1845 data: []const u8,
1951 .symtab => |x| x.cmdsize,
1952 .dysymtab => |x| x.cmdsize,
1953 .main => |x| x.cmdsize,
1954 .version_min => |x| x.cmdsize,
1955 .source_version => |x| x.cmdsize,
1956 .linkedit_data => |x| x.cmdsize,
1957 .uuid => |x| x.cmdsize,
1958 .segment => |x| x.inner.cmdsize,
1959 .dylinker => |x| x.inner.cmdsize,
1960 .dylib => |x| x.inner.cmdsize,
1961 .rpath => |x| x.inner.cmdsize,
1962 .build_version => |x| x.inner.cmdsize,
1963 .unknown => |x| x.inner.cmdsize,
1964 };
1965 }
1966
1967 pub fn deinit(self: *LoadCommand, allocator: Allocator) void {
1968 return switch (self.*) {
1969 .segment => |*x| x.deinit(allocator),
1970 .dylinker => |*x| x.deinit(allocator),
1971 .dylib => |*x| x.deinit(allocator),
1972 .rpath => |*x| x.deinit(allocator),
1973 .build_version => |*x| x.deinit(allocator),
1974 .unknown => |*x| x.deinit(allocator),
1975 else => {},
1976 };
1977 }
1978
1979 fn writeStruct(command: anytype, writer: anytype) !void {
1980 return writer.writeAll(mem.asBytes(&command));
1981 }
19821846
1983 pub fn eql(self: LoadCommand, other: LoadCommand) bool {1847 pub fn cmd(lc: LoadCommand) LC {
1984 if (@as(meta.Tag(LoadCommand), self) != @as(meta.Tag(LoadCommand), other)) return false;1848 return lc.hdr.cmd;
1985 return switch (self) {
1986 .dyld_info_only => |x| meta.eql(x, other.dyld_info_only),
1987 .symtab => |x| meta.eql(x, other.symtab),
1988 .dysymtab => |x| meta.eql(x, other.dysymtab),
1989 .main => |x| meta.eql(x, other.main),
1990 .version_min => |x| meta.eql(x, other.version_min),
1991 .source_version => |x| meta.eql(x, other.source_version),
1992 .build_version => |x| x.eql(other.build_version),
1993 .uuid => |x| meta.eql(x, other.uuid),
1994 .linkedit_data => |x| meta.eql(x, other.linkedit_data),
1995 .segment => |x| x.eql(other.segment),
1996 .dylinker => |x| x.eql(other.dylinker),
1997 .dylib => |x| x.eql(other.dylib),
1998 .rpath => |x| x.eql(other.rpath),
1999 .unknown => |x| x.eql(other.unknown),
2000 };
2001 }
2002};
2003
2004/// A Zig wrapper for segment_command_64.
2005/// Encloses the extern struct together with a list of sections for this segment.
2006pub const SegmentCommand = struct {
2007 inner: segment_command_64,
2008 sections: std.ArrayListUnmanaged(section_64) = .{},
2009
2010 pub fn read(allocator: Allocator, reader: anytype) !SegmentCommand {
2011 const inner = try reader.readStruct(segment_command_64);
2012 var segment = SegmentCommand{
2013 .inner = inner,
2014 };
2015 try segment.sections.ensureTotalCapacityPrecise(allocator, inner.nsects);
2016
2017 var i: usize = 0;
2018 while (i < inner.nsects) : (i += 1) {
2019 const sect = try reader.readStruct(section_64);
2020 segment.sections.appendAssumeCapacity(sect);
2021 }1849 }
20221850
2023 return segment;1851 pub fn cmdsize(lc: LoadCommand) u32 {
2024 }1852 return lc.hdr.cmdsize;
2025
2026 pub fn write(self: SegmentCommand, writer: anytype) !void {
2027 try writer.writeAll(mem.asBytes(&self.inner));
2028 for (self.sections.items) |sect| {
2029 try writer.writeAll(mem.asBytes(&sect));
2030 }
2031 }
2032
2033 pub fn deinit(self: *SegmentCommand, allocator: Allocator) void {
2034 self.sections.deinit(allocator);
2035 }
2036
2037 pub fn eql(self: SegmentCommand, other: SegmentCommand) bool {
2038 if (!meta.eql(self.inner, other.inner)) return false;
2039 const lhs = self.sections.items;
2040 const rhs = other.sections.items;
2041 var i: usize = 0;
2042 while (i < self.inner.nsects) : (i += 1) {
2043 if (!meta.eql(lhs[i], rhs[i])) return false;
2044 }1853 }
2045 return true;
2046 }
2047};
2048
2049pub fn emptyGenericCommandWithData(cmd: anytype) GenericCommandWithData(@TypeOf(cmd)) {
2050 return .{ .inner = cmd };
2051}
20521854
2053/// A Zig wrapper for a generic load command with variable-length data.1855 pub fn cast(lc: LoadCommand, comptime Cmd: type) ?Cmd {
2054pub fn GenericCommandWithData(comptime Cmd: type) type {1856 if (lc.data.len < @sizeOf(Cmd)) return null;
2055 return struct {1857 return @ptrCast(*const Cmd, @alignCast(@alignOf(Cmd), &lc.data[0])).*;
2056 inner: Cmd,
2057 /// This field remains undefined until `read` is called.
2058 data: []u8 = undefined,
2059
2060 const Self = @This();
2061
2062 pub fn read(allocator: Allocator, reader: anytype) !Self {
2063 const inner = try reader.readStruct(Cmd);
2064 var data = try allocator.alloc(u8, inner.cmdsize - @sizeOf(Cmd));
2065 errdefer allocator.free(data);
2066 try reader.readNoEof(data);
2067 return Self{
2068 .inner = inner,
2069 .data = data,
2070 };
2071 }1858 }
20721859
2073 pub fn write(self: Self, writer: anytype) !void {1860 /// Asserts LoadCommand is of type segment_command_64.
2074 try writer.writeAll(mem.asBytes(&self.inner));1861 pub fn getSections(lc: LoadCommand) []const section_64 {
2075 try writer.writeAll(self.data);1862 const segment_lc = lc.cast(segment_command_64).?;
1863 if (segment_lc.nsects == 0) return &[0]section_64{};
1864 const data = lc.data[@sizeOf(segment_command_64)..];
1865 const sections = @ptrCast(
1866 [*]const section_64,
1867 @alignCast(@alignOf(section_64), &data[0]),
1868 )[0..segment_lc.nsects];
1869 return sections;
2076 }1870 }
20771871
2078 pub fn deinit(self: *Self, allocator: Allocator) void {1872 /// Asserts LoadCommand is of type dylib_command.
2079 allocator.free(self.data);1873 pub fn getDylibPathName(lc: LoadCommand) []const u8 {
1874 const dylib_lc = lc.cast(dylib_command).?;
1875 const data = lc.data[dylib_lc.dylib.name..];
1876 return mem.sliceTo(data, 0);
2080 }1877 }
20811878
2082 pub fn eql(self: Self, other: Self) bool {1879 /// Asserts LoadCommand is of type rpath_command.
2083 if (!meta.eql(self.inner, other.inner)) return false;1880 pub fn getRpathPathName(lc: LoadCommand) []const u8 {
2084 return mem.eql(u8, self.data, other.data);1881 const rpath_lc = lc.cast(rpath_command).?;
1882 const data = lc.data[rpath_lc.path..];
1883 return mem.sliceTo(data, 0);
2085 }1884 }
2086 };1885 };
2087}
20881886
2089pub fn createLoadDylibCommand(1887 pub fn next(it: *LoadCommandIterator) ?LoadCommand {
2090 allocator: Allocator,1888 if (it.index >= it.ncmds) return null;
2091 cmd_id: LC,
2092 name: []const u8,
2093 timestamp: u32,
2094 current_version: u32,
2095 compatibility_version: u32,
2096) !GenericCommandWithData(dylib_command) {
2097 assert(cmd_id == .LOAD_DYLIB or cmd_id == .LOAD_WEAK_DYLIB or cmd_id == .REEXPORT_DYLIB or cmd_id == .ID_DYLIB);
2098 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
2099 u64,
2100 @sizeOf(dylib_command) + name.len + 1, // +1 for nul
2101 @sizeOf(u64),
2102 ));
2103
2104 var dylib_cmd = emptyGenericCommandWithData(dylib_command{
2105 .cmd = cmd_id,
2106 .cmdsize = cmdsize,
2107 .dylib = .{
2108 .name = @sizeOf(dylib_command),
2109 .timestamp = timestamp,
2110 .current_version = current_version,
2111 .compatibility_version = compatibility_version,
2112 },
2113 });
2114 dylib_cmd.data = try allocator.alloc(u8, cmdsize - dylib_cmd.inner.dylib.name);
2115
2116 mem.set(u8, dylib_cmd.data, 0);
2117 mem.copy(u8, dylib_cmd.data, name);
2118
2119 return dylib_cmd;
2120}
2121
2122fn testRead(allocator: Allocator, buffer: []const u8, expected: anytype) !void {
2123 var stream = io.fixedBufferStream(buffer);
2124 var given = try LoadCommand.read(allocator, stream.reader());
2125 defer given.deinit(allocator);
2126 try testing.expect(expected.eql(given));
2127}
2128
2129fn testWrite(buffer: []u8, cmd: LoadCommand, expected: []const u8) !void {
2130 var stream = io.fixedBufferStream(buffer);
2131 try cmd.write(stream.writer());
2132 try testing.expect(mem.eql(u8, expected, buffer[0..expected.len]));
2133}
2134
2135fn makeStaticString(bytes: []const u8) [16]u8 {
2136 var buf = [_]u8{0} ** 16;
2137 assert(bytes.len <= buf.len);
2138 mem.copy(u8, &buf, bytes);
2139 return buf;
2140}
21411889
2142test "read-write segment command" {1890 const hdr = @ptrCast(
2143 // TODO compiling for macOS from big-endian arch1891 *const load_command,
2144 if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest;1892 @alignCast(@alignOf(load_command), &it.buffer[0]),
21451893 ).*;
2146 var gpa = testing.allocator;1894 const cmd = LoadCommand{
2147 const in_buffer = &[_]u8{1895 .hdr = hdr,
2148 0x19, 0x00, 0x00, 0x00, // cmd1896 .data = it.buffer[0..hdr.cmdsize],
2149 0x98, 0x00, 0x00, 0x00, // cmdsize1897 };
2150 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname
2151 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // vmaddr
2152 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // vmsize
2153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // fileoff
2154 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // filesize
2155 0x07, 0x00, 0x00, 0x00, // maxprot
2156 0x05, 0x00, 0x00, 0x00, // initprot
2157 0x01, 0x00, 0x00, 0x00, // nsects
2158 0x00, 0x00, 0x00, 0x00, // flags
2159 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sectname
2160 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segname
2161 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // address
2162 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size
2163 0x00, 0x40, 0x00, 0x00, // offset
2164 0x02, 0x00, 0x00, 0x00, // alignment
2165 0x00, 0x00, 0x00, 0x00, // reloff
2166 0x00, 0x00, 0x00, 0x00, // nreloc
2167 0x00, 0x04, 0x00, 0x80, // flags
2168 0x00, 0x00, 0x00, 0x00, // reserved1
2169 0x00, 0x00, 0x00, 0x00, // reserved2
2170 0x00, 0x00, 0x00, 0x00, // reserved3
2171 };
2172 var cmd = SegmentCommand{
2173 .inner = .{
2174 .cmdsize = 152,
2175 .segname = makeStaticString("__TEXT"),
2176 .vmaddr = 4294967296,
2177 .vmsize = 294912,
2178 .filesize = 294912,
2179 .maxprot = PROT.READ | PROT.WRITE | PROT.EXEC,
2180 .initprot = PROT.EXEC | PROT.READ,
2181 .nsects = 1,
2182 },
2183 };
2184 try cmd.sections.append(gpa, .{
2185 .sectname = makeStaticString("__text"),
2186 .segname = makeStaticString("__TEXT"),
2187 .addr = 4294983680,
2188 .size = 448,
2189 .offset = 16384,
2190 .@"align" = 2,
2191 .flags = S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS,
2192 });
2193 defer cmd.deinit(gpa);
2194 try testRead(gpa, in_buffer, LoadCommand{ .segment = cmd });
2195
2196 var out_buffer: [in_buffer.len]u8 = undefined;
2197 try testWrite(&out_buffer, LoadCommand{ .segment = cmd }, in_buffer);
2198}
2199
2200test "read-write generic command with data" {
2201 // TODO compiling for macOS from big-endian arch
2202 if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest;
2203
2204 var gpa = testing.allocator;
2205 const in_buffer = &[_]u8{
2206 0x0c, 0x00, 0x00, 0x00, // cmd
2207 0x20, 0x00, 0x00, 0x00, // cmdsize
2208 0x18, 0x00, 0x00, 0x00, // name
2209 0x02, 0x00, 0x00, 0x00, // timestamp
2210 0x00, 0x00, 0x00, 0x00, // current_version
2211 0x00, 0x00, 0x00, 0x00, // compatibility_version
2212 0x2f, 0x75, 0x73, 0x72, 0x00, 0x00, 0x00, 0x00, // data
2213 };
2214 var cmd = GenericCommandWithData(dylib_command){
2215 .inner = .{
2216 .cmd = .LOAD_DYLIB,
2217 .cmdsize = 32,
2218 .dylib = .{
2219 .name = 24,
2220 .timestamp = 2,
2221 .current_version = 0,
2222 .compatibility_version = 0,
2223 },
2224 },
2225 };
2226 cmd.data = try gpa.alloc(u8, 8);
2227 defer gpa.free(cmd.data);
2228 cmd.data[0] = 0x2f;
2229 cmd.data[1] = 0x75;
2230 cmd.data[2] = 0x73;
2231 cmd.data[3] = 0x72;
2232 cmd.data[4] = 0x0;
2233 cmd.data[5] = 0x0;
2234 cmd.data[6] = 0x0;
2235 cmd.data[7] = 0x0;
2236 try testRead(gpa, in_buffer, LoadCommand{ .dylib = cmd });
2237
2238 var out_buffer: [in_buffer.len]u8 = undefined;
2239 try testWrite(&out_buffer, LoadCommand{ .dylib = cmd }, in_buffer);
2240}
2241
2242test "read-write C struct command" {
2243 // TODO compiling for macOS from big-endian arch
2244 if (builtin.target.cpu.arch.endian() != .Little) return error.SkipZigTest;
22451898
2246 var gpa = testing.allocator;1899 it.buffer = it.buffer[hdr.cmdsize..];
2247 const in_buffer = &[_]u8{1900 it.index += 1;
2248 0x28, 0x00, 0x00, 0x80, // cmd
2249 0x18, 0x00, 0x00, 0x00, // cmdsize
2250 0x04, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // entryoff
2251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // stacksize
2252 };
2253 const cmd = .{
2254 .cmd = .MAIN,
2255 .cmdsize = 24,
2256 .entryoff = 16644,
2257 .stacksize = 0,
2258 };
2259 try testRead(gpa, in_buffer, LoadCommand{ .main = cmd });
22601901
2261 var out_buffer: [in_buffer.len]u8 = undefined;1902 return cmd;
2262 try testWrite(&out_buffer, LoadCommand{ .main = cmd }, in_buffer);1903 }
2263}1904};
src/link/Dwarf.zig+18-26
...@@ -853,8 +853,7 @@ pub fn commitDeclState(...@@ -853,8 +853,7 @@ pub fn commitDeclState(
853 .macho => {853 .macho => {
854 const macho_file = file.cast(File.MachO).?;854 const macho_file = file.cast(File.MachO).?;
855 const d_sym = &macho_file.d_sym.?;855 const d_sym = &macho_file.d_sym.?;
856 const dwarf_segment = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;856 const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?];
857 const debug_line_sect = &dwarf_segment.sections.items[d_sym.debug_line_section_index.?];
858 const file_pos = debug_line_sect.offset + src_fn.off;857 const file_pos = debug_line_sect.offset + src_fn.off;
859 try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);858 try pwriteDbgLineNops(d_sym.file, file_pos, 0, &[0]u8{}, src_fn.len);
860 },859 },
...@@ -933,8 +932,8 @@ pub fn commitDeclState(...@@ -933,8 +932,8 @@ pub fn commitDeclState(
933 .macho => {932 .macho => {
934 const macho_file = file.cast(File.MachO).?;933 const macho_file = file.cast(File.MachO).?;
935 const d_sym = &macho_file.d_sym.?;934 const d_sym = &macho_file.d_sym.?;
936 const dwarf_segment = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;935 const dwarf_segment = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?];
937 const debug_line_sect = &dwarf_segment.sections.items[d_sym.debug_line_section_index.?];936 const debug_line_sect = &d_sym.sections.items[d_sym.debug_line_section_index.?];
938 if (needed_size != debug_line_sect.size) {937 if (needed_size != debug_line_sect.size) {
939 if (needed_size > d_sym.allocatedSize(debug_line_sect.offset)) {938 if (needed_size > d_sym.allocatedSize(debug_line_sect.offset)) {
940 const new_offset = d_sym.findFreeSpace(needed_size, 1);939 const new_offset = d_sym.findFreeSpace(needed_size, 1);
...@@ -955,10 +954,9 @@ pub fn commitDeclState(...@@ -955,10 +954,9 @@ pub fn commitDeclState(
955 );954 );
956955
957 debug_line_sect.offset = @intCast(u32, new_offset);956 debug_line_sect.offset = @intCast(u32, new_offset);
958 debug_line_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;957 debug_line_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff;
959 }958 }
960 debug_line_sect.size = needed_size;959 debug_line_sect.size = needed_size;
961 d_sym.load_commands_dirty = true; // TODO look into making only the one section dirty
962 d_sym.debug_line_header_dirty = true;960 d_sym.debug_line_header_dirty = true;
963 }961 }
964 const file_pos = debug_line_sect.offset + src_fn.off;962 const file_pos = debug_line_sect.offset + src_fn.off;
...@@ -1137,8 +1135,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3...@@ -1137,8 +1135,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3
1137 .macho => {1135 .macho => {
1138 const macho_file = file.cast(File.MachO).?;1136 const macho_file = file.cast(File.MachO).?;
1139 const d_sym = &macho_file.d_sym.?;1137 const d_sym = &macho_file.d_sym.?;
1140 const dwarf_segment = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;1138 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];
1141 const debug_info_sect = &dwarf_segment.sections.items[d_sym.debug_info_section_index.?];
1142 const file_pos = debug_info_sect.offset + atom.off;1139 const file_pos = debug_info_sect.offset + atom.off;
1143 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);1140 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, &[0]u8{}, atom.len, false);
1144 },1141 },
...@@ -1235,8 +1232,8 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1235,8 +1232,8 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
1235 .macho => {1232 .macho => {
1236 const macho_file = file.cast(File.MachO).?;1233 const macho_file = file.cast(File.MachO).?;
1237 const d_sym = &macho_file.d_sym.?;1234 const d_sym = &macho_file.d_sym.?;
1238 const dwarf_segment = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;1235 const dwarf_segment = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?];
1239 const debug_info_sect = &dwarf_segment.sections.items[d_sym.debug_info_section_index.?];1236 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];
1240 if (needed_size != debug_info_sect.size) {1237 if (needed_size != debug_info_sect.size) {
1241 if (needed_size > d_sym.allocatedSize(debug_info_sect.offset)) {1238 if (needed_size > d_sym.allocatedSize(debug_info_sect.offset)) {
1242 const new_offset = d_sym.findFreeSpace(needed_size, 1);1239 const new_offset = d_sym.findFreeSpace(needed_size, 1);
...@@ -1257,10 +1254,9 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1257,10 +1254,9 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
1257 );1254 );
12581255
1259 debug_info_sect.offset = @intCast(u32, new_offset);1256 debug_info_sect.offset = @intCast(u32, new_offset);
1260 debug_info_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;1257 debug_info_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff;
1261 }1258 }
1262 debug_info_sect.size = needed_size;1259 debug_info_sect.size = needed_size;
1263 d_sym.load_commands_dirty = true; // TODO look into making only the one section dirty
1264 d_sym.debug_line_header_dirty = true;1260 d_sym.debug_line_header_dirty = true;
1265 }1261 }
1266 const file_pos = debug_info_sect.offset + atom.off;1262 const file_pos = debug_info_sect.offset + atom.off;
...@@ -1330,8 +1326,7 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)...@@ -1330,8 +1326,7 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl)
1330 .macho => {1326 .macho => {
1331 const macho_file = file.cast(File.MachO).?;1327 const macho_file = file.cast(File.MachO).?;
1332 const d_sym = macho_file.d_sym.?;1328 const d_sym = macho_file.d_sym.?;
1333 const dwarf_seg = d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;1329 const sect = d_sym.sections.items[d_sym.debug_line_section_index.?];
1334 const sect = dwarf_seg.sections.items[d_sym.debug_line_section_index.?];
1335 const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff();1330 const file_pos = sect.offset + decl.fn_link.macho.off + self.getRelocDbgLineOff();
1336 try d_sym.file.pwriteAll(&data, file_pos);1331 try d_sym.file.pwriteAll(&data, file_pos);
1337 },1332 },
...@@ -1557,14 +1552,14 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {...@@ -1557,14 +1552,14 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
1557 .macho => {1552 .macho => {
1558 const macho_file = file.cast(File.MachO).?;1553 const macho_file = file.cast(File.MachO).?;
1559 const d_sym = &macho_file.d_sym.?;1554 const d_sym = &macho_file.d_sym.?;
1560 const dwarf_segment = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;1555 const dwarf_segment = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?];
1561 const debug_abbrev_sect = &dwarf_segment.sections.items[d_sym.debug_abbrev_section_index.?];1556 const debug_abbrev_sect = &d_sym.sections.items[d_sym.debug_abbrev_section_index.?];
1562 const allocated_size = d_sym.allocatedSize(debug_abbrev_sect.offset);1557 const allocated_size = d_sym.allocatedSize(debug_abbrev_sect.offset);
1563 if (needed_size > allocated_size) {1558 if (needed_size > allocated_size) {
1564 debug_abbrev_sect.size = 0; // free the space1559 debug_abbrev_sect.size = 0; // free the space
1565 const offset = d_sym.findFreeSpace(needed_size, 1);1560 const offset = d_sym.findFreeSpace(needed_size, 1);
1566 debug_abbrev_sect.offset = @intCast(u32, offset);1561 debug_abbrev_sect.offset = @intCast(u32, offset);
1567 debug_abbrev_sect.addr = dwarf_segment.inner.vmaddr + offset - dwarf_segment.inner.fileoff;1562 debug_abbrev_sect.addr = dwarf_segment.vmaddr + offset - dwarf_segment.fileoff;
1568 }1563 }
1569 debug_abbrev_sect.size = needed_size;1564 debug_abbrev_sect.size = needed_size;
1570 log.debug("__debug_abbrev start=0x{x} end=0x{x}", .{1565 log.debug("__debug_abbrev start=0x{x} end=0x{x}", .{
...@@ -1681,8 +1676,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6...@@ -1681,8 +1676,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1681 .macho => {1676 .macho => {
1682 const macho_file = file.cast(File.MachO).?;1677 const macho_file = file.cast(File.MachO).?;
1683 const d_sym = &macho_file.d_sym.?;1678 const d_sym = &macho_file.d_sym.?;
1684 const dwarf_seg = d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;1679 const debug_info_sect = d_sym.sections.items[d_sym.debug_info_section_index.?];
1685 const debug_info_sect = dwarf_seg.sections.items[d_sym.debug_info_section_index.?];
1686 const file_pos = debug_info_sect.offset;1680 const file_pos = debug_info_sect.offset;
1687 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);1681 try pwriteDbgInfoNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt, false);
1688 },1682 },
...@@ -1998,13 +1992,13 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {...@@ -1998,13 +1992,13 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void {
1998 .macho => {1992 .macho => {
1999 const macho_file = file.cast(File.MachO).?;1993 const macho_file = file.cast(File.MachO).?;
2000 const d_sym = &macho_file.d_sym.?;1994 const d_sym = &macho_file.d_sym.?;
2001 const dwarf_seg = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;1995 const dwarf_seg = d_sym.segments.items[d_sym.dwarf_segment_cmd_index.?];
2002 const debug_aranges_sect = &dwarf_seg.sections.items[d_sym.debug_aranges_section_index.?];1996 const debug_aranges_sect = &d_sym.sections.items[d_sym.debug_aranges_section_index.?];
2003 const allocated_size = d_sym.allocatedSize(debug_aranges_sect.offset);1997 const allocated_size = d_sym.allocatedSize(debug_aranges_sect.offset);
2004 if (needed_size > allocated_size) {1998 if (needed_size > allocated_size) {
2005 debug_aranges_sect.size = 0; // free the space1999 debug_aranges_sect.size = 0; // free the space
2006 const new_offset = d_sym.findFreeSpace(needed_size, 16);2000 const new_offset = d_sym.findFreeSpace(needed_size, 16);
2007 debug_aranges_sect.addr = dwarf_seg.inner.vmaddr + new_offset - dwarf_seg.inner.fileoff;2001 debug_aranges_sect.addr = dwarf_seg.vmaddr + new_offset - dwarf_seg.fileoff;
2008 debug_aranges_sect.offset = @intCast(u32, new_offset);2002 debug_aranges_sect.offset = @intCast(u32, new_offset);
2009 }2003 }
2010 debug_aranges_sect.size = needed_size;2004 debug_aranges_sect.size = needed_size;
...@@ -2134,8 +2128,7 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2134,8 +2128,7 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void {
2134 .macho => {2128 .macho => {
2135 const macho_file = file.cast(File.MachO).?;2129 const macho_file = file.cast(File.MachO).?;
2136 const d_sym = &macho_file.d_sym.?;2130 const d_sym = &macho_file.d_sym.?;
2137 const dwarf_seg = d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;2131 const debug_line_sect = d_sym.sections.items[d_sym.debug_line_section_index.?];
2138 const debug_line_sect = dwarf_seg.sections.items[d_sym.debug_line_section_index.?];
2139 const file_pos = debug_line_sect.offset;2132 const file_pos = debug_line_sect.offset;
2140 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);2133 try pwriteDbgLineNops(d_sym.file, file_pos, 0, di_buf.items, jmp_amt);
2141 },2134 },
...@@ -2264,8 +2257,7 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2264,8 +2257,7 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
2264 .macho => {2257 .macho => {
2265 const macho_file = file.cast(File.MachO).?;2258 const macho_file = file.cast(File.MachO).?;
2266 const d_sym = &macho_file.d_sym.?;2259 const d_sym = &macho_file.d_sym.?;
2267 const dwarf_segment = &d_sym.load_commands.items[d_sym.dwarf_segment_cmd_index.?].segment;2260 const debug_info_sect = &d_sym.sections.items[d_sym.debug_info_section_index.?];
2268 const debug_info_sect = &dwarf_segment.sections.items[d_sym.debug_info_section_index.?];
2269 break :blk debug_info_sect.offset;2261 break :blk debug_info_sect.offset;
2270 },2262 },
2271 // for wasm, the offset is always 0 as we write to memory first2263 // for wasm, the offset is always 0 as we write to memory first
src/link/MachO.zig+1563-1912
...@@ -17,6 +17,7 @@ const aarch64 = @import("../arch/aarch64/bits.zig");...@@ -17,6 +17,7 @@ const aarch64 = @import("../arch/aarch64/bits.zig");
17const bind = @import("MachO/bind.zig");17const bind = @import("MachO/bind.zig");
18const codegen = @import("../codegen.zig");18const codegen = @import("../codegen.zig");
19const dead_strip = @import("MachO/dead_strip.zig");19const dead_strip = @import("MachO/dead_strip.zig");
20const fat = @import("MachO/fat.zig");
20const link = @import("../link.zig");21const link = @import("../link.zig");
21const llvm_backend = @import("../codegen/llvm.zig");22const llvm_backend = @import("../codegen/llvm.zig");
22const target_util = @import("../target.zig");23const target_util = @import("../target.zig");
...@@ -60,6 +61,29 @@ const SystemLib = struct {...@@ -60,6 +61,29 @@ const SystemLib = struct {
60 weak: bool = false,61 weak: bool = false,
61};62};
6263
64const Section = struct {
65 header: macho.section_64,
66 segment_index: u8,
67 last_atom: ?*Atom = null, // TODO temporary hack; we really should shrink section to 0
68
69 /// A list of atoms that have surplus capacity. This list can have false
70 /// positives, as functions grow and shrink over time, only sometimes being added
71 /// or removed from the freelist.
72 ///
73 /// An atom has surplus capacity when its overcapacity value is greater than
74 /// padToIdeal(minimum_atom_size). That is, when it has so
75 /// much extra capacity, that we could fit a small new symbol in it, itself with
76 /// ideal_capacity or more.
77 ///
78 /// Ideal capacity is defined by size + (size / ideal_factor).
79 ///
80 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
81 /// overcapacity can be negative. A simple way to have negative overcapacity is to
82 /// allocate a fresh atom, which will have ideal capacity, and then grow it
83 /// by 1 byte. It will then have -1 overcapacity.
84 free_list: std.ArrayListUnmanaged(*Atom) = .{},
85};
86
63base: File,87base: File,
6488
65/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.89/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
...@@ -77,80 +101,67 @@ page_size: u16,...@@ -77,80 +101,67 @@ page_size: u16,
77/// fashion (default for LLVM backend).101/// fashion (default for LLVM backend).
78mode: enum { incremental, one_shot },102mode: enum { incremental, one_shot },
79103
80/// The absolute address of the entry point.104uuid: macho.uuid_command = .{
81entry_addr: ?u64 = null,105 .cmdsize = @sizeOf(macho.uuid_command),
82106 .uuid = undefined,
83/// Code signature (if any)107},
84code_signature: ?CodeSignature = null,
85108
86objects: std.ArrayListUnmanaged(Object) = .{},109objects: std.ArrayListUnmanaged(Object) = .{},
87archives: std.ArrayListUnmanaged(Archive) = .{},110archives: std.ArrayListUnmanaged(Archive) = .{},
88
89dylibs: std.ArrayListUnmanaged(Dylib) = .{},111dylibs: std.ArrayListUnmanaged(Dylib) = .{},
90dylibs_map: std.StringHashMapUnmanaged(u16) = .{},112dylibs_map: std.StringHashMapUnmanaged(u16) = .{},
91referenced_dylibs: std.AutoArrayHashMapUnmanaged(u16, void) = .{},113referenced_dylibs: std.AutoArrayHashMapUnmanaged(u16, void) = .{},
92114
93load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},115segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
94116sections: std.MultiArrayList(Section) = .{},
95pagezero_segment_cmd_index: ?u16 = null,117
96text_segment_cmd_index: ?u16 = null,118pagezero_segment_cmd_index: ?u8 = null,
97data_const_segment_cmd_index: ?u16 = null,119text_segment_cmd_index: ?u8 = null,
98data_segment_cmd_index: ?u16 = null,120data_const_segment_cmd_index: ?u8 = null,
99linkedit_segment_cmd_index: ?u16 = null,121data_segment_cmd_index: ?u8 = null,
100dyld_info_cmd_index: ?u16 = null,122linkedit_segment_cmd_index: ?u8 = null,
101symtab_cmd_index: ?u16 = null,
102dysymtab_cmd_index: ?u16 = null,
103dylinker_cmd_index: ?u16 = null,
104data_in_code_cmd_index: ?u16 = null,
105function_starts_cmd_index: ?u16 = null,
106main_cmd_index: ?u16 = null,
107dylib_id_cmd_index: ?u16 = null,
108source_version_cmd_index: ?u16 = null,
109build_version_cmd_index: ?u16 = null,
110uuid_cmd_index: ?u16 = null,
111code_signature_cmd_index: ?u16 = null,
112123
113// __TEXT segment sections124// __TEXT segment sections
114text_section_index: ?u16 = null,125text_section_index: ?u8 = null,
115stubs_section_index: ?u16 = null,126stubs_section_index: ?u8 = null,
116stub_helper_section_index: ?u16 = null,127stub_helper_section_index: ?u8 = null,
117text_const_section_index: ?u16 = null,128text_const_section_index: ?u8 = null,
118cstring_section_index: ?u16 = null,129cstring_section_index: ?u8 = null,
119ustring_section_index: ?u16 = null,130ustring_section_index: ?u8 = null,
120gcc_except_tab_section_index: ?u16 = null,131gcc_except_tab_section_index: ?u8 = null,
121unwind_info_section_index: ?u16 = null,132unwind_info_section_index: ?u8 = null,
122eh_frame_section_index: ?u16 = null,133eh_frame_section_index: ?u8 = null,
123134
124objc_methlist_section_index: ?u16 = null,135objc_methlist_section_index: ?u8 = null,
125objc_methname_section_index: ?u16 = null,136objc_methname_section_index: ?u8 = null,
126objc_methtype_section_index: ?u16 = null,137objc_methtype_section_index: ?u8 = null,
127objc_classname_section_index: ?u16 = null,138objc_classname_section_index: ?u8 = null,
128139
129// __DATA_CONST segment sections140// __DATA_CONST segment sections
130got_section_index: ?u16 = null,141got_section_index: ?u8 = null,
131mod_init_func_section_index: ?u16 = null,142mod_init_func_section_index: ?u8 = null,
132mod_term_func_section_index: ?u16 = null,143mod_term_func_section_index: ?u8 = null,
133data_const_section_index: ?u16 = null,144data_const_section_index: ?u8 = null,
134145
135objc_cfstring_section_index: ?u16 = null,146objc_cfstring_section_index: ?u8 = null,
136objc_classlist_section_index: ?u16 = null,147objc_classlist_section_index: ?u8 = null,
137objc_imageinfo_section_index: ?u16 = null,148objc_imageinfo_section_index: ?u8 = null,
138149
139// __DATA segment sections150// __DATA segment sections
140tlv_section_index: ?u16 = null,151tlv_section_index: ?u8 = null,
141tlv_data_section_index: ?u16 = null,152tlv_data_section_index: ?u8 = null,
142tlv_bss_section_index: ?u16 = null,153tlv_bss_section_index: ?u8 = null,
143tlv_ptrs_section_index: ?u16 = null,154tlv_ptrs_section_index: ?u8 = null,
144la_symbol_ptr_section_index: ?u16 = null,155la_symbol_ptr_section_index: ?u8 = null,
145data_section_index: ?u16 = null,156data_section_index: ?u8 = null,
146bss_section_index: ?u16 = null,157bss_section_index: ?u8 = null,
147158
148objc_const_section_index: ?u16 = null,159objc_const_section_index: ?u8 = null,
149objc_selrefs_section_index: ?u16 = null,160objc_selrefs_section_index: ?u8 = null,
150objc_classrefs_section_index: ?u16 = null,161objc_classrefs_section_index: ?u8 = null,
151objc_data_section_index: ?u16 = null,162objc_data_section_index: ?u8 = null,
152163
153rustc_section_index: ?u16 = null,164rustc_section_index: ?u8 = null,
154rustc_section_size: u64 = 0,165rustc_section_size: u64 = 0,
155166
156locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},167locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
...@@ -188,37 +199,12 @@ stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},...@@ -188,37 +199,12 @@ stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
188199
189error_flags: File.ErrorFlags = File.ErrorFlags{},200error_flags: File.ErrorFlags = File.ErrorFlags{},
190201
191load_commands_dirty: bool = false,
192sections_order_dirty: bool = false,
193
194/// A helper var to indicate if we are at the start of the incremental updates, or202/// A helper var to indicate if we are at the start of the incremental updates, or
195/// already somewhere further along the update-and-run chain.203/// already somewhere further along the update-and-run chain.
196/// TODO once we add opening a prelinked output binary from file, this will become204/// TODO once we add opening a prelinked output binary from file, this will become
197/// obsolete as we will carry on where we left off.205/// obsolete as we will carry on where we left off.
198cold_start: bool = true,206cold_start: bool = true,
199207
200section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{},
201
202/// A list of atoms that have surplus capacity. This list can have false
203/// positives, as functions grow and shrink over time, only sometimes being added
204/// or removed from the freelist.
205///
206/// An atom has surplus capacity when its overcapacity value is greater than
207/// padToIdeal(minimum_atom_size). That is, when it has so
208/// much extra capacity, that we could fit a small new symbol in it, itself with
209/// ideal_capacity or more.
210///
211/// Ideal capacity is defined by size + (size / ideal_factor).
212///
213/// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
214/// overcapacity can be negative. A simple way to have negative overcapacity is to
215/// allocate a fresh atom, which will have ideal capacity, and then grow it
216/// by 1 byte. It will then have -1 overcapacity.
217atom_free_lists: std.AutoHashMapUnmanaged(MatchingSection, std.ArrayListUnmanaged(*Atom)) = .{},
218
219/// Pointer to the last allocated atom
220atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{},
221
222/// List of atoms that are either synthetic or map directly to the Zig source program.208/// List of atoms that are either synthetic or map directly to the Zig source program.
223managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},209managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
224210
...@@ -250,7 +236,7 @@ unnamed_const_atoms: UnnamedConstTable = .{},...@@ -250,7 +236,7 @@ unnamed_const_atoms: UnnamedConstTable = .{},
250/// We store them here so that we can properly dispose of any allocated236/// We store them here so that we can properly dispose of any allocated
251/// memory within the atom in the incremental linker.237/// memory within the atom in the incremental linker.
252/// TODO consolidate this.238/// TODO consolidate this.
253decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?MatchingSection) = .{},239decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?u8) = .{},
254240
255const Entry = struct {241const Entry = struct {
256 target: SymbolWithLoc,242 target: SymbolWithLoc,
...@@ -408,12 +394,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {...@@ -408,12 +394,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
408394
409pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {395pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
410 const cpu_arch = options.target.cpu.arch;396 const cpu_arch = options.target.cpu.arch;
411 const os_tag = options.target.os.tag;
412 const abi = options.target.abi;
413 const page_size: u16 = if (cpu_arch == .aarch64) 0x4000 else 0x1000;397 const page_size: u16 = if (cpu_arch == .aarch64) 0x4000 else 0x1000;
414 // Adhoc code signature is required when targeting aarch64-macos either directly or indirectly via the simulator
415 // ABI such as aarch64-ios-simulator, etc.
416 const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator);
417 const use_llvm = build_options.have_llvm and options.use_llvm;398 const use_llvm = build_options.have_llvm and options.use_llvm;
418 const use_stage1 = build_options.is_stage1 and options.use_stage1;399 const use_stage1 = build_options.is_stage1 and options.use_stage1;
419400
...@@ -428,10 +409,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {...@@ -428,10 +409,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
428 .file = null,409 .file = null,
429 },410 },
430 .page_size = page_size,411 .page_size = page_size,
431 .code_signature = if (requires_adhoc_codesig)
432 CodeSignature.init(page_size)
433 else
434 null,
435 .mode = if (use_stage1 or use_llvm or options.module == null or options.cache_mode == .whole)412 .mode = if (use_stage1 or use_llvm or options.module == null or options.cache_mode == .whole)
436 .one_shot413 .one_shot
437 else414 else
...@@ -562,8 +539,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -562,8 +539,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
562 var dependent_libs = std.fifo.LinearFifo(struct {539 var dependent_libs = std.fifo.LinearFifo(struct {
563 id: Dylib.Id,540 id: Dylib.Id,
564 parent: u16,541 parent: u16,
565 }, .Dynamic).init(self.base.allocator);542 }, .Dynamic).init(arena);
566 defer dependent_libs.deinit();543
567 try self.parseLibs(libs.keys(), libs.values(), self.base.options.sysroot, &dependent_libs);544 try self.parseLibs(libs.keys(), libs.values(), self.base.options.sysroot, &dependent_libs);
568 try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);545 try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);
569 }546 }
...@@ -573,7 +550,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -573,7 +550,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
573 try self.createDyldPrivateAtom();550 try self.createDyldPrivateAtom();
574 try self.createStubHelperPreambleAtom();551 try self.createStubHelperPreambleAtom();
575 try self.resolveSymbolsInDylibs();552 try self.resolveSymbolsInDylibs();
576 try self.addCodeSignatureLC();
577553
578 if (self.unresolved.count() > 0) {554 if (self.unresolved.count() > 0) {
579 return error.UndefinedSymbolReference;555 return error.UndefinedSymbolReference;
...@@ -583,67 +559,91 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -583,67 +559,91 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
583559
584 if (build_options.enable_logging) {560 if (build_options.enable_logging) {
585 self.logSymtab();561 self.logSymtab();
586 self.logSectionOrdinals();
587 self.logAtoms();562 self.logAtoms();
588 }563 }
589564
590 try self.writeAtomsIncremental();565 try self.writeAtomsIncremental();
591566
592 try self.setEntryPoint();567 var lc_buffer = std.ArrayList(u8).init(arena);
593 try self.updateSectionOrdinals();568 const lc_writer = lc_buffer.writer();
594 try self.writeLinkeditSegment();569 var ncmds: u32 = 0;
595570
596 if (self.d_sym) |*d_sym| {571 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
597 // Flush debug symbols bundle.572 try writeDylinkerLC(&ncmds, lc_writer);
598 try d_sym.flushModule(self.base.allocator, self.base.options);573
574 self.writeMainLC(&ncmds, lc_writer) catch |err| switch (err) {
575 error.MissingMainEntrypoint => {
576 self.error_flags.no_entry_point_found = true;
577 },
578 else => |e| return e,
579 };
580
581 try self.writeDylibIdLC(&ncmds, lc_writer);
582 try self.writeRpathLCs(&ncmds, lc_writer);
583
584 {
585 try lc_writer.writeStruct(macho.source_version_command{
586 .cmdsize = @sizeOf(macho.source_version_command),
587 .version = 0x0,
588 });
589 ncmds += 1;
599 }590 }
600591
601 // code signature and entitlements592 try self.writeBuildVersionLC(&ncmds, lc_writer);
602 if (self.base.options.entitlements) |path| {593
603 if (self.code_signature) |*csig| {594 {
604 try csig.addEntitlements(self.base.allocator, path);595 std.crypto.random.bytes(&self.uuid.uuid);
605 csig.code_directory.ident = self.base.options.emit.?.sub_path;596 try lc_writer.writeStruct(self.uuid);
606 } else {597 ncmds += 1;
607 var csig = CodeSignature.init(self.page_size);
608 try csig.addEntitlements(self.base.allocator, path);
609 csig.code_directory.ident = self.base.options.emit.?.sub_path;
610 self.code_signature = csig;
611 }
612 }598 }
613599
614 if (self.code_signature) |*csig| {600 try self.writeLoadDylibLCs(&ncmds, lc_writer);
615 csig.clear(self.base.allocator);601
616 csig.code_directory.ident = self.base.options.emit.?.sub_path;602 const target = self.base.options.target;
603 const requires_codesig = blk: {
604 if (self.base.options.entitlements) |_| break :blk true;
605 if (target.cpu.arch == .aarch64 and (target.os.tag == .macos or target.abi == .simulator))
606 break :blk true;
607 break :blk false;
608 };
609 var codesig_offset: ?u32 = null;
610 var codesig: ?CodeSignature = if (requires_codesig) blk: {
617 // Preallocate space for the code signature.611 // Preallocate space for the code signature.
618 // We need to do this at this stage so that we have the load commands with proper values612 // We need to do this at this stage so that we have the load commands with proper values
619 // written out to the file.613 // written out to the file.
620 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment614 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
621 // where the code signature goes into.615 // where the code signature goes into.
622 try self.writeCodeSignaturePadding(csig);616 var codesig = CodeSignature.init(self.page_size);
623 }617 codesig.code_directory.ident = self.base.options.emit.?.sub_path;
618 if (self.base.options.entitlements) |path| {
619 try codesig.addEntitlements(arena, path);
620 }
621 codesig_offset = try self.writeCodeSignaturePadding(&codesig, &ncmds, lc_writer);
622 break :blk codesig;
623 } else null;
624624
625 try self.writeLoadCommands();625 var headers_buf = std.ArrayList(u8).init(arena);
626 try self.writeHeader();626 try self.writeSegmentHeaders(0, self.segments.items.len, &ncmds, headers_buf.writer());
627627
628 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {628 try self.base.file.?.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
629 log.debug("flushing. no_entry_point_found = true", .{});629 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
630 self.error_flags.no_entry_point_found = true;
631 } else {
632 log.debug("flushing. no_entry_point_found = false", .{});
633 self.error_flags.no_entry_point_found = false;
634 }
635630
636 assert(!self.load_commands_dirty);631 try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
637632
638 if (self.code_signature) |*csig| {633 if (codesig) |*csig| {
639 try self.writeCodeSignature(csig); // code signing always comes last634 try self.writeCodeSignature(csig, codesig_offset.?); // code signing always comes last
640 }635 }
641636
642 if (build_options.enable_link_snapshots) {637 if (self.d_sym) |*d_sym| {
643 if (self.base.options.enable_link_snapshots)638 // Flush debug symbols bundle.
644 try self.snapshotState();639 try d_sym.flushModule(self.base.allocator, self.base.options);
645 }640 }
646641
642 // if (build_options.enable_link_snapshots) {
643 // if (self.base.options.enable_link_snapshots)
644 // try self.snapshotState();
645 // }
646
647 if (cache_miss) {647 if (cache_miss) {
648 // Update the file with the digest. If it fails we can continue; it only648 // Update the file with the digest. If it fails we can continue; it only
649 // means that the next invocation will have an unnecessary cache miss.649 // means that the next invocation will have an unnecessary cache miss.
...@@ -708,6 +708,9 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -708,6 +708,9 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
708 sub_prog_node.context.refresh();708 sub_prog_node.context.refresh();
709 defer sub_prog_node.end();709 defer sub_prog_node.end();
710710
711 const cpu_arch = self.base.options.target.cpu.arch;
712 const os_tag = self.base.options.target.os.tag;
713 const abi = self.base.options.target.abi;
711 const is_lib = self.base.options.output_mode == .Lib;714 const is_lib = self.base.options.output_mode == .Lib;
712 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;715 const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
713 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;716 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
...@@ -990,40 +993,6 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -990,40 +993,6 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
990 }993 }
991 }994 }
992995
993 // rpaths
994 var rpath_table = std.StringArrayHashMap(void).init(arena);
995 for (self.base.options.rpath_list) |rpath| {
996 if (rpath_table.contains(rpath)) continue;
997 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
998 u64,
999 @sizeOf(macho.rpath_command) + rpath.len + 1,
1000 @sizeOf(u64),
1001 ));
1002 var rpath_cmd = macho.emptyGenericCommandWithData(macho.rpath_command{
1003 .cmdsize = cmdsize,
1004 .path = @sizeOf(macho.rpath_command),
1005 });
1006 rpath_cmd.data = try gpa.alloc(u8, cmdsize - rpath_cmd.inner.path);
1007 mem.set(u8, rpath_cmd.data, 0);
1008 mem.copy(u8, rpath_cmd.data, rpath);
1009 try self.load_commands.append(gpa, .{ .rpath = rpath_cmd });
1010 try rpath_table.putNoClobber(rpath, {});
1011 self.load_commands_dirty = true;
1012 }
1013
1014 // code signature and entitlements
1015 if (self.base.options.entitlements) |path| {
1016 if (self.code_signature) |*csig| {
1017 try csig.addEntitlements(gpa, path);
1018 csig.code_directory.ident = self.base.options.emit.?.sub_path;
1019 } else {
1020 var csig = CodeSignature.init(self.page_size);
1021 try csig.addEntitlements(gpa, path);
1022 csig.code_directory.ident = self.base.options.emit.?.sub_path;
1023 self.code_signature = csig;
1024 }
1025 }
1026
1027 if (self.base.options.verbose_link) {996 if (self.base.options.verbose_link) {
1028 var argv = std.ArrayList([]const u8).init(arena);997 var argv = std.ArrayList([]const u8).init(arena);
1029998
...@@ -1048,7 +1017,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1048,7 +1017,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
1048 try argv.append(syslibroot);1017 try argv.append(syslibroot);
1049 }1018 }
10501019
1051 for (rpath_table.keys()) |rpath| {1020 for (self.base.options.rpath_list) |rpath| {
1052 try argv.append("-rpath");1021 try argv.append("-rpath");
1053 try argv.append(rpath);1022 try argv.append(rpath);
1054 }1023 }
...@@ -1157,15 +1126,15 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1157,15 +1126,15 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
1157 var dependent_libs = std.fifo.LinearFifo(struct {1126 var dependent_libs = std.fifo.LinearFifo(struct {
1158 id: Dylib.Id,1127 id: Dylib.Id,
1159 parent: u16,1128 parent: u16,
1160 }, .Dynamic).init(gpa);1129 }, .Dynamic).init(arena);
1161 defer dependent_libs.deinit();1130
1162 try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);1131 try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs);
1163 try self.parseAndForceLoadStaticArchives(must_link_archives.keys());1132 try self.parseAndForceLoadStaticArchives(must_link_archives.keys());
1164 try self.parseLibs(libs.keys(), libs.values(), self.base.options.sysroot, &dependent_libs);1133 try self.parseLibs(libs.keys(), libs.values(), self.base.options.sysroot, &dependent_libs);
1165 try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);1134 try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs);
11661135
1167 for (self.objects.items) |*object, object_id| {1136 for (self.objects.items) |_, object_id| {
1168 try self.resolveSymbolsInObject(object, @intCast(u16, object_id));1137 try self.resolveSymbolsInObject(@intCast(u16, object_id));
1169 }1138 }
11701139
1171 try self.resolveSymbolsInArchives();1140 try self.resolveSymbolsInArchives();
...@@ -1175,7 +1144,6 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1175,7 +1144,6 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
1175 try self.resolveSymbolsInDylibs();1144 try self.resolveSymbolsInDylibs();
1176 try self.createMhExecuteHeaderSymbol();1145 try self.createMhExecuteHeaderSymbol();
1177 try self.createDsoHandleSymbol();1146 try self.createDsoHandleSymbol();
1178 try self.addCodeSignatureLC();
1179 try self.resolveSymbolsAtLoading();1147 try self.resolveSymbolsAtLoading();
11801148
1181 if (self.unresolved.count() > 0) {1149 if (self.unresolved.count() > 0) {
...@@ -1206,41 +1174,79 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1206,41 +1174,79 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
12061174
1207 if (build_options.enable_logging) {1175 if (build_options.enable_logging) {
1208 self.logSymtab();1176 self.logSymtab();
1209 self.logSectionOrdinals();
1210 self.logAtoms();1177 self.logAtoms();
1211 }1178 }
12121179
1213 try self.writeAtomsOneShot();1180 try self.writeAtomsOneShot();
12141181
1215 if (self.rustc_section_index) |id| {1182 if (self.rustc_section_index) |id| {
1216 const sect = self.getSectionPtr(.{1183 const header = &self.sections.items(.header)[id];
1217 .seg = self.data_segment_cmd_index.?,1184 header.size = self.rustc_section_size;
1218 .sect = id,1185 }
1186
1187 var lc_buffer = std.ArrayList(u8).init(arena);
1188 const lc_writer = lc_buffer.writer();
1189 var ncmds: u32 = 0;
1190
1191 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
1192 try writeDylinkerLC(&ncmds, lc_writer);
1193 try self.writeMainLC(&ncmds, lc_writer);
1194 try self.writeDylibIdLC(&ncmds, lc_writer);
1195 try self.writeRpathLCs(&ncmds, lc_writer);
1196
1197 {
1198 try lc_writer.writeStruct(macho.source_version_command{
1199 .cmdsize = @sizeOf(macho.source_version_command),
1200 .version = 0x0,
1219 });1201 });
1220 sect.size = self.rustc_section_size;1202 ncmds += 1;
1203 }
1204
1205 try self.writeBuildVersionLC(&ncmds, lc_writer);
1206
1207 {
1208 var uuid_lc = macho.uuid_command{
1209 .cmdsize = @sizeOf(macho.uuid_command),
1210 .uuid = undefined,
1211 };
1212 std.crypto.random.bytes(&uuid_lc.uuid);
1213 try lc_writer.writeStruct(uuid_lc);
1214 ncmds += 1;
1221 }1215 }
12221216
1223 try self.setEntryPoint();1217 try self.writeLoadDylibLCs(&ncmds, lc_writer);
1224 try self.writeLinkeditSegment();
12251218
1226 if (self.code_signature) |*csig| {1219 const requires_codesig = blk: {
1227 csig.clear(gpa);1220 if (self.base.options.entitlements) |_| break :blk true;
1228 csig.code_directory.ident = self.base.options.emit.?.sub_path;1221 if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true;
1222 break :blk false;
1223 };
1224 var codesig_offset: ?u32 = null;
1225 var codesig: ?CodeSignature = if (requires_codesig) blk: {
1229 // Preallocate space for the code signature.1226 // Preallocate space for the code signature.
1230 // We need to do this at this stage so that we have the load commands with proper values1227 // We need to do this at this stage so that we have the load commands with proper values
1231 // written out to the file.1228 // written out to the file.
1232 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment1229 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
1233 // where the code signature goes into.1230 // where the code signature goes into.
1234 try self.writeCodeSignaturePadding(csig);1231 var codesig = CodeSignature.init(self.page_size);
1235 }1232 codesig.code_directory.ident = self.base.options.emit.?.sub_path;
1233 if (self.base.options.entitlements) |path| {
1234 try codesig.addEntitlements(arena, path);
1235 }
1236 codesig_offset = try self.writeCodeSignaturePadding(&codesig, &ncmds, lc_writer);
1237 break :blk codesig;
1238 } else null;
12361239
1237 try self.writeLoadCommands();1240 var headers_buf = std.ArrayList(u8).init(arena);
1238 try self.writeHeader();1241 try self.writeSegmentHeaders(0, self.segments.items.len, &ncmds, headers_buf.writer());
12391242
1240 assert(!self.load_commands_dirty);1243 try self.base.file.?.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
1244 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
12411245
1242 if (self.code_signature) |*csig| {1246 try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
1243 try self.writeCodeSignature(csig); // code signing always comes last1247
1248 if (codesig) |*csig| {
1249 try self.writeCodeSignature(csig, codesig_offset.?); // code signing always comes last
1244 }1250 }
1245 }1251 }
12461252
...@@ -1395,66 +1401,77 @@ fn resolveFramework(...@@ -1395,66 +1401,77 @@ fn resolveFramework(
1395}1401}
13961402
1397fn parseObject(self: *MachO, path: []const u8) !bool {1403fn parseObject(self: *MachO, path: []const u8) !bool {
1404 const gpa = self.base.allocator;
1398 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {1405 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
1399 error.FileNotFound => return false,1406 error.FileNotFound => return false,
1400 else => |e| return e,1407 else => |e| return e,
1401 };1408 };
1402 errdefer file.close();1409 defer file.close();
1403
1404 const name = try self.base.allocator.dupe(u8, path);
1405 errdefer self.base.allocator.free(name);
14061410
1411 const name = try gpa.dupe(u8, path);
1412 errdefer gpa.free(name);
1413 const cpu_arch = self.base.options.target.cpu.arch;
1407 const mtime: u64 = mtime: {1414 const mtime: u64 = mtime: {
1408 const stat = file.stat() catch break :mtime 0;1415 const stat = file.stat() catch break :mtime 0;
1409 break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));1416 break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
1410 };1417 };
1418 const file_stat = try file.stat();
1419 const file_size = math.cast(usize, file_stat.size) orelse return error.Overflow;
1420 const contents = try file.readToEndAllocOptions(gpa, file_size, file_size, @alignOf(u64), null);
14111421
1412 var object = Object{1422 var object = Object{
1413 .name = name,1423 .name = name,
1414 .file = file,
1415 .mtime = mtime,1424 .mtime = mtime,
1425 .contents = contents,
1416 };1426 };
14171427
1418 object.parse(self.base.allocator, self.base.options.target.cpu.arch) catch |err| switch (err) {1428 object.parse(gpa, cpu_arch) catch |err| switch (err) {
1419 error.EndOfStream, error.NotObject => {1429 error.EndOfStream, error.NotObject => {
1420 object.deinit(self.base.allocator);1430 object.deinit(gpa);
1421 return false;1431 return false;
1422 },1432 },
1423 else => |e| return e,1433 else => |e| return e,
1424 };1434 };
14251435
1426 try self.objects.append(self.base.allocator, object);1436 try self.objects.append(gpa, object);
14271437
1428 return true;1438 return true;
1429}1439}
14301440
1431fn parseArchive(self: *MachO, path: []const u8, force_load: bool) !bool {1441fn parseArchive(self: *MachO, path: []const u8, force_load: bool) !bool {
1442 const gpa = self.base.allocator;
1432 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {1443 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
1433 error.FileNotFound => return false,1444 error.FileNotFound => return false,
1434 else => |e| return e,1445 else => |e| return e,
1435 };1446 };
1436 errdefer file.close();1447 errdefer file.close();
14371448
1438 const name = try self.base.allocator.dupe(u8, path);1449 const name = try gpa.dupe(u8, path);
1439 errdefer self.base.allocator.free(name);1450 errdefer gpa.free(name);
1451 const cpu_arch = self.base.options.target.cpu.arch;
1452 const reader = file.reader();
1453 const fat_offset = try fat.getLibraryOffset(reader, cpu_arch);
1454 try reader.context.seekTo(fat_offset);
14401455
1441 var archive = Archive{1456 var archive = Archive{
1442 .name = name,1457 .name = name,
1458 .fat_offset = fat_offset,
1443 .file = file,1459 .file = file,
1444 };1460 };
14451461
1446 archive.parse(self.base.allocator, self.base.options.target.cpu.arch) catch |err| switch (err) {1462 archive.parse(gpa, reader) catch |err| switch (err) {
1447 error.EndOfStream, error.NotArchive => {1463 error.EndOfStream, error.NotArchive => {
1448 archive.deinit(self.base.allocator);1464 archive.deinit(gpa);
1449 return false;1465 return false;
1450 },1466 },
1451 else => |e| return e,1467 else => |e| return e,
1452 };1468 };
14531469
1454 if (force_load) {1470 if (force_load) {
1455 defer archive.deinit(self.base.allocator);1471 defer archive.deinit(gpa);
1472 defer file.close();
1456 // Get all offsets from the ToC1473 // Get all offsets from the ToC
1457 var offsets = std.AutoArrayHashMap(u32, void).init(self.base.allocator);1474 var offsets = std.AutoArrayHashMap(u32, void).init(gpa);
1458 defer offsets.deinit();1475 defer offsets.deinit();
1459 for (archive.toc.values()) |offs| {1476 for (archive.toc.values()) |offs| {
1460 for (offs.items) |off| {1477 for (offs.items) |off| {
...@@ -1462,15 +1479,11 @@ fn parseArchive(self: *MachO, path: []const u8, force_load: bool) !bool {...@@ -1462,15 +1479,11 @@ fn parseArchive(self: *MachO, path: []const u8, force_load: bool) !bool {
1462 }1479 }
1463 }1480 }
1464 for (offsets.keys()) |off| {1481 for (offsets.keys()) |off| {
1465 const object = try self.objects.addOne(self.base.allocator);1482 const object = try archive.parseObject(gpa, cpu_arch, off);
1466 object.* = try archive.parseObject(1483 try self.objects.append(gpa, object);
1467 self.base.allocator,
1468 self.base.options.target.cpu.arch,
1469 off,
1470 );
1471 }1484 }
1472 } else {1485 } else {
1473 try self.archives.append(self.base.allocator, archive);1486 try self.archives.append(gpa, archive);
1474 }1487 }
14751488
1476 return true;1489 return true;
...@@ -1481,6 +1494,7 @@ const ParseDylibError = error{...@@ -1481,6 +1494,7 @@ const ParseDylibError = error{
1481 EmptyStubFile,1494 EmptyStubFile,
1482 MismatchedCpuArchitecture,1495 MismatchedCpuArchitecture,
1483 UnsupportedCpuArchitecture,1496 UnsupportedCpuArchitecture,
1497 EndOfStream,
1484} || fs.File.OpenError || std.os.PReadError || Dylib.Id.ParseError;1498} || fs.File.OpenError || std.os.PReadError || Dylib.Id.ParseError;
14851499
1486const DylibCreateOpts = struct {1500const DylibCreateOpts = struct {
...@@ -1497,43 +1511,52 @@ pub fn parseDylib(...@@ -1497,43 +1511,52 @@ pub fn parseDylib(
1497 dependent_libs: anytype,1511 dependent_libs: anytype,
1498 opts: DylibCreateOpts,1512 opts: DylibCreateOpts,
1499) ParseDylibError!bool {1513) ParseDylibError!bool {
1514 const gpa = self.base.allocator;
1500 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {1515 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
1501 error.FileNotFound => return false,1516 error.FileNotFound => return false,
1502 else => |e| return e,1517 else => |e| return e,
1503 };1518 };
1504 errdefer file.close();1519 defer file.close();
1520
1521 const cpu_arch = self.base.options.target.cpu.arch;
1522 const file_stat = try file.stat();
1523 var file_size = math.cast(usize, file_stat.size) orelse return error.Overflow;
1524
1525 const reader = file.reader();
1526 const fat_offset = try fat.getLibraryOffset(reader, cpu_arch);
1527 try file.seekTo(fat_offset);
1528 file_size -= fat_offset;
15051529
1506 const name = try self.base.allocator.dupe(u8, path);1530 const contents = try file.readToEndAllocOptions(gpa, file_size, file_size, @alignOf(u64), null);
1507 errdefer self.base.allocator.free(name);1531 defer gpa.free(contents);
15081532
1509 const dylib_id = @intCast(u16, self.dylibs.items.len);1533 const dylib_id = @intCast(u16, self.dylibs.items.len);
1510 var dylib = Dylib{1534 var dylib = Dylib{ .weak = opts.weak };
1511 .name = name,
1512 .file = file,
1513 .weak = opts.weak,
1514 };
15151535
1516 dylib.parse(1536 dylib.parseFromBinary(
1517 self.base.allocator,1537 gpa,
1518 self.base.options.target.cpu.arch,1538 cpu_arch,
1519 dylib_id,1539 dylib_id,
1520 dependent_libs,1540 dependent_libs,
1541 path,
1542 contents,
1521 ) catch |err| switch (err) {1543 ) catch |err| switch (err) {
1522 error.EndOfStream, error.NotDylib => {1544 error.EndOfStream, error.NotDylib => {
1523 try file.seekTo(0);1545 try file.seekTo(0);
15241546
1525 var lib_stub = LibStub.loadFromFile(self.base.allocator, file) catch {1547 var lib_stub = LibStub.loadFromFile(gpa, file) catch {
1526 dylib.deinit(self.base.allocator);1548 dylib.deinit(gpa);
1527 return false;1549 return false;
1528 };1550 };
1529 defer lib_stub.deinit();1551 defer lib_stub.deinit();
15301552
1531 try dylib.parseFromStub(1553 try dylib.parseFromStub(
1532 self.base.allocator,1554 gpa,
1533 self.base.options.target,1555 self.base.options.target,
1534 lib_stub,1556 lib_stub,
1535 dylib_id,1557 dylib_id,
1536 dependent_libs,1558 dependent_libs,
1559 path,
1537 );1560 );
1538 },1561 },
1539 else => |e| return e,1562 else => |e| return e,
...@@ -1547,13 +1570,13 @@ pub fn parseDylib(...@@ -1547,13 +1570,13 @@ pub fn parseDylib(
1547 log.warn(" dylib version: {}", .{dylib.id.?.current_version});1570 log.warn(" dylib version: {}", .{dylib.id.?.current_version});
15481571
1549 // TODO maybe this should be an error and facilitate auto-cleanup?1572 // TODO maybe this should be an error and facilitate auto-cleanup?
1550 dylib.deinit(self.base.allocator);1573 dylib.deinit(gpa);
1551 return false;1574 return false;
1552 }1575 }
1553 }1576 }
15541577
1555 try self.dylibs.append(self.base.allocator, dylib);1578 try self.dylibs.append(gpa, dylib);
1556 try self.dylibs_map.putNoClobber(self.base.allocator, dylib.id.?.name, dylib_id);1579 try self.dylibs_map.putNoClobber(gpa, dylib.id.?.name, dylib_id);
15571580
1558 const should_link_dylib_even_if_unreachable = blk: {1581 const should_link_dylib_even_if_unreachable = blk: {
1559 if (self.base.options.dead_strip_dylibs and !opts.needed) break :blk false;1582 if (self.base.options.dead_strip_dylibs and !opts.needed) break :blk false;
...@@ -1561,8 +1584,7 @@ pub fn parseDylib(...@@ -1561,8 +1584,7 @@ pub fn parseDylib(
1561 };1584 };
15621585
1563 if (should_link_dylib_even_if_unreachable) {1586 if (should_link_dylib_even_if_unreachable) {
1564 try self.addLoadDylibLC(dylib_id);1587 try self.referenced_dylibs.putNoClobber(gpa, dylib_id, {});
1565 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});
1566 }1588 }
15671589
1568 return true;1590 return true;
...@@ -1572,10 +1594,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const...@@ -1572,10 +1594,8 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const
1572 for (files) |file_name| {1594 for (files) |file_name| {
1573 const full_path = full_path: {1595 const full_path = full_path: {
1574 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;1596 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
1575 const path = try fs.realpath(file_name, &buffer);1597 break :full_path try fs.realpath(file_name, &buffer);
1576 break :full_path try self.base.allocator.dupe(u8, path);
1577 };1598 };
1578 defer self.base.allocator.free(full_path);
1579 log.debug("parsing input file path '{s}'", .{full_path});1599 log.debug("parsing input file path '{s}'", .{full_path});
15801600
1581 if (try self.parseObject(full_path)) continue;1601 if (try self.parseObject(full_path)) continue;
...@@ -1592,10 +1612,8 @@ fn parseAndForceLoadStaticArchives(self: *MachO, files: []const []const u8) !voi...@@ -1592,10 +1612,8 @@ fn parseAndForceLoadStaticArchives(self: *MachO, files: []const []const u8) !voi
1592 for (files) |file_name| {1612 for (files) |file_name| {
1593 const full_path = full_path: {1613 const full_path = full_path: {
1594 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;1614 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
1595 const path = try fs.realpath(file_name, &buffer);1615 break :full_path try fs.realpath(file_name, &buffer);
1596 break :full_path try self.base.allocator.dupe(u8, path);
1597 };1616 };
1598 defer self.base.allocator.free(full_path);
1599 log.debug("parsing and force loading static archive '{s}'", .{full_path});1617 log.debug("parsing and force loading static archive '{s}'", .{full_path});
16001618
1601 if (try self.parseArchive(full_path, true)) continue;1619 if (try self.parseArchive(full_path, true)) continue;
...@@ -1669,24 +1687,10 @@ fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs: any...@@ -1669,24 +1687,10 @@ fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs: any
1669 }1687 }
1670}1688}
16711689
1672pub const MatchingSection = struct {1690pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
1673 seg: u16,
1674 sect: u16,
1675
1676 pub fn eql(this: MatchingSection, other: struct {
1677 seg: ?u16,
1678 sect: ?u16,
1679 }) bool {
1680 const seg = other.seg orelse return false;
1681 const sect = other.sect orelse return false;
1682 return this.seg == seg and this.sect == sect;
1683 }
1684};
1685
1686pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSection {
1687 const segname = sect.segName();1691 const segname = sect.segName();
1688 const sectname = sect.sectName();1692 const sectname = sect.sectName();
1689 const res: ?MatchingSection = blk: {1693 const res: ?u8 = blk: {
1690 switch (sect.type_()) {1694 switch (sect.type_()) {
1691 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {1695 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
1692 if (self.text_const_section_index == null) {1696 if (self.text_const_section_index == null) {
...@@ -1698,11 +1702,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1698,11 +1702,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1698 .{},1702 .{},
1699 );1703 );
1700 }1704 }
17011705 break :blk self.text_const_section_index.?;
1702 break :blk .{
1703 .seg = self.text_segment_cmd_index.?,
1704 .sect = self.text_const_section_index.?,
1705 };
1706 },1706 },
1707 macho.S_CSTRING_LITERALS => {1707 macho.S_CSTRING_LITERALS => {
1708 if (mem.eql(u8, sectname, "__objc_methname")) {1708 if (mem.eql(u8, sectname, "__objc_methname")) {
...@@ -1717,11 +1717,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1717,11 +1717,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1717 .{},1717 .{},
1718 );1718 );
1719 }1719 }
17201720 break :blk self.objc_methname_section_index.?;
1721 break :blk .{
1722 .seg = self.text_segment_cmd_index.?,
1723 .sect = self.objc_methname_section_index.?,
1724 };
1725 } else if (mem.eql(u8, sectname, "__objc_methtype")) {1721 } else if (mem.eql(u8, sectname, "__objc_methtype")) {
1726 if (self.objc_methtype_section_index == null) {1722 if (self.objc_methtype_section_index == null) {
1727 self.objc_methtype_section_index = try self.initSection(1723 self.objc_methtype_section_index = try self.initSection(
...@@ -1732,11 +1728,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1732,11 +1728,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1732 .{},1728 .{},
1733 );1729 );
1734 }1730 }
17351731 break :blk self.objc_methtype_section_index.?;
1736 break :blk .{
1737 .seg = self.text_segment_cmd_index.?,
1738 .sect = self.objc_methtype_section_index.?,
1739 };
1740 } else if (mem.eql(u8, sectname, "__objc_classname")) {1732 } else if (mem.eql(u8, sectname, "__objc_classname")) {
1741 if (self.objc_classname_section_index == null) {1733 if (self.objc_classname_section_index == null) {
1742 self.objc_classname_section_index = try self.initSection(1734 self.objc_classname_section_index = try self.initSection(
...@@ -1747,11 +1739,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1747,11 +1739,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1747 .{},1739 .{},
1748 );1740 );
1749 }1741 }
17501742 break :blk self.objc_classname_section_index.?;
1751 break :blk .{
1752 .seg = self.text_segment_cmd_index.?,
1753 .sect = self.objc_classname_section_index.?,
1754 };
1755 }1743 }
17561744
1757 if (self.cstring_section_index == null) {1745 if (self.cstring_section_index == null) {
...@@ -1765,11 +1753,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1765,11 +1753,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1765 },1753 },
1766 );1754 );
1767 }1755 }
17681756 break :blk self.cstring_section_index.?;
1769 break :blk .{
1770 .seg = self.text_segment_cmd_index.?,
1771 .sect = self.cstring_section_index.?,
1772 };
1773 },1757 },
1774 macho.S_LITERAL_POINTERS => {1758 macho.S_LITERAL_POINTERS => {
1775 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {1759 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {
...@@ -1784,11 +1768,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1784,11 +1768,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1784 },1768 },
1785 );1769 );
1786 }1770 }
17871771 break :blk self.objc_selrefs_section_index.?;
1788 break :blk .{
1789 .seg = self.data_segment_cmd_index.?,
1790 .sect = self.objc_selrefs_section_index.?,
1791 };
1792 } else {1772 } else {
1793 // TODO investigate1773 // TODO investigate
1794 break :blk null;1774 break :blk null;
...@@ -1806,11 +1786,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1806,11 +1786,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1806 },1786 },
1807 );1787 );
1808 }1788 }
18091789 break :blk self.mod_init_func_section_index.?;
1810 break :blk .{
1811 .seg = self.data_const_segment_cmd_index.?,
1812 .sect = self.mod_init_func_section_index.?,
1813 };
1814 },1790 },
1815 macho.S_MOD_TERM_FUNC_POINTERS => {1791 macho.S_MOD_TERM_FUNC_POINTERS => {
1816 if (self.mod_term_func_section_index == null) {1792 if (self.mod_term_func_section_index == null) {
...@@ -1824,11 +1800,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1824,11 +1800,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1824 },1800 },
1825 );1801 );
1826 }1802 }
18271803 break :blk self.mod_term_func_section_index.?;
1828 break :blk .{
1829 .seg = self.data_const_segment_cmd_index.?,
1830 .sect = self.mod_term_func_section_index.?,
1831 };
1832 },1804 },
1833 macho.S_ZEROFILL => {1805 macho.S_ZEROFILL => {
1834 if (self.bss_section_index == null) {1806 if (self.bss_section_index == null) {
...@@ -1842,11 +1814,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1842,11 +1814,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1842 },1814 },
1843 );1815 );
1844 }1816 }
18451817 break :blk self.bss_section_index.?;
1846 break :blk .{
1847 .seg = self.data_segment_cmd_index.?,
1848 .sect = self.bss_section_index.?,
1849 };
1850 },1818 },
1851 macho.S_THREAD_LOCAL_VARIABLES => {1819 macho.S_THREAD_LOCAL_VARIABLES => {
1852 if (self.tlv_section_index == null) {1820 if (self.tlv_section_index == null) {
...@@ -1860,11 +1828,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1860,11 +1828,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1860 },1828 },
1861 );1829 );
1862 }1830 }
18631831 break :blk self.tlv_section_index.?;
1864 break :blk .{
1865 .seg = self.data_segment_cmd_index.?,
1866 .sect = self.tlv_section_index.?,
1867 };
1868 },1832 },
1869 macho.S_THREAD_LOCAL_VARIABLE_POINTERS => {1833 macho.S_THREAD_LOCAL_VARIABLE_POINTERS => {
1870 if (self.tlv_ptrs_section_index == null) {1834 if (self.tlv_ptrs_section_index == null) {
...@@ -1878,11 +1842,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1878,11 +1842,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1878 },1842 },
1879 );1843 );
1880 }1844 }
18811845 break :blk self.tlv_ptrs_section_index.?;
1882 break :blk .{
1883 .seg = self.data_segment_cmd_index.?,
1884 .sect = self.tlv_ptrs_section_index.?,
1885 };
1886 },1846 },
1887 macho.S_THREAD_LOCAL_REGULAR => {1847 macho.S_THREAD_LOCAL_REGULAR => {
1888 if (self.tlv_data_section_index == null) {1848 if (self.tlv_data_section_index == null) {
...@@ -1896,11 +1856,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1896,11 +1856,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1896 },1856 },
1897 );1857 );
1898 }1858 }
18991859 break :blk self.tlv_data_section_index.?;
1900 break :blk .{
1901 .seg = self.data_segment_cmd_index.?,
1902 .sect = self.tlv_data_section_index.?,
1903 };
1904 },1860 },
1905 macho.S_THREAD_LOCAL_ZEROFILL => {1861 macho.S_THREAD_LOCAL_ZEROFILL => {
1906 if (self.tlv_bss_section_index == null) {1862 if (self.tlv_bss_section_index == null) {
...@@ -1914,11 +1870,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1914,11 +1870,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1914 },1870 },
1915 );1871 );
1916 }1872 }
19171873 break :blk self.tlv_bss_section_index.?;
1918 break :blk .{
1919 .seg = self.data_segment_cmd_index.?,
1920 .sect = self.tlv_bss_section_index.?,
1921 };
1922 },1874 },
1923 macho.S_COALESCED => {1875 macho.S_COALESCED => {
1924 if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) {1876 if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) {
...@@ -1933,11 +1885,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1933,11 +1885,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1933 .{},1885 .{},
1934 );1886 );
1935 }1887 }
19361888 break :blk self.eh_frame_section_index.?;
1937 break :blk .{
1938 .seg = self.text_segment_cmd_index.?,
1939 .sect = self.eh_frame_section_index.?,
1940 };
1941 }1889 }
19421890
1943 // TODO audit this: is this the right mapping?1891 // TODO audit this: is this the right mapping?
...@@ -1951,10 +1899,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1951,10 +1899,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1951 );1899 );
1952 }1900 }
19531901
1954 break :blk .{1902 break :blk self.data_const_section_index.?;
1955 .seg = self.data_const_segment_cmd_index.?,
1956 .sect = self.data_const_section_index.?,
1957 };
1958 },1903 },
1959 macho.S_REGULAR => {1904 macho.S_REGULAR => {
1960 if (sect.isCode()) {1905 if (sect.isCode()) {
...@@ -1971,11 +1916,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1971,11 +1916,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1971 },1916 },
1972 );1917 );
1973 }1918 }
19741919 break :blk self.text_section_index.?;
1975 break :blk .{
1976 .seg = self.text_segment_cmd_index.?,
1977 .sect = self.text_section_index.?,
1978 };
1979 }1920 }
1980 if (sect.isDebug()) {1921 if (sect.isDebug()) {
1981 // TODO debug attributes1922 // TODO debug attributes
...@@ -1998,11 +1939,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1998,11 +1939,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1998 .{},1939 .{},
1999 );1940 );
2000 }1941 }
20011942 break :blk self.ustring_section_index.?;
2002 break :blk .{
2003 .seg = self.text_segment_cmd_index.?,
2004 .sect = self.ustring_section_index.?,
2005 };
2006 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {1943 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {
2007 if (self.gcc_except_tab_section_index == null) {1944 if (self.gcc_except_tab_section_index == null) {
2008 self.gcc_except_tab_section_index = try self.initSection(1945 self.gcc_except_tab_section_index = try self.initSection(
...@@ -2013,11 +1950,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2013,11 +1950,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2013 .{},1950 .{},
2014 );1951 );
2015 }1952 }
20161953 break :blk self.gcc_except_tab_section_index.?;
2017 break :blk .{
2018 .seg = self.text_segment_cmd_index.?,
2019 .sect = self.gcc_except_tab_section_index.?,
2020 };
2021 } else if (mem.eql(u8, sectname, "__objc_methlist")) {1954 } else if (mem.eql(u8, sectname, "__objc_methlist")) {
2022 if (self.objc_methlist_section_index == null) {1955 if (self.objc_methlist_section_index == null) {
2023 self.objc_methlist_section_index = try self.initSection(1956 self.objc_methlist_section_index = try self.initSection(
...@@ -2028,11 +1961,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2028,11 +1961,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2028 .{},1961 .{},
2029 );1962 );
2030 }1963 }
20311964 break :blk self.objc_methlist_section_index.?;
2032 break :blk .{
2033 .seg = self.text_segment_cmd_index.?,
2034 .sect = self.objc_methlist_section_index.?,
2035 };
2036 } else if (mem.eql(u8, sectname, "__rodata") or1965 } else if (mem.eql(u8, sectname, "__rodata") or
2037 mem.eql(u8, sectname, "__typelink") or1966 mem.eql(u8, sectname, "__typelink") or
2038 mem.eql(u8, sectname, "__itablink") or1967 mem.eql(u8, sectname, "__itablink") or
...@@ -2048,11 +1977,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2048,11 +1977,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2048 .{},1977 .{},
2049 );1978 );
2050 }1979 }
20511980 break :blk self.data_const_section_index.?;
2052 break :blk .{
2053 .seg = self.data_const_segment_cmd_index.?,
2054 .sect = self.data_const_section_index.?,
2055 };
2056 } else {1981 } else {
2057 if (self.text_const_section_index == null) {1982 if (self.text_const_section_index == null) {
2058 self.text_const_section_index = try self.initSection(1983 self.text_const_section_index = try self.initSection(
...@@ -2063,11 +1988,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2063,11 +1988,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2063 .{},1988 .{},
2064 );1989 );
2065 }1990 }
20661991 break :blk self.text_const_section_index.?;
2067 break :blk .{
2068 .seg = self.text_segment_cmd_index.?,
2069 .sect = self.text_const_section_index.?,
2070 };
2071 }1992 }
2072 }1993 }
20731994
...@@ -2081,11 +2002,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2081,11 +2002,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2081 .{},2002 .{},
2082 );2003 );
2083 }2004 }
20842005 break :blk self.data_const_section_index.?;
2085 break :blk .{
2086 .seg = self.data_const_segment_cmd_index.?,
2087 .sect = self.data_const_section_index.?,
2088 };
2089 }2006 }
20902007
2091 if (mem.eql(u8, segname, "__DATA")) {2008 if (mem.eql(u8, segname, "__DATA")) {
...@@ -2099,11 +2016,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2099,11 +2016,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2099 .{},2016 .{},
2100 );2017 );
2101 }2018 }
21022019 break :blk self.data_const_section_index.?;
2103 break :blk .{
2104 .seg = self.data_const_segment_cmd_index.?,
2105 .sect = self.data_const_section_index.?,
2106 };
2107 } else if (mem.eql(u8, sectname, "__cfstring")) {2020 } else if (mem.eql(u8, sectname, "__cfstring")) {
2108 if (self.objc_cfstring_section_index == null) {2021 if (self.objc_cfstring_section_index == null) {
2109 self.objc_cfstring_section_index = try self.initSection(2022 self.objc_cfstring_section_index = try self.initSection(
...@@ -2114,11 +2027,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2114,11 +2027,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2114 .{},2027 .{},
2115 );2028 );
2116 }2029 }
21172030 break :blk self.objc_cfstring_section_index.?;
2118 break :blk .{
2119 .seg = self.data_const_segment_cmd_index.?,
2120 .sect = self.objc_cfstring_section_index.?,
2121 };
2122 } else if (mem.eql(u8, sectname, "__objc_classlist")) {2031 } else if (mem.eql(u8, sectname, "__objc_classlist")) {
2123 if (self.objc_classlist_section_index == null) {2032 if (self.objc_classlist_section_index == null) {
2124 self.objc_classlist_section_index = try self.initSection(2033 self.objc_classlist_section_index = try self.initSection(
...@@ -2129,11 +2038,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2129,11 +2038,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2129 .{},2038 .{},
2130 );2039 );
2131 }2040 }
21322041 break :blk self.objc_classlist_section_index.?;
2133 break :blk .{
2134 .seg = self.data_const_segment_cmd_index.?,
2135 .sect = self.objc_classlist_section_index.?,
2136 };
2137 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {2042 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {
2138 if (self.objc_imageinfo_section_index == null) {2043 if (self.objc_imageinfo_section_index == null) {
2139 self.objc_imageinfo_section_index = try self.initSection(2044 self.objc_imageinfo_section_index = try self.initSection(
...@@ -2144,11 +2049,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2144,11 +2049,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2144 .{},2049 .{},
2145 );2050 );
2146 }2051 }
21472052 break :blk self.objc_imageinfo_section_index.?;
2148 break :blk .{
2149 .seg = self.data_const_segment_cmd_index.?,
2150 .sect = self.objc_imageinfo_section_index.?,
2151 };
2152 } else if (mem.eql(u8, sectname, "__objc_const")) {2053 } else if (mem.eql(u8, sectname, "__objc_const")) {
2153 if (self.objc_const_section_index == null) {2054 if (self.objc_const_section_index == null) {
2154 self.objc_const_section_index = try self.initSection(2055 self.objc_const_section_index = try self.initSection(
...@@ -2159,11 +2060,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2159,11 +2060,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2159 .{},2060 .{},
2160 );2061 );
2161 }2062 }
21622063 break :blk self.objc_const_section_index.?;
2163 break :blk .{
2164 .seg = self.data_segment_cmd_index.?,
2165 .sect = self.objc_const_section_index.?,
2166 };
2167 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {2064 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {
2168 if (self.objc_classrefs_section_index == null) {2065 if (self.objc_classrefs_section_index == null) {
2169 self.objc_classrefs_section_index = try self.initSection(2066 self.objc_classrefs_section_index = try self.initSection(
...@@ -2174,11 +2071,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2174,11 +2071,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2174 .{},2071 .{},
2175 );2072 );
2176 }2073 }
21772074 break :blk self.objc_classrefs_section_index.?;
2178 break :blk .{
2179 .seg = self.data_segment_cmd_index.?,
2180 .sect = self.objc_classrefs_section_index.?,
2181 };
2182 } else if (mem.eql(u8, sectname, "__objc_data")) {2075 } else if (mem.eql(u8, sectname, "__objc_data")) {
2183 if (self.objc_data_section_index == null) {2076 if (self.objc_data_section_index == null) {
2184 self.objc_data_section_index = try self.initSection(2077 self.objc_data_section_index = try self.initSection(
...@@ -2189,11 +2082,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2189,11 +2082,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2189 .{},2082 .{},
2190 );2083 );
2191 }2084 }
21922085 break :blk self.objc_data_section_index.?;
2193 break :blk .{
2194 .seg = self.data_segment_cmd_index.?,
2195 .sect = self.objc_data_section_index.?,
2196 };
2197 } else if (mem.eql(u8, sectname, ".rustc")) {2086 } else if (mem.eql(u8, sectname, ".rustc")) {
2198 if (self.rustc_section_index == null) {2087 if (self.rustc_section_index == null) {
2199 self.rustc_section_index = try self.initSection(2088 self.rustc_section_index = try self.initSection(
...@@ -2207,11 +2096,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2207,11 +2096,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2207 // decompress the metadata.2096 // decompress the metadata.
2208 self.rustc_section_size = sect.size;2097 self.rustc_section_size = sect.size;
2209 }2098 }
22102099 break :blk self.rustc_section_index.?;
2211 break :blk .{
2212 .seg = self.data_segment_cmd_index.?,
2213 .sect = self.rustc_section_index.?,
2214 };
2215 } else {2100 } else {
2216 if (self.data_section_index == null) {2101 if (self.data_section_index == null) {
2217 self.data_section_index = try self.initSection(2102 self.data_section_index = try self.initSection(
...@@ -2222,11 +2107,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -2222,11 +2107,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
2222 .{},2107 .{},
2223 );2108 );
2224 }2109 }
22252110 break :blk self.data_section_index.?;
2226 break :blk .{
2227 .seg = self.data_segment_cmd_index.?,
2228 .sect = self.data_section_index.?,
2229 };
2230 }2111 }
2231 }2112 }
22322113
...@@ -2259,30 +2140,33 @@ pub fn createEmptyAtom(gpa: Allocator, sym_index: u32, size: u64, alignment: u32...@@ -2259,30 +2140,33 @@ pub fn createEmptyAtom(gpa: Allocator, sym_index: u32, size: u64, alignment: u32
2259 return atom;2140 return atom;
2260}2141}
22612142
2262pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {2143pub fn writeAtom(self: *MachO, atom: *Atom, sect_id: u8) !void {
2263 const sect = self.getSection(match);2144 const section = self.sections.get(sect_id);
2264 const sym = atom.getSymbol(self);2145 const sym = atom.getSymbol(self);
2265 const file_offset = sect.offset + sym.n_value - sect.addr;2146 const file_offset = section.header.offset + sym.n_value - section.header.addr;
2266 try atom.resolveRelocs(self);2147 try atom.resolveRelocs(self);
2267 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });2148 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
2268 try self.base.file.?.pwriteAll(atom.code.items, file_offset);2149 try self.base.file.?.pwriteAll(atom.code.items, file_offset);
2269}2150}
22702151
2271fn allocateSymbols(self: *MachO) !void {2152fn allocateSymbols(self: *MachO) !void {
2272 var it = self.atoms.iterator();2153 const slice = self.sections.slice();
2273 while (it.next()) |entry| {2154 for (slice.items(.last_atom)) |last_atom, sect_id| {
2274 const match = entry.key_ptr.*;2155 const header = slice.items(.header)[sect_id];
2275 var atom = entry.value_ptr.*;2156 var atom = last_atom orelse continue;
22762157
2277 while (atom.prev) |prev| {2158 while (atom.prev) |prev| {
2278 atom = prev;2159 atom = prev;
2279 }2160 }
22802161
2281 const n_sect = self.getSectionOrdinal(match);2162 const n_sect = @intCast(u8, sect_id + 1);
2282 const sect = self.getSection(match);2163 var base_vaddr = header.addr;
2283 var base_vaddr = sect.addr;
22842164
2285 log.debug("allocating local symbols in sect({d}, '{s},{s}')", .{ n_sect, sect.segName(), sect.sectName() });2165 log.debug("allocating local symbols in sect({d}, '{s},{s}')", .{
2166 n_sect,
2167 header.segName(),
2168 header.sectName(),
2169 });
22862170
2287 while (true) {2171 while (true) {
2288 const alignment = try math.powi(u32, 2, atom.alignment);2172 const alignment = try math.powi(u32, 2, atom.alignment);
...@@ -2296,7 +2180,10 @@ fn allocateSymbols(self: *MachO) !void {...@@ -2296,7 +2180,10 @@ fn allocateSymbols(self: *MachO) !void {
22962180
2297 // Update each symbol contained within the atom2181 // Update each symbol contained within the atom
2298 for (atom.contained.items) |sym_at_off| {2182 for (atom.contained.items) |sym_at_off| {
2299 const contained_sym = self.getSymbolPtr(.{ .sym_index = sym_at_off.sym_index, .file = atom.file });2183 const contained_sym = self.getSymbolPtr(.{
2184 .sym_index = sym_at_off.sym_index,
2185 .file = atom.file,
2186 });
2300 contained_sym.n_value = base_vaddr + sym_at_off.offset;2187 contained_sym.n_value = base_vaddr + sym_at_off.offset;
2301 contained_sym.n_sect = n_sect;2188 contained_sym.n_sect = n_sect;
2302 }2189 }
...@@ -2310,15 +2197,18 @@ fn allocateSymbols(self: *MachO) !void {...@@ -2310,15 +2197,18 @@ fn allocateSymbols(self: *MachO) !void {
2310 }2197 }
2311}2198}
23122199
2313fn shiftLocalsByOffset(self: *MachO, match: MatchingSection, offset: i64) !void {2200fn shiftLocalsByOffset(self: *MachO, sect_id: u8, offset: i64) !void {
2314 var atom = self.atoms.get(match) orelse return;2201 var atom = self.sections.items(.last_atom)[sect_id] orelse return;
23152202
2316 while (true) {2203 while (true) {
2317 const atom_sym = atom.getSymbolPtr(self);2204 const atom_sym = atom.getSymbolPtr(self);
2318 atom_sym.n_value = @intCast(u64, @intCast(i64, atom_sym.n_value) + offset);2205 atom_sym.n_value = @intCast(u64, @intCast(i64, atom_sym.n_value) + offset);
23192206
2320 for (atom.contained.items) |sym_at_off| {2207 for (atom.contained.items) |sym_at_off| {
2321 const contained_sym = self.getSymbolPtr(.{ .sym_index = sym_at_off.sym_index, .file = atom.file });2208 const contained_sym = self.getSymbolPtr(.{
2209 .sym_index = sym_at_off.sym_index,
2210 .file = atom.file,
2211 });
2322 contained_sym.n_value = @intCast(u64, @intCast(i64, contained_sym.n_value) + offset);2212 contained_sym.n_value = @intCast(u64, @intCast(i64, contained_sym.n_value) + offset);
2323 }2213 }
23242214
...@@ -2336,16 +2226,13 @@ fn allocateSpecialSymbols(self: *MachO) !void {...@@ -2336,16 +2226,13 @@ fn allocateSpecialSymbols(self: *MachO) !void {
2336 const global = self.globals.get(name) orelse continue;2226 const global = self.globals.get(name) orelse continue;
2337 if (global.file != null) continue;2227 if (global.file != null) continue;
2338 const sym = self.getSymbolPtr(global);2228 const sym = self.getSymbolPtr(global);
2339 const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;2229 const seg = self.segments.items[self.text_segment_cmd_index.?];
2340 sym.n_sect = self.getSectionOrdinal(.{2230 sym.n_sect = 1;
2341 .seg = self.text_segment_cmd_index.?,2231 sym.n_value = seg.vmaddr;
2342 .sect = 0,
2343 });
2344 sym.n_value = seg.inner.vmaddr;
23452232
2346 log.debug("allocating {s} at the start of {s}", .{2233 log.debug("allocating {s} at the start of {s}", .{
2347 name,2234 name,
2348 seg.inner.segName(),2235 seg.segName(),
2349 });2236 });
2350 }2237 }
2351}2238}
...@@ -2353,18 +2240,20 @@ fn allocateSpecialSymbols(self: *MachO) !void {...@@ -2353,18 +2240,20 @@ fn allocateSpecialSymbols(self: *MachO) !void {
2353fn writeAtomsOneShot(self: *MachO) !void {2240fn writeAtomsOneShot(self: *MachO) !void {
2354 assert(self.mode == .one_shot);2241 assert(self.mode == .one_shot);
23552242
2356 var it = self.atoms.iterator();2243 const gpa = self.base.allocator;
2357 while (it.next()) |entry| {2244 const slice = self.sections.slice();
2358 const sect = self.getSection(entry.key_ptr.*);2245
2359 var atom: *Atom = entry.value_ptr.*;2246 for (slice.items(.last_atom)) |last_atom, sect_id| {
2247 const header = slice.items(.header)[sect_id];
2248 var atom = last_atom.?;
23602249
2361 if (sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL) continue;2250 if (header.flags == macho.S_ZEROFILL or header.flags == macho.S_THREAD_LOCAL_ZEROFILL) continue;
23622251
2363 var buffer = std.ArrayList(u8).init(self.base.allocator);2252 var buffer = std.ArrayList(u8).init(gpa);
2364 defer buffer.deinit();2253 defer buffer.deinit();
2365 try buffer.ensureTotalCapacity(math.cast(usize, sect.size) orelse return error.Overflow);2254 try buffer.ensureTotalCapacity(math.cast(usize, header.size) orelse return error.Overflow);
23662255
2367 log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() });2256 log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() });
23682257
2369 while (atom.prev) |prev| {2258 while (atom.prev) |prev| {
2370 atom = prev;2259 atom = prev;
...@@ -2399,18 +2288,18 @@ fn writeAtomsOneShot(self: *MachO) !void {...@@ -2399,18 +2288,18 @@ fn writeAtomsOneShot(self: *MachO) !void {
2399 if (atom.next) |next| {2288 if (atom.next) |next| {
2400 atom = next;2289 atom = next;
2401 } else {2290 } else {
2402 assert(buffer.items.len == sect.size);2291 assert(buffer.items.len == header.size);
2403 log.debug(" (writing at file offset 0x{x})", .{sect.offset});2292 log.debug(" (writing at file offset 0x{x})", .{header.offset});
2404 try self.base.file.?.pwriteAll(buffer.items, sect.offset);2293 try self.base.file.?.pwriteAll(buffer.items, header.offset);
2405 break;2294 break;
2406 }2295 }
2407 }2296 }
2408 }2297 }
2409}2298}
24102299
2411fn writePadding(self: *MachO, match: MatchingSection, size: usize, writer: anytype) !void {2300fn writePadding(self: *MachO, sect_id: u8, size: usize, writer: anytype) !void {
2412 const is_code = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;2301 const header = self.sections.items(.header)[sect_id];
2413 const min_alignment: u3 = if (!is_code)2302 const min_alignment: u3 = if (!header.isCode())
2414 12303 1
2415 else switch (self.base.options.target.cpu.arch) {2304 else switch (self.base.options.target.cpu.arch) {
2416 .aarch64 => @sizeOf(u32),2305 .aarch64 => @sizeOf(u32),
...@@ -2421,7 +2310,7 @@ fn writePadding(self: *MachO, match: MatchingSection, size: usize, writer: anyty...@@ -2421,7 +2310,7 @@ fn writePadding(self: *MachO, match: MatchingSection, size: usize, writer: anyty
2421 const len = @divExact(size, min_alignment);2310 const len = @divExact(size, min_alignment);
2422 var i: usize = 0;2311 var i: usize = 0;
2423 while (i < len) : (i += 1) {2312 while (i < len) : (i += 1) {
2424 if (!is_code) {2313 if (!header.isCode()) {
2425 try writer.writeByte(0);2314 try writer.writeByte(0);
2426 } else switch (self.base.options.target.cpu.arch) {2315 } else switch (self.base.options.target.cpu.arch) {
2427 .aarch64 => {2316 .aarch64 => {
...@@ -2439,20 +2328,20 @@ fn writePadding(self: *MachO, match: MatchingSection, size: usize, writer: anyty...@@ -2439,20 +2328,20 @@ fn writePadding(self: *MachO, match: MatchingSection, size: usize, writer: anyty
2439fn writeAtomsIncremental(self: *MachO) !void {2328fn writeAtomsIncremental(self: *MachO) !void {
2440 assert(self.mode == .incremental);2329 assert(self.mode == .incremental);
24412330
2442 var it = self.atoms.iterator();2331 const slice = self.sections.slice();
2443 while (it.next()) |entry| {2332 for (slice.items(.last_atom)) |last, i| {
2444 const match = entry.key_ptr.*;2333 var atom: *Atom = last orelse continue;
2445 const sect = self.getSection(match);2334 const sect_i = @intCast(u8, i);
2446 var atom: *Atom = entry.value_ptr.*;2335 const header = slice.items(.header)[sect_i];
24472336
2448 // TODO handle zerofill in stage22337 // TODO handle zerofill in stage2
2449 // if (sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL) continue;2338 // if (sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL) continue;
24502339
2451 log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() });2340 log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() });
24522341
2453 while (true) {2342 while (true) {
2454 if (atom.dirty) {2343 if (atom.dirty) {
2455 try self.writeAtom(atom, match);2344 try self.writeAtom(atom, sect_i);
2456 atom.dirty = false;2345 atom.dirty = false;
2457 }2346 }
24582347
...@@ -2503,10 +2392,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {...@@ -2503,10 +2392,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
2503 try self.managed_atoms.append(gpa, atom);2392 try self.managed_atoms.append(gpa, atom);
2504 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);2393 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
25052394
2506 try self.allocateAtomCommon(atom, .{2395 try self.allocateAtomCommon(atom, self.got_section_index.?);
2507 .seg = self.data_const_segment_cmd_index.?,
2508 .sect = self.got_section_index.?,
2509 });
25102396
2511 return atom;2397 return atom;
2512}2398}
...@@ -2535,7 +2421,7 @@ pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom {...@@ -2535,7 +2421,7 @@ pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
2535 try self.managed_atoms.append(gpa, atom);2421 try self.managed_atoms.append(gpa, atom);
2536 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);2422 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
25372423
2538 const match = (try self.getMatchingSection(.{2424 const match = (try self.getOutputSection(.{
2539 .segname = makeStaticString("__DATA"),2425 .segname = makeStaticString("__DATA"),
2540 .sectname = makeStaticString("__thread_ptrs"),2426 .sectname = makeStaticString("__thread_ptrs"),
2541 .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,2427 .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
...@@ -2561,10 +2447,7 @@ fn createDyldPrivateAtom(self: *MachO) !void {...@@ -2561,10 +2447,7 @@ fn createDyldPrivateAtom(self: *MachO) !void {
2561 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);2447 const atom = try MachO.createEmptyAtom(gpa, sym_index, @sizeOf(u64), 3);
2562 self.dyld_private_atom = atom;2448 self.dyld_private_atom = atom;
25632449
2564 try self.allocateAtomCommon(atom, .{2450 try self.allocateAtomCommon(atom, self.data_section_index.?);
2565 .seg = self.data_segment_cmd_index.?,
2566 .sect = self.data_section_index.?,
2567 });
25682451
2569 try self.managed_atoms.append(gpa, atom);2452 try self.managed_atoms.append(gpa, atom);
2570 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);2453 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
...@@ -2692,10 +2575,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -2692,10 +2575,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
2692 }2575 }
2693 self.stub_helper_preamble_atom = atom;2576 self.stub_helper_preamble_atom = atom;
26942577
2695 try self.allocateAtomCommon(atom, .{2578 try self.allocateAtomCommon(atom, self.stub_helper_section_index.?);
2696 .seg = self.text_segment_cmd_index.?,
2697 .sect = self.stub_helper_section_index.?,
2698 });
26992579
2700 try self.managed_atoms.append(gpa, atom);2580 try self.managed_atoms.append(gpa, atom);
2701 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);2581 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
...@@ -2771,10 +2651,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {...@@ -2771,10 +2651,7 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom {
2771 try self.managed_atoms.append(gpa, atom);2651 try self.managed_atoms.append(gpa, atom);
2772 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);2652 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
27732653
2774 try self.allocateAtomCommon(atom, .{2654 try self.allocateAtomCommon(atom, self.stub_helper_section_index.?);
2775 .seg = self.text_segment_cmd_index.?,
2776 .sect = self.stub_helper_section_index.?,
2777 });
27782655
2779 return atom;2656 return atom;
2780}2657}
...@@ -2814,10 +2691,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi...@@ -2814,10 +2691,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi
2814 try self.managed_atoms.append(gpa, atom);2691 try self.managed_atoms.append(gpa, atom);
2815 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);2692 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
28162693
2817 try self.allocateAtomCommon(atom, .{2694 try self.allocateAtomCommon(atom, self.la_symbol_ptr_section_index.?);
2818 .seg = self.data_segment_cmd_index.?,
2819 .sect = self.la_symbol_ptr_section_index.?,
2820 });
28212695
2822 return atom;2696 return atom;
2823}2697}
...@@ -2896,10 +2770,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {...@@ -2896,10 +2770,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom {
2896 try self.managed_atoms.append(gpa, atom);2770 try self.managed_atoms.append(gpa, atom);
2897 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);2771 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom);
28982772
2899 try self.allocateAtomCommon(atom, .{2773 try self.allocateAtomCommon(atom, self.stubs_section_index.?);
2900 .seg = self.text_segment_cmd_index.?,
2901 .sect = self.stubs_section_index.?,
2902 });
29032774
2904 return atom;2775 return atom;
2905}2776}
...@@ -2917,12 +2788,6 @@ fn createTentativeDefAtoms(self: *MachO) !void {...@@ -2917,12 +2788,6 @@ fn createTentativeDefAtoms(self: *MachO) !void {
29172788
2918 // Convert any tentative definition into a regular symbol and allocate2789 // Convert any tentative definition into a regular symbol and allocate
2919 // text blocks for each tentative definition.2790 // text blocks for each tentative definition.
2920 const match = MatchingSection{
2921 .seg = self.data_segment_cmd_index.?,
2922 .sect = self.bss_section_index.?,
2923 };
2924 _ = try self.section_ordinals.getOrPut(gpa, match);
2925
2926 const size = sym.n_value;2791 const size = sym.n_value;
2927 const alignment = (sym.n_desc >> 8) & 0x0f;2792 const alignment = (sym.n_desc >> 8) & 0x0f;
29282793
...@@ -2937,7 +2802,7 @@ fn createTentativeDefAtoms(self: *MachO) !void {...@@ -2937,7 +2802,7 @@ fn createTentativeDefAtoms(self: *MachO) !void {
2937 const atom = try MachO.createEmptyAtom(gpa, global.sym_index, size, alignment);2802 const atom = try MachO.createEmptyAtom(gpa, global.sym_index, size, alignment);
2938 atom.file = global.file;2803 atom.file = global.file;
29392804
2940 try self.allocateAtomCommon(atom, match);2805 try self.allocateAtomCommon(atom, self.bss_section_index.?);
29412806
2942 if (global.file) |file| {2807 if (global.file) |file| {
2943 const object = &self.objects.items[file];2808 const object = &self.objects.items[file];
...@@ -3060,7 +2925,8 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -3060,7 +2925,8 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
3060 gop.value_ptr.* = current;2925 gop.value_ptr.* = current;
3061}2926}
30622927
3063fn resolveSymbolsInObject(self: *MachO, object: *Object, object_id: u16) !void {2928fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2929 const object = &self.objects.items[object_id];
3064 log.debug("resolving symbols in '{s}'", .{object.name});2930 log.debug("resolving symbols in '{s}'", .{object.name});
30652931
3066 for (object.symtab.items) |sym, index| {2932 for (object.symtab.items) |sym, index| {
...@@ -3115,6 +2981,8 @@ fn resolveSymbolsInObject(self: *MachO, object: *Object, object_id: u16) !void {...@@ -3115,6 +2981,8 @@ fn resolveSymbolsInObject(self: *MachO, object: *Object, object_id: u16) !void {
3115fn resolveSymbolsInArchives(self: *MachO) !void {2981fn resolveSymbolsInArchives(self: *MachO) !void {
3116 if (self.archives.items.len == 0) return;2982 if (self.archives.items.len == 0) return;
31172983
2984 const gpa = self.base.allocator;
2985 const cpu_arch = self.base.options.target.cpu.arch;
3118 var next_sym: usize = 0;2986 var next_sym: usize = 0;
3119 loop: while (next_sym < self.unresolved.count()) {2987 loop: while (next_sym < self.unresolved.count()) {
3120 const global = self.globals.values()[self.unresolved.keys()[next_sym]];2988 const global = self.globals.values()[self.unresolved.keys()[next_sym]];
...@@ -3129,13 +2997,9 @@ fn resolveSymbolsInArchives(self: *MachO) !void {...@@ -3129,13 +2997,9 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
3129 assert(offsets.items.len > 0);2997 assert(offsets.items.len > 0);
31302998
3131 const object_id = @intCast(u16, self.objects.items.len);2999 const object_id = @intCast(u16, self.objects.items.len);
3132 const object = try self.objects.addOne(self.base.allocator);3000 const object = try archive.parseObject(gpa, cpu_arch, offsets.items[0]);
3133 object.* = try archive.parseObject(3001 try self.objects.append(gpa, object);
3134 self.base.allocator,3002 try self.resolveSymbolsInObject(object_id);
3135 self.base.options.target.cpu.arch,
3136 offsets.items[0],
3137 );
3138 try self.resolveSymbolsInObject(object, object_id);
31393003
3140 continue :loop;3004 continue :loop;
3141 }3005 }
...@@ -3159,7 +3023,6 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {...@@ -3159,7 +3023,6 @@ fn resolveSymbolsInDylibs(self: *MachO) !void {
31593023
3160 const dylib_id = @intCast(u16, id);3024 const dylib_id = @intCast(u16, id);
3161 if (!self.referenced_dylibs.contains(dylib_id)) {3025 if (!self.referenced_dylibs.contains(dylib_id)) {
3162 try self.addLoadDylibLC(dylib_id);
3163 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});3026 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});
3164 }3027 }
31653028
...@@ -3257,7 +3120,6 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -3257,7 +3120,6 @@ fn resolveDyldStubBinder(self: *MachO) !void {
32573120
3258 const dylib_id = @intCast(u16, id);3121 const dylib_id = @intCast(u16, id);
3259 if (!self.referenced_dylibs.contains(dylib_id)) {3122 if (!self.referenced_dylibs.contains(dylib_id)) {
3260 try self.addLoadDylibLC(dylib_id);
3261 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});3123 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});
3262 }3124 }
32633125
...@@ -3280,47 +3142,192 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -3280,47 +3142,192 @@ fn resolveDyldStubBinder(self: *MachO) !void {
3280 self.got_entries.items[got_index].sym_index = got_atom.sym_index;3142 self.got_entries.items[got_index].sym_index = got_atom.sym_index;
3281}3143}
32823144
3283fn addLoadDylibLC(self: *MachO, id: u16) !void {3145fn writeDylinkerLC(ncmds: *u32, lc_writer: anytype) !void {
3284 const dylib = self.dylibs.items[id];3146 const name_len = mem.sliceTo(default_dyld_path, 0).len;
3285 const dylib_id = dylib.id orelse unreachable;3147 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
3286 var dylib_cmd = try macho.createLoadDylibCommand(3148 u64,
3287 self.base.allocator,3149 @sizeOf(macho.dylinker_command) + name_len,
3288 if (dylib.weak) .LOAD_WEAK_DYLIB else .LOAD_DYLIB,3150 @sizeOf(u64),
3289 dylib_id.name,3151 ));
3290 dylib_id.timestamp,3152 try lc_writer.writeStruct(macho.dylinker_command{
3291 dylib_id.current_version,3153 .cmd = .LOAD_DYLINKER,
3292 dylib_id.compatibility_version,3154 .cmdsize = cmdsize,
3293 );3155 .name = @sizeOf(macho.dylinker_command),
3294 errdefer dylib_cmd.deinit(self.base.allocator);3156 });
3295 try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd });3157 try lc_writer.writeAll(mem.sliceTo(default_dyld_path, 0));
3296 self.load_commands_dirty = true;3158 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;
3159 if (padding > 0) {
3160 try lc_writer.writeByteNTimes(0, padding);
3161 }
3162 ncmds.* += 1;
3163}
3164
3165fn writeMainLC(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3166 if (self.base.options.output_mode != .Exe) return;
3167 const seg = self.segments.items[self.text_segment_cmd_index.?];
3168 const global = try self.getEntryPoint();
3169 const sym = self.getSymbol(global);
3170 try lc_writer.writeStruct(macho.entry_point_command{
3171 .cmd = .MAIN,
3172 .cmdsize = @sizeOf(macho.entry_point_command),
3173 .entryoff = @intCast(u32, sym.n_value - seg.vmaddr),
3174 .stacksize = self.base.options.stack_size_override orelse 0,
3175 });
3176 ncmds.* += 1;
3297}3177}
32983178
3299fn addCodeSignatureLC(self: *MachO) !void {3179const WriteDylibLCCtx = struct {
3300 if (self.code_signature_cmd_index != null or self.code_signature == null) return;3180 cmd: macho.LC,
3301 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);3181 name: []const u8,
3302 try self.load_commands.append(self.base.allocator, .{3182 timestamp: u32 = 2,
3303 .linkedit_data = .{3183 current_version: u32 = 0x10000,
3304 .cmd = .CODE_SIGNATURE,3184 compatibility_version: u32 = 0x10000,
3305 .cmdsize = @sizeOf(macho.linkedit_data_command),3185};
3306 .dataoff = 0,3186
3307 .datasize = 0,3187fn writeDylibLC(ctx: WriteDylibLCCtx, ncmds: *u32, lc_writer: anytype) !void {
3188 const name_len = ctx.name.len + 1;
3189 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
3190 u64,
3191 @sizeOf(macho.dylib_command) + name_len,
3192 @sizeOf(u64),
3193 ));
3194 try lc_writer.writeStruct(macho.dylib_command{
3195 .cmd = ctx.cmd,
3196 .cmdsize = cmdsize,
3197 .dylib = .{
3198 .name = @sizeOf(macho.dylib_command),
3199 .timestamp = ctx.timestamp,
3200 .current_version = ctx.current_version,
3201 .compatibility_version = ctx.compatibility_version,
3308 },3202 },
3309 });3203 });
3310 self.load_commands_dirty = true;3204 try lc_writer.writeAll(ctx.name);
3205 try lc_writer.writeByte(0);
3206 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;
3207 if (padding > 0) {
3208 try lc_writer.writeByteNTimes(0, padding);
3209 }
3210 ncmds.* += 1;
3311}3211}
33123212
3313fn setEntryPoint(self: *MachO) !void {3213fn writeDylibIdLC(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3314 if (self.base.options.output_mode != .Exe) return;3214 if (self.base.options.output_mode != .Lib) return;
3215 const install_name = self.base.options.install_name orelse self.base.options.emit.?.sub_path;
3216 const curr = self.base.options.version orelse std.builtin.Version{
3217 .major = 1,
3218 .minor = 0,
3219 .patch = 0,
3220 };
3221 const compat = self.base.options.compatibility_version orelse std.builtin.Version{
3222 .major = 1,
3223 .minor = 0,
3224 .patch = 0,
3225 };
3226 try writeDylibLC(.{
3227 .cmd = .ID_DYLIB,
3228 .name = install_name,
3229 .current_version = curr.major << 16 | curr.minor << 8 | curr.patch,
3230 .compatibility_version = compat.major << 16 | compat.minor << 8 | compat.patch,
3231 }, ncmds, lc_writer);
3232}
33153233
3316 const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;3234const RpathIterator = struct {
3317 const global = try self.getEntryPoint();3235 buffer: []const []const u8,
3318 const sym = self.getSymbol(global);3236 table: std.StringHashMap(void),
3319 const ec = &self.load_commands.items[self.main_cmd_index.?].main;3237 count: usize = 0,
3320 ec.entryoff = @intCast(u32, sym.n_value - seg.inner.vmaddr);3238
3321 ec.stacksize = self.base.options.stack_size_override orelse 0;3239 fn init(gpa: Allocator, rpaths: []const []const u8) RpathIterator {
3322 self.entry_addr = sym.n_value;3240 return .{ .buffer = rpaths, .table = std.StringHashMap(void).init(gpa) };
3323 self.load_commands_dirty = true;3241 }
3242
3243 fn deinit(it: *RpathIterator) void {
3244 it.table.deinit();
3245 }
3246
3247 fn next(it: *RpathIterator) !?[]const u8 {
3248 while (true) {
3249 if (it.count >= it.buffer.len) return null;
3250 const rpath = it.buffer[it.count];
3251 it.count += 1;
3252 const gop = try it.table.getOrPut(rpath);
3253 if (gop.found_existing) continue;
3254 return rpath;
3255 }
3256 }
3257};
3258
3259fn writeRpathLCs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3260 const gpa = self.base.allocator;
3261
3262 var it = RpathIterator.init(gpa, self.base.options.rpath_list);
3263 defer it.deinit();
3264
3265 while (try it.next()) |rpath| {
3266 const rpath_len = rpath.len + 1;
3267 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
3268 u64,
3269 @sizeOf(macho.rpath_command) + rpath_len,
3270 @sizeOf(u64),
3271 ));
3272 try lc_writer.writeStruct(macho.rpath_command{
3273 .cmdsize = cmdsize,
3274 .path = @sizeOf(macho.rpath_command),
3275 });
3276 try lc_writer.writeAll(rpath);
3277 try lc_writer.writeByte(0);
3278 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
3279 if (padding > 0) {
3280 try lc_writer.writeByteNTimes(0, padding);
3281 }
3282 ncmds.* += 1;
3283 }
3284}
3285
3286fn writeBuildVersionLC(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3287 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
3288 const platform_version = blk: {
3289 const ver = self.base.options.target.os.version_range.semver.min;
3290 const platform_version = ver.major << 16 | ver.minor << 8;
3291 break :blk platform_version;
3292 };
3293 const sdk_version = if (self.base.options.native_darwin_sdk) |sdk| blk: {
3294 const ver = sdk.version;
3295 const sdk_version = ver.major << 16 | ver.minor << 8;
3296 break :blk sdk_version;
3297 } else platform_version;
3298 const is_simulator_abi = self.base.options.target.abi == .simulator;
3299 try lc_writer.writeStruct(macho.build_version_command{
3300 .cmdsize = cmdsize,
3301 .platform = switch (self.base.options.target.os.tag) {
3302 .macos => .MACOS,
3303 .ios => if (is_simulator_abi) macho.PLATFORM.IOSSIMULATOR else macho.PLATFORM.IOS,
3304 .watchos => if (is_simulator_abi) macho.PLATFORM.WATCHOSSIMULATOR else macho.PLATFORM.WATCHOS,
3305 .tvos => if (is_simulator_abi) macho.PLATFORM.TVOSSIMULATOR else macho.PLATFORM.TVOS,
3306 else => unreachable,
3307 },
3308 .minos = platform_version,
3309 .sdk = sdk_version,
3310 .ntools = 1,
3311 });
3312 try lc_writer.writeAll(mem.asBytes(&macho.build_tool_version{
3313 .tool = .LD,
3314 .version = 0x0,
3315 }));
3316 ncmds.* += 1;
3317}
3318
3319fn writeLoadDylibLCs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3320 for (self.referenced_dylibs.keys()) |id| {
3321 const dylib = self.dylibs.items[id];
3322 const dylib_id = dylib.id orelse unreachable;
3323 try writeDylibLC(.{
3324 .cmd = if (dylib.weak) .LOAD_WEAK_DYLIB else .LOAD_DYLIB,
3325 .name = dylib_id.name,
3326 .timestamp = dylib_id.timestamp,
3327 .current_version = dylib_id.current_version,
3328 .compatibility_version = dylib_id.compatibility_version,
3329 }, ncmds, lc_writer);
3330 }
3324}3331}
33253332
3326pub fn deinit(self: *MachO) void {3333pub fn deinit(self: *MachO) void {
...@@ -3334,7 +3341,6 @@ pub fn deinit(self: *MachO) void {...@@ -3334,7 +3341,6 @@ pub fn deinit(self: *MachO) void {
3334 d_sym.deinit(gpa);3341 d_sym.deinit(gpa);
3335 }3342 }
33363343
3337 self.section_ordinals.deinit(gpa);
3338 self.tlv_ptr_entries.deinit(gpa);3344 self.tlv_ptr_entries.deinit(gpa);
3339 self.tlv_ptr_entries_free_list.deinit(gpa);3345 self.tlv_ptr_entries_free_list.deinit(gpa);
3340 self.tlv_ptr_entries_table.deinit(gpa);3346 self.tlv_ptr_entries_table.deinit(gpa);
...@@ -3371,24 +3377,19 @@ pub fn deinit(self: *MachO) void {...@@ -3371,24 +3377,19 @@ pub fn deinit(self: *MachO) void {
3371 self.dylibs_map.deinit(gpa);3377 self.dylibs_map.deinit(gpa);
3372 self.referenced_dylibs.deinit(gpa);3378 self.referenced_dylibs.deinit(gpa);
33733379
3374 for (self.load_commands.items) |*lc| {3380 self.segments.deinit(gpa);
3375 lc.deinit(gpa);3381
3382 for (self.sections.items(.free_list)) |*list| {
3383 list.deinit(gpa);
3376 }3384 }
3377 self.load_commands.deinit(gpa);3385 self.sections.deinit(gpa);
33783386
3379 for (self.managed_atoms.items) |atom| {3387 for (self.managed_atoms.items) |atom| {
3380 atom.deinit(gpa);3388 atom.deinit(gpa);
3381 gpa.destroy(atom);3389 gpa.destroy(atom);
3382 }3390 }
3383 self.managed_atoms.deinit(gpa);3391 self.managed_atoms.deinit(gpa);
3384 self.atoms.deinit(gpa);3392
3385 {
3386 var it = self.atom_free_lists.valueIterator();
3387 while (it.next()) |free_list| {
3388 free_list.deinit(gpa);
3389 }
3390 self.atom_free_lists.deinit(gpa);
3391 }
3392 if (self.base.options.module) |mod| {3393 if (self.base.options.module) |mod| {
3393 for (self.decls.keys()) |decl_index| {3394 for (self.decls.keys()) |decl_index| {
3394 const decl = mod.declPtr(decl_index);3395 const decl = mod.declPtr(decl_index);
...@@ -3408,34 +3409,24 @@ pub fn deinit(self: *MachO) void {...@@ -3408,34 +3409,24 @@ pub fn deinit(self: *MachO) void {
3408 }3409 }
34093410
3410 self.atom_by_index_table.deinit(gpa);3411 self.atom_by_index_table.deinit(gpa);
3411
3412 if (self.code_signature) |*csig| {
3413 csig.deinit(gpa);
3414 }
3415}3412}
34163413
3417pub fn closeFiles(self: MachO) void {3414pub fn closeFiles(self: MachO) void {
3418 for (self.objects.items) |object| {
3419 object.file.close();
3420 }
3421 for (self.archives.items) |archive| {3415 for (self.archives.items) |archive| {
3422 archive.file.close();3416 archive.file.close();
3423 }3417 }
3424 for (self.dylibs.items) |dylib| {
3425 dylib.file.close();
3426 }
3427 if (self.d_sym) |ds| {3418 if (self.d_sym) |ds| {
3428 ds.file.close();3419 ds.file.close();
3429 }3420 }
3430}3421}
34313422
3432fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool) void {3423fn freeAtom(self: *MachO, atom: *Atom, sect_id: u8, owns_atom: bool) void {
3433 log.debug("freeAtom {*}", .{atom});3424 log.debug("freeAtom {*}", .{atom});
3434 if (!owns_atom) {3425 if (!owns_atom) {
3435 atom.deinit(self.base.allocator);3426 atom.deinit(self.base.allocator);
3436 }3427 }
34373428
3438 const free_list = self.atom_free_lists.getPtr(match).?;3429 const free_list = &self.sections.items(.free_list)[sect_id];
3439 var already_have_free_list_node = false;3430 var already_have_free_list_node = false;
3440 {3431 {
3441 var i: usize = 0;3432 var i: usize = 0;
...@@ -3452,13 +3443,14 @@ fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool)...@@ -3452,13 +3443,14 @@ fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool)
3452 }3443 }
3453 }3444 }
34543445
3455 if (self.atoms.getPtr(match)) |last_atom| {3446 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];
3456 if (last_atom.* == atom) {3447 if (maybe_last_atom.*) |last_atom| {
3448 if (last_atom == atom) {
3457 if (atom.prev) |prev| {3449 if (atom.prev) |prev| {
3458 // TODO shrink the section size here3450 // TODO shrink the section size here
3459 last_atom.* = prev;3451 maybe_last_atom.* = prev;
3460 } else {3452 } else {
3461 _ = self.atoms.fetchRemove(match);3453 maybe_last_atom.* = null;
3462 }3454 }
3463 }3455 }
3464 }3456 }
...@@ -3486,21 +3478,21 @@ fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool)...@@ -3486,21 +3478,21 @@ fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool)
3486 }3478 }
3487}3479}
34883480
3489fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64, match: MatchingSection) void {3481fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64, sect_id: u8) void {
3490 _ = self;3482 _ = self;
3491 _ = atom;3483 _ = atom;
3492 _ = new_block_size;3484 _ = new_block_size;
3493 _ = match;3485 _ = sect_id;
3494 // TODO check the new capacity, and if it crosses the size threshold into a big enough3486 // TODO check the new capacity, and if it crosses the size threshold into a big enough
3495 // capacity, insert a free list node for it.3487 // capacity, insert a free list node for it.
3496}3488}
34973489
3498fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 {3490fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, sect_id: u8) !u64 {
3499 const sym = atom.getSymbol(self);3491 const sym = atom.getSymbol(self);
3500 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;3492 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;
3501 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);3493 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
3502 if (!need_realloc) return sym.n_value;3494 if (!need_realloc) return sym.n_value;
3503 return self.allocateAtom(atom, new_atom_size, alignment, match);3495 return self.allocateAtom(atom, new_atom_size, alignment, sect_id);
3504}3496}
35053497
3506fn allocateSymbol(self: *MachO) !u32 {3498fn allocateSymbol(self: *MachO) !u32 {
...@@ -3671,10 +3663,11 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -3671,10 +3663,11 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
3671}3663}
36723664
3673pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {3665pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
3674 var code_buffer = std.ArrayList(u8).init(self.base.allocator);3666 const gpa = self.base.allocator;
3667
3668 var code_buffer = std.ArrayList(u8).init(gpa);
3675 defer code_buffer.deinit();3669 defer code_buffer.deinit();
36763670
3677 const gpa = self.base.allocator;
3678 const module = self.base.options.module.?;3671 const module = self.base.options.module.?;
3679 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);3672 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
3680 if (!gop.found_existing) {3673 if (!gop.found_existing) {
...@@ -3725,25 +3718,25 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -3725,25 +3718,25 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
3725 atom.code.clearRetainingCapacity();3718 atom.code.clearRetainingCapacity();
3726 try atom.code.appendSlice(gpa, code);3719 try atom.code.appendSlice(gpa, code);
37273720
3728 const match = try self.getMatchingSectionAtom(3721 const sect_id = try self.getOutputSectionAtom(
3729 atom,3722 atom,
3730 decl_name,3723 decl_name,
3731 typed_value.ty,3724 typed_value.ty,
3732 typed_value.val,3725 typed_value.val,
3733 required_alignment,3726 required_alignment,
3734 );3727 );
3735 const addr = try self.allocateAtom(atom, code.len, required_alignment, match);3728 const addr = try self.allocateAtom(atom, code.len, required_alignment, sect_id);
37363729
3737 log.debug("allocated atom for {?s} at 0x{x}", .{ name, addr });3730 log.debug("allocated atom for {?s} at 0x{x}", .{ name, addr });
3738 log.debug(" (required alignment 0x{x})", .{required_alignment});3731 log.debug(" (required alignment 0x{x})", .{required_alignment});
37393732
3740 errdefer self.freeAtom(atom, match, true);3733 errdefer self.freeAtom(atom, sect_id, true);
37413734
3742 const symbol = atom.getSymbolPtr(self);3735 const symbol = atom.getSymbolPtr(self);
3743 symbol.* = .{3736 symbol.* = .{
3744 .n_strx = name_str_index,3737 .n_strx = name_str_index,
3745 .n_type = macho.N_SECT,3738 .n_type = macho.N_SECT,
3746 .n_sect = self.getSectionOrdinal(match),3739 .n_sect = sect_id + 1,
3747 .n_desc = 0,3740 .n_desc = 0,
3748 .n_value = addr,3741 .n_value = addr,
3749 };3742 };
...@@ -3894,44 +3887,35 @@ fn needsPointerRebase(ty: Type, val: Value, mod: *Module) bool {...@@ -3894,44 +3887,35 @@ fn needsPointerRebase(ty: Type, val: Value, mod: *Module) bool {
3894 }3887 }
3895}3888}
38963889
3897fn getMatchingSectionAtom(3890fn getOutputSectionAtom(
3898 self: *MachO,3891 self: *MachO,
3899 atom: *Atom,3892 atom: *Atom,
3900 name: []const u8,3893 name: []const u8,
3901 ty: Type,3894 ty: Type,
3902 val: Value,3895 val: Value,
3903 alignment: u32,3896 alignment: u32,
3904) !MatchingSection {3897) !u8 {
3905 const code = atom.code.items;3898 const code = atom.code.items;
3906 const mod = self.base.options.module.?;3899 const mod = self.base.options.module.?;
3907 const align_log_2 = math.log2(alignment);3900 const align_log_2 = math.log2(alignment);
3908 const zig_ty = ty.zigTypeTag();3901 const zig_ty = ty.zigTypeTag();
3909 const mode = self.base.options.optimize_mode;3902 const mode = self.base.options.optimize_mode;
3910 const match: MatchingSection = blk: {3903 const sect_id: u8 = blk: {
3911 // TODO finish and audit this function3904 // TODO finish and audit this function
3912 if (val.isUndefDeep()) {3905 if (val.isUndefDeep()) {
3913 if (mode == .ReleaseFast or mode == .ReleaseSmall) {3906 if (mode == .ReleaseFast or mode == .ReleaseSmall) {
3914 break :blk MatchingSection{3907 break :blk self.bss_section_index.?;
3915 .seg = self.data_segment_cmd_index.?,
3916 .sect = self.bss_section_index.?,
3917 };
3918 } else {3908 } else {
3919 break :blk MatchingSection{3909 break :blk self.data_section_index.?;
3920 .seg = self.data_segment_cmd_index.?,
3921 .sect = self.data_section_index.?,
3922 };
3923 }3910 }
3924 }3911 }
39253912
3926 if (val.castTag(.variable)) |_| {3913 if (val.castTag(.variable)) |_| {
3927 break :blk MatchingSection{3914 break :blk self.data_section_index.?;
3928 .seg = self.data_segment_cmd_index.?,
3929 .sect = self.data_section_index.?,
3930 };
3931 }3915 }
39323916
3933 if (needsPointerRebase(ty, val, mod)) {3917 if (needsPointerRebase(ty, val, mod)) {
3934 break :blk (try self.getMatchingSection(.{3918 break :blk (try self.getOutputSection(.{
3935 .segname = makeStaticString("__DATA_CONST"),3919 .segname = makeStaticString("__DATA_CONST"),
3936 .sectname = makeStaticString("__const"),3920 .sectname = makeStaticString("__const"),
3937 .size = code.len,3921 .size = code.len,
...@@ -3941,10 +3925,7 @@ fn getMatchingSectionAtom(...@@ -3941,10 +3925,7 @@ fn getMatchingSectionAtom(
39413925
3942 switch (zig_ty) {3926 switch (zig_ty) {
3943 .Fn => {3927 .Fn => {
3944 break :blk MatchingSection{3928 break :blk self.text_section_index.?;
3945 .seg = self.text_segment_cmd_index.?,
3946 .sect = self.text_section_index.?,
3947 };
3948 },3929 },
3949 .Array => {3930 .Array => {
3950 if (val.tag() == .bytes) {3931 if (val.tag() == .bytes) {
...@@ -3953,7 +3934,7 @@ fn getMatchingSectionAtom(...@@ -3953,7 +3934,7 @@ fn getMatchingSectionAtom(
3953 .const_slice_u8_sentinel_0,3934 .const_slice_u8_sentinel_0,
3954 .manyptr_const_u8_sentinel_0,3935 .manyptr_const_u8_sentinel_0,
3955 => {3936 => {
3956 break :blk (try self.getMatchingSection(.{3937 break :blk (try self.getOutputSection(.{
3957 .segname = makeStaticString("__TEXT"),3938 .segname = makeStaticString("__TEXT"),
3958 .sectname = makeStaticString("__cstring"),3939 .sectname = makeStaticString("__cstring"),
3959 .flags = macho.S_CSTRING_LITERALS,3940 .flags = macho.S_CSTRING_LITERALS,
...@@ -3967,22 +3948,21 @@ fn getMatchingSectionAtom(...@@ -3967,22 +3948,21 @@ fn getMatchingSectionAtom(
3967 },3948 },
3968 else => {},3949 else => {},
3969 }3950 }
3970 break :blk (try self.getMatchingSection(.{3951 break :blk (try self.getOutputSection(.{
3971 .segname = makeStaticString("__TEXT"),3952 .segname = makeStaticString("__TEXT"),
3972 .sectname = makeStaticString("__const"),3953 .sectname = makeStaticString("__const"),
3973 .size = code.len,3954 .size = code.len,
3974 .@"align" = align_log_2,3955 .@"align" = align_log_2,
3975 })).?;3956 })).?;
3976 };3957 };
3977 const sect = self.getSection(match);3958 const header = self.sections.items(.header)[sect_id];
3978 log.debug(" allocating atom '{s}' in '{s},{s}' ({d},{d})", .{3959 log.debug(" allocating atom '{s}' in '{s},{s}', ord({d})", .{
3979 name,3960 name,
3980 sect.segName(),3961 header.segName(),
3981 sect.sectName(),3962 header.sectName(),
3982 match.seg,3963 sect_id,
3983 match.sect,
3984 });3964 });
3985 return match;3965 return sect_id;
3986}3966}
39873967
3988fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64 {3968fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64 {
...@@ -3996,7 +3976,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64...@@ -3996,7 +3976,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64
39963976
3997 const decl_ptr = self.decls.getPtr(decl_index).?;3977 const decl_ptr = self.decls.getPtr(decl_index).?;
3998 if (decl_ptr.* == null) {3978 if (decl_ptr.* == null) {
3999 decl_ptr.* = try self.getMatchingSectionAtom(3979 decl_ptr.* = try self.getOutputSectionAtom(
4000 &decl.link.macho,3980 &decl.link.macho,
4001 sym_name,3981 sym_name,
4002 decl.ty,3982 decl.ty,
...@@ -4045,7 +4025,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64...@@ -4045,7 +4025,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64
4045 symbol.* = .{4025 symbol.* = .{
4046 .n_strx = name_str_index,4026 .n_strx = name_str_index,
4047 .n_type = macho.N_SECT,4027 .n_type = macho.N_SECT,
4048 .n_sect = self.getSectionOrdinal(match),4028 .n_sect = match + 1,
4049 .n_desc = 0,4029 .n_desc = 0,
4050 .n_value = addr,4030 .n_value = addr,
4051 };4031 };
...@@ -4134,10 +4114,7 @@ pub fn updateDeclExports(...@@ -4134,10 +4114,7 @@ pub fn updateDeclExports(
4134 sym.* = .{4114 sym.* = .{
4135 .n_strx = try self.strtab.insert(gpa, exp_name),4115 .n_strx = try self.strtab.insert(gpa, exp_name),
4136 .n_type = macho.N_SECT | macho.N_EXT,4116 .n_type = macho.N_SECT | macho.N_EXT,
4137 .n_sect = self.getSectionOrdinal(.{4117 .n_sect = self.text_section_index.? + 1, // TODO what if we export a variable?
4138 .seg = self.text_segment_cmd_index.?,
4139 .sect = self.text_section_index.?, // TODO what if we export a variable?
4140 }),
4141 .n_desc = 0,4118 .n_desc = 0,
4142 .n_value = decl_sym.n_value,4119 .n_value = decl_sym.n_value,
4143 };4120 };
...@@ -4208,10 +4185,7 @@ pub fn deleteExport(self: *MachO, exp: Export) void {...@@ -4208,10 +4185,7 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
4208fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {4185fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {
4209 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;4186 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
4210 for (unnamed_consts.items) |atom| {4187 for (unnamed_consts.items) |atom| {
4211 self.freeAtom(atom, .{4188 self.freeAtom(atom, self.text_const_section_index.?, true);
4212 .seg = self.text_segment_cmd_index.?,
4213 .sect = self.text_const_section_index.?,
4214 }, true);
4215 self.locals_free_list.append(self.base.allocator, atom.sym_index) catch {};4189 self.locals_free_list.append(self.base.allocator, atom.sym_index) catch {};
4216 self.locals.items[atom.sym_index].n_type = 0;4190 self.locals.items[atom.sym_index].n_type = 0;
4217 _ = self.atom_by_index_table.remove(atom.sym_index);4191 _ = self.atom_by_index_table.remove(atom.sym_index);
...@@ -4294,6 +4268,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -4294,6 +4268,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
4294}4268}
42954269
4296fn populateMissingMetadata(self: *MachO) !void {4270fn populateMissingMetadata(self: *MachO) !void {
4271 const gpa = self.base.allocator;
4297 const cpu_arch = self.base.options.target.cpu.arch;4272 const cpu_arch = self.base.options.target.cpu.arch;
4298 const pagezero_vmsize = self.base.options.pagezero_size orelse default_pagezero_vmsize;4273 const pagezero_vmsize = self.base.options.pagezero_size orelse default_pagezero_vmsize;
4299 const aligned_pagezero_vmsize = mem.alignBackwardGeneric(u64, pagezero_vmsize, self.page_size);4274 const aligned_pagezero_vmsize = mem.alignBackwardGeneric(u64, pagezero_vmsize, self.page_size);
...@@ -4305,21 +4280,16 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4305,21 +4280,16 @@ fn populateMissingMetadata(self: *MachO) !void {
4305 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});4280 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});
4306 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});4281 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});
4307 }4282 }
4308 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);4283 self.pagezero_segment_cmd_index = @intCast(u8, self.segments.items.len);
4309 try self.load_commands.append(self.base.allocator, .{4284 try self.segments.append(gpa, .{
4310 .segment = .{4285 .segname = makeStaticString("__PAGEZERO"),
4311 .inner = .{4286 .vmsize = aligned_pagezero_vmsize,
4312 .segname = makeStaticString("__PAGEZERO"),4287 .cmdsize = @sizeOf(macho.segment_command_64),
4313 .vmsize = aligned_pagezero_vmsize,
4314 .cmdsize = @sizeOf(macho.segment_command_64),
4315 },
4316 },
4317 });4288 });
4318 self.load_commands_dirty = true;
4319 }4289 }
43204290
4321 if (self.text_segment_cmd_index == null) {4291 if (self.text_segment_cmd_index == null) {
4322 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);4292 self.text_segment_cmd_index = @intCast(u8, self.segments.items.len);
4323 const needed_size = if (self.mode == .incremental) blk: {4293 const needed_size = if (self.mode == .incremental) blk: {
4324 const headerpad_size = @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size);4294 const headerpad_size = @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size);
4325 const program_code_size_hint = self.base.options.program_code_size_hint;4295 const program_code_size_hint = self.base.options.program_code_size_hint;
...@@ -4329,20 +4299,15 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4329,20 +4299,15 @@ fn populateMissingMetadata(self: *MachO) !void {
4329 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });4299 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
4330 break :blk needed_size;4300 break :blk needed_size;
4331 } else 0;4301 } else 0;
4332 try self.load_commands.append(self.base.allocator, .{4302 try self.segments.append(gpa, .{
4333 .segment = .{4303 .segname = makeStaticString("__TEXT"),
4334 .inner = .{4304 .vmaddr = aligned_pagezero_vmsize,
4335 .segname = makeStaticString("__TEXT"),4305 .vmsize = needed_size,
4336 .vmaddr = aligned_pagezero_vmsize,4306 .filesize = needed_size,
4337 .vmsize = needed_size,4307 .maxprot = macho.PROT.READ | macho.PROT.EXEC,
4338 .filesize = needed_size,4308 .initprot = macho.PROT.READ | macho.PROT.EXEC,
4339 .maxprot = macho.PROT.READ | macho.PROT.EXEC,4309 .cmdsize = @sizeOf(macho.segment_command_64),
4340 .initprot = macho.PROT.READ | macho.PROT.EXEC,
4341 .cmdsize = @sizeOf(macho.segment_command_64),
4342 },
4343 },
4344 });4310 });
4345 self.load_commands_dirty = true;
4346 }4311 }
43474312
4348 if (self.text_section_index == null) {4313 if (self.text_section_index == null) {
...@@ -4419,7 +4384,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4419,7 +4384,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4419 }4384 }
44204385
4421 if (self.data_const_segment_cmd_index == null) {4386 if (self.data_const_segment_cmd_index == null) {
4422 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);4387 self.data_const_segment_cmd_index = @intCast(u8, self.segments.items.len);
4423 var vmaddr: u64 = 0;4388 var vmaddr: u64 = 0;
4424 var fileoff: u64 = 0;4389 var fileoff: u64 = 0;
4425 var needed_size: u64 = 0;4390 var needed_size: u64 = 0;
...@@ -4434,21 +4399,16 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4434,21 +4399,16 @@ fn populateMissingMetadata(self: *MachO) !void {
4434 fileoff + needed_size,4399 fileoff + needed_size,
4435 });4400 });
4436 }4401 }
4437 try self.load_commands.append(self.base.allocator, .{4402 try self.segments.append(gpa, .{
4438 .segment = .{4403 .segname = makeStaticString("__DATA_CONST"),
4439 .inner = .{4404 .vmaddr = vmaddr,
4440 .segname = makeStaticString("__DATA_CONST"),4405 .vmsize = needed_size,
4441 .vmaddr = vmaddr,4406 .fileoff = fileoff,
4442 .vmsize = needed_size,4407 .filesize = needed_size,
4443 .fileoff = fileoff,4408 .maxprot = macho.PROT.READ | macho.PROT.WRITE,
4444 .filesize = needed_size,4409 .initprot = macho.PROT.READ | macho.PROT.WRITE,
4445 .maxprot = macho.PROT.READ | macho.PROT.WRITE,4410 .cmdsize = @sizeOf(macho.segment_command_64),
4446 .initprot = macho.PROT.READ | macho.PROT.WRITE,
4447 .cmdsize = @sizeOf(macho.segment_command_64),
4448 },
4449 },
4450 });4411 });
4451 self.load_commands_dirty = true;
4452 }4412 }
44534413
4454 if (self.got_section_index == null) {4414 if (self.got_section_index == null) {
...@@ -4469,7 +4429,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4469,7 +4429,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4469 }4429 }
44704430
4471 if (self.data_segment_cmd_index == null) {4431 if (self.data_segment_cmd_index == null) {
4472 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);4432 self.data_segment_cmd_index = @intCast(u8, self.segments.items.len);
4473 var vmaddr: u64 = 0;4433 var vmaddr: u64 = 0;
4474 var fileoff: u64 = 0;4434 var fileoff: u64 = 0;
4475 var needed_size: u64 = 0;4435 var needed_size: u64 = 0;
...@@ -4484,21 +4444,16 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4484,21 +4444,16 @@ fn populateMissingMetadata(self: *MachO) !void {
4484 fileoff + needed_size,4444 fileoff + needed_size,
4485 });4445 });
4486 }4446 }
4487 try self.load_commands.append(self.base.allocator, .{4447 try self.segments.append(gpa, .{
4488 .segment = .{4448 .segname = makeStaticString("__DATA"),
4489 .inner = .{4449 .vmaddr = vmaddr,
4490 .segname = makeStaticString("__DATA"),4450 .vmsize = needed_size,
4491 .vmaddr = vmaddr,4451 .fileoff = fileoff,
4492 .vmsize = needed_size,4452 .filesize = needed_size,
4493 .fileoff = fileoff,4453 .maxprot = macho.PROT.READ | macho.PROT.WRITE,
4494 .filesize = needed_size,4454 .initprot = macho.PROT.READ | macho.PROT.WRITE,
4495 .maxprot = macho.PROT.READ | macho.PROT.WRITE,4455 .cmdsize = @sizeOf(macho.segment_command_64),
4496 .initprot = macho.PROT.READ | macho.PROT.WRITE,
4497 .cmdsize = @sizeOf(macho.segment_command_64),
4498 },
4499 },
4500 });4456 });
4501 self.load_commands_dirty = true;
4502 }4457 }
45034458
4504 if (self.la_symbol_ptr_section_index == null) {4459 if (self.la_symbol_ptr_section_index == null) {
...@@ -4602,7 +4557,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4602,7 +4557,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4602 }4557 }
46034558
4604 if (self.linkedit_segment_cmd_index == null) {4559 if (self.linkedit_segment_cmd_index == null) {
4605 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);4560 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
4606 var vmaddr: u64 = 0;4561 var vmaddr: u64 = 0;
4607 var fileoff: u64 = 0;4562 var fileoff: u64 = 0;
4608 if (self.mode == .incremental) {4563 if (self.mode == .incremental) {
...@@ -4611,249 +4566,113 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4611,249 +4566,113 @@ fn populateMissingMetadata(self: *MachO) !void {
4611 fileoff = base.fileoff;4566 fileoff = base.fileoff;
4612 log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});4567 log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});
4613 }4568 }
4614 try self.load_commands.append(self.base.allocator, .{4569 try self.segments.append(gpa, .{
4615 .segment = .{4570 .segname = makeStaticString("__LINKEDIT"),
4616 .inner = .{4571 .vmaddr = vmaddr,
4617 .segname = makeStaticString("__LINKEDIT"),4572 .fileoff = fileoff,
4618 .vmaddr = vmaddr,4573 .maxprot = macho.PROT.READ,
4619 .fileoff = fileoff,4574 .initprot = macho.PROT.READ,
4620 .maxprot = macho.PROT.READ,4575 .cmdsize = @sizeOf(macho.segment_command_64),
4621 .initprot = macho.PROT.READ,
4622 .cmdsize = @sizeOf(macho.segment_command_64),
4623 },
4624 },
4625 });4576 });
4626 self.load_commands_dirty = true;
4627 }
4628
4629 if (self.dyld_info_cmd_index == null) {
4630 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
4631 try self.load_commands.append(self.base.allocator, .{
4632 .dyld_info_only = .{
4633 .cmd = .DYLD_INFO_ONLY,
4634 .cmdsize = @sizeOf(macho.dyld_info_command),
4635 .rebase_off = 0,
4636 .rebase_size = 0,
4637 .bind_off = 0,
4638 .bind_size = 0,
4639 .weak_bind_off = 0,
4640 .weak_bind_size = 0,
4641 .lazy_bind_off = 0,
4642 .lazy_bind_size = 0,
4643 .export_off = 0,
4644 .export_size = 0,
4645 },
4646 });
4647 self.load_commands_dirty = true;
4648 }
4649
4650 if (self.symtab_cmd_index == null) {
4651 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
4652 try self.load_commands.append(self.base.allocator, .{
4653 .symtab = .{
4654 .cmdsize = @sizeOf(macho.symtab_command),
4655 .symoff = 0,
4656 .nsyms = 0,
4657 .stroff = 0,
4658 .strsize = 0,
4659 },
4660 });
4661 self.load_commands_dirty = true;
4662 }
4663
4664 if (self.dysymtab_cmd_index == null) {
4665 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
4666 try self.load_commands.append(self.base.allocator, .{
4667 .dysymtab = .{
4668 .cmdsize = @sizeOf(macho.dysymtab_command),
4669 .ilocalsym = 0,
4670 .nlocalsym = 0,
4671 .iextdefsym = 0,
4672 .nextdefsym = 0,
4673 .iundefsym = 0,
4674 .nundefsym = 0,
4675 .tocoff = 0,
4676 .ntoc = 0,
4677 .modtaboff = 0,
4678 .nmodtab = 0,
4679 .extrefsymoff = 0,
4680 .nextrefsyms = 0,
4681 .indirectsymoff = 0,
4682 .nindirectsyms = 0,
4683 .extreloff = 0,
4684 .nextrel = 0,
4685 .locreloff = 0,
4686 .nlocrel = 0,
4687 },
4688 });
4689 self.load_commands_dirty = true;
4690 }4577 }
4578}
46914579
4692 if (self.dylinker_cmd_index == null) {4580inline fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool) u64 {
4693 self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);4581 const name_len = if (assume_max_path_len) std.os.PATH_MAX else std.mem.len(name) + 1;
4694 const cmdsize = @intCast(u32, mem.alignForwardGeneric(4582 return mem.alignForwardGeneric(u64, cmd_size + name_len, @alignOf(u64));
4695 u64,4583}
4696 @sizeOf(macho.dylinker_command) + mem.sliceTo(default_dyld_path, 0).len,
4697 @sizeOf(u64),
4698 ));
4699 var dylinker_cmd = macho.emptyGenericCommandWithData(macho.dylinker_command{
4700 .cmd = .LOAD_DYLINKER,
4701 .cmdsize = cmdsize,
4702 .name = @sizeOf(macho.dylinker_command),
4703 });
4704 dylinker_cmd.data = try self.base.allocator.alloc(u8, cmdsize - dylinker_cmd.inner.name);
4705 mem.set(u8, dylinker_cmd.data, 0);
4706 mem.copy(u8, dylinker_cmd.data, mem.sliceTo(default_dyld_path, 0));
4707 try self.load_commands.append(self.base.allocator, .{ .dylinker = dylinker_cmd });
4708 self.load_commands_dirty = true;
4709 }
4710
4711 if (self.main_cmd_index == null and self.base.options.output_mode == .Exe) {
4712 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
4713 try self.load_commands.append(self.base.allocator, .{
4714 .main = .{
4715 .cmdsize = @sizeOf(macho.entry_point_command),
4716 .entryoff = 0x0,
4717 .stacksize = 0,
4718 },
4719 });
4720 self.load_commands_dirty = true;
4721 }
47224584
4723 if (self.dylib_id_cmd_index == null and self.base.options.output_mode == .Lib) {4585fn calcLCsSize(self: *MachO, assume_max_path_len: bool) !u32 {
4724 self.dylib_id_cmd_index = @intCast(u16, self.load_commands.items.len);4586 const gpa = self.base.allocator;
4725 const install_name = self.base.options.install_name orelse self.base.options.emit.?.sub_path;4587 var sizeofcmds: u64 = 0;
4726 const current_version = self.base.options.version orelse4588 for (self.segments.items) |seg| {
4727 std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };4589 sizeofcmds += seg.nsects * @sizeOf(macho.section_64) + @sizeOf(macho.segment_command_64);
4728 const compat_version = self.base.options.compatibility_version orelse4590 }
4729 std.builtin.Version{ .major = 1, .minor = 0, .patch = 0 };4591
4730 var dylib_cmd = try macho.createLoadDylibCommand(4592 // LC_DYLD_INFO_ONLY
4731 self.base.allocator,4593 sizeofcmds += @sizeOf(macho.dyld_info_command);
4732 .ID_DYLIB,4594 // LC_FUNCTION_STARTS
4733 install_name,4595 if (self.text_section_index != null) {
4734 2,4596 sizeofcmds += @sizeOf(macho.linkedit_data_command);
4735 current_version.major << 16 | current_version.minor << 8 | current_version.patch,4597 }
4736 compat_version.major << 16 | compat_version.minor << 8 | compat_version.patch,4598 // LC_DATA_IN_CODE
4599 sizeofcmds += @sizeOf(macho.linkedit_data_command);
4600 // LC_SYMTAB
4601 sizeofcmds += @sizeOf(macho.symtab_command);
4602 // LC_DYSYMTAB
4603 sizeofcmds += @sizeOf(macho.dysymtab_command);
4604 // LC_LOAD_DYLINKER
4605 sizeofcmds += calcInstallNameLen(
4606 @sizeOf(macho.dylinker_command),
4607 mem.sliceTo(default_dyld_path, 0),
4608 false,
4609 );
4610 // LC_MAIN
4611 if (self.base.options.output_mode == .Exe) {
4612 sizeofcmds += @sizeOf(macho.entry_point_command);
4613 }
4614 // LC_ID_DYLIB
4615 if (self.base.options.output_mode == .Lib) {
4616 sizeofcmds += blk: {
4617 const install_name = self.base.options.install_name orelse self.base.options.emit.?.sub_path;
4618 break :blk calcInstallNameLen(
4619 @sizeOf(macho.dylib_command),
4620 install_name,
4621 assume_max_path_len,
4622 );
4623 };
4624 }
4625 // LC_RPATH
4626 {
4627 var it = RpathIterator.init(gpa, self.base.options.rpath_list);
4628 defer it.deinit();
4629 while (try it.next()) |rpath| {
4630 sizeofcmds += calcInstallNameLen(
4631 @sizeOf(macho.rpath_command),
4632 rpath,
4633 assume_max_path_len,
4634 );
4635 }
4636 }
4637 // LC_SOURCE_VERSION
4638 sizeofcmds += @sizeOf(macho.source_version_command);
4639 // LC_BUILD_VERSION
4640 sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
4641 // LC_UUID
4642 sizeofcmds += @sizeOf(macho.uuid_command);
4643 // LC_LOAD_DYLIB
4644 for (self.referenced_dylibs.keys()) |id| {
4645 const dylib = self.dylibs.items[id];
4646 const dylib_id = dylib.id orelse unreachable;
4647 sizeofcmds += calcInstallNameLen(
4648 @sizeOf(macho.dylib_command),
4649 dylib_id.name,
4650 assume_max_path_len,
4737 );4651 );
4738 errdefer dylib_cmd.deinit(self.base.allocator);
4739 try self.load_commands.append(self.base.allocator, .{ .dylib = dylib_cmd });
4740 self.load_commands_dirty = true;
4741 }4652 }
47424653 // LC_CODE_SIGNATURE
4743 if (self.source_version_cmd_index == null) {4654 {
4744 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);4655 const target = self.base.options.target;
4745 try self.load_commands.append(self.base.allocator, .{4656 const requires_codesig = blk: {
4746 .source_version = .{4657 if (self.base.options.entitlements) |_| break :blk true;
4747 .cmdsize = @sizeOf(macho.source_version_command),4658 if (target.cpu.arch == .aarch64 and (target.os.tag == .macos or target.abi == .simulator))
4748 .version = 0x0,4659 break :blk true;
4749 },4660 break :blk false;
4750 });4661 };
4751 self.load_commands_dirty = true;4662 if (requires_codesig) {
4663 sizeofcmds += @sizeOf(macho.linkedit_data_command);
4664 }
4752 }4665 }
47534666
4754 if (self.build_version_cmd_index == null) {4667 return @intCast(u32, sizeofcmds);
4755 self.build_version_cmd_index = @intCast(u16, self.load_commands.items.len);
4756 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
4757 u64,
4758 @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version),
4759 @sizeOf(u64),
4760 ));
4761 const platform_version = blk: {
4762 const ver = self.base.options.target.os.version_range.semver.min;
4763 const platform_version = ver.major << 16 | ver.minor << 8;
4764 break :blk platform_version;
4765 };
4766 const sdk_version = if (self.base.options.native_darwin_sdk) |sdk| blk: {
4767 const ver = sdk.version;
4768 const sdk_version = ver.major << 16 | ver.minor << 8;
4769 break :blk sdk_version;
4770 } else platform_version;
4771 const is_simulator_abi = self.base.options.target.abi == .simulator;
4772 var cmd = macho.emptyGenericCommandWithData(macho.build_version_command{
4773 .cmdsize = cmdsize,
4774 .platform = switch (self.base.options.target.os.tag) {
4775 .macos => .MACOS,
4776 .ios => if (is_simulator_abi) macho.PLATFORM.IOSSIMULATOR else macho.PLATFORM.IOS,
4777 .watchos => if (is_simulator_abi) macho.PLATFORM.WATCHOSSIMULATOR else macho.PLATFORM.WATCHOS,
4778 .tvos => if (is_simulator_abi) macho.PLATFORM.TVOSSIMULATOR else macho.PLATFORM.TVOS,
4779 else => unreachable,
4780 },
4781 .minos = platform_version,
4782 .sdk = sdk_version,
4783 .ntools = 1,
4784 });
4785 const ld_ver = macho.build_tool_version{
4786 .tool = .LD,
4787 .version = 0x0,
4788 };
4789 cmd.data = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.build_version_command));
4790 mem.set(u8, cmd.data, 0);
4791 mem.copy(u8, cmd.data, mem.asBytes(&ld_ver));
4792 try self.load_commands.append(self.base.allocator, .{ .build_version = cmd });
4793 self.load_commands_dirty = true;
4794 }
4795
4796 if (self.uuid_cmd_index == null) {
4797 self.uuid_cmd_index = @intCast(u16, self.load_commands.items.len);
4798 var uuid_cmd: macho.uuid_command = .{
4799 .cmdsize = @sizeOf(macho.uuid_command),
4800 .uuid = undefined,
4801 };
4802 std.crypto.random.bytes(&uuid_cmd.uuid);
4803 try self.load_commands.append(self.base.allocator, .{ .uuid = uuid_cmd });
4804 self.load_commands_dirty = true;
4805 }
4806
4807 if (self.function_starts_cmd_index == null) {
4808 self.function_starts_cmd_index = @intCast(u16, self.load_commands.items.len);
4809 try self.load_commands.append(self.base.allocator, .{
4810 .linkedit_data = .{
4811 .cmd = .FUNCTION_STARTS,
4812 .cmdsize = @sizeOf(macho.linkedit_data_command),
4813 .dataoff = 0,
4814 .datasize = 0,
4815 },
4816 });
4817 self.load_commands_dirty = true;
4818 }
4819
4820 if (self.data_in_code_cmd_index == null) {
4821 self.data_in_code_cmd_index = @intCast(u16, self.load_commands.items.len);
4822 try self.load_commands.append(self.base.allocator, .{
4823 .linkedit_data = .{
4824 .cmd = .DATA_IN_CODE,
4825 .cmdsize = @sizeOf(macho.linkedit_data_command),
4826 .dataoff = 0,
4827 .datasize = 0,
4828 },
4829 });
4830 self.load_commands_dirty = true;
4831 }
4832}4668}
48334669
4834fn calcMinHeaderpad(self: *MachO) u64 {4670fn calcMinHeaderPad(self: *MachO) !u64 {
4835 var sizeofcmds: u32 = 0;4671 var padding: u32 = (try self.calcLCsSize(false)) + (self.base.options.headerpad_size orelse 0);
4836 for (self.load_commands.items) |lc| {
4837 if (lc.cmd() == .NONE) continue;
4838 sizeofcmds += lc.cmdsize();
4839 }
4840
4841 var padding: u32 = sizeofcmds + (self.base.options.headerpad_size orelse 0);
4842 log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});4672 log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});
48434673
4844 if (self.base.options.headerpad_max_install_names) {4674 if (self.base.options.headerpad_max_install_names) {
4845 var min_headerpad_size: u32 = 0;4675 var min_headerpad_size: u32 = try self.calcLCsSize(true);
4846 for (self.load_commands.items) |lc| switch (lc.cmd()) {
4847 .ID_DYLIB,
4848 .LOAD_WEAK_DYLIB,
4849 .LOAD_DYLIB,
4850 .REEXPORT_DYLIB,
4851 => {
4852 min_headerpad_size += @sizeOf(macho.dylib_command) + std.os.PATH_MAX + 1;
4853 },
4854
4855 else => {},
4856 };
4857 log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{4676 log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{
4858 min_headerpad_size + @sizeOf(macho.mach_header_64),4677 min_headerpad_size + @sizeOf(macho.mach_header_64),
4859 });4678 });
...@@ -4868,32 +4687,31 @@ fn calcMinHeaderpad(self: *MachO) u64 {...@@ -4868,32 +4687,31 @@ fn calcMinHeaderpad(self: *MachO) u64 {
4868fn allocateSegments(self: *MachO) !void {4687fn allocateSegments(self: *MachO) !void {
4869 try self.allocateSegment(self.text_segment_cmd_index, &.{4688 try self.allocateSegment(self.text_segment_cmd_index, &.{
4870 self.pagezero_segment_cmd_index,4689 self.pagezero_segment_cmd_index,
4871 }, self.calcMinHeaderpad());4690 }, try self.calcMinHeaderPad());
48724691
4873 if (self.text_segment_cmd_index) |index| blk: {4692 if (self.text_segment_cmd_index) |index| blk: {
4874 const seg = &self.load_commands.items[index].segment;4693 const seg = &self.segments.items[index];
4875 if (seg.sections.items.len == 0) break :blk;4694 if (seg.nsects == 0) break :blk;
48764695
4877 // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.4696 // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.
4878 var min_alignment: u32 = 0;4697 var min_alignment: u32 = 0;
4879 for (seg.sections.items) |sect| {4698 for (self.sections.items(.header)[0..seg.nsects]) |header| {
4880 const alignment = try math.powi(u32, 2, sect.@"align");4699 const alignment = try math.powi(u32, 2, header.@"align");
4881 min_alignment = math.max(min_alignment, alignment);4700 min_alignment = math.max(min_alignment, alignment);
4882 }4701 }
48834702
4884 assert(min_alignment > 0);4703 assert(min_alignment > 0);
4885 const last_sect_idx = seg.sections.items.len - 1;4704 const last_header = self.sections.items(.header)[seg.nsects - 1];
4886 const last_sect = seg.sections.items[last_sect_idx];
4887 const shift: u32 = shift: {4705 const shift: u32 = shift: {
4888 const diff = seg.inner.filesize - last_sect.offset - last_sect.size;4706 const diff = seg.filesize - last_header.offset - last_header.size;
4889 const factor = @divTrunc(diff, min_alignment);4707 const factor = @divTrunc(diff, min_alignment);
4890 break :shift @intCast(u32, factor * min_alignment);4708 break :shift @intCast(u32, factor * min_alignment);
4891 };4709 };
48924710
4893 if (shift > 0) {4711 if (shift > 0) {
4894 for (seg.sections.items) |*sect| {4712 for (self.sections.items(.header)[0..seg.nsects]) |*header| {
4895 sect.offset += shift;4713 header.offset += shift;
4896 sect.addr += shift;4714 header.addr += shift;
4897 }4715 }
4898 }4716 }
4899 }4717 }
...@@ -4917,42 +4735,42 @@ fn allocateSegments(self: *MachO) !void {...@@ -4917,42 +4735,42 @@ fn allocateSegments(self: *MachO) !void {
4917 }, 0);4735 }, 0);
4918}4736}
49194737
4920fn allocateSegment(self: *MachO, maybe_index: ?u16, indices: []const ?u16, init_size: u64) !void {4738fn allocateSegment(self: *MachO, maybe_index: ?u8, indices: []const ?u8, init_size: u64) !void {
4921 const index = maybe_index orelse return;4739 const index = maybe_index orelse return;
4922 const seg = &self.load_commands.items[index].segment;4740 const seg = &self.segments.items[index];
49234741
4924 const base = self.getSegmentAllocBase(indices);4742 const base = self.getSegmentAllocBase(indices);
4925 seg.inner.vmaddr = base.vmaddr;4743 seg.vmaddr = base.vmaddr;
4926 seg.inner.fileoff = base.fileoff;4744 seg.fileoff = base.fileoff;
4927 seg.inner.filesize = init_size;4745 seg.filesize = init_size;
4928 seg.inner.vmsize = init_size;4746 seg.vmsize = init_size;
49294747
4930 // Allocate the sections according to their alignment at the beginning of the segment.4748 // Allocate the sections according to their alignment at the beginning of the segment.
4931 var start = init_size;4749 var start = init_size;
4932 for (seg.sections.items) |*sect| {4750 const slice = self.sections.slice();
4933 const is_zerofill = sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL;4751 for (slice.items(.header)) |*header, sect_id| {
4934 const use_llvm = build_options.have_llvm and self.base.options.use_llvm;4752 const segment_index = slice.items(.segment_index)[sect_id];
4935 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;4753 if (segment_index != index) continue;
4936 const alignment = try math.powi(u32, 2, sect.@"align");4754 const is_zerofill = header.flags == macho.S_ZEROFILL or header.flags == macho.S_THREAD_LOCAL_ZEROFILL;
4755 const alignment = try math.powi(u32, 2, header.@"align");
4937 const start_aligned = mem.alignForwardGeneric(u64, start, alignment);4756 const start_aligned = mem.alignForwardGeneric(u64, start, alignment);
49384757
4939 // TODO handle zerofill sections in stage24758 header.offset = if (is_zerofill)
4940 sect.offset = if (is_zerofill and (use_stage1 or use_llvm))
4941 04759 0
4942 else4760 else
4943 @intCast(u32, seg.inner.fileoff + start_aligned);4761 @intCast(u32, seg.fileoff + start_aligned);
4944 sect.addr = seg.inner.vmaddr + start_aligned;4762 header.addr = seg.vmaddr + start_aligned;
49454763
4946 start = start_aligned + sect.size;4764 start = start_aligned + header.size;
49474765
4948 if (!(is_zerofill and (use_stage1 or use_llvm))) {4766 if (!is_zerofill) {
4949 seg.inner.filesize = start;4767 seg.filesize = start;
4950 }4768 }
4951 seg.inner.vmsize = start;4769 seg.vmsize = start;
4952 }4770 }
49534771
4954 seg.inner.filesize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size);4772 seg.filesize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
4955 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.vmsize, self.page_size);4773 seg.vmsize = mem.alignForwardGeneric(u64, seg.vmsize, self.page_size);
4956}4774}
49574775
4958const InitSectionOpts = struct {4776const InitSectionOpts = struct {
...@@ -4963,16 +4781,16 @@ const InitSectionOpts = struct {...@@ -4963,16 +4781,16 @@ const InitSectionOpts = struct {
49634781
4964fn initSection(4782fn initSection(
4965 self: *MachO,4783 self: *MachO,
4966 segment_id: u16,4784 segment_id: u8,
4967 sectname: []const u8,4785 sectname: []const u8,
4968 size: u64,4786 size: u64,
4969 alignment: u32,4787 alignment: u32,
4970 opts: InitSectionOpts,4788 opts: InitSectionOpts,
4971) !u16 {4789) !u8 {
4972 const seg = &self.load_commands.items[segment_id].segment;4790 const seg = &self.segments.items[segment_id];
4973 var sect = macho.section_64{4791 var header = macho.section_64{
4974 .sectname = makeStaticString(sectname),4792 .sectname = makeStaticString(sectname),
4975 .segname = seg.inner.segname,4793 .segname = seg.segname,
4976 .size = if (self.mode == .incremental) @intCast(u32, size) else 0,4794 .size = if (self.mode == .incremental) @intCast(u32, size) else 0,
4977 .@"align" = alignment,4795 .@"align" = alignment,
4978 .flags = opts.flags,4796 .flags = opts.flags,
...@@ -4982,165 +4800,157 @@ fn initSection(...@@ -4982,165 +4800,157 @@ fn initSection(
49824800
4983 if (self.mode == .incremental) {4801 if (self.mode == .incremental) {
4984 const alignment_pow_2 = try math.powi(u32, 2, alignment);4802 const alignment_pow_2 = try math.powi(u32, 2, alignment);
4985 const padding: ?u32 = if (segment_id == self.text_segment_cmd_index.?)4803 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?)
4986 @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size)4804 try self.calcMinHeaderPad()
4987 else4805 else
4988 null;4806 null;
4989 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);4807 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
4990 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{4808 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
4991 sect.segName(),4809 header.segName(),
4992 sect.sectName(),4810 header.sectName(),
4993 off,4811 off,
4994 off + size,4812 off + size,
4995 });4813 });
49964814
4997 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;4815 header.addr = seg.vmaddr + off - seg.fileoff;
4998
4999 const is_zerofill = opts.flags == macho.S_ZEROFILL or opts.flags == macho.S_THREAD_LOCAL_ZEROFILL;
5000 const use_llvm = build_options.have_llvm and self.base.options.use_llvm;
5001 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
50024816
5003 // TODO handle zerofill in stage24817 // TODO handle zerofill in stage2
5004 if (!(is_zerofill and (use_stage1 or use_llvm))) {4818 // const is_zerofill = opts.flags == macho.S_ZEROFILL or opts.flags == macho.S_THREAD_LOCAL_ZEROFILL;
5005 sect.offset = @intCast(u32, off);4819 header.offset = @intCast(u32, off);
5006 }
5007 }
50084820
5009 const index = @intCast(u16, seg.sections.items.len);4821 try self.updateSectionOrdinals();
5010 try seg.sections.append(self.base.allocator, sect);4822 }
5011 seg.inner.cmdsize += @sizeOf(macho.section_64);
5012 seg.inner.nsects += 1;
5013
5014 const match = MatchingSection{
5015 .seg = segment_id,
5016 .sect = index,
5017 };
5018 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
5019 try self.atom_free_lists.putNoClobber(self.base.allocator, match, .{});
50204823
5021 self.load_commands_dirty = true;4824 const index = @intCast(u8, self.sections.slice().len);
5022 self.sections_order_dirty = true;4825 try self.sections.append(self.base.allocator, .{
4826 .segment_index = segment_id,
4827 .header = header,
4828 });
4829 seg.cmdsize += @sizeOf(macho.section_64);
4830 seg.nsects += 1;
50234831
5024 return index;4832 return index;
5025}4833}
50264834
5027fn findFreeSpace(self: MachO, segment_id: u16, alignment: u64, start: ?u32) u64 {4835fn findFreeSpace(self: MachO, segment_id: u8, alignment: u64, start: ?u64) u64 {
5028 const seg = self.load_commands.items[segment_id].segment;4836 const seg = self.segments.items[segment_id];
5029 if (seg.sections.items.len == 0) {4837 const indexes = self.getSectionIndexes(segment_id);
5030 return if (start) |v| v else seg.inner.fileoff;4838 if (indexes.end - indexes.start == 0) {
4839 return if (start) |v| v else seg.fileoff;
5031 }4840 }
5032 const last_sect = seg.sections.items[seg.sections.items.len - 1];4841 const last_sect = self.sections.items(.header)[indexes.end - 1];
5033 const final_off = last_sect.offset + padToIdeal(last_sect.size);4842 const final_off = last_sect.offset + padToIdeal(last_sect.size);
5034 return mem.alignForwardGeneric(u64, final_off, alignment);4843 return mem.alignForwardGeneric(u64, final_off, alignment);
5035}4844}
50364845
5037fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {4846fn growSegment(self: *MachO, segment_index: u8, new_size: u64) !void {
5038 const seg = &self.load_commands.items[seg_id].segment;4847 const segment = &self.segments.items[segment_index];
5039 const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);4848 const new_segment_size = mem.alignForwardGeneric(u64, new_size, self.page_size);
5040 assert(new_seg_size > seg.inner.filesize);4849 assert(new_segment_size > segment.filesize);
5041 const offset_amt = new_seg_size - seg.inner.filesize;4850 const offset_amt = new_segment_size - segment.filesize;
5042 log.debug("growing segment {s} from 0x{x} to 0x{x}", .{4851 log.debug("growing segment {s} from 0x{x} to 0x{x}", .{
5043 seg.inner.segname,4852 segment.segname,
5044 seg.inner.filesize,4853 segment.filesize,
5045 new_seg_size,4854 new_segment_size,
5046 });4855 });
5047 seg.inner.filesize = new_seg_size;4856 segment.filesize = new_segment_size;
5048 seg.inner.vmsize = new_seg_size;4857 segment.vmsize = new_segment_size;
50494858
5050 log.debug(" (new segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{4859 log.debug(" (new segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
5051 seg.inner.fileoff,4860 segment.fileoff,
5052 seg.inner.fileoff + seg.inner.filesize,4861 segment.fileoff + segment.filesize,
5053 seg.inner.vmaddr,4862 segment.vmaddr,
5054 seg.inner.vmaddr + seg.inner.vmsize,4863 segment.vmaddr + segment.vmsize,
5055 });4864 });
50564865
5057 var next: usize = seg_id + 1;4866 var next: u8 = segment_index + 1;
5058 while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) {4867 while (next < self.linkedit_segment_cmd_index.? + 1) : (next += 1) {
5059 const next_seg = &self.load_commands.items[next].segment;4868 const next_segment = &self.segments.items[next];
50604869
5061 try MachO.copyRangeAllOverlappingAlloc(4870 try MachO.copyRangeAllOverlappingAlloc(
5062 self.base.allocator,4871 self.base.allocator,
5063 self.base.file.?,4872 self.base.file.?,
5064 next_seg.inner.fileoff,4873 next_segment.fileoff,
5065 next_seg.inner.fileoff + offset_amt,4874 next_segment.fileoff + offset_amt,
5066 math.cast(usize, next_seg.inner.filesize) orelse return error.Overflow,4875 math.cast(usize, next_segment.filesize) orelse return error.Overflow,
5067 );4876 );
50684877
5069 next_seg.inner.fileoff += offset_amt;4878 next_segment.fileoff += offset_amt;
5070 next_seg.inner.vmaddr += offset_amt;4879 next_segment.vmaddr += offset_amt;
50714880
5072 log.debug(" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{4881 log.debug(" (new {s} segment file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
5073 next_seg.inner.segname,4882 next_segment.segname,
5074 next_seg.inner.fileoff,4883 next_segment.fileoff,
5075 next_seg.inner.fileoff + next_seg.inner.filesize,4884 next_segment.fileoff + next_segment.filesize,
5076 next_seg.inner.vmaddr,4885 next_segment.vmaddr,
5077 next_seg.inner.vmaddr + next_seg.inner.vmsize,4886 next_segment.vmaddr + next_segment.vmsize,
5078 });4887 });
50794888
5080 for (next_seg.sections.items) |*moved_sect, moved_sect_id| {4889 const indexes = self.getSectionIndexes(next);
5081 moved_sect.offset += @intCast(u32, offset_amt);4890 for (self.sections.items(.header)[indexes.start..indexes.end]) |*header, i| {
5082 moved_sect.addr += offset_amt;4891 header.offset += @intCast(u32, offset_amt);
4892 header.addr += offset_amt;
50834893
5084 log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{4894 log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
5085 moved_sect.segName(),4895 header.segName(),
5086 moved_sect.sectName(),4896 header.sectName(),
5087 moved_sect.offset,4897 header.offset,
5088 moved_sect.offset + moved_sect.size,4898 header.offset + header.size,
5089 moved_sect.addr,4899 header.addr,
5090 moved_sect.addr + moved_sect.size,4900 header.addr + header.size,
5091 });4901 });
50924902
5093 try self.shiftLocalsByOffset(.{4903 try self.shiftLocalsByOffset(@intCast(u8, i + indexes.start), @intCast(i64, offset_amt));
5094 .seg = @intCast(u16, next),
5095 .sect = @intCast(u16, moved_sect_id),
5096 }, @intCast(i64, offset_amt));
5097 }4904 }
5098 }4905 }
5099}4906}
51004907
5101fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {4908fn growSection(self: *MachO, sect_id: u8, new_size: u32) !void {
5102 const tracy = trace(@src());4909 const tracy = trace(@src());
5103 defer tracy.end();4910 defer tracy.end();
51044911
5105 const seg = &self.load_commands.items[match.seg].segment;4912 const section = self.sections.get(sect_id);
5106 const sect = &seg.sections.items[match.sect];4913 const segment_index = section.segment_index;
4914 const header = section.header;
4915 const segment = self.segments.items[segment_index];
51074916
5108 const alignment = try math.powi(u32, 2, sect.@"align");4917 const alignment = try math.powi(u32, 2, header.@"align");
5109 const max_size = self.allocatedSize(match.seg, sect.offset);4918 const max_size = self.allocatedSize(segment_index, header.offset);
5110 const ideal_size = padToIdeal(new_size);4919 const ideal_size = padToIdeal(new_size);
5111 const needed_size = mem.alignForwardGeneric(u32, ideal_size, alignment);4920 const needed_size = mem.alignForwardGeneric(u32, ideal_size, alignment);
51124921
5113 if (needed_size > max_size) blk: {4922 if (needed_size > max_size) blk: {
5114 log.debug(" (need to grow! needed 0x{x}, max 0x{x})", .{ needed_size, max_size });4923 log.debug(" (need to grow! needed 0x{x}, max 0x{x})", .{ needed_size, max_size });
51154924
5116 if (match.sect == seg.sections.items.len - 1) {4925 const indexes = self.getSectionIndexes(segment_index);
4926 if (sect_id == indexes.end - 1) {
5117 // Last section, just grow segments4927 // Last section, just grow segments
5118 try self.growSegment(match.seg, seg.inner.filesize + needed_size - max_size);4928 try self.growSegment(segment_index, segment.filesize + needed_size - max_size);
5119 break :blk;4929 break :blk;
5120 }4930 }
51214931
5122 // Need to move all sections below in file and address spaces.4932 // Need to move all sections below in file and address spaces.
5123 const offset_amt = offset: {4933 const offset_amt = offset: {
5124 const max_alignment = try self.getSectionMaxAlignment(match.seg, match.sect + 1);4934 const max_alignment = try self.getSectionMaxAlignment(sect_id + 1, indexes.end);
5125 break :offset mem.alignForwardGeneric(u64, needed_size - max_size, max_alignment);4935 break :offset mem.alignForwardGeneric(u64, needed_size - max_size, max_alignment);
5126 };4936 };
51274937
5128 // Before we commit to this, check if the segment needs to grow too.4938 // Before we commit to this, check if the segment needs to grow too.
5129 // We assume that each section header is growing linearly with the increasing4939 // We assume that each section header is growing linearly with the increasing
5130 // file offset / virtual memory address space.4940 // file offset / virtual memory address space.
5131 const last_sect = seg.sections.items[seg.sections.items.len - 1];4941 const last_sect_header = self.sections.items(.header)[indexes.end - 1];
5132 const last_sect_off = last_sect.offset + last_sect.size;4942 const last_sect_off = last_sect_header.offset + last_sect_header.size;
5133 const seg_off = seg.inner.fileoff + seg.inner.filesize;4943 const seg_off = segment.fileoff + segment.filesize;
51344944
5135 if (last_sect_off + offset_amt > seg_off) {4945 if (last_sect_off + offset_amt > seg_off) {
5136 // Need to grow segment first.4946 // Need to grow segment first.
5137 const spill_size = (last_sect_off + offset_amt) - seg_off;4947 const spill_size = (last_sect_off + offset_amt) - seg_off;
5138 try self.growSegment(match.seg, seg.inner.filesize + spill_size);4948 try self.growSegment(segment_index, segment.filesize + spill_size);
5139 }4949 }
51404950
5141 // We have enough space to expand within the segment, so move all sections by4951 // We have enough space to expand within the segment, so move all sections by
5142 // the required amount and update their header offsets.4952 // the required amount and update their header offsets.
5143 const next_sect = seg.sections.items[match.sect + 1];4953 const next_sect = self.sections.items(.header)[sect_id + 1];
5144 const total_size = last_sect_off - next_sect.offset;4954 const total_size = last_sect_off - next_sect.offset;
51454955
5146 try MachO.copyRangeAllOverlappingAlloc(4956 try MachO.copyRangeAllOverlappingAlloc(
...@@ -5151,9 +4961,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {...@@ -5151,9 +4961,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
5151 math.cast(usize, total_size) orelse return error.Overflow,4961 math.cast(usize, total_size) orelse return error.Overflow,
5152 );4962 );
51534963
5154 var next = match.sect + 1;4964 for (self.sections.items(.header)[sect_id + 1 .. indexes.end]) |*moved_sect, i| {
5155 while (next < seg.sections.items.len) : (next += 1) {
5156 const moved_sect = &seg.sections.items[next];
5157 moved_sect.offset += @intCast(u32, offset_amt);4965 moved_sect.offset += @intCast(u32, offset_amt);
5158 moved_sect.addr += offset_amt;4966 moved_sect.addr += offset_amt;
51594967
...@@ -5166,49 +4974,45 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {...@@ -5166,49 +4974,45 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
5166 moved_sect.addr + moved_sect.size,4974 moved_sect.addr + moved_sect.size,
5167 });4975 });
51684976
5169 try self.shiftLocalsByOffset(.{4977 try self.shiftLocalsByOffset(@intCast(u8, sect_id + 1 + i), @intCast(i64, offset_amt));
5170 .seg = match.seg,
5171 .sect = next,
5172 }, @intCast(i64, offset_amt));
5173 }4978 }
5174 }4979 }
5175}4980}
51764981
5177fn allocatedSize(self: MachO, segment_id: u16, start: u64) u64 {4982fn allocatedSize(self: MachO, segment_id: u8, start: u64) u64 {
5178 const seg = self.load_commands.items[segment_id].segment;4983 const segment = self.segments.items[segment_id];
5179 assert(start >= seg.inner.fileoff);4984 const indexes = self.getSectionIndexes(segment_id);
5180 var min_pos: u64 = seg.inner.fileoff + seg.inner.filesize;4985 assert(start >= segment.fileoff);
4986 var min_pos: u64 = segment.fileoff + segment.filesize;
5181 if (start > min_pos) return 0;4987 if (start > min_pos) return 0;
5182 for (seg.sections.items) |section| {4988 for (self.sections.items(.header)[indexes.start..indexes.end]) |header| {
5183 if (section.offset <= start) continue;4989 if (header.offset <= start) continue;
5184 if (section.offset < min_pos) min_pos = section.offset;4990 if (header.offset < min_pos) min_pos = header.offset;
5185 }4991 }
5186 return min_pos - start;4992 return min_pos - start;
5187}4993}
51884994
5189fn getSectionMaxAlignment(self: *MachO, segment_id: u16, start_sect_id: u16) !u32 {4995fn getSectionMaxAlignment(self: *MachO, start: u8, end: u8) !u32 {
5190 const seg = self.load_commands.items[segment_id].segment;
5191 var max_alignment: u32 = 1;4996 var max_alignment: u32 = 1;
5192 var next = start_sect_id;4997 const slice = self.sections.slice();
5193 while (next < seg.sections.items.len) : (next += 1) {4998 for (slice.items(.header)[start..end]) |header| {
5194 const sect = seg.sections.items[next];4999 const alignment = try math.powi(u32, 2, header.@"align");
5195 const alignment = try math.powi(u32, 2, sect.@"align");
5196 max_alignment = math.max(max_alignment, alignment);5000 max_alignment = math.max(max_alignment, alignment);
5197 }5001 }
5198 return max_alignment;5002 return max_alignment;
5199}5003}
52005004
5201fn allocateAtomCommon(self: *MachO, atom: *Atom, match: MatchingSection) !void {5005fn allocateAtomCommon(self: *MachO, atom: *Atom, sect_id: u8) !void {
5202 const sym = atom.getSymbolPtr(self);5006 const sym = atom.getSymbolPtr(self);
5203 if (self.mode == .incremental) {5007 if (self.mode == .incremental) {
5204 const size = atom.size;5008 const size = atom.size;
5205 const alignment = try math.powi(u32, 2, atom.alignment);5009 const alignment = try math.powi(u32, 2, atom.alignment);
5206 const vaddr = try self.allocateAtom(atom, size, alignment, match);5010 const vaddr = try self.allocateAtom(atom, size, alignment, sect_id);
5207 const sym_name = atom.getName(self);5011 const sym_name = atom.getName(self);
5208 log.debug("allocated {s} atom at 0x{x}", .{ sym_name, vaddr });5012 log.debug("allocated {s} atom at 0x{x}", .{ sym_name, vaddr });
5209 sym.n_value = vaddr;5013 sym.n_value = vaddr;
5210 } else try self.addAtomToSection(atom, match);5014 } else try self.addAtomToSection(atom, sect_id);
5211 sym.n_sect = self.getSectionOrdinal(match);5015 sym.n_sect = sect_id + 1;
5212}5016}
52135017
5214fn allocateAtom(5018fn allocateAtom(
...@@ -5216,15 +5020,15 @@ fn allocateAtom(...@@ -5216,15 +5020,15 @@ fn allocateAtom(
5216 atom: *Atom,5020 atom: *Atom,
5217 new_atom_size: u64,5021 new_atom_size: u64,
5218 alignment: u64,5022 alignment: u64,
5219 match: MatchingSection,5023 sect_id: u8,
5220) !u64 {5024) !u64 {
5221 const tracy = trace(@src());5025 const tracy = trace(@src());
5222 defer tracy.end();5026 defer tracy.end();
52235027
5224 const sect = self.getSectionPtr(match);5028 const header = &self.sections.items(.header)[sect_id];
5225 var free_list = self.atom_free_lists.get(match).?;5029 const free_list = &self.sections.items(.free_list)[sect_id];
5226 const needs_padding = match.seg == self.text_segment_cmd_index.? and match.sect == self.text_section_index.?;5030 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];
5227 const new_atom_ideal_capacity = if (needs_padding) padToIdeal(new_atom_size) else new_atom_size;5031 const new_atom_ideal_capacity = if (header.isCode()) padToIdeal(new_atom_size) else new_atom_size;
52285032
5229 // We use these to indicate our intention to update metadata, placing the new atom,5033 // We use these to indicate our intention to update metadata, placing the new atom,
5230 // and possibly removing a free list node.5034 // and possibly removing a free list node.
...@@ -5244,7 +5048,7 @@ fn allocateAtom(...@@ -5244,7 +5048,7 @@ fn allocateAtom(
5244 // Is it enough that we could fit this new atom?5048 // Is it enough that we could fit this new atom?
5245 const sym = big_atom.getSymbol(self);5049 const sym = big_atom.getSymbol(self);
5246 const capacity = big_atom.capacity(self);5050 const capacity = big_atom.capacity(self);
5247 const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity;5051 const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity;
5248 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;5052 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;
5249 const capacity_end_vaddr = sym.n_value + capacity;5053 const capacity_end_vaddr = sym.n_value + capacity;
5250 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;5054 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
...@@ -5272,30 +5076,28 @@ fn allocateAtom(...@@ -5272,30 +5076,28 @@ fn allocateAtom(
5272 free_list_removal = i;5076 free_list_removal = i;
5273 }5077 }
5274 break :blk new_start_vaddr;5078 break :blk new_start_vaddr;
5275 } else if (self.atoms.get(match)) |last| {5079 } else if (maybe_last_atom.*) |last| {
5276 const last_symbol = last.getSymbol(self);5080 const last_symbol = last.getSymbol(self);
5277 const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size;5081 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
5278 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;5082 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
5279 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);5083 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
5280 atom_placement = last;5084 atom_placement = last;
5281 break :blk new_start_vaddr;5085 break :blk new_start_vaddr;
5282 } else {5086 } else {
5283 break :blk mem.alignForwardGeneric(u64, sect.addr, alignment);5087 break :blk mem.alignForwardGeneric(u64, header.addr, alignment);
5284 }5088 }
5285 };5089 };
52865090
5287 const expand_section = atom_placement == null or atom_placement.?.next == null;5091 const expand_section = atom_placement == null or atom_placement.?.next == null;
5288 if (expand_section) {5092 if (expand_section) {
5289 const needed_size = @intCast(u32, (vaddr + new_atom_size) - sect.addr);5093 const needed_size = @intCast(u32, (vaddr + new_atom_size) - header.addr);
5290 try self.growSection(match, needed_size);5094 try self.growSection(sect_id, needed_size);
5291 _ = try self.atoms.put(self.base.allocator, match, atom);5095 maybe_last_atom.* = atom;
5292 sect.size = needed_size;5096 header.size = needed_size;
5293 self.load_commands_dirty = true;
5294 }5097 }
5295 const align_pow = @intCast(u32, math.log2(alignment));5098 const align_pow = @intCast(u32, math.log2(alignment));
5296 if (sect.@"align" < align_pow) {5099 if (header.@"align" < align_pow) {
5297 sect.@"align" = align_pow;5100 header.@"align" = align_pow;
5298 self.load_commands_dirty = true;
5299 }5101 }
5300 atom.size = new_atom_size;5102 atom.size = new_atom_size;
5301 atom.alignment = align_pow;5103 atom.alignment = align_pow;
...@@ -5322,20 +5124,19 @@ fn allocateAtom(...@@ -5322,20 +5124,19 @@ fn allocateAtom(
5322 return vaddr;5124 return vaddr;
5323}5125}
53245126
5325pub fn addAtomToSection(self: *MachO, atom: *Atom, match: MatchingSection) !void {5127pub fn addAtomToSection(self: *MachO, atom: *Atom, sect_id: u8) !void {
5326 if (self.atoms.getPtr(match)) |last| {5128 var section = self.sections.get(sect_id);
5327 last.*.next = atom;5129 if (section.header.size > 0) {
5328 atom.prev = last.*;5130 section.last_atom.?.next = atom;
5329 last.* = atom;5131 atom.prev = section.last_atom.?;
5330 } else {
5331 try self.atoms.putNoClobber(self.base.allocator, match, atom);
5332 }5132 }
5333 const sect = self.getSectionPtr(match);5133 section.last_atom = atom;
5334 const atom_alignment = try math.powi(u32, 2, atom.alignment);5134 const atom_alignment = try math.powi(u32, 2, atom.alignment);
5335 const aligned_end_addr = mem.alignForwardGeneric(u64, sect.size, atom_alignment);5135 const aligned_end_addr = mem.alignForwardGeneric(u64, section.header.size, atom_alignment);
5336 const padding = aligned_end_addr - sect.size;5136 const padding = aligned_end_addr - section.header.size;
5337 sect.size += padding + atom.size;5137 section.header.size += padding + atom.size;
5338 sect.@"align" = @maximum(sect.@"align", atom.alignment);5138 section.header.@"align" = @maximum(section.header.@"align", atom.alignment);
5139 self.sections.set(sect_id, section);
5339}5140}
53405141
5341pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {5142pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {
...@@ -5368,74 +5169,27 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {...@@ -5368,74 +5169,27 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {
5368 return sym_index;5169 return sym_index;
5369}5170}
53705171
5371fn getSegmentAllocBase(self: MachO, indices: []const ?u16) struct { vmaddr: u64, fileoff: u64 } {5172fn getSegmentAllocBase(self: MachO, indices: []const ?u8) struct { vmaddr: u64, fileoff: u64 } {
5372 for (indices) |maybe_prev_id| {5173 for (indices) |maybe_prev_id| {
5373 const prev_id = maybe_prev_id orelse continue;5174 const prev_id = maybe_prev_id orelse continue;
5374 const prev = self.load_commands.items[prev_id].segment;5175 const prev = self.segments.items[prev_id];
5375 return .{5176 return .{
5376 .vmaddr = prev.inner.vmaddr + prev.inner.vmsize,5177 .vmaddr = prev.vmaddr + prev.vmsize,
5377 .fileoff = prev.inner.fileoff + prev.inner.filesize,5178 .fileoff = prev.fileoff + prev.filesize,
5378 };5179 };
5379 }5180 }
5380 return .{ .vmaddr = 0, .fileoff = 0 };5181 return .{ .vmaddr = 0, .fileoff = 0 };
5381}5182}
53825183
5383fn pruneAndSortSectionsInSegment(self: *MachO, maybe_seg_id: *?u16, indices: []*?u16) !void {5184fn pruneAndSortSections(self: *MachO) !void {
5384 const seg_id = maybe_seg_id.* orelse return;5185 const gpa = self.base.allocator;
5385
5386 var mapping = std.AutoArrayHashMap(u16, ?u16).init(self.base.allocator);
5387 defer mapping.deinit();
5388
5389 const seg = &self.load_commands.items[seg_id].segment;
5390 var sections = seg.sections.toOwnedSlice(self.base.allocator);
5391 defer self.base.allocator.free(sections);
5392 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
5393
5394 for (indices) |maybe_index| {
5395 const old_idx = maybe_index.* orelse continue;
5396 const sect = &sections[old_idx];
5397 if (sect.size == 0) {
5398 log.debug("pruning section {s},{s}", .{ sect.segName(), sect.sectName() });
5399 maybe_index.* = null;
5400 seg.inner.cmdsize -= @sizeOf(macho.section_64);
5401 seg.inner.nsects -= 1;
5402 } else {
5403 maybe_index.* = @intCast(u16, seg.sections.items.len);
5404 seg.sections.appendAssumeCapacity(sect.*);
5405 }
5406 try mapping.putNoClobber(old_idx, maybe_index.*);
5407 }
5408
5409 var atoms = std.ArrayList(struct { match: MatchingSection, atom: *Atom }).init(self.base.allocator);
5410 defer atoms.deinit();
5411 try atoms.ensureTotalCapacity(mapping.count());
5412
5413 for (mapping.keys()) |old_sect| {
5414 const new_sect = mapping.get(old_sect).? orelse {
5415 _ = self.atoms.remove(.{ .seg = seg_id, .sect = old_sect });
5416 continue;
5417 };
5418 const kv = self.atoms.fetchRemove(.{ .seg = seg_id, .sect = old_sect }).?;
5419 atoms.appendAssumeCapacity(.{
5420 .match = .{ .seg = seg_id, .sect = new_sect },
5421 .atom = kv.value,
5422 });
5423 }
54245186
5425 while (atoms.popOrNull()) |next| {5187 var sections = self.sections.toOwnedSlice();
5426 try self.atoms.putNoClobber(self.base.allocator, next.match, next.atom);5188 defer sections.deinit(gpa);
5427 }5189 try self.sections.ensureTotalCapacity(gpa, sections.len);
54285190
5429 if (seg.inner.nsects == 0 and !mem.eql(u8, "__TEXT", seg.inner.segName())) {5191 for (&[_]*?u8{
5430 // Segment has now become empty, so mark it as such5192 // __TEXT
5431 log.debug("marking segment {s} as dead", .{seg.inner.segName()});
5432 seg.inner.cmd = @intToEnum(macho.LC, 0);
5433 maybe_seg_id.* = null;
5434 }
5435}
5436
5437fn pruneAndSortSections(self: *MachO) !void {
5438 try self.pruneAndSortSectionsInSegment(&self.text_segment_cmd_index, &.{
5439 &self.text_section_index,5193 &self.text_section_index,
5440 &self.stubs_section_index,5194 &self.stubs_section_index,
5441 &self.stub_helper_section_index,5195 &self.stub_helper_section_index,
...@@ -5448,9 +5202,7 @@ fn pruneAndSortSections(self: *MachO) !void {...@@ -5448,9 +5202,7 @@ fn pruneAndSortSections(self: *MachO) !void {
5448 &self.objc_methtype_section_index,5202 &self.objc_methtype_section_index,
5449 &self.objc_classname_section_index,5203 &self.objc_classname_section_index,
5450 &self.eh_frame_section_index,5204 &self.eh_frame_section_index,
5451 });5205 // __DATA_CONST
5452
5453 try self.pruneAndSortSectionsInSegment(&self.data_const_segment_cmd_index, &.{
5454 &self.got_section_index,5206 &self.got_section_index,
5455 &self.mod_init_func_section_index,5207 &self.mod_init_func_section_index,
5456 &self.mod_term_func_section_index,5208 &self.mod_term_func_section_index,
...@@ -5458,9 +5210,7 @@ fn pruneAndSortSections(self: *MachO) !void {...@@ -5458,9 +5210,7 @@ fn pruneAndSortSections(self: *MachO) !void {
5458 &self.objc_cfstring_section_index,5210 &self.objc_cfstring_section_index,
5459 &self.objc_classlist_section_index,5211 &self.objc_classlist_section_index,
5460 &self.objc_imageinfo_section_index,5212 &self.objc_imageinfo_section_index,
5461 });5213 // __DATA
5462
5463 try self.pruneAndSortSectionsInSegment(&self.data_segment_cmd_index, &.{
5464 &self.rustc_section_index,5214 &self.rustc_section_index,
5465 &self.la_symbol_ptr_section_index,5215 &self.la_symbol_ptr_section_index,
5466 &self.objc_const_section_index,5216 &self.objc_const_section_index,
...@@ -5473,103 +5223,129 @@ fn pruneAndSortSections(self: *MachO) !void {...@@ -5473,103 +5223,129 @@ fn pruneAndSortSections(self: *MachO) !void {
5473 &self.tlv_data_section_index,5223 &self.tlv_data_section_index,
5474 &self.tlv_bss_section_index,5224 &self.tlv_bss_section_index,
5475 &self.bss_section_index,5225 &self.bss_section_index,
5476 });5226 }) |maybe_index| {
54775227 const old_idx = maybe_index.* orelse continue;
5478 // Create new section ordinals.5228 const segment_index = sections.items(.segment_index)[old_idx];
5479 self.section_ordinals.clearRetainingCapacity();5229 const header = sections.items(.header)[old_idx];
5480 if (self.text_segment_cmd_index) |seg_id| {5230 const last_atom = sections.items(.last_atom)[old_idx];
5481 const seg = self.load_commands.items[seg_id].segment;5231 if (header.size == 0) {
5482 for (seg.sections.items) |_, sect_id| {5232 log.debug("pruning section {s},{s}", .{ header.segName(), header.sectName() });
5483 const res = self.section_ordinals.getOrPutAssumeCapacity(.{5233 maybe_index.* = null;
5484 .seg = seg_id,5234 const seg = &self.segments.items[segment_index];
5485 .sect = @intCast(u16, sect_id),5235 seg.cmdsize -= @sizeOf(macho.section_64);
5486 });5236 seg.nsects -= 1;
5487 assert(!res.found_existing);5237 } else {
5488 }5238 maybe_index.* = @intCast(u8, self.sections.slice().len);
5489 }5239 self.sections.appendAssumeCapacity(.{
5490 if (self.data_const_segment_cmd_index) |seg_id| {5240 .segment_index = segment_index,
5491 const seg = self.load_commands.items[seg_id].segment;5241 .header = header,
5492 for (seg.sections.items) |_, sect_id| {5242 .last_atom = last_atom,
5493 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
5494 .seg = seg_id,
5495 .sect = @intCast(u16, sect_id),
5496 });5243 });
5497 assert(!res.found_existing);
5498 }5244 }
5499 }5245 }
5500 if (self.data_segment_cmd_index) |seg_id| {5246
5501 const seg = self.load_commands.items[seg_id].segment;5247 for (self.segments.items) |*seg| {
5502 for (seg.sections.items) |_, sect_id| {5248 const segname = seg.segName();
5503 const res = self.section_ordinals.getOrPutAssumeCapacity(.{5249 if (seg.nsects == 0 and
5504 .seg = seg_id,5250 !mem.eql(u8, "__TEXT", segname) and
5505 .sect = @intCast(u16, sect_id),5251 !mem.eql(u8, "__PAGEZERO", segname) and
5506 });5252 !mem.eql(u8, "__LINKEDIT", segname))
5507 assert(!res.found_existing);5253 {
5254 // Segment has now become empty, so mark it as such
5255 log.debug("marking segment {s} as dead", .{seg.segName()});
5256 seg.cmd = @intToEnum(macho.LC, 0);
5508 }5257 }
5509 }5258 }
5510 self.sections_order_dirty = false;
5511}5259}
55125260
5513fn updateSectionOrdinals(self: *MachO) !void {5261fn updateSectionOrdinals(self: *MachO) !void {
5514 if (!self.sections_order_dirty) return;5262 _ = self;
5515
5516 const tracy = trace(@src());5263 const tracy = trace(@src());
5517 defer tracy.end();5264 defer tracy.end();
55185265
5519 log.debug("updating section ordinals", .{});5266 @panic("updating section ordinals");
55205267
5521 const gpa = self.base.allocator;5268 // const gpa = self.base.allocator;
5269
5270 // var ordinal_remap = std.AutoHashMap(u8, u8).init(gpa);
5271 // defer ordinal_remap.deinit();
5272 // var ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{};
5273
5274 // var new_ordinal: u8 = 0;
5275 // for (&[_]?u16{
5276 // self.text_segment_cmd_index,
5277 // self.data_const_segment_cmd_index,
5278 // self.data_segment_cmd_index,
5279 // }) |maybe_index| {
5280 // const index = maybe_index orelse continue;
5281 // const seg = self.load_commands.items[index].segment;
5282 // for (seg.sections.items) |sect, sect_id| {
5283 // const match = MatchingSection{
5284 // .seg = @intCast(u16, index),
5285 // .sect = @intCast(u16, sect_id),
5286 // };
5287 // const old_ordinal = self.getSectionOrdinal(match);
5288 // new_ordinal += 1;
5289 // log.debug("'{s},{s}': sect({d}, '_,_') => sect({d}, '_,_')", .{
5290 // sect.segName(),
5291 // sect.sectName(),
5292 // old_ordinal,
5293 // new_ordinal,
5294 // });
5295 // try ordinal_remap.putNoClobber(old_ordinal, new_ordinal);
5296 // try ordinals.putNoClobber(gpa, match, {});
5297 // }
5298 // }
5299
5300 // // FIXME Jakub
5301 // // TODO no need for duping work here; simply walk the atom graph
5302 // for (self.locals.items) |*sym| {
5303 // if (sym.undf()) continue;
5304 // if (sym.n_sect == 0) continue;
5305 // sym.n_sect = ordinal_remap.get(sym.n_sect).?;
5306 // }
5307 // for (self.objects.items) |*object| {
5308 // for (object.symtab.items) |*sym| {
5309 // if (sym.undf()) continue;
5310 // if (sym.n_sect == 0) continue;
5311 // sym.n_sect = ordinal_remap.get(sym.n_sect).?;
5312 // }
5313 // }
5314
5315 // self.section_ordinals.deinit(gpa);
5316 // self.section_ordinals = ordinals;
5317}
55225318
5523 var ordinal_remap = std.AutoHashMap(u8, u8).init(gpa);5319pub fn writeSegmentHeaders(self: *MachO, start: usize, end: usize, ncmds: *u32, writer: anytype) !void {
5524 defer ordinal_remap.deinit();5320 var count: usize = 0;
5525 var ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{};5321 for (self.segments.items[start..end]) |seg| {
5322 if (seg.cmd == .NONE) continue;
5323 try writer.writeStruct(seg);
55265324
5527 var new_ordinal: u8 = 0;5325 // TODO
5528 for (&[_]?u16{5326 for (self.sections.items(.header)[count..][0..seg.nsects]) |header| {
5529 self.text_segment_cmd_index,5327 try writer.writeStruct(header);
5530 self.data_const_segment_cmd_index,
5531 self.data_segment_cmd_index,
5532 }) |maybe_index| {
5533 const index = maybe_index orelse continue;
5534 const seg = self.load_commands.items[index].segment;
5535 for (seg.sections.items) |sect, sect_id| {
5536 const match = MatchingSection{
5537 .seg = @intCast(u16, index),
5538 .sect = @intCast(u16, sect_id),
5539 };
5540 const old_ordinal = self.getSectionOrdinal(match);
5541 new_ordinal += 1;
5542 log.debug("'{s},{s}': sect({d}, '_,_') => sect({d}, '_,_')", .{
5543 sect.segName(),
5544 sect.sectName(),
5545 old_ordinal,
5546 new_ordinal,
5547 });
5548 try ordinal_remap.putNoClobber(old_ordinal, new_ordinal);
5549 try ordinals.putNoClobber(gpa, match, {});
5550 }5328 }
5551 }
55525329
5553 // FIXME Jakub5330 count += seg.nsects;
5554 // TODO no need for duping work here; simply walk the atom graph5331 ncmds.* += 1;
5555 for (self.locals.items) |*sym| {
5556 if (sym.undf()) continue;
5557 if (sym.n_sect == 0) continue;
5558 sym.n_sect = ordinal_remap.get(sym.n_sect).?;
5559 }
5560 for (self.objects.items) |*object| {
5561 for (object.symtab.items) |*sym| {
5562 if (sym.undf()) continue;
5563 if (sym.n_sect == 0) continue;
5564 sym.n_sect = ordinal_remap.get(sym.n_sect).?;
5565 }
5566 }5332 }
5333}
5334
5335fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5336 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
5337 seg.filesize = 0;
5338 seg.vmsize = 0;
55675339
5568 self.section_ordinals.deinit(gpa);5340 try self.writeDyldInfoData(ncmds, lc_writer);
5569 self.section_ordinals = ordinals;5341 try self.writeFunctionStarts(ncmds, lc_writer);
5342 try self.writeDataInCode(ncmds, lc_writer);
5343 try self.writeSymtabs(ncmds, lc_writer);
5344
5345 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
5570}5346}
55715347
5572fn writeDyldInfoData(self: *MachO) !void {5348fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5573 const tracy = trace(@src());5349 const tracy = trace(@src());
5574 defer tracy.end();5350 defer tracy.end();
55755351
...@@ -5582,89 +5358,86 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5582,89 +5358,86 @@ fn writeDyldInfoData(self: *MachO) !void {
5582 var lazy_bind_pointers = std.ArrayList(bind.Pointer).init(gpa);5358 var lazy_bind_pointers = std.ArrayList(bind.Pointer).init(gpa);
5583 defer lazy_bind_pointers.deinit();5359 defer lazy_bind_pointers.deinit();
55845360
5585 {5361 const slice = self.sections.slice();
5586 var it = self.atoms.iterator();5362 for (slice.items(.last_atom)) |last_atom, sect_id| {
5587 while (it.next()) |entry| {5363 var atom = last_atom orelse continue;
5588 const match = entry.key_ptr.*;5364 const segment_index = slice.items(.segment_index)[sect_id];
5589 var atom: *Atom = entry.value_ptr.*;5365 const header = slice.items(.header)[sect_id];
55905366
5591 if (self.text_segment_cmd_index) |seg| {5367 if (mem.eql(u8, header.segName(), "__TEXT")) continue; // __TEXT is non-writable
5592 if (match.seg == seg) continue; // __TEXT is non-writable
5593 }
55945368
5595 const seg = self.getSegment(match);5369 log.debug("dyld info for {s},{s}", .{ header.segName(), header.sectName() });
5596 const sect = self.getSection(match);
5597 log.debug("dyld info for {s},{s}", .{ sect.segName(), sect.sectName() });
55985370
5599 while (true) {5371 const seg = self.segments.items[segment_index];
5600 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });
5601 const sym = atom.getSymbol(self);
5602 const base_offset = sym.n_value - seg.inner.vmaddr;
56035372
5604 for (atom.rebases.items) |offset| {5373 while (true) {
5605 log.debug(" | rebase at {x}", .{base_offset + offset});5374 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });
5606 try rebase_pointers.append(.{5375 const sym = atom.getSymbol(self);
5607 .offset = base_offset + offset,5376 const base_offset = sym.n_value - seg.vmaddr;
5608 .segment_id = match.seg,
5609 });
5610 }
56115377
5612 for (atom.bindings.items) |binding| {5378 for (atom.rebases.items) |offset| {
5613 const bind_sym = self.getSymbol(binding.target);5379 log.debug(" | rebase at {x}", .{base_offset + offset});
5614 const bind_sym_name = self.getSymbolName(binding.target);5380 try rebase_pointers.append(.{
5615 const dylib_ordinal = @divTrunc(5381 .offset = base_offset + offset,
5616 @bitCast(i16, bind_sym.n_desc),5382 .segment_id = segment_index,
5617 macho.N_SYMBOL_RESOLVER,5383 });
5618 );5384 }
5619 var flags: u4 = 0;
5620 log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
5621 binding.offset + base_offset,
5622 bind_sym_name,
5623 dylib_ordinal,
5624 });
5625 if (bind_sym.weakRef()) {
5626 log.debug(" | marking as weak ref ", .{});
5627 flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);
5628 }
5629 try bind_pointers.append(.{
5630 .offset = binding.offset + base_offset,
5631 .segment_id = match.seg,
5632 .dylib_ordinal = dylib_ordinal,
5633 .name = bind_sym_name,
5634 .bind_flags = flags,
5635 });
5636 }
56375385
5638 for (atom.lazy_bindings.items) |binding| {5386 for (atom.bindings.items) |binding| {
5639 const bind_sym = self.getSymbol(binding.target);5387 const bind_sym = self.getSymbol(binding.target);
5640 const bind_sym_name = self.getSymbolName(binding.target);5388 const bind_sym_name = self.getSymbolName(binding.target);
5641 const dylib_ordinal = @divTrunc(5389 const dylib_ordinal = @divTrunc(
5642 @bitCast(i16, bind_sym.n_desc),5390 @bitCast(i16, bind_sym.n_desc),
5643 macho.N_SYMBOL_RESOLVER,5391 macho.N_SYMBOL_RESOLVER,
5644 );5392 );
5645 var flags: u4 = 0;5393 var flags: u4 = 0;
5646 log.debug(" | lazy bind at {x} import('{s}') ord({d})", .{5394 log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
5647 binding.offset + base_offset,5395 binding.offset + base_offset,
5648 bind_sym_name,5396 bind_sym_name,
5649 dylib_ordinal,5397 dylib_ordinal,
5650 });5398 });
5651 if (bind_sym.weakRef()) {5399 if (bind_sym.weakRef()) {
5652 log.debug(" | marking as weak ref ", .{});5400 log.debug(" | marking as weak ref ", .{});
5653 flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);5401 flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);
5654 }
5655 try lazy_bind_pointers.append(.{
5656 .offset = binding.offset + base_offset,
5657 .segment_id = match.seg,
5658 .dylib_ordinal = dylib_ordinal,
5659 .name = bind_sym_name,
5660 .bind_flags = flags,
5661 });
5662 }5402 }
5403 try bind_pointers.append(.{
5404 .offset = binding.offset + base_offset,
5405 .segment_id = segment_index,
5406 .dylib_ordinal = dylib_ordinal,
5407 .name = bind_sym_name,
5408 .bind_flags = flags,
5409 });
5410 }
56635411
5664 if (atom.prev) |prev| {5412 for (atom.lazy_bindings.items) |binding| {
5665 atom = prev;5413 const bind_sym = self.getSymbol(binding.target);
5666 } else break;5414 const bind_sym_name = self.getSymbolName(binding.target);
5415 const dylib_ordinal = @divTrunc(
5416 @bitCast(i16, bind_sym.n_desc),
5417 macho.N_SYMBOL_RESOLVER,
5418 );
5419 var flags: u4 = 0;
5420 log.debug(" | lazy bind at {x} import('{s}') ord({d})", .{
5421 binding.offset + base_offset,
5422 bind_sym_name,
5423 dylib_ordinal,
5424 });
5425 if (bind_sym.weakRef()) {
5426 log.debug(" | marking as weak ref ", .{});
5427 flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT);
5428 }
5429 try lazy_bind_pointers.append(.{
5430 .offset = binding.offset + base_offset,
5431 .segment_id = segment_index,
5432 .dylib_ordinal = dylib_ordinal,
5433 .name = bind_sym_name,
5434 .bind_flags = flags,
5435 });
5667 }5436 }
5437
5438 if (atom.prev) |prev| {
5439 atom = prev;
5440 } else break;
5668 }5441 }
5669 }5442 }
56705443
...@@ -5675,8 +5448,8 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5675,8 +5448,8 @@ fn writeDyldInfoData(self: *MachO) !void {
5675 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.5448 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
5676 log.debug("generating export trie", .{});5449 log.debug("generating export trie", .{});
56775450
5678 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;5451 const text_segment = self.segments.items[self.text_segment_cmd_index.?];
5679 const base_address = text_segment.inner.vmaddr;5452 const base_address = text_segment.vmaddr;
56805453
5681 if (self.base.options.output_mode == .Exe) {5454 if (self.base.options.output_mode == .Exe) {
5682 for (&[_]SymbolWithLoc{5455 for (&[_]SymbolWithLoc{
...@@ -5714,48 +5487,27 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5714,48 +5487,27 @@ fn writeDyldInfoData(self: *MachO) !void {
5714 try trie.finalize(gpa);5487 try trie.finalize(gpa);
5715 }5488 }
57165489
5717 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;5490 const link_seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
5718 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].dyld_info_only;5491 const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64));
57195492 assert(rebase_off == link_seg.fileoff);
5720 const rebase_off = mem.alignForwardGeneric(u64, seg.inner.fileoff, @alignOf(u64));
5721 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);5493 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
5722 dyld_info.rebase_off = @intCast(u32, rebase_off);5494 log.debug("writing rebase info from 0x{x} to 0x{x}", .{ rebase_off, rebase_off + rebase_size });
5723 dyld_info.rebase_size = @intCast(u32, rebase_size);
5724 log.debug("writing rebase info from 0x{x} to 0x{x}", .{
5725 dyld_info.rebase_off,
5726 dyld_info.rebase_off + dyld_info.rebase_size,
5727 });
57285495
5729 const bind_off = mem.alignForwardGeneric(u64, dyld_info.rebase_off + dyld_info.rebase_size, @alignOf(u64));5496 const bind_off = mem.alignForwardGeneric(u64, rebase_off + rebase_size, @alignOf(u64));
5730 const bind_size = try bind.bindInfoSize(bind_pointers.items);5497 const bind_size = try bind.bindInfoSize(bind_pointers.items);
5731 dyld_info.bind_off = @intCast(u32, bind_off);5498 log.debug("writing bind info from 0x{x} to 0x{x}", .{ bind_off, bind_off + bind_size });
5732 dyld_info.bind_size = @intCast(u32, bind_size);
5733 log.debug("writing bind info from 0x{x} to 0x{x}", .{
5734 dyld_info.bind_off,
5735 dyld_info.bind_off + dyld_info.bind_size,
5736 });
57375499
5738 const lazy_bind_off = mem.alignForwardGeneric(u64, dyld_info.bind_off + dyld_info.bind_size, @alignOf(u64));5500 const lazy_bind_off = mem.alignForwardGeneric(u64, bind_off + bind_size, @alignOf(u64));
5739 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);5501 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
5740 dyld_info.lazy_bind_off = @intCast(u32, lazy_bind_off);5502 log.debug("writing lazy bind info from 0x{x} to 0x{x}", .{ lazy_bind_off, lazy_bind_off + lazy_bind_size });
5741 dyld_info.lazy_bind_size = @intCast(u32, lazy_bind_size);
5742 log.debug("writing lazy bind info from 0x{x} to 0x{x}", .{
5743 dyld_info.lazy_bind_off,
5744 dyld_info.lazy_bind_off + dyld_info.lazy_bind_size,
5745 });
57465503
5747 const export_off = mem.alignForwardGeneric(u64, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size, @alignOf(u64));5504 const export_off = mem.alignForwardGeneric(u64, lazy_bind_off + lazy_bind_size, @alignOf(u64));
5748 const export_size = trie.size;5505 const export_size = trie.size;
5749 dyld_info.export_off = @intCast(u32, export_off);5506 log.debug("writing export trie from 0x{x} to 0x{x}", .{ export_off, export_off + export_size });
5750 dyld_info.export_size = @intCast(u32, export_size);
5751 log.debug("writing export trie from 0x{x} to 0x{x}", .{
5752 dyld_info.export_off,
5753 dyld_info.export_off + dyld_info.export_size,
5754 });
57555507
5756 seg.inner.filesize = dyld_info.export_off + dyld_info.export_size - seg.inner.fileoff;5508 const needed_size = export_off + export_size - rebase_off;
5509 link_seg.filesize = needed_size;
57575510
5758 const needed_size = dyld_info.export_off + dyld_info.export_size - dyld_info.rebase_off;
5759 var buffer = try gpa.alloc(u8, needed_size);5511 var buffer = try gpa.alloc(u8, needed_size);
5760 defer gpa.free(buffer);5512 defer gpa.free(buffer);
5761 mem.set(u8, buffer, 0);5513 mem.set(u8, buffer, 0);
...@@ -5763,54 +5515,61 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5763,54 +5515,61 @@ fn writeDyldInfoData(self: *MachO) !void {
5763 var stream = std.io.fixedBufferStream(buffer);5515 var stream = std.io.fixedBufferStream(buffer);
5764 const writer = stream.writer();5516 const writer = stream.writer();
57655517
5766 const base_off = dyld_info.rebase_off;
5767 try bind.writeRebaseInfo(rebase_pointers.items, writer);5518 try bind.writeRebaseInfo(rebase_pointers.items, writer);
5768 try stream.seekTo(dyld_info.bind_off - base_off);5519 try stream.seekTo(bind_off - rebase_off);
57695520
5770 try bind.writeBindInfo(bind_pointers.items, writer);5521 try bind.writeBindInfo(bind_pointers.items, writer);
5771 try stream.seekTo(dyld_info.lazy_bind_off - base_off);5522 try stream.seekTo(lazy_bind_off - rebase_off);
57725523
5773 try bind.writeLazyBindInfo(lazy_bind_pointers.items, writer);5524 try bind.writeLazyBindInfo(lazy_bind_pointers.items, writer);
5774 try stream.seekTo(dyld_info.export_off - base_off);5525 try stream.seekTo(export_off - rebase_off);
57755526
5776 _ = try trie.write(writer);5527 _ = try trie.write(writer);
57775528
5778 log.debug("writing dyld info from 0x{x} to 0x{x}", .{5529 log.debug("writing dyld info from 0x{x} to 0x{x}", .{
5779 dyld_info.rebase_off,5530 rebase_off,
5780 dyld_info.rebase_off + needed_size,5531 rebase_off + needed_size,
5781 });5532 });
57825533
5783 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);5534 try self.base.file.?.pwriteAll(buffer, rebase_off);
5784 try self.populateLazyBindOffsetsInStubHelper(5535 try self.populateLazyBindOffsetsInStubHelper(buffer[lazy_bind_off - rebase_off ..][0..lazy_bind_size]);
5785 buffer[dyld_info.lazy_bind_off - base_off ..][0..dyld_info.lazy_bind_size],5536
5786 );5537 try lc_writer.writeStruct(macho.dyld_info_command{
57875538 .cmd = .DYLD_INFO_ONLY,
5788 self.load_commands_dirty = true;5539 .cmdsize = @sizeOf(macho.dyld_info_command),
5540 .rebase_off = @intCast(u32, rebase_off),
5541 .rebase_size = @intCast(u32, rebase_size),
5542 .bind_off = @intCast(u32, bind_off),
5543 .bind_size = @intCast(u32, bind_size),
5544 .weak_bind_off = 0,
5545 .weak_bind_size = 0,
5546 .lazy_bind_off = @intCast(u32, lazy_bind_off),
5547 .lazy_bind_size = @intCast(u32, lazy_bind_size),
5548 .export_off = @intCast(u32, export_off),
5549 .export_size = @intCast(u32, export_size),
5550 });
5551 ncmds.* += 1;
5789}5552}
57905553
5791fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {5554fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
5792 const gpa = self.base.allocator;5555 const gpa = self.base.allocator;
5793 const text_segment_cmd_index = self.text_segment_cmd_index orelse return;5556
5794 const stub_helper_section_index = self.stub_helper_section_index orelse return;5557 const stub_helper_section_index = self.stub_helper_section_index orelse return;
5795 const last_atom = self.atoms.get(.{
5796 .seg = text_segment_cmd_index,
5797 .sect = stub_helper_section_index,
5798 }) orelse return;
5799 if (self.stub_helper_preamble_atom == null) return;5558 if (self.stub_helper_preamble_atom == null) return;
5800 if (last_atom == self.stub_helper_preamble_atom.?) return;5559
5560 const section = self.sections.get(stub_helper_section_index);
5561 const last_atom = section.last_atom orelse return;
5562 if (last_atom == self.stub_helper_preamble_atom.?) return; // TODO is this a redundant check?
58015563
5802 var table = std.AutoHashMap(i64, *Atom).init(gpa);5564 var table = std.AutoHashMap(i64, *Atom).init(gpa);
5803 defer table.deinit();5565 defer table.deinit();
58045566
5805 {5567 {
5806 var stub_atom = last_atom;5568 var stub_atom = last_atom;
5807 var laptr_atom = self.atoms.get(.{5569 var laptr_atom = self.sections.items(.last_atom)[self.la_symbol_ptr_section_index.?].?;
5808 .seg = self.data_segment_cmd_index.?,
5809 .sect = self.la_symbol_ptr_section_index.?,
5810 }).?;
5811 const base_addr = blk: {5570 const base_addr = blk: {
5812 const seg = self.load_commands.items[self.data_segment_cmd_index.?].segment;5571 const seg = self.segments.items[self.data_segment_cmd_index.?];
5813 break :blk seg.inner.vmaddr;5572 break :blk seg.vmaddr;
5814 };5573 };
58155574
5816 while (true) {5575 while (true) {
...@@ -5871,10 +5630,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -5871,10 +5630,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
5871 }5630 }
5872 }5631 }
58735632
5874 const sect = self.getSection(.{5633 const header = self.sections.items(.header)[stub_helper_section_index];
5875 .seg = text_segment_cmd_index,
5876 .sect = stub_helper_section_index,
5877 });
5878 const stub_offset: u4 = switch (self.base.options.target.cpu.arch) {5634 const stub_offset: u4 = switch (self.base.options.target.cpu.arch) {
5879 .x86_64 => 1,5635 .x86_64 => 1,
5880 .aarch64 => 2 * @sizeOf(u32),5636 .aarch64 => 2 * @sizeOf(u32),
...@@ -5886,7 +5642,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -5886,7 +5642,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
5886 while (offsets.popOrNull()) |bind_offset| {5642 while (offsets.popOrNull()) |bind_offset| {
5887 const atom = table.get(bind_offset.sym_offset).?;5643 const atom = table.get(bind_offset.sym_offset).?;
5888 const sym = atom.getSymbol(self);5644 const sym = atom.getSymbol(self);
5889 const file_offset = sect.offset + sym.n_value - sect.addr + stub_offset;5645 const file_offset = header.offset + sym.n_value - header.addr + stub_offset;
5890 mem.writeIntLittle(u32, &buf, bind_offset.offset);5646 mem.writeIntLittle(u32, &buf, bind_offset.offset);
5891 log.debug("writing lazy bind offset in stub helper of 0x{x} for symbol {s} at offset 0x{x}", .{5647 log.debug("writing lazy bind offset in stub helper of 0x{x} for symbol {s} at offset 0x{x}", .{
5892 bind_offset.offset,5648 bind_offset.offset,
...@@ -5899,14 +5655,14 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -5899,14 +5655,14 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
58995655
5900const asc_u64 = std.sort.asc(u64);5656const asc_u64 = std.sort.asc(u64);
59015657
5902fn writeFunctionStarts(self: *MachO) !void {5658fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5903 const text_seg_index = self.text_segment_cmd_index orelse return;
5904 const text_sect_index = self.text_section_index orelse return;
5905 const text_seg = self.load_commands.items[text_seg_index].segment;
5906
5907 const tracy = trace(@src());5659 const tracy = trace(@src());
5908 defer tracy.end();5660 defer tracy.end();
59095661
5662 const text_seg_index = self.text_segment_cmd_index orelse return;
5663 const text_sect_index = self.text_section_index orelse return;
5664 const text_seg = self.segments.items[text_seg_index];
5665
5910 const gpa = self.base.allocator;5666 const gpa = self.base.allocator;
59115667
5912 // We need to sort by address first5668 // We need to sort by address first
...@@ -5918,8 +5674,8 @@ fn writeFunctionStarts(self: *MachO) !void {...@@ -5918,8 +5674,8 @@ fn writeFunctionStarts(self: *MachO) !void {
5918 const sym = self.getSymbol(global);5674 const sym = self.getSymbol(global);
5919 if (sym.undf()) continue;5675 if (sym.undf()) continue;
5920 if (sym.n_desc == N_DESC_GCED) continue;5676 if (sym.n_desc == N_DESC_GCED) continue;
5921 const match = self.getMatchingSectionFromOrdinal(sym.n_sect);5677 const sect_id = sym.n_sect - 1;
5922 if (match.seg != text_seg_index or match.sect != text_sect_index) continue;5678 if (sect_id != text_sect_index) continue;
59235679
5924 addresses.appendAssumeCapacity(sym.n_value);5680 addresses.appendAssumeCapacity(sym.n_value);
5925 }5681 }
...@@ -5932,7 +5688,7 @@ fn writeFunctionStarts(self: *MachO) !void {...@@ -5932,7 +5688,7 @@ fn writeFunctionStarts(self: *MachO) !void {
59325688
5933 var last_off: u32 = 0;5689 var last_off: u32 = 0;
5934 for (addresses.items) |addr| {5690 for (addresses.items) |addr| {
5935 const offset = @intCast(u32, addr - text_seg.inner.vmaddr);5691 const offset = @intCast(u32, addr - text_seg.vmaddr);
5936 const diff = offset - last_off;5692 const diff = offset - last_off;
59375693
5938 if (diff == 0) continue;5694 if (diff == 0) continue;
...@@ -5951,22 +5707,22 @@ fn writeFunctionStarts(self: *MachO) !void {...@@ -5951,22 +5707,22 @@ fn writeFunctionStarts(self: *MachO) !void {
5951 try std.leb.writeULEB128(buffer.writer(), offset);5707 try std.leb.writeULEB128(buffer.writer(), offset);
5952 }5708 }
59535709
5954 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;5710 const link_seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
5955 const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].linkedit_data;5711 const offset = mem.alignForwardGeneric(u64, link_seg.fileoff + link_seg.filesize, @alignOf(u64));
5712 const needed_size = buffer.items.len;
5713 link_seg.filesize = offset + needed_size - link_seg.fileoff;
59565714
5957 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));5715 log.debug("writing function starts info from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
5958 const datasize = buffer.items.len;
5959 fn_cmd.dataoff = @intCast(u32, dataoff);
5960 fn_cmd.datasize = @intCast(u32, datasize);
5961 seg.inner.filesize = fn_cmd.dataoff + fn_cmd.datasize - seg.inner.fileoff;
59625716
5963 log.debug("writing function starts info from 0x{x} to 0x{x}", .{5717 try self.base.file.?.pwriteAll(buffer.items, offset);
5964 fn_cmd.dataoff,
5965 fn_cmd.dataoff + fn_cmd.datasize,
5966 });
59675718
5968 try self.base.file.?.pwriteAll(buffer.items, fn_cmd.dataoff);5719 try lc_writer.writeStruct(macho.linkedit_data_command{
5969 self.load_commands_dirty = true;5720 .cmd = .FUNCTION_STARTS,
5721 .cmdsize = @sizeOf(macho.linkedit_data_command),
5722 .dataoff = @intCast(u32, offset),
5723 .datasize = @intCast(u32, needed_size),
5724 });
5725 ncmds.* += 1;
5970}5726}
59715727
5972fn filterDataInCode(5728fn filterDataInCode(
...@@ -5988,17 +5744,15 @@ fn filterDataInCode(...@@ -5988,17 +5744,15 @@ fn filterDataInCode(
5988 return dices[start..end];5744 return dices[start..end];
5989}5745}
59905746
5991fn writeDataInCode(self: *MachO) !void {5747fn writeDataInCode(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5992 const tracy = trace(@src());5748 const tracy = trace(@src());
5993 defer tracy.end();5749 defer tracy.end();
59945750
5995 var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.base.allocator);5751 var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.base.allocator);
5996 defer out_dice.deinit();5752 defer out_dice.deinit();
59975753
5998 const text_sect = self.getSection(.{5754 const text_sect_id = self.text_section_index orelse return;
5999 .seg = self.text_segment_cmd_index orelse return,5755 const text_sect_header = self.sections.items(.header)[text_sect_id];
6000 .sect = self.text_section_index orelse return,
6001 });
60025756
6003 for (self.objects.items) |object| {5757 for (self.objects.items) |object| {
6004 const dice = object.parseDataInCode() orelse continue;5758 const dice = object.parseDataInCode() orelse continue;
...@@ -6008,15 +5762,15 @@ fn writeDataInCode(self: *MachO) !void {...@@ -6008,15 +5762,15 @@ fn writeDataInCode(self: *MachO) !void {
6008 const sym = atom.getSymbol(self);5762 const sym = atom.getSymbol(self);
6009 if (sym.n_desc == N_DESC_GCED) continue;5763 if (sym.n_desc == N_DESC_GCED) continue;
60105764
6011 const match = self.getMatchingSectionFromOrdinal(sym.n_sect);5765 const sect_id = sym.n_sect - 1;
6012 if (match.seg != self.text_segment_cmd_index.? and match.sect != self.text_section_index.?) {5766 if (sect_id != self.text_section_index.?) {
6013 continue;5767 continue;
6014 }5768 }
60155769
6016 const source_sym = object.getSourceSymbol(atom.sym_index) orelse continue;5770 const source_sym = object.getSourceSymbol(atom.sym_index) orelse continue;
6017 const source_addr = math.cast(u32, source_sym.n_value) orelse return error.Overflow;5771 const source_addr = math.cast(u32, source_sym.n_value) orelse return error.Overflow;
6018 const filtered_dice = filterDataInCode(dice, source_addr, source_addr + atom.size);5772 const filtered_dice = filterDataInCode(dice, source_addr, source_addr + atom.size);
6019 const base = math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset) orelse5773 const base = math.cast(u32, sym.n_value - text_sect_header.addr + text_sect_header.offset) orelse
6020 return error.Overflow;5774 return error.Overflow;
60215775
6022 for (filtered_dice) |single| {5776 for (filtered_dice) |single| {
...@@ -6030,33 +5784,63 @@ fn writeDataInCode(self: *MachO) !void {...@@ -6030,33 +5784,63 @@ fn writeDataInCode(self: *MachO) !void {
6030 }5784 }
6031 }5785 }
60325786
6033 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;5787 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
6034 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data;5788 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
5789 const needed_size = out_dice.items.len * @sizeOf(macho.data_in_code_entry);
5790 seg.filesize = offset + needed_size - seg.fileoff;
60355791
6036 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));5792 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
6037 const datasize = out_dice.items.len * @sizeOf(macho.data_in_code_entry);
6038 dice_cmd.dataoff = @intCast(u32, dataoff);
6039 dice_cmd.datasize = @intCast(u32, datasize);
6040 seg.inner.filesize = dice_cmd.dataoff + dice_cmd.datasize - seg.inner.fileoff;
60415793
6042 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{5794 try self.base.file.?.pwriteAll(mem.sliceAsBytes(out_dice.items), offset);
6043 dice_cmd.dataoff,5795 try lc_writer.writeStruct(macho.linkedit_data_command{
6044 dice_cmd.dataoff + dice_cmd.datasize,5796 .cmd = .DATA_IN_CODE,
5797 .cmdsize = @sizeOf(macho.linkedit_data_command),
5798 .dataoff = @intCast(u32, offset),
5799 .datasize = @intCast(u32, needed_size),
6045 });5800 });
60465801 ncmds.* += 1;
6047 try self.base.file.?.pwriteAll(mem.sliceAsBytes(out_dice.items), dice_cmd.dataoff);
6048 self.load_commands_dirty = true;
6049}5802}
60505803
6051fn writeSymtab(self: *MachO) !void {5804fn writeSymtabs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
6052 const tracy = trace(@src());5805 var symtab_cmd = macho.symtab_command{
6053 defer tracy.end();5806 .cmdsize = @sizeOf(macho.symtab_command),
5807 .symoff = 0,
5808 .nsyms = 0,
5809 .stroff = 0,
5810 .strsize = 0,
5811 };
5812 var dysymtab_cmd = macho.dysymtab_command{
5813 .cmdsize = @sizeOf(macho.dysymtab_command),
5814 .ilocalsym = 0,
5815 .nlocalsym = 0,
5816 .iextdefsym = 0,
5817 .nextdefsym = 0,
5818 .iundefsym = 0,
5819 .nundefsym = 0,
5820 .tocoff = 0,
5821 .ntoc = 0,
5822 .modtaboff = 0,
5823 .nmodtab = 0,
5824 .extrefsymoff = 0,
5825 .nextrefsyms = 0,
5826 .indirectsymoff = 0,
5827 .nindirectsyms = 0,
5828 .extreloff = 0,
5829 .nextrel = 0,
5830 .locreloff = 0,
5831 .nlocrel = 0,
5832 };
5833 var ctx = try self.writeSymtab(&symtab_cmd);
5834 defer ctx.imports_table.deinit();
5835 try self.writeDysymtab(ctx, &dysymtab_cmd);
5836 try self.writeStrtab(&symtab_cmd);
5837 try lc_writer.writeStruct(symtab_cmd);
5838 try lc_writer.writeStruct(dysymtab_cmd);
5839 ncmds.* += 2;
5840}
60545841
5842fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
6055 const gpa = self.base.allocator;5843 const gpa = self.base.allocator;
6056 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6057 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
6058 const symoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(macho.nlist_64));
6059 symtab.symoff = @intCast(u32, symoff);
60605844
6061 var locals = std.ArrayList(macho.nlist_64).init(gpa);5845 var locals = std.ArrayList(macho.nlist_64).init(gpa);
6062 defer locals.deinit();5846 defer locals.deinit();
...@@ -6101,8 +5885,8 @@ fn writeSymtab(self: *MachO) !void {...@@ -6101,8 +5885,8 @@ fn writeSymtab(self: *MachO) !void {
61015885
6102 var imports = std.ArrayList(macho.nlist_64).init(gpa);5886 var imports = std.ArrayList(macho.nlist_64).init(gpa);
6103 defer imports.deinit();5887 defer imports.deinit();
5888
6104 var imports_table = std.AutoHashMap(SymbolWithLoc, u32).init(gpa);5889 var imports_table = std.AutoHashMap(SymbolWithLoc, u32).init(gpa);
6105 defer imports_table.deinit();
61065890
6107 for (self.globals.values()) |global| {5891 for (self.globals.values()) |global| {
6108 const sym = self.getSymbol(global);5892 const sym = self.getSymbol(global);
...@@ -6115,56 +5899,84 @@ fn writeSymtab(self: *MachO) !void {...@@ -6115,56 +5899,84 @@ fn writeSymtab(self: *MachO) !void {
6115 try imports_table.putNoClobber(global, new_index);5899 try imports_table.putNoClobber(global, new_index);
6116 }5900 }
61175901
6118 const nlocals = locals.items.len;5902 const nlocals = @intCast(u32, locals.items.len);
6119 const nexports = exports.items.len;5903 const nexports = @intCast(u32, exports.items.len);
6120 const nimports = imports.items.len;5904 const nimports = @intCast(u32, imports.items.len);
6121 symtab.nsyms = @intCast(u32, nlocals + nexports + nimports);5905 const nsyms = nlocals + nexports + nimports;
5906
5907 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
5908 const offset = mem.alignForwardGeneric(
5909 u64,
5910 seg.fileoff + seg.filesize,
5911 @alignOf(macho.nlist_64),
5912 );
5913 const needed_size = nsyms * @sizeOf(macho.nlist_64);
5914 seg.filesize = offset + needed_size - seg.fileoff;
61225915
6123 var buffer = std.ArrayList(u8).init(gpa);5916 var buffer = std.ArrayList(u8).init(gpa);
6124 defer buffer.deinit();5917 defer buffer.deinit();
6125 try buffer.ensureTotalCapacityPrecise(symtab.nsyms * @sizeOf(macho.nlist_64));5918 try buffer.ensureTotalCapacityPrecise(needed_size);
6126 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(locals.items));5919 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(locals.items));
6127 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(exports.items));5920 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(exports.items));
6128 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(imports.items));5921 buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(imports.items));
61295922
6130 log.debug("writing symtab from 0x{x} to 0x{x}", .{ symtab.symoff, symtab.symoff + buffer.items.len });5923 log.debug("writing symtab from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
6131 try self.base.file.?.pwriteAll(buffer.items, symtab.symoff);5924 try self.base.file.?.pwriteAll(buffer.items, offset);
5925
5926 lc.symoff = @intCast(u32, offset);
5927 lc.nsyms = nsyms;
61325928
6133 seg.inner.filesize = symtab.symoff + buffer.items.len - seg.inner.fileoff;5929 return SymtabCtx{
5930 .nlocalsym = nlocals,
5931 .nextdefsym = nexports,
5932 .nundefsym = nimports,
5933 .imports_table = imports_table,
5934 };
5935}
61345936
6135 // Update dynamic symbol table.5937fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {
6136 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].dysymtab;5938 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
6137 dysymtab.nlocalsym = @intCast(u32, nlocals);5939 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
6138 dysymtab.iextdefsym = dysymtab.nlocalsym;5940 const needed_size = self.strtab.buffer.items.len;
6139 dysymtab.nextdefsym = @intCast(u32, nexports);5941 seg.filesize = offset + needed_size - seg.fileoff;
6140 dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;
6141 dysymtab.nundefsym = @intCast(u32, nimports);
61425942
5943 log.debug("writing string table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
5944
5945 try self.base.file.?.pwriteAll(self.strtab.buffer.items, offset);
5946
5947 lc.stroff = @intCast(u32, offset);
5948 lc.strsize = @intCast(u32, needed_size);
5949}
5950
5951const SymtabCtx = struct {
5952 nlocalsym: u32,
5953 nextdefsym: u32,
5954 nundefsym: u32,
5955 imports_table: std.AutoHashMap(SymbolWithLoc, u32),
5956};
5957
5958fn writeDysymtab(self: *MachO, ctx: SymtabCtx, lc: *macho.dysymtab_command) !void {
5959 const gpa = self.base.allocator;
6143 const nstubs = @intCast(u32, self.stubs_table.count());5960 const nstubs = @intCast(u32, self.stubs_table.count());
6144 const ngot_entries = @intCast(u32, self.got_entries_table.count());5961 const ngot_entries = @intCast(u32, self.got_entries_table.count());
5962 const nindirectsyms = nstubs * 2 + ngot_entries;
5963 const iextdefsym = ctx.nlocalsym;
5964 const iundefsym = iextdefsym + ctx.nextdefsym;
61455965
6146 const indirectsymoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));5966 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
6147 dysymtab.indirectsymoff = @intCast(u32, indirectsymoff);5967 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
6148 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;5968 const needed_size = nindirectsyms * @sizeOf(u32);
5969 seg.filesize = offset + needed_size - seg.fileoff;
61495970
6150 seg.inner.filesize = dysymtab.indirectsymoff + dysymtab.nindirectsyms * @sizeOf(u32) - seg.inner.fileoff;5971 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
6151
6152 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{
6153 dysymtab.indirectsymoff,
6154 dysymtab.indirectsymoff + dysymtab.nindirectsyms * @sizeOf(u32),
6155 });
61565972
6157 var buf = std.ArrayList(u8).init(gpa);5973 var buf = std.ArrayList(u8).init(gpa);
6158 defer buf.deinit();5974 defer buf.deinit();
6159 try buf.ensureTotalCapacity(dysymtab.nindirectsyms * @sizeOf(u32));5975 try buf.ensureTotalCapacity(needed_size);
6160 const writer = buf.writer();5976 const writer = buf.writer();
61615977
6162 if (self.text_segment_cmd_index) |text_segment_cmd_index| blk: {5978 if (self.stubs_section_index) |sect_id| {
6163 const stubs_section_index = self.stubs_section_index orelse break :blk;5979 const stubs = &self.sections.items(.header)[sect_id];
6164 const stubs = self.getSectionPtr(.{
6165 .seg = text_segment_cmd_index,
6166 .sect = stubs_section_index,
6167 });
6168 stubs.reserved1 = 0;5980 stubs.reserved1 = 0;
6169 for (self.stubs.items) |entry| {5981 for (self.stubs.items) |entry| {
6170 if (entry.sym_index == 0) continue;5982 if (entry.sym_index == 0) continue;
...@@ -6172,16 +5984,12 @@ fn writeSymtab(self: *MachO) !void {...@@ -6172,16 +5984,12 @@ fn writeSymtab(self: *MachO) !void {
6172 if (atom_sym.n_desc == N_DESC_GCED) continue;5984 if (atom_sym.n_desc == N_DESC_GCED) continue;
6173 const target_sym = self.getSymbol(entry.target);5985 const target_sym = self.getSymbol(entry.target);
6174 assert(target_sym.undf());5986 assert(target_sym.undf());
6175 try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(entry.target).?);5987 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);
6176 }5988 }
6177 }5989 }
61785990
6179 if (self.data_const_segment_cmd_index) |data_const_segment_cmd_index| blk: {5991 if (self.got_section_index) |sect_id| {
6180 const got_section_index = self.got_section_index orelse break :blk;5992 const got = &self.sections.items(.header)[sect_id];
6181 const got = self.getSectionPtr(.{
6182 .seg = data_const_segment_cmd_index,
6183 .sect = got_section_index,
6184 });
6185 got.reserved1 = nstubs;5993 got.reserved1 = nstubs;
6186 for (self.got_entries.items) |entry| {5994 for (self.got_entries.items) |entry| {
6187 if (entry.sym_index == 0) continue;5995 if (entry.sym_index == 0) continue;
...@@ -6189,19 +5997,15 @@ fn writeSymtab(self: *MachO) !void {...@@ -6189,19 +5997,15 @@ fn writeSymtab(self: *MachO) !void {
6189 if (atom_sym.n_desc == N_DESC_GCED) continue;5997 if (atom_sym.n_desc == N_DESC_GCED) continue;
6190 const target_sym = self.getSymbol(entry.target);5998 const target_sym = self.getSymbol(entry.target);
6191 if (target_sym.undf()) {5999 if (target_sym.undf()) {
6192 try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(entry.target).?);6000 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);
6193 } else {6001 } else {
6194 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);6002 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
6195 }6003 }
6196 }6004 }
6197 }6005 }
61986006
6199 if (self.data_segment_cmd_index) |data_segment_cmd_index| blk: {6007 if (self.la_symbol_ptr_section_index) |sect_id| {
6200 const la_symbol_ptr_section_index = self.la_symbol_ptr_section_index orelse break :blk;6008 const la_symbol_ptr = &self.sections.items(.header)[sect_id];
6201 const la_symbol_ptr = self.getSectionPtr(.{
6202 .seg = data_segment_cmd_index,
6203 .sect = la_symbol_ptr_section_index,
6204 });
6205 la_symbol_ptr.reserved1 = nstubs + ngot_entries;6009 la_symbol_ptr.reserved1 = nstubs + ngot_entries;
6206 for (self.stubs.items) |entry| {6010 for (self.stubs.items) |entry| {
6207 if (entry.sym_index == 0) continue;6011 if (entry.sym_index == 0) continue;
...@@ -6209,131 +6013,76 @@ fn writeSymtab(self: *MachO) !void {...@@ -6209,131 +6013,76 @@ fn writeSymtab(self: *MachO) !void {
6209 if (atom_sym.n_desc == N_DESC_GCED) continue;6013 if (atom_sym.n_desc == N_DESC_GCED) continue;
6210 const target_sym = self.getSymbol(entry.target);6014 const target_sym = self.getSymbol(entry.target);
6211 assert(target_sym.undf());6015 assert(target_sym.undf());
6212 try writer.writeIntLittle(u32, dysymtab.iundefsym + imports_table.get(entry.target).?);6016 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);
6213 }6017 }
6214 }6018 }
62156019
6216 assert(buf.items.len == dysymtab.nindirectsyms * @sizeOf(u32));6020 assert(buf.items.len == needed_size);
62176021 try self.base.file.?.pwriteAll(buf.items, offset);
6218 try self.base.file.?.pwriteAll(buf.items, dysymtab.indirectsymoff);
6219 self.load_commands_dirty = true;
6220}
6221
6222fn writeStrtab(self: *MachO) !void {
6223 const tracy = trace(@src());
6224 defer tracy.end();
6225
6226 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6227 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
6228 const stroff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
6229
6230 const strsize = self.strtab.buffer.items.len;
6231 symtab.stroff = @intCast(u32, stroff);
6232 symtab.strsize = @intCast(u32, strsize);
6233 seg.inner.filesize = symtab.stroff + symtab.strsize - seg.inner.fileoff;
62346022
6235 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });6023 lc.nlocalsym = ctx.nlocalsym;
62366024 lc.iextdefsym = iextdefsym;
6237 try self.base.file.?.pwriteAll(self.strtab.buffer.items, symtab.stroff);6025 lc.nextdefsym = ctx.nextdefsym;
62386026 lc.iundefsym = iundefsym;
6239 self.load_commands_dirty = true;6027 lc.nundefsym = ctx.nundefsym;
6240}6028 lc.indirectsymoff = @intCast(u32, offset);
62416029 lc.nindirectsyms = nindirectsyms;
6242fn writeLinkeditSegment(self: *MachO) !void {
6243 const tracy = trace(@src());
6244 defer tracy.end();
6245
6246 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6247 seg.inner.filesize = 0;
6248
6249 try self.writeDyldInfoData();
6250 try self.writeFunctionStarts();
6251 try self.writeDataInCode();
6252 try self.writeSymtab();
6253 try self.writeStrtab();
6254
6255 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size);
6256}6030}
62576031
6258fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {6032fn writeCodeSignaturePadding(
6259 const tracy = trace(@src());6033 self: *MachO,
6260 defer tracy.end();6034 code_sig: *CodeSignature,
62616035 ncmds: *u32,
6262 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;6036 lc_writer: anytype,
6263 const cs_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;6037) !u32 {
6038 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
6264 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file6039 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
6265 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L2716040 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271
6266 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, 16);6041 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, 16);
6267 const datasize = code_sig.estimateSize(dataoff);6042 const needed_size = code_sig.estimateSize(offset);
6268 cs_cmd.dataoff = @intCast(u32, dataoff);6043 seg.filesize = offset + needed_size - seg.fileoff;
6269 cs_cmd.datasize = @intCast(u32, code_sig.estimateSize(dataoff));6044 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
62706045 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
6271 // Advance size of __LINKEDIT segment
6272 seg.inner.filesize = cs_cmd.dataoff + cs_cmd.datasize - seg.inner.fileoff;
6273 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size);
6274 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ dataoff, dataoff + datasize });
6275 // Pad out the space. We need to do this to calculate valid hashes for everything in the file6046 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
6276 // except for code signature data.6047 // except for code signature data.
6277 try self.base.file.?.pwriteAll(&[_]u8{0}, dataoff + datasize - 1);6048 try self.base.file.?.pwriteAll(&[_]u8{0}, offset + needed_size - 1);
6278 self.load_commands_dirty = true;
6279}
62806049
6281fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {6050 try lc_writer.writeStruct(macho.linkedit_data_command{
6282 const tracy = trace(@src());6051 .cmd = .CODE_SIGNATURE,
6283 defer tracy.end();6052 .cmdsize = @sizeOf(macho.linkedit_data_command),
6053 .dataoff = @intCast(u32, offset),
6054 .datasize = @intCast(u32, needed_size),
6055 });
6056 ncmds.* += 1;
6057
6058 return @intCast(u32, offset);
6059}
62846060
6285 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;6061fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature, offset: u32) !void {
6286 const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment;6062 const seg = self.segments.items[self.text_segment_cmd_index.?];
62876063
6288 var buffer = std.ArrayList(u8).init(self.base.allocator);6064 var buffer = std.ArrayList(u8).init(self.base.allocator);
6289 defer buffer.deinit();6065 defer buffer.deinit();
6290 try buffer.ensureTotalCapacityPrecise(code_sig.size());6066 try buffer.ensureTotalCapacityPrecise(code_sig.size());
6291 try code_sig.writeAdhocSignature(self.base.allocator, .{6067 try code_sig.writeAdhocSignature(self.base.allocator, .{
6292 .file = self.base.file.?,6068 .file = self.base.file.?,
6293 .exec_seg_base = seg.inner.fileoff,6069 .exec_seg_base = seg.fileoff,
6294 .exec_seg_limit = seg.inner.filesize,6070 .exec_seg_limit = seg.filesize,
6295 .code_sig_cmd = code_sig_cmd,6071 .file_size = offset,
6296 .output_mode = self.base.options.output_mode,6072 .output_mode = self.base.options.output_mode,
6297 }, buffer.writer());6073 }, buffer.writer());
6298 assert(buffer.items.len == code_sig.size());6074 assert(buffer.items.len == code_sig.size());
62996075
6300 log.debug("writing code signature from 0x{x} to 0x{x}", .{6076 log.debug("writing code signature from 0x{x} to 0x{x}", .{
6301 code_sig_cmd.dataoff,6077 offset,
6302 code_sig_cmd.dataoff + buffer.items.len,6078 offset + buffer.items.len,
6303 });6079 });
63046080
6305 try self.base.file.?.pwriteAll(buffer.items, code_sig_cmd.dataoff);6081 try self.base.file.?.pwriteAll(buffer.items, offset);
6306}
6307
6308/// Writes all load commands and section headers.
6309fn writeLoadCommands(self: *MachO) !void {
6310 if (!self.load_commands_dirty) return;
6311
6312 var sizeofcmds: u32 = 0;
6313 for (self.load_commands.items) |lc| {
6314 if (lc.cmd() == .NONE) continue;
6315 sizeofcmds += lc.cmdsize();
6316 }
6317
6318 var buffer = try self.base.allocator.alloc(u8, sizeofcmds);
6319 defer self.base.allocator.free(buffer);
6320 var fib = std.io.fixedBufferStream(buffer);
6321 const writer = fib.writer();
6322 for (self.load_commands.items) |lc| {
6323 if (lc.cmd() == .NONE) continue;
6324 try lc.write(writer);
6325 }
6326
6327 const off = @sizeOf(macho.mach_header_64);
6328
6329 log.debug("writing load commands from 0x{x} to 0x{x}", .{ off, off + sizeofcmds });
6330
6331 try self.base.file.?.pwriteAll(buffer, off);
6332 self.load_commands_dirty = false;
6333}6082}
63346083
6335/// Writes Mach-O file header.6084/// Writes Mach-O file header.
6336fn writeHeader(self: *MachO) !void {6085fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
6337 var header: macho.mach_header_64 = .{};6086 var header: macho.mach_header_64 = .{};
6338 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;6087 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
63396088
...@@ -6365,14 +6114,8 @@ fn writeHeader(self: *MachO) !void {...@@ -6365,14 +6114,8 @@ fn writeHeader(self: *MachO) !void {
6365 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;6114 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;
6366 }6115 }
63676116
6368 header.ncmds = 0;6117 header.ncmds = ncmds;
6369 header.sizeofcmds = 0;6118 header.sizeofcmds = sizeofcmds;
6370
6371 for (self.load_commands.items) |cmd| {
6372 if (cmd.cmd() == .NONE) continue;
6373 header.sizeofcmds += cmd.cmdsize();
6374 header.ncmds += 1;
6375 }
63766119
6377 log.debug("writing Mach-O header {}", .{header});6120 log.debug("writing Mach-O header {}", .{header});
63786121
...@@ -6392,33 +6135,13 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {...@@ -6392,33 +6135,13 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {
6392 return buf;6135 return buf;
6393}6136}
63946137
6395pub fn getSectionOrdinal(self: *MachO, match: MatchingSection) u8 {6138fn getSectionIndexes(self: MachO, segment_index: u8) struct { start: u8, end: u8 } {
6396 return @intCast(u8, self.section_ordinals.getIndex(match).?) + 1;6139 var start: u8 = 0;
6397}6140 const nsects = for (self.segments.items) |seg, i| {
63986141 if (i == segment_index) break @intCast(u8, seg.nsects);
6399pub fn getMatchingSectionFromOrdinal(self: *MachO, ord: u8) MatchingSection {6142 start += @intCast(u8, seg.nsects);
6400 const index = ord - 1;6143 } else 0;
6401 assert(index < self.section_ordinals.count());6144 return .{ .start = start, .end = start + nsects };
6402 return self.section_ordinals.keys()[index];
6403}
6404
6405pub fn getSegmentPtr(self: *MachO, match: MatchingSection) *macho.SegmentCommand {
6406 assert(match.seg < self.load_commands.items.len);
6407 return &self.load_commands.items[match.seg].segment;
6408}
6409
6410pub fn getSegment(self: *MachO, match: MatchingSection) macho.SegmentCommand {
6411 return self.getSegmentPtr(match).*;
6412}
6413
6414pub fn getSectionPtr(self: *MachO, match: MatchingSection) *macho.section_64 {
6415 const seg = self.getSegmentPtr(match);
6416 assert(match.sect < seg.sections.items.len);
6417 return &seg.sections.items[match.sect];
6418}
6419
6420pub fn getSection(self: *MachO, match: MatchingSection) macho.section_64 {
6421 return self.getSectionPtr(match).*;
6422}6145}
64236146
6424pub fn symbolIsTemp(self: *MachO, sym_with_loc: SymbolWithLoc) bool {6147pub fn symbolIsTemp(self: *MachO, sym_with_loc: SymbolWithLoc) bool {
...@@ -6512,72 +6235,6 @@ pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate:...@@ -6512,72 +6235,6 @@ pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate:
6512 return i;6235 return i;
6513}6236}
65146237
6515const DebugInfo = struct {
6516 inner: dwarf.DwarfInfo,
6517 debug_info: []const u8,
6518 debug_abbrev: []const u8,
6519 debug_str: []const u8,
6520 debug_line: []const u8,
6521 debug_line_str: []const u8,
6522 debug_ranges: []const u8,
6523
6524 pub fn parse(allocator: Allocator, object: Object) !?DebugInfo {
6525 var debug_info = blk: {
6526 const index = object.dwarf_debug_info_index orelse return null;
6527 break :blk try object.getSectionContents(index);
6528 };
6529 var debug_abbrev = blk: {
6530 const index = object.dwarf_debug_abbrev_index orelse return null;
6531 break :blk try object.getSectionContents(index);
6532 };
6533 var debug_str = blk: {
6534 const index = object.dwarf_debug_str_index orelse return null;
6535 break :blk try object.getSectionContents(index);
6536 };
6537 var debug_line = blk: {
6538 const index = object.dwarf_debug_line_index orelse return null;
6539 break :blk try object.getSectionContents(index);
6540 };
6541 var debug_line_str = blk: {
6542 if (object.dwarf_debug_line_str_index) |ind| {
6543 break :blk try object.getSectionContents(ind);
6544 }
6545 break :blk &[0]u8{};
6546 };
6547 var debug_ranges = blk: {
6548 if (object.dwarf_debug_ranges_index) |ind| {
6549 break :blk try object.getSectionContents(ind);
6550 }
6551 break :blk &[0]u8{};
6552 };
6553
6554 var inner: dwarf.DwarfInfo = .{
6555 .endian = .Little,
6556 .debug_info = debug_info,
6557 .debug_abbrev = debug_abbrev,
6558 .debug_str = debug_str,
6559 .debug_line = debug_line,
6560 .debug_line_str = debug_line_str,
6561 .debug_ranges = debug_ranges,
6562 };
6563 try dwarf.openDwarfDebugInfo(&inner, allocator);
6564
6565 return DebugInfo{
6566 .inner = inner,
6567 .debug_info = debug_info,
6568 .debug_abbrev = debug_abbrev,
6569 .debug_str = debug_str,
6570 .debug_line = debug_line,
6571 .debug_line_str = debug_line_str,
6572 .debug_ranges = debug_ranges,
6573 };
6574 }
6575
6576 pub fn deinit(self: *DebugInfo, allocator: Allocator) void {
6577 self.inner.deinit(allocator);
6578 }
6579};
6580
6581pub fn generateSymbolStabs(6238pub fn generateSymbolStabs(
6582 self: *MachO,6239 self: *MachO,
6583 object: Object,6240 object: Object,
...@@ -6585,14 +6242,15 @@ pub fn generateSymbolStabs(...@@ -6585,14 +6242,15 @@ pub fn generateSymbolStabs(
6585) !void {6242) !void {
6586 assert(!self.base.options.strip);6243 assert(!self.base.options.strip);
65876244
6588 const gpa = self.base.allocator;
6589
6590 log.debug("parsing debug info in '{s}'", .{object.name});6245 log.debug("parsing debug info in '{s}'", .{object.name});
65916246
6592 var debug_info = (try DebugInfo.parse(gpa, object)) orelse return;6247 const gpa = self.base.allocator;
6248 var debug_info = try object.parseDwarfInfo();
6249 defer debug_info.deinit(gpa);
6250 try dwarf.openDwarfDebugInfo(&debug_info, gpa);
65936251
6594 // We assume there is only one CU.6252 // We assume there is only one CU.
6595 const compile_unit = debug_info.inner.findCompileUnit(0x0) catch |err| switch (err) {6253 const compile_unit = debug_info.findCompileUnit(0x0) catch |err| switch (err) {
6596 error.MissingDebugInfo => {6254 error.MissingDebugInfo => {
6597 // TODO audit cases with missing debug info and audit our dwarf.zig module.6255 // TODO audit cases with missing debug info and audit our dwarf.zig module.
6598 log.debug("invalid or missing debug info in {s}; skipping", .{object.name});6256 log.debug("invalid or missing debug info in {s}; skipping", .{object.name});
...@@ -6600,8 +6258,8 @@ pub fn generateSymbolStabs(...@@ -6600,8 +6258,8 @@ pub fn generateSymbolStabs(
6600 },6258 },
6601 else => |e| return e,6259 else => |e| return e,
6602 };6260 };
6603 const tu_name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.name);6261 const tu_name = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.name);
6604 const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir);6262 const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.comp_dir);
66056263
6606 // Open scope6264 // Open scope
6607 try locals.ensureUnusedCapacity(3);6265 try locals.ensureUnusedCapacity(3);
...@@ -6664,7 +6322,7 @@ pub fn generateSymbolStabs(...@@ -6664,7 +6322,7 @@ pub fn generateSymbolStabs(
6664fn generateSymbolStabsForSymbol(6322fn generateSymbolStabsForSymbol(
6665 self: *MachO,6323 self: *MachO,
6666 sym_loc: SymbolWithLoc,6324 sym_loc: SymbolWithLoc,
6667 debug_info: DebugInfo,6325 debug_info: dwarf.DwarfInfo,
6668 buf: *[4]macho.nlist_64,6326 buf: *[4]macho.nlist_64,
6669) ![]const macho.nlist_64 {6327) ![]const macho.nlist_64 {
6670 const gpa = self.base.allocator;6328 const gpa = self.base.allocator;
...@@ -6679,7 +6337,7 @@ fn generateSymbolStabsForSymbol(...@@ -6679,7 +6337,7 @@ fn generateSymbolStabsForSymbol(
6679 const source_sym = object.getSourceSymbol(sym_loc.sym_index) orelse return buf[0..0];6337 const source_sym = object.getSourceSymbol(sym_loc.sym_index) orelse return buf[0..0];
6680 const size: ?u64 = size: {6338 const size: ?u64 = size: {
6681 if (source_sym.tentative()) break :size null;6339 if (source_sym.tentative()) break :size null;
6682 for (debug_info.inner.func_list.items) |func| {6340 for (debug_info.func_list.items) |func| {
6683 if (func.pc_range) |range| {6341 if (func.pc_range) |range| {
6684 if (source_sym.n_value >= range.start and source_sym.n_value < range.end) {6342 if (source_sym.n_value >= range.start and source_sym.n_value < range.end) {
6685 break :size range.end - range.start;6343 break :size range.end - range.start;
...@@ -6731,260 +6389,260 @@ fn generateSymbolStabsForSymbol(...@@ -6731,260 +6389,260 @@ fn generateSymbolStabsForSymbol(
6731 }6389 }
6732}6390}
67336391
6734fn snapshotState(self: *MachO) !void {6392// fn snapshotState(self: *MachO) !void {
6735 const emit = self.base.options.emit orelse {6393// const emit = self.base.options.emit orelse {
6736 log.debug("no emit directory found; skipping snapshot...", .{});6394// log.debug("no emit directory found; skipping snapshot...", .{});
6737 return;6395// return;
6738 };6396// };
67396397
6740 const Snapshot = struct {6398// const Snapshot = struct {
6741 const Node = struct {6399// const Node = struct {
6742 const Tag = enum {6400// const Tag = enum {
6743 section_start,6401// section_start,
6744 section_end,6402// section_end,
6745 atom_start,6403// atom_start,
6746 atom_end,6404// atom_end,
6747 relocation,6405// relocation,
67486406
6749 pub fn jsonStringify(6407// pub fn jsonStringify(
6750 tag: Tag,6408// tag: Tag,
6751 options: std.json.StringifyOptions,6409// options: std.json.StringifyOptions,
6752 out_stream: anytype,6410// out_stream: anytype,
6753 ) !void {6411// ) !void {
6754 _ = options;6412// _ = options;
6755 switch (tag) {6413// switch (tag) {
6756 .section_start => try out_stream.writeAll("\"section_start\""),6414// .section_start => try out_stream.writeAll("\"section_start\""),
6757 .section_end => try out_stream.writeAll("\"section_end\""),6415// .section_end => try out_stream.writeAll("\"section_end\""),
6758 .atom_start => try out_stream.writeAll("\"atom_start\""),6416// .atom_start => try out_stream.writeAll("\"atom_start\""),
6759 .atom_end => try out_stream.writeAll("\"atom_end\""),6417// .atom_end => try out_stream.writeAll("\"atom_end\""),
6760 .relocation => try out_stream.writeAll("\"relocation\""),6418// .relocation => try out_stream.writeAll("\"relocation\""),
6761 }6419// }
6762 }6420// }
6763 };6421// };
6764 const Payload = struct {6422// const Payload = struct {
6765 name: []const u8 = "",6423// name: []const u8 = "",
6766 aliases: [][]const u8 = &[0][]const u8{},6424// aliases: [][]const u8 = &[0][]const u8{},
6767 is_global: bool = false,6425// is_global: bool = false,
6768 target: u64 = 0,6426// target: u64 = 0,
6769 };6427// };
6770 address: u64,6428// address: u64,
6771 tag: Tag,6429// tag: Tag,
6772 payload: Payload,6430// payload: Payload,
6773 };6431// };
6774 timestamp: i128,6432// timestamp: i128,
6775 nodes: []Node,6433// nodes: []Node,
6776 };6434// };
67776435
6778 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);6436// var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
6779 defer arena_allocator.deinit();6437// defer arena_allocator.deinit();
6780 const arena = arena_allocator.allocator();6438// const arena = arena_allocator.allocator();
67816439
6782 const out_file = try emit.directory.handle.createFile("snapshots.json", .{6440// const out_file = try emit.directory.handle.createFile("snapshots.json", .{
6783 .truncate = false,6441// .truncate = false,
6784 .read = true,6442// .read = true,
6785 });6443// });
6786 defer out_file.close();6444// defer out_file.close();
67876445
6788 if (out_file.seekFromEnd(-1)) {6446// if (out_file.seekFromEnd(-1)) {
6789 try out_file.writer().writeByte(',');6447// try out_file.writer().writeByte(',');
6790 } else |err| switch (err) {6448// } else |err| switch (err) {
6791 error.Unseekable => try out_file.writer().writeByte('['),6449// error.Unseekable => try out_file.writer().writeByte('['),
6792 else => |e| return e,6450// else => |e| return e,
6793 }6451// }
6794 const writer = out_file.writer();6452// const writer = out_file.writer();
67956453
6796 var snapshot = Snapshot{6454// var snapshot = Snapshot{
6797 .timestamp = std.time.nanoTimestamp(),6455// .timestamp = std.time.nanoTimestamp(),
6798 .nodes = undefined,6456// .nodes = undefined,
6799 };6457// };
6800 var nodes = std.ArrayList(Snapshot.Node).init(arena);6458// var nodes = std.ArrayList(Snapshot.Node).init(arena);
68016459
6802 for (self.section_ordinals.keys()) |key| {6460// for (self.section_ordinals.keys()) |key| {
6803 const sect = self.getSection(key);6461// const sect = self.getSection(key);
6804 const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() });6462// const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() });
6805 try nodes.append(.{6463// try nodes.append(.{
6806 .address = sect.addr,6464// .address = sect.addr,
6807 .tag = .section_start,6465// .tag = .section_start,
6808 .payload = .{ .name = sect_name },6466// .payload = .{ .name = sect_name },
6809 });6467// });
68106468
6811 const is_tlv = sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;6469// const is_tlv = sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
68126470
6813 var atom: *Atom = self.atoms.get(key) orelse {6471// var atom: *Atom = self.atoms.get(key) orelse {
6814 try nodes.append(.{6472// try nodes.append(.{
6815 .address = sect.addr + sect.size,6473// .address = sect.addr + sect.size,
6816 .tag = .section_end,6474// .tag = .section_end,
6817 .payload = .{},6475// .payload = .{},
6818 });6476// });
6819 continue;6477// continue;
6820 };6478// };
68216479
6822 while (atom.prev) |prev| {6480// while (atom.prev) |prev| {
6823 atom = prev;6481// atom = prev;
6824 }6482// }
68256483
6826 while (true) {6484// while (true) {
6827 const atom_sym = atom.getSymbol(self);6485// const atom_sym = atom.getSymbol(self);
6828 var node = Snapshot.Node{6486// var node = Snapshot.Node{
6829 .address = atom_sym.n_value,6487// .address = atom_sym.n_value,
6830 .tag = .atom_start,6488// .tag = .atom_start,
6831 .payload = .{6489// .payload = .{
6832 .name = atom.getName(self),6490// .name = atom.getName(self),
6833 .is_global = self.globals.contains(atom.getName(self)),6491// .is_global = self.globals.contains(atom.getName(self)),
6834 },6492// },
6835 };6493// };
68366494
6837 var aliases = std.ArrayList([]const u8).init(arena);6495// var aliases = std.ArrayList([]const u8).init(arena);
6838 for (atom.contained.items) |sym_off| {6496// for (atom.contained.items) |sym_off| {
6839 if (sym_off.offset == 0) {6497// if (sym_off.offset == 0) {
6840 try aliases.append(self.getSymbolName(.{6498// try aliases.append(self.getSymbolName(.{
6841 .sym_index = sym_off.sym_index,6499// .sym_index = sym_off.sym_index,
6842 .file = atom.file,6500// .file = atom.file,
6843 }));6501// }));
6844 }6502// }
6845 }6503// }
6846 node.payload.aliases = aliases.toOwnedSlice();6504// node.payload.aliases = aliases.toOwnedSlice();
6847 try nodes.append(node);6505// try nodes.append(node);
68486506
6849 var relocs = try std.ArrayList(Snapshot.Node).initCapacity(arena, atom.relocs.items.len);6507// var relocs = try std.ArrayList(Snapshot.Node).initCapacity(arena, atom.relocs.items.len);
6850 for (atom.relocs.items) |rel| {6508// for (atom.relocs.items) |rel| {
6851 const source_addr = blk: {6509// const source_addr = blk: {
6852 const source_sym = atom.getSymbol(self);6510// const source_sym = atom.getSymbol(self);
6853 break :blk source_sym.n_value + rel.offset;6511// break :blk source_sym.n_value + rel.offset;
6854 };6512// };
6855 const target_addr = blk: {6513// const target_addr = blk: {
6856 const target_atom = rel.getTargetAtom(self) orelse {6514// const target_atom = rel.getTargetAtom(self) orelse {
6857 // If there is no atom for target, we still need to check for special, atom-less6515// // If there is no atom for target, we still need to check for special, atom-less
6858 // symbols such as `___dso_handle`.6516// // symbols such as `___dso_handle`.
6859 const target_name = self.getSymbolName(rel.target);6517// const target_name = self.getSymbolName(rel.target);
6860 if (self.globals.contains(target_name)) {6518// if (self.globals.contains(target_name)) {
6861 const atomless_sym = self.getSymbol(rel.target);6519// const atomless_sym = self.getSymbol(rel.target);
6862 break :blk atomless_sym.n_value;6520// break :blk atomless_sym.n_value;
6863 }6521// }
6864 break :blk 0;6522// break :blk 0;
6865 };6523// };
6866 const target_sym = if (target_atom.isSymbolContained(rel.target, self))6524// const target_sym = if (target_atom.isSymbolContained(rel.target, self))
6867 self.getSymbol(rel.target)6525// self.getSymbol(rel.target)
6868 else6526// else
6869 target_atom.getSymbol(self);6527// target_atom.getSymbol(self);
6870 const base_address: u64 = if (is_tlv) base_address: {6528// const base_address: u64 = if (is_tlv) base_address: {
6871 const sect_id: u16 = sect_id: {6529// const sect_id: u16 = sect_id: {
6872 if (self.tlv_data_section_index) |i| {6530// if (self.tlv_data_section_index) |i| {
6873 break :sect_id i;6531// break :sect_id i;
6874 } else if (self.tlv_bss_section_index) |i| {6532// } else if (self.tlv_bss_section_index) |i| {
6875 break :sect_id i;6533// break :sect_id i;
6876 } else unreachable;6534// } else unreachable;
6877 };6535// };
6878 break :base_address self.getSection(.{6536// break :base_address self.getSection(.{
6879 .seg = self.data_segment_cmd_index.?,6537// .seg = self.data_segment_cmd_index.?,
6880 .sect = sect_id,6538// .sect = sect_id,
6881 }).addr;6539// }).addr;
6882 } else 0;6540// } else 0;
6883 break :blk target_sym.n_value - base_address;6541// break :blk target_sym.n_value - base_address;
6884 };6542// };
68856543
6886 relocs.appendAssumeCapacity(.{6544// relocs.appendAssumeCapacity(.{
6887 .address = source_addr,6545// .address = source_addr,
6888 .tag = .relocation,6546// .tag = .relocation,
6889 .payload = .{ .target = target_addr },6547// .payload = .{ .target = target_addr },
6890 });6548// });
6891 }6549// }
68926550
6893 if (atom.contained.items.len == 0) {6551// if (atom.contained.items.len == 0) {
6894 try nodes.appendSlice(relocs.items);6552// try nodes.appendSlice(relocs.items);
6895 } else {6553// } else {
6896 // Need to reverse iteration order of relocs since by default for relocatable sources6554// // Need to reverse iteration order of relocs since by default for relocatable sources
6897 // they come in reverse. For linking, this doesn't matter in any way, however, for6555// // they come in reverse. For linking, this doesn't matter in any way, however, for
6898 // arranging the memoryline for displaying it does.6556// // arranging the memoryline for displaying it does.
6899 std.mem.reverse(Snapshot.Node, relocs.items);6557// std.mem.reverse(Snapshot.Node, relocs.items);
69006558
6901 var next_i: usize = 0;6559// var next_i: usize = 0;
6902 var last_rel: usize = 0;6560// var last_rel: usize = 0;
6903 while (next_i < atom.contained.items.len) : (next_i += 1) {6561// while (next_i < atom.contained.items.len) : (next_i += 1) {
6904 const loc = SymbolWithLoc{6562// const loc = SymbolWithLoc{
6905 .sym_index = atom.contained.items[next_i].sym_index,6563// .sym_index = atom.contained.items[next_i].sym_index,
6906 .file = atom.file,6564// .file = atom.file,
6907 };6565// };
6908 const cont_sym = self.getSymbol(loc);6566// const cont_sym = self.getSymbol(loc);
6909 const cont_sym_name = self.getSymbolName(loc);6567// const cont_sym_name = self.getSymbolName(loc);
6910 var contained_node = Snapshot.Node{6568// var contained_node = Snapshot.Node{
6911 .address = cont_sym.n_value,6569// .address = cont_sym.n_value,
6912 .tag = .atom_start,6570// .tag = .atom_start,
6913 .payload = .{6571// .payload = .{
6914 .name = cont_sym_name,6572// .name = cont_sym_name,
6915 .is_global = self.globals.contains(cont_sym_name),6573// .is_global = self.globals.contains(cont_sym_name),
6916 },6574// },
6917 };6575// };
69186576
6919 // Accumulate aliases6577// // Accumulate aliases
6920 var inner_aliases = std.ArrayList([]const u8).init(arena);6578// var inner_aliases = std.ArrayList([]const u8).init(arena);
6921 while (true) {6579// while (true) {
6922 if (next_i + 1 >= atom.contained.items.len) break;6580// if (next_i + 1 >= atom.contained.items.len) break;
6923 const next_sym_loc = SymbolWithLoc{6581// const next_sym_loc = SymbolWithLoc{
6924 .sym_index = atom.contained.items[next_i + 1].sym_index,6582// .sym_index = atom.contained.items[next_i + 1].sym_index,
6925 .file = atom.file,6583// .file = atom.file,
6926 };6584// };
6927 const next_sym = self.getSymbol(next_sym_loc);6585// const next_sym = self.getSymbol(next_sym_loc);
6928 if (next_sym.n_value != cont_sym.n_value) break;6586// if (next_sym.n_value != cont_sym.n_value) break;
6929 const next_sym_name = self.getSymbolName(next_sym_loc);6587// const next_sym_name = self.getSymbolName(next_sym_loc);
6930 if (self.globals.contains(next_sym_name)) {6588// if (self.globals.contains(next_sym_name)) {
6931 try inner_aliases.append(contained_node.payload.name);6589// try inner_aliases.append(contained_node.payload.name);
6932 contained_node.payload.name = next_sym_name;6590// contained_node.payload.name = next_sym_name;
6933 contained_node.payload.is_global = true;6591// contained_node.payload.is_global = true;
6934 } else try inner_aliases.append(next_sym_name);6592// } else try inner_aliases.append(next_sym_name);
6935 next_i += 1;6593// next_i += 1;
6936 }6594// }
69376595
6938 const cont_size = if (next_i + 1 < atom.contained.items.len)6596// const cont_size = if (next_i + 1 < atom.contained.items.len)
6939 self.getSymbol(.{6597// self.getSymbol(.{
6940 .sym_index = atom.contained.items[next_i + 1].sym_index,6598// .sym_index = atom.contained.items[next_i + 1].sym_index,
6941 .file = atom.file,6599// .file = atom.file,
6942 }).n_value - cont_sym.n_value6600// }).n_value - cont_sym.n_value
6943 else6601// else
6944 atom_sym.n_value + atom.size - cont_sym.n_value;6602// atom_sym.n_value + atom.size - cont_sym.n_value;
69456603
6946 contained_node.payload.aliases = inner_aliases.toOwnedSlice();6604// contained_node.payload.aliases = inner_aliases.toOwnedSlice();
6947 try nodes.append(contained_node);6605// try nodes.append(contained_node);
69486606
6949 for (relocs.items[last_rel..]) |rel| {6607// for (relocs.items[last_rel..]) |rel| {
6950 if (rel.address >= cont_sym.n_value + cont_size) {6608// if (rel.address >= cont_sym.n_value + cont_size) {
6951 break;6609// break;
6952 }6610// }
6953 try nodes.append(rel);6611// try nodes.append(rel);
6954 last_rel += 1;6612// last_rel += 1;
6955 }6613// }
69566614
6957 try nodes.append(.{6615// try nodes.append(.{
6958 .address = cont_sym.n_value + cont_size,6616// .address = cont_sym.n_value + cont_size,
6959 .tag = .atom_end,6617// .tag = .atom_end,
6960 .payload = .{},6618// .payload = .{},
6961 });6619// });
6962 }6620// }
6963 }6621// }
69646622
6965 try nodes.append(.{6623// try nodes.append(.{
6966 .address = atom_sym.n_value + atom.size,6624// .address = atom_sym.n_value + atom.size,
6967 .tag = .atom_end,6625// .tag = .atom_end,
6968 .payload = .{},6626// .payload = .{},
6969 });6627// });
69706628
6971 if (atom.next) |next| {6629// if (atom.next) |next| {
6972 atom = next;6630// atom = next;
6973 } else break;6631// } else break;
6974 }6632// }
69756633
6976 try nodes.append(.{6634// try nodes.append(.{
6977 .address = sect.addr + sect.size,6635// .address = sect.addr + sect.size,
6978 .tag = .section_end,6636// .tag = .section_end,
6979 .payload = .{},6637// .payload = .{},
6980 });6638// });
6981 }6639// }
69826640
6983 snapshot.nodes = nodes.toOwnedSlice();6641// snapshot.nodes = nodes.toOwnedSlice();
69846642
6985 try std.json.stringify(snapshot, .{}, writer);6643// try std.json.stringify(snapshot, .{}, writer);
6986 try writer.writeByte(']');6644// try writer.writeByte(']');
6987}6645// }
69886646
6989fn logSymAttributes(sym: macho.nlist_64, buf: *[9]u8) []const u8 {6647fn logSymAttributes(sym: macho.nlist_64, buf: *[9]u8) []const u8 {
6990 mem.set(u8, buf[0..4], '_');6648 mem.set(u8, buf[0..4], '_');
...@@ -7104,26 +6762,19 @@ fn logSymtab(self: *MachO) void {...@@ -7104,26 +6762,19 @@ fn logSymtab(self: *MachO) void {
7104 }6762 }
7105}6763}
71066764
7107fn logSectionOrdinals(self: *MachO) void {
7108 for (self.section_ordinals.keys()) |match, i| {
7109 const sect = self.getSection(match);
7110 log.debug("sect({d}, '{s},{s}')", .{ i + 1, sect.segName(), sect.sectName() });
7111 }
7112}
7113
7114fn logAtoms(self: *MachO) void {6765fn logAtoms(self: *MachO) void {
7115 log.debug("atoms:", .{});6766 log.debug("atoms:", .{});
7116 var it = self.atoms.iterator();6767
7117 while (it.next()) |entry| {6768 const slice = self.sections.slice();
7118 const match = entry.key_ptr.*;6769 for (slice.items(.last_atom)) |last, i| {
7119 var atom = entry.value_ptr.*;6770 var atom = last orelse continue;
6771 const header = slice.items(.header)[i];
71206772
7121 while (atom.prev) |prev| {6773 while (atom.prev) |prev| {
7122 atom = prev;6774 atom = prev;
7123 }6775 }
71246776
7125 const sect = self.getSection(match);6777 log.debug("{s},{s}", .{ header.segName(), header.sectName() });
7126 log.debug("{s},{s}", .{ sect.segName(), sect.sectName() });
71276778
7128 while (true) {6779 while (true) {
7129 self.logAtom(atom);6780 self.logAtom(atom);
src/link/MachO/Archive.zig+33-25
...@@ -6,19 +6,14 @@ const fs = std.fs;...@@ -6,19 +6,14 @@ const fs = std.fs;
6const log = std.log.scoped(.link);6const log = std.log.scoped(.link);
7const macho = std.macho;7const macho = std.macho;
8const mem = std.mem;8const mem = std.mem;
9const fat = @import("fat.zig");
109
11const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
12const Object = @import("Object.zig");11const Object = @import("Object.zig");
1312
14file: fs.File,13file: fs.File,
14fat_offset: u64,
15name: []const u8,15name: []const u8,
1616header: ar_hdr = undefined,
17header: ?ar_hdr = null,
18
19// The actual contents we care about linking with will be embedded at
20// an offset within a file if we are linking against a fat lib
21library_offset: u64 = 0,
2217
23/// Parsed table of contents.18/// Parsed table of contents.
24/// Each symbol name points to a list of all definition19/// Each symbol name points to a list of all definition
...@@ -103,11 +98,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {...@@ -103,11 +98,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
103 allocator.free(self.name);98 allocator.free(self.name);
104}99}
105100
106pub fn parse(self: *Archive, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) !void {101pub fn parse(self: *Archive, allocator: Allocator, reader: anytype) !void {
107 const reader = self.file.reader();
108 self.library_offset = try fat.getLibraryOffset(reader, cpu_arch);
109 try self.file.seekTo(self.library_offset);
110
111 const magic = try reader.readBytesNoEof(SARMAG);102 const magic = try reader.readBytesNoEof(SARMAG);
112 if (!mem.eql(u8, &magic, ARMAG)) {103 if (!mem.eql(u8, &magic, ARMAG)) {
113 log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });104 log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
...@@ -115,21 +106,23 @@ pub fn parse(self: *Archive, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch...@@ -115,21 +106,23 @@ pub fn parse(self: *Archive, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch
115 }106 }
116107
117 self.header = try reader.readStruct(ar_hdr);108 self.header = try reader.readStruct(ar_hdr);
118 if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {109 if (!mem.eql(u8, &self.header.ar_fmag, ARFMAG)) {
119 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });110 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{
111 ARFMAG,
112 self.header.ar_fmag,
113 });
120 return error.NotArchive;114 return error.NotArchive;
121 }115 }
122116
123 var embedded_name = try parseName(allocator, self.header.?, reader);117 const name_or_length = try self.header.nameOrLength();
118 var embedded_name = try parseName(allocator, name_or_length, reader);
124 log.debug("parsing archive '{s}' at '{s}'", .{ embedded_name, self.name });119 log.debug("parsing archive '{s}' at '{s}'", .{ embedded_name, self.name });
125 defer allocator.free(embedded_name);120 defer allocator.free(embedded_name);
126121
127 try self.parseTableOfContents(allocator, reader);122 try self.parseTableOfContents(allocator, reader);
128 try reader.context.seekTo(0);
129}123}
130124
131fn parseName(allocator: Allocator, header: ar_hdr, reader: anytype) ![]u8 {125fn parseName(allocator: Allocator, name_or_length: ar_hdr.NameOrLength, reader: anytype) ![]u8 {
132 const name_or_length = try header.nameOrLength();
133 var name: []u8 = undefined;126 var name: []u8 = undefined;
134 switch (name_or_length) {127 switch (name_or_length) {
135 .Name => |n| {128 .Name => |n| {
...@@ -187,9 +180,14 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !...@@ -187,9 +180,14 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
187 }180 }
188}181}
189182
190pub fn parseObject(self: Archive, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch, offset: u32) !Object {183pub fn parseObject(
184 self: Archive,
185 allocator: Allocator,
186 cpu_arch: std.Target.Cpu.Arch,
187 offset: u32,
188) !Object {
191 const reader = self.file.reader();189 const reader = self.file.reader();
192 try reader.context.seekTo(offset + self.library_offset);190 try reader.context.seekTo(self.fat_offset + offset);
193191
194 const object_header = try reader.readStruct(ar_hdr);192 const object_header = try reader.readStruct(ar_hdr);
195193
...@@ -198,7 +196,8 @@ pub fn parseObject(self: Archive, allocator: Allocator, cpu_arch: std.Target.Cpu...@@ -198,7 +196,8 @@ pub fn parseObject(self: Archive, allocator: Allocator, cpu_arch: std.Target.Cpu
198 return error.MalformedArchive;196 return error.MalformedArchive;
199 }197 }
200198
201 const object_name = try parseName(allocator, object_header, reader);199 const name_or_length = try object_header.nameOrLength();
200 const object_name = try parseName(allocator, name_or_length, reader);
202 defer allocator.free(object_name);201 defer allocator.free(object_name);
203202
204 log.debug("extracting object '{s}' from archive '{s}'", .{ object_name, self.name });203 log.debug("extracting object '{s}' from archive '{s}'", .{ object_name, self.name });
...@@ -209,15 +208,24 @@ pub fn parseObject(self: Archive, allocator: Allocator, cpu_arch: std.Target.Cpu...@@ -209,15 +208,24 @@ pub fn parseObject(self: Archive, allocator: Allocator, cpu_arch: std.Target.Cpu
209 break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name });208 break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name });
210 };209 };
211210
211 const object_name_len = switch (name_or_length) {
212 .Name => 0,
213 .Length => |len| len,
214 };
215 const object_size = (try object_header.size()) - object_name_len;
216 const contents = try allocator.allocWithOptions(u8, object_size, @alignOf(u64), null);
217 const amt = try reader.readAll(contents);
218 if (amt != object_size) {
219 return error.InputOutput;
220 }
221
212 var object = Object{222 var object = Object{
213 .file = try fs.cwd().openFile(self.name, .{}),
214 .name = name,223 .name = name,
215 .file_offset = @intCast(u32, try reader.context.getPos()),224 .mtime = try self.header.date(),
216 .mtime = try self.header.?.date(),225 .contents = contents,
217 };226 };
218227
219 try object.parse(allocator, cpu_arch);228 try object.parse(allocator, cpu_arch);
220 try reader.context.seekTo(0);
221229
222 return object;230 return object;
223}231}
src/link/MachO/Atom.zig+18-17
...@@ -246,7 +246,7 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context:...@@ -246,7 +246,7 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context:
246 else => {246 else => {
247 log.err("unexpected relocation type after ARM64_RELOC_ADDEND", .{});247 log.err("unexpected relocation type after ARM64_RELOC_ADDEND", .{});
248 log.err(" expected ARM64_RELOC_PAGE21 or ARM64_RELOC_PAGEOFF12", .{});248 log.err(" expected ARM64_RELOC_PAGE21 or ARM64_RELOC_PAGEOFF12", .{});
249 log.err(" found {}", .{next});249 log.err(" found {s}", .{@tagName(next)});
250 return error.UnexpectedRelocationType;250 return error.UnexpectedRelocationType;
251 },251 },
252 }252 }
...@@ -285,7 +285,9 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context:...@@ -285,7 +285,9 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context:
285 else => {285 else => {
286 log.err("unexpected relocation type after ARM64_RELOC_ADDEND", .{});286 log.err("unexpected relocation type after ARM64_RELOC_ADDEND", .{});
287 log.err(" expected ARM64_RELOC_UNSIGNED", .{});287 log.err(" expected ARM64_RELOC_UNSIGNED", .{});
288 log.err(" found {}", .{@intToEnum(macho.reloc_type_arm64, relocs[i + 1].r_type)});288 log.err(" found {s}", .{
289 @tagName(@intToEnum(macho.reloc_type_arm64, relocs[i + 1].r_type)),
290 });
289 return error.UnexpectedRelocationType;291 return error.UnexpectedRelocationType;
290 },292 },
291 },293 },
...@@ -294,7 +296,9 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context:...@@ -294,7 +296,9 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context:
294 else => {296 else => {
295 log.err("unexpected relocation type after X86_64_RELOC_ADDEND", .{});297 log.err("unexpected relocation type after X86_64_RELOC_ADDEND", .{});
296 log.err(" expected X86_64_RELOC_UNSIGNED", .{});298 log.err(" expected X86_64_RELOC_UNSIGNED", .{});
297 log.err(" found {}", .{@intToEnum(macho.reloc_type_x86_64, relocs[i + 1].r_type)});299 log.err(" found {s}", .{
300 @tagName(@intToEnum(macho.reloc_type_x86_64, relocs[i + 1].r_type)),
301 });
298 return error.UnexpectedRelocationType;302 return error.UnexpectedRelocationType;
299 },303 },
300 },304 },
...@@ -309,13 +313,13 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context:...@@ -309,13 +313,13 @@ pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context:
309 const sect_id = @intCast(u16, rel.r_symbolnum - 1);313 const sect_id = @intCast(u16, rel.r_symbolnum - 1);
310 const sym_index = object.sections_as_symbols.get(sect_id) orelse blk: {314 const sym_index = object.sections_as_symbols.get(sect_id) orelse blk: {
311 const sect = object.getSourceSection(sect_id);315 const sect = object.getSourceSection(sect_id);
312 const match = (try context.macho_file.getMatchingSection(sect)) orelse316 const match = (try context.macho_file.getOutputSection(sect)) orelse
313 unreachable;317 unreachable;
314 const sym_index = @intCast(u32, object.symtab.items.len);318 const sym_index = @intCast(u32, object.symtab.items.len);
315 try object.symtab.append(gpa, .{319 try object.symtab.append(gpa, .{
316 .n_strx = 0,320 .n_strx = 0,
317 .n_type = macho.N_SECT,321 .n_type = macho.N_SECT,
318 .n_sect = context.macho_file.getSectionOrdinal(match),322 .n_sect = match + 1,
319 .n_desc = 0,323 .n_desc = 0,
320 .n_value = sect.addr,324 .n_value = sect.addr,
321 });325 });
...@@ -459,9 +463,10 @@ fn addPtrBindingOrRebase(...@@ -459,9 +463,10 @@ fn addPtrBindingOrRebase(
459 });463 });
460 } else {464 } else {
461 const source_sym = self.getSymbol(context.macho_file);465 const source_sym = self.getSymbol(context.macho_file);
462 const match = context.macho_file.getMatchingSectionFromOrdinal(source_sym.n_sect);466 const section = context.macho_file.sections.get(source_sym.n_sect - 1);
463 const sect = context.macho_file.getSection(match);467 const header = section.header;
464 const sect_type = sect.type_();468 const segment_index = section.segment_index;
469 const sect_type = header.type_();
465470
466 const should_rebase = rebase: {471 const should_rebase = rebase: {
467 if (rel.r_length != 3) break :rebase false;472 if (rel.r_length != 3) break :rebase false;
...@@ -470,12 +475,12 @@ fn addPtrBindingOrRebase(...@@ -470,12 +475,12 @@ fn addPtrBindingOrRebase(
470 // that the segment is writable should be enough here.475 // that the segment is writable should be enough here.
471 const is_right_segment = blk: {476 const is_right_segment = blk: {
472 if (context.macho_file.data_segment_cmd_index) |idx| {477 if (context.macho_file.data_segment_cmd_index) |idx| {
473 if (match.seg == idx) {478 if (segment_index == idx) {
474 break :blk true;479 break :blk true;
475 }480 }
476 }481 }
477 if (context.macho_file.data_const_segment_cmd_index) |idx| {482 if (context.macho_file.data_const_segment_cmd_index) |idx| {
478 if (match.seg == idx) {483 if (segment_index == idx) {
479 break :blk true;484 break :blk true;
480 }485 }
481 }486 }
...@@ -565,9 +570,8 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {...@@ -565,9 +570,8 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
565 };570 };
566 const is_tlv = is_tlv: {571 const is_tlv = is_tlv: {
567 const source_sym = self.getSymbol(macho_file);572 const source_sym = self.getSymbol(macho_file);
568 const match = macho_file.getMatchingSectionFromOrdinal(source_sym.n_sect);573 const header = macho_file.sections.items(.header)[source_sym.n_sect - 1];
569 const sect = macho_file.getSection(match);574 break :is_tlv header.type_() == macho.S_THREAD_LOCAL_VARIABLES;
570 break :is_tlv sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
571 };575 };
572 const target_addr = blk: {576 const target_addr = blk: {
573 const target_atom = rel.getTargetAtom(macho_file) orelse {577 const target_atom = rel.getTargetAtom(macho_file) orelse {
...@@ -608,10 +612,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {...@@ -608,10 +612,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
608 return error.FailedToResolveRelocationTarget;612 return error.FailedToResolveRelocationTarget;
609 }613 }
610 };614 };
611 break :base_address macho_file.getSection(.{615 break :base_address macho_file.sections.items(.header)[sect_id].addr;
612 .seg = macho_file.data_segment_cmd_index.?,
613 .sect = sect_id,
614 }).addr;
615 } else 0;616 } else 0;
616 break :blk target_sym.n_value - base_address;617 break :blk target_sym.n_value - base_address;
617 };618 };
src/link/MachO/CodeSignature.zig+7-5
...@@ -252,7 +252,7 @@ pub const WriteOpts = struct {...@@ -252,7 +252,7 @@ pub const WriteOpts = struct {
252 file: fs.File,252 file: fs.File,
253 exec_seg_base: u64,253 exec_seg_base: u64,
254 exec_seg_limit: u64,254 exec_seg_limit: u64,
255 code_sig_cmd: macho.linkedit_data_command,255 file_size: u32,
256 output_mode: std.builtin.OutputMode,256 output_mode: std.builtin.OutputMode,
257};257};
258258
...@@ -274,10 +274,9 @@ pub fn writeAdhocSignature(...@@ -274,10 +274,9 @@ pub fn writeAdhocSignature(
274 self.code_directory.inner.execSegBase = opts.exec_seg_base;274 self.code_directory.inner.execSegBase = opts.exec_seg_base;
275 self.code_directory.inner.execSegLimit = opts.exec_seg_limit;275 self.code_directory.inner.execSegLimit = opts.exec_seg_limit;
276 self.code_directory.inner.execSegFlags = if (opts.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0;276 self.code_directory.inner.execSegFlags = if (opts.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0;
277 const file_size = opts.code_sig_cmd.dataoff;277 self.code_directory.inner.codeLimit = opts.file_size;
278 self.code_directory.inner.codeLimit = file_size;
279278
280 const total_pages = mem.alignForward(file_size, self.page_size) / self.page_size;279 const total_pages = mem.alignForward(opts.file_size, self.page_size) / self.page_size;
281280
282 var buffer = try allocator.alloc(u8, self.page_size);281 var buffer = try allocator.alloc(u8, self.page_size);
283 defer allocator.free(buffer);282 defer allocator.free(buffer);
...@@ -289,7 +288,10 @@ pub fn writeAdhocSignature(...@@ -289,7 +288,10 @@ pub fn writeAdhocSignature(
289 var i: usize = 0;288 var i: usize = 0;
290 while (i < total_pages) : (i += 1) {289 while (i < total_pages) : (i += 1) {
291 const fstart = i * self.page_size;290 const fstart = i * self.page_size;
292 const fsize = if (fstart + self.page_size > file_size) file_size - fstart else self.page_size;291 const fsize = if (fstart + self.page_size > opts.file_size)
292 opts.file_size - fstart
293 else
294 self.page_size;
293 const len = try opts.file.preadAll(buffer, fstart);295 const len = try opts.file.preadAll(buffer, fstart);
294 assert(fsize <= len);296 assert(fsize <= len);
295297
src/link/MachO/DebugSymbols.zig+174-336
...@@ -25,35 +25,18 @@ base: *MachO,...@@ -25,35 +25,18 @@ base: *MachO,
25dwarf: Dwarf,25dwarf: Dwarf,
26file: fs.File,26file: fs.File,
2727
28/// Table of all load commands28segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
29load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},29sections: std.ArrayListUnmanaged(macho.section_64) = .{},
30/// __PAGEZERO segment30
31pagezero_segment_cmd_index: ?u16 = null,31linkedit_segment_cmd_index: ?u8 = null,
32/// __TEXT segment32dwarf_segment_cmd_index: ?u8 = null,
33text_segment_cmd_index: ?u16 = null,33
34/// __DATA_CONST segment34debug_info_section_index: ?u8 = null,
35data_const_segment_cmd_index: ?u16 = null,35debug_abbrev_section_index: ?u8 = null,
36/// __DATA segment36debug_str_section_index: ?u8 = null,
37data_segment_cmd_index: ?u16 = null,37debug_aranges_section_index: ?u8 = null,
38/// __LINKEDIT segment38debug_line_section_index: ?u8 = null,
39linkedit_segment_cmd_index: ?u16 = null,39
40/// __DWARF segment
41dwarf_segment_cmd_index: ?u16 = null,
42/// Symbol table
43symtab_cmd_index: ?u16 = null,
44/// UUID load command
45uuid_cmd_index: ?u16 = null,
46
47/// Index into __TEXT,__text section.
48text_section_index: ?u16 = null,
49
50debug_info_section_index: ?u16 = null,
51debug_abbrev_section_index: ?u16 = null,
52debug_str_section_index: ?u16 = null,
53debug_aranges_section_index: ?u16 = null,
54debug_line_section_index: ?u16 = null,
55
56load_commands_dirty: bool = false,
57debug_string_table_dirty: bool = false,40debug_string_table_dirty: bool = false,
58debug_abbrev_section_dirty: bool = false,41debug_abbrev_section_dirty: bool = false,
59debug_aranges_section_dirty: bool = false,42debug_aranges_section_dirty: bool = false,
...@@ -78,98 +61,40 @@ pub const Reloc = struct {...@@ -78,98 +61,40 @@ pub const Reloc = struct {
78/// You must call this function *after* `MachO.populateMissingMetadata()`61/// You must call this function *after* `MachO.populateMissingMetadata()`
79/// has been called to get a viable debug symbols output.62/// has been called to get a viable debug symbols output.
80pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {63pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {
81 if (self.uuid_cmd_index == null) {
82 const base_cmd = self.base.load_commands.items[self.base.uuid_cmd_index.?];
83 self.uuid_cmd_index = @intCast(u16, self.load_commands.items.len);
84 try self.load_commands.append(allocator, base_cmd);
85 self.load_commands_dirty = true;
86 }
87
88 if (self.symtab_cmd_index == null) {
89 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
90 try self.load_commands.append(self.base.base.allocator, .{
91 .symtab = .{
92 .cmdsize = @sizeOf(macho.symtab_command),
93 .symoff = 0,
94 .nsyms = 0,
95 .stroff = 0,
96 .strsize = 0,
97 },
98 });
99 try self.strtab.buffer.append(allocator, 0);
100 self.load_commands_dirty = true;
101 }
102
103 if (self.pagezero_segment_cmd_index == null) {
104 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
105 const base_cmd = self.base.load_commands.items[self.base.pagezero_segment_cmd_index.?].segment;
106 const cmd = try self.copySegmentCommand(allocator, base_cmd);
107 try self.load_commands.append(allocator, .{ .segment = cmd });
108 self.load_commands_dirty = true;
109 }
110
111 if (self.text_segment_cmd_index == null) {
112 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
113 const base_cmd = self.base.load_commands.items[self.base.text_segment_cmd_index.?].segment;
114 const cmd = try self.copySegmentCommand(allocator, base_cmd);
115 try self.load_commands.append(allocator, .{ .segment = cmd });
116 self.load_commands_dirty = true;
117 }
118
119 if (self.data_const_segment_cmd_index == null) outer: {
120 if (self.base.data_const_segment_cmd_index == null) break :outer; // __DATA_CONST is optional
121 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
122 const base_cmd = self.base.load_commands.items[self.base.data_const_segment_cmd_index.?].segment;
123 const cmd = try self.copySegmentCommand(allocator, base_cmd);
124 try self.load_commands.append(allocator, .{ .segment = cmd });
125 self.load_commands_dirty = true;
126 }
127
128 if (self.data_segment_cmd_index == null) outer: {
129 if (self.base.data_segment_cmd_index == null) break :outer; // __DATA is optional
130 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
131 const base_cmd = self.base.load_commands.items[self.base.data_segment_cmd_index.?].segment;
132 const cmd = try self.copySegmentCommand(allocator, base_cmd);
133 try self.load_commands.append(allocator, .{ .segment = cmd });
134 self.load_commands_dirty = true;
135 }
136
137 if (self.linkedit_segment_cmd_index == null) {64 if (self.linkedit_segment_cmd_index == null) {
138 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);65 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
139 const base_cmd = self.base.load_commands.items[self.base.linkedit_segment_cmd_index.?].segment;
140 var cmd = try self.copySegmentCommand(allocator, base_cmd);
141 // TODO this needs reworking66 // TODO this needs reworking
142 cmd.inner.vmsize = self.base.page_size;67 try self.segments.append(allocator, .{
143 cmd.inner.fileoff = self.base.page_size;68 .segname = makeStaticString("__LINKEDIT"),
144 cmd.inner.filesize = self.base.page_size;69 .vmaddr = self.base.page_size,
145 try self.load_commands.append(allocator, .{ .segment = cmd });70 .vmsize = self.base.page_size,
146 self.load_commands_dirty = true;71 .fileoff = self.base.page_size,
72 .filesize = self.base.page_size,
73 .maxprot = macho.PROT.READ,
74 .initprot = macho.PROT.READ,
75 .cmdsize = @sizeOf(macho.segment_command_64),
76 });
147 }77 }
14878
149 if (self.dwarf_segment_cmd_index == null) {79 if (self.dwarf_segment_cmd_index == null) {
150 self.dwarf_segment_cmd_index = @intCast(u16, self.load_commands.items.len);80 self.dwarf_segment_cmd_index = @intCast(u8, self.segments.items.len);
15181
152 const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;82 const linkedit = self.segments.items[self.base.linkedit_segment_cmd_index.?];
153 const ideal_size: u16 = 200 + 128 + 160 + 250;83 const ideal_size: u16 = 200 + 128 + 160 + 250;
154 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.base.page_size);84 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.base.page_size);
155 const fileoff = linkedit.inner.fileoff + linkedit.inner.filesize;85 const fileoff = linkedit.fileoff + linkedit.filesize;
156 const vmaddr = linkedit.inner.vmaddr + linkedit.inner.vmsize;86 const vmaddr = linkedit.vmaddr + linkedit.vmsize;
15787
158 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });88 log.debug("found __DWARF segment free space 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
15989
160 try self.load_commands.append(allocator, .{90 try self.segments.append(allocator, .{
161 .segment = .{91 .segname = makeStaticString("__DWARF"),
162 .inner = .{92 .vmaddr = vmaddr,
163 .segname = makeStaticString("__DWARF"),93 .vmsize = needed_size,
164 .vmaddr = vmaddr,94 .fileoff = fileoff,
165 .vmsize = needed_size,95 .filesize = needed_size,
166 .fileoff = fileoff,96 .cmdsize = @sizeOf(macho.segment_command_64),
167 .filesize = needed_size,
168 .cmdsize = @sizeOf(macho.segment_command_64),
169 },
170 },
171 });97 });
172 self.load_commands_dirty = true;
173 }98 }
17499
175 if (self.debug_str_section_index == null) {100 if (self.debug_str_section_index == null) {
...@@ -203,18 +128,18 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void...@@ -203,18 +128,18 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
203 }128 }
204}129}
205130
206fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u16 {131fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignment: u16) !u8 {
207 const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;132 const segment = &self.segments.items[self.dwarf_segment_cmd_index.?];
208 var sect = macho.section_64{133 var sect = macho.section_64{
209 .sectname = makeStaticString(sectname),134 .sectname = makeStaticString(sectname),
210 .segname = seg.inner.segname,135 .segname = segment.segname,
211 .size = @intCast(u32, size),136 .size = @intCast(u32, size),
212 .@"align" = alignment,137 .@"align" = alignment,
213 };138 };
214 const alignment_pow_2 = try math.powi(u32, 2, alignment);139 const alignment_pow_2 = try math.powi(u32, 2, alignment);
215 const off = self.findFreeSpace(size, alignment_pow_2);140 const off = self.findFreeSpace(size, alignment_pow_2);
216141
217 assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand142 assert(off + size <= segment.fileoff + segment.filesize); // TODO expand
218143
219 log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{144 log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{
220 sect.segName(),145 sect.segName(),
...@@ -223,31 +148,20 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme...@@ -223,31 +148,20 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
223 off + size,148 off + size,
224 });149 });
225150
226 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;151 sect.addr = segment.vmaddr + off - segment.fileoff;
227 sect.offset = @intCast(u32, off);152 sect.offset = @intCast(u32, off);
228153
229 const index = @intCast(u16, seg.sections.items.len);154 const index = @intCast(u8, self.sections.items.len);
230 try seg.sections.append(self.base.base.allocator, sect);155 try self.sections.append(self.base.base.allocator, sect);
231 seg.inner.cmdsize += @sizeOf(macho.section_64);156 segment.cmdsize += @sizeOf(macho.section_64);
232 seg.inner.nsects += 1;157 segment.nsects += 1;
233
234 // TODO
235 // const match = MatchingSection{
236 // .seg = segment_id,
237 // .sect = index,
238 // };
239 // _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
240 // try self.block_free_lists.putNoClobber(self.base.allocator, match, .{});
241
242 self.load_commands_dirty = true;
243158
244 return index;159 return index;
245}160}
246161
247fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {162fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {
248 const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
249 const end = start + padToIdeal(size);163 const end = start + padToIdeal(size);
250 for (seg.sections.items) |section| {164 for (self.sections.items) |section| {
251 const increased_size = padToIdeal(section.size);165 const increased_size = padToIdeal(section.size);
252 const test_end = section.offset + increased_size;166 const test_end = section.offset + increased_size;
253 if (end > section.offset and start < test_end) {167 if (end > section.offset and start < test_end) {
...@@ -258,8 +172,8 @@ fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {...@@ -258,8 +172,8 @@ fn detectAllocCollision(self: *DebugSymbols, start: u64, size: u64) ?u64 {
258}172}
259173
260pub fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {174pub fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 {
261 const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;175 const segment = self.segments.items[self.dwarf_segment_cmd_index.?];
262 var offset: u64 = seg.inner.fileoff;176 var offset: u64 = segment.fileoff;
263 while (self.detectAllocCollision(offset, object_size)) |item_end| {177 while (self.detectAllocCollision(offset, object_size)) |item_end| {
264 offset = mem.alignForwardGeneric(u64, item_end, min_alignment);178 offset = mem.alignForwardGeneric(u64, item_end, min_alignment);
265 }179 }
...@@ -296,8 +210,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -296,8 +210,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
296 break :blk got_entry.getName(self.base);210 break :blk got_entry.getName(self.base);
297 },211 },
298 };212 };
299 const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;213 const sect = &self.sections.items[self.debug_info_section_index.?];
300 const sect = &seg.sections.items[self.debug_info_section_index.?];
301 const file_offset = sect.offset + reloc.offset;214 const file_offset = sect.offset + reloc.offset;
302 log.debug("resolving relocation: {d}@{x} ('{s}') at offset {x}", .{215 log.debug("resolving relocation: {d}@{x} ('{s}') at offset {x}", .{
303 reloc.target,216 reloc.target,
...@@ -311,15 +224,13 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -311,15 +224,13 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
311224
312 if (self.debug_abbrev_section_dirty) {225 if (self.debug_abbrev_section_dirty) {
313 try self.dwarf.writeDbgAbbrev(&self.base.base);226 try self.dwarf.writeDbgAbbrev(&self.base.base);
314 self.load_commands_dirty = true;
315 self.debug_abbrev_section_dirty = false;227 self.debug_abbrev_section_dirty = false;
316 }228 }
317229
318 if (self.debug_info_header_dirty) {230 if (self.debug_info_header_dirty) {
319 // Currently only one compilation unit is supported, so the address range is simply231 // Currently only one compilation unit is supported, so the address range is simply
320 // identical to the main program header virtual address and memory size.232 // identical to the main program header virtual address and memory size.
321 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;233 const text_section = self.base.sections.items(.header)[self.base.text_section_index.?];
322 const text_section = text_segment.sections.items[self.text_section_index.?];
323 const low_pc = text_section.addr;234 const low_pc = text_section.addr;
324 const high_pc = text_section.addr + text_section.size;235 const high_pc = text_section.addr + text_section.size;
325 try self.dwarf.writeDbgInfoHeader(&self.base.base, module, low_pc, high_pc);236 try self.dwarf.writeDbgInfoHeader(&self.base.base, module, low_pc, high_pc);
...@@ -329,10 +240,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -329,10 +240,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
329 if (self.debug_aranges_section_dirty) {240 if (self.debug_aranges_section_dirty) {
330 // Currently only one compilation unit is supported, so the address range is simply241 // Currently only one compilation unit is supported, so the address range is simply
331 // identical to the main program header virtual address and memory size.242 // identical to the main program header virtual address and memory size.
332 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment;243 const text_section = self.base.sections.items(.header)[self.base.text_section_index.?];
333 const text_section = text_segment.sections.items[self.text_section_index.?];
334 try self.dwarf.writeDbgAranges(&self.base.base, text_section.addr, text_section.size);244 try self.dwarf.writeDbgAranges(&self.base.base, text_section.addr, text_section.size);
335 self.load_commands_dirty = true;
336 self.debug_aranges_section_dirty = false;245 self.debug_aranges_section_dirty = false;
337 }246 }
338247
...@@ -342,8 +251,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -342,8 +251,8 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
342 }251 }
343252
344 {253 {
345 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;254 const dwarf_segment = &self.segments.items[self.dwarf_segment_cmd_index.?];
346 const debug_strtab_sect = &dwarf_segment.sections.items[self.debug_str_section_index.?];255 const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];
347 if (self.debug_string_table_dirty or self.dwarf.strtab.items.len != debug_strtab_sect.size) {256 if (self.debug_string_table_dirty or self.dwarf.strtab.items.len != debug_strtab_sect.size) {
348 const allocated_size = self.allocatedSize(debug_strtab_sect.offset);257 const allocated_size = self.allocatedSize(debug_strtab_sect.offset);
349 const needed_size = self.dwarf.strtab.items.len;258 const needed_size = self.dwarf.strtab.items.len;
...@@ -351,7 +260,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -351,7 +260,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
351 if (needed_size > allocated_size) {260 if (needed_size > allocated_size) {
352 debug_strtab_sect.size = 0; // free the space261 debug_strtab_sect.size = 0; // free the space
353 const new_offset = self.findFreeSpace(needed_size, 1);262 const new_offset = self.findFreeSpace(needed_size, 1);
354 debug_strtab_sect.addr = dwarf_segment.inner.vmaddr + new_offset - dwarf_segment.inner.fileoff;263 debug_strtab_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff;
355 debug_strtab_sect.offset = @intCast(u32, new_offset);264 debug_strtab_sect.offset = @intCast(u32, new_offset);
356 }265 }
357 debug_strtab_sect.size = @intCast(u32, needed_size);266 debug_strtab_sect.size = @intCast(u32, needed_size);
...@@ -362,28 +271,53 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -362,28 +271,53 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
362 });271 });
363272
364 try self.file.pwriteAll(self.dwarf.strtab.items, debug_strtab_sect.offset);273 try self.file.pwriteAll(self.dwarf.strtab.items, debug_strtab_sect.offset);
365 self.load_commands_dirty = true;
366 self.debug_string_table_dirty = false;274 self.debug_string_table_dirty = false;
367 }275 }
368 }276 }
369277
278 var lc_buffer = std.ArrayList(u8).init(allocator);
279 defer lc_buffer.deinit();
280 const lc_writer = lc_buffer.writer();
281 var ncmds: u32 = 0;
282
283 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
370 self.updateDwarfSegment();284 self.updateDwarfSegment();
371 try self.writeLinkeditSegment();
372 try self.updateVirtualMemoryMapping();
373 try self.writeLoadCommands(allocator);
374 try self.writeHeader();
375285
376 assert(!self.load_commands_dirty);286 {
287 try lc_writer.writeStruct(self.base.uuid);
288 ncmds += 1;
289 }
290
291 var headers_buf = std.ArrayList(u8).init(allocator);
292 defer headers_buf.deinit();
293 try self.base.writeSegmentHeaders(
294 0,
295 self.base.linkedit_segment_cmd_index.?,
296 &ncmds,
297 headers_buf.writer(),
298 );
299
300 for (self.segments.items) |seg| {
301 try headers_buf.writer().writeStruct(seg);
302 ncmds += 2;
303 }
304 for (self.sections.items) |header| {
305 try headers_buf.writer().writeStruct(header);
306 }
307
308 try self.file.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
309 try self.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
310
311 try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
312
377 assert(!self.debug_abbrev_section_dirty);313 assert(!self.debug_abbrev_section_dirty);
378 assert(!self.debug_aranges_section_dirty);314 assert(!self.debug_aranges_section_dirty);
379 assert(!self.debug_string_table_dirty);315 assert(!self.debug_string_table_dirty);
380}316}
381317
382pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {318pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {
383 for (self.load_commands.items) |*lc| {319 self.segments.deinit(allocator);
384 lc.deinit(allocator);320 self.sections.deinit(allocator);
385 }
386 self.load_commands.deinit(allocator);
387 self.dwarf.deinit();321 self.dwarf.deinit();
388 self.strtab.deinit(allocator);322 self.strtab.deinit(allocator);
389 self.relocs.deinit(allocator);323 self.relocs.deinit(allocator);
...@@ -402,59 +336,19 @@ pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {...@@ -402,59 +336,19 @@ pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {
402 }336 }
403}337}
404338
405fn copySegmentCommand(339fn updateDwarfSegment(self: *DebugSymbols) void {
406 self: *DebugSymbols,340 const linkedit = self.segments.items[self.linkedit_segment_cmd_index.?];
407 allocator: Allocator,341 const dwarf_segment = &self.segments.items[self.dwarf_segment_cmd_index.?];
408 base_cmd: macho.SegmentCommand,
409) !macho.SegmentCommand {
410 var cmd = macho.SegmentCommand{
411 .inner = .{
412 .segname = undefined,
413 .cmdsize = base_cmd.inner.cmdsize,
414 .vmaddr = base_cmd.inner.vmaddr,
415 .vmsize = base_cmd.inner.vmsize,
416 .maxprot = base_cmd.inner.maxprot,
417 .initprot = base_cmd.inner.initprot,
418 .nsects = base_cmd.inner.nsects,
419 .flags = base_cmd.inner.flags,
420 },
421 };
422 mem.copy(u8, &cmd.inner.segname, &base_cmd.inner.segname);
423
424 try cmd.sections.ensureTotalCapacity(allocator, cmd.inner.nsects);
425 for (base_cmd.sections.items) |base_sect, i| {
426 var sect = macho.section_64{
427 .sectname = undefined,
428 .segname = undefined,
429 .addr = base_sect.addr,
430 .size = base_sect.size,
431 .offset = 0,
432 .@"align" = base_sect.@"align",
433 .reloff = 0,
434 .nreloc = 0,
435 .flags = base_sect.flags,
436 .reserved1 = base_sect.reserved1,
437 .reserved2 = base_sect.reserved2,
438 .reserved3 = base_sect.reserved3,
439 };
440 mem.copy(u8, &sect.sectname, &base_sect.sectname);
441 mem.copy(u8, &sect.segname, &base_sect.segname);
442
443 if (self.base.text_section_index.? == i) {
444 self.text_section_index = @intCast(u16, i);
445 }
446342
447 cmd.sections.appendAssumeCapacity(sect);343 const new_start_aligned = linkedit.vmaddr + linkedit.vmsize;
344 const old_start_aligned = dwarf_segment.vmaddr;
345 const diff = new_start_aligned - old_start_aligned;
346 if (diff > 0) {
347 dwarf_segment.vmaddr = new_start_aligned;
448 }348 }
449349
450 return cmd;
451}
452
453fn updateDwarfSegment(self: *DebugSymbols) void {
454 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
455
456 var max_offset: u64 = 0;350 var max_offset: u64 = 0;
457 for (dwarf_segment.sections.items) |sect| {351 for (self.sections.items) |*sect| {
458 log.debug(" {s},{s} - 0x{x}-0x{x} - 0x{x}-0x{x}", .{352 log.debug(" {s},{s} - 0x{x}-0x{x} - 0x{x}-0x{x}", .{
459 sect.segName(),353 sect.segName(),
460 sect.sectName(),354 sect.sectName(),
...@@ -466,44 +360,19 @@ fn updateDwarfSegment(self: *DebugSymbols) void {...@@ -466,44 +360,19 @@ fn updateDwarfSegment(self: *DebugSymbols) void {
466 if (sect.offset + sect.size > max_offset) {360 if (sect.offset + sect.size > max_offset) {
467 max_offset = sect.offset + sect.size;361 max_offset = sect.offset + sect.size;
468 }362 }
363 sect.addr += diff;
469 }364 }
470365
471 const file_size = max_offset - dwarf_segment.inner.fileoff;366 const file_size = max_offset - dwarf_segment.fileoff;
472 log.debug("__DWARF size 0x{x}", .{file_size});367 log.debug("__DWARF size 0x{x}", .{file_size});
473368
474 if (file_size != dwarf_segment.inner.filesize) {369 if (file_size != dwarf_segment.filesize) {
475 dwarf_segment.inner.filesize = file_size;370 dwarf_segment.filesize = file_size;
476 if (dwarf_segment.inner.vmsize < dwarf_segment.inner.filesize) {371 dwarf_segment.vmsize = mem.alignForwardGeneric(u64, dwarf_segment.filesize, self.base.page_size);
477 dwarf_segment.inner.vmsize = mem.alignForwardGeneric(u64, dwarf_segment.inner.filesize, self.base.page_size);
478 }
479 self.load_commands_dirty = true;
480 }
481}
482
483/// Writes all load commands and section headers.
484fn writeLoadCommands(self: *DebugSymbols, allocator: Allocator) !void {
485 if (!self.load_commands_dirty) return;
486
487 var sizeofcmds: u32 = 0;
488 for (self.load_commands.items) |lc| {
489 sizeofcmds += lc.cmdsize();
490 }372 }
491
492 var buffer = try allocator.alloc(u8, sizeofcmds);
493 defer allocator.free(buffer);
494 var fib = std.io.fixedBufferStream(buffer);
495 const writer = fib.writer();
496 for (self.load_commands.items) |lc| {
497 try lc.write(writer);
498 }
499
500 const off = @sizeOf(macho.mach_header_64);
501 log.debug("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds });
502 try self.file.pwriteAll(buffer, off);
503 self.load_commands_dirty = false;
504}373}
505374
506fn writeHeader(self: *DebugSymbols) !void {375fn writeHeader(self: *DebugSymbols, ncmds: u32, sizeofcmds: u32) !void {
507 var header: macho.mach_header_64 = .{};376 var header: macho.mach_header_64 = .{};
508 header.filetype = macho.MH_DSYM;377 header.filetype = macho.MH_DSYM;
509378
...@@ -519,12 +388,8 @@ fn writeHeader(self: *DebugSymbols) !void {...@@ -519,12 +388,8 @@ fn writeHeader(self: *DebugSymbols) !void {
519 else => return error.UnsupportedCpuArchitecture,388 else => return error.UnsupportedCpuArchitecture,
520 }389 }
521390
522 header.ncmds = @intCast(u32, self.load_commands.items.len);391 header.ncmds = ncmds;
523 header.sizeofcmds = 0;392 header.sizeofcmds = sizeofcmds;
524
525 for (self.load_commands.items) |cmd| {
526 header.sizeofcmds += cmd.cmdsize();
527 }
528393
529 log.debug("writing Mach-O header {}", .{header});394 log.debug("writing Mach-O header {}", .{header});
530395
...@@ -532,79 +397,46 @@ fn writeHeader(self: *DebugSymbols) !void {...@@ -532,79 +397,46 @@ fn writeHeader(self: *DebugSymbols) !void {
532}397}
533398
534pub fn allocatedSize(self: *DebugSymbols, start: u64) u64 {399pub fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
535 const seg = self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;400 const seg = self.segments.items[self.dwarf_segment_cmd_index.?];
536 assert(start >= seg.inner.fileoff);401 assert(start >= seg.fileoff);
537 var min_pos: u64 = std.math.maxInt(u64);402 var min_pos: u64 = std.math.maxInt(u64);
538 for (seg.sections.items) |section| {403 for (self.sections.items) |section| {
539 if (section.offset <= start) continue;404 if (section.offset <= start) continue;
540 if (section.offset < min_pos) min_pos = section.offset;405 if (section.offset < min_pos) min_pos = section.offset;
541 }406 }
542 return min_pos - start;407 return min_pos - start;
543}408}
544409
545fn updateVirtualMemoryMapping(self: *DebugSymbols) !void {410fn writeLinkeditSegmentData(self: *DebugSymbols, ncmds: *u32, lc_writer: anytype) !void {
546 const macho_file = self.base;
547 const allocator = macho_file.base.allocator;
548
549 const IndexTuple = std.meta.Tuple(&[_]type{ *?u16, *?u16 });
550 const indices = &[_]IndexTuple{
551 .{ &macho_file.text_segment_cmd_index, &self.text_segment_cmd_index },
552 .{ &macho_file.data_const_segment_cmd_index, &self.data_const_segment_cmd_index },
553 .{ &macho_file.data_segment_cmd_index, &self.data_segment_cmd_index },
554 };
555
556 for (indices) |tuple| {
557 const orig_cmd = macho_file.load_commands.items[tuple[0].*.?].segment;
558 const cmd = try self.copySegmentCommand(allocator, orig_cmd);
559 const comp_cmd = &self.load_commands.items[tuple[1].*.?];
560 comp_cmd.deinit(allocator);
561 self.load_commands.items[tuple[1].*.?] = .{ .segment = cmd };
562 }
563
564 // TODO should we set the linkedit vmsize to that of the binary?
565 const orig_cmd = macho_file.load_commands.items[macho_file.linkedit_segment_cmd_index.?].segment;
566 const orig_vmaddr = orig_cmd.inner.vmaddr;
567 const linkedit_cmd = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
568 linkedit_cmd.inner.vmaddr = orig_vmaddr;
569
570 // Update VM address for the DWARF segment and sections including re-running relocations.
571 // TODO re-run relocations
572 const dwarf_cmd = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
573 const new_start_aligned = orig_vmaddr + linkedit_cmd.inner.vmsize;
574 const old_start_aligned = dwarf_cmd.inner.vmaddr;
575 const diff = new_start_aligned - old_start_aligned;
576 if (diff > 0) {
577 dwarf_cmd.inner.vmaddr = new_start_aligned;
578
579 for (dwarf_cmd.sections.items) |*sect| {
580 sect.addr += (new_start_aligned - old_start_aligned);
581 }
582 }
583
584 self.load_commands_dirty = true;
585}
586
587fn writeLinkeditSegment(self: *DebugSymbols) !void {
588 const tracy = trace(@src());411 const tracy = trace(@src());
589 defer tracy.end();412 defer tracy.end();
590413
591 try self.writeSymbolTable();414 const source_vmaddr = self.base.segments.items[self.base.linkedit_segment_cmd_index.?].vmaddr;
592 try self.writeStringTable();415 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
416 seg.vmaddr = source_vmaddr;
593417
594 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;418 var symtab_cmd = macho.symtab_command{
595 const aligned_size = mem.alignForwardGeneric(u64, seg.inner.filesize, self.base.page_size);419 .cmdsize = @sizeOf(macho.symtab_command),
596 seg.inner.filesize = aligned_size;420 .symoff = 0,
597 seg.inner.vmsize = aligned_size;421 .nsyms = 0,
422 .stroff = 0,
423 .strsize = 0,
424 };
425 try self.writeSymtab(&symtab_cmd);
426 try self.writeStrtab(&symtab_cmd);
427 try lc_writer.writeStruct(symtab_cmd);
428 ncmds.* += 1;
429
430 const aligned_size = mem.alignForwardGeneric(u64, seg.filesize, self.base.page_size);
431 seg.filesize = aligned_size;
432 seg.vmsize = aligned_size;
598}433}
599434
600fn writeSymbolTable(self: *DebugSymbols) !void {435fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
601 const tracy = trace(@src());436 const tracy = trace(@src());
602 defer tracy.end();437 defer tracy.end();
603438
604 const gpa = self.base.base.allocator;439 const gpa = self.base.base.allocator;
605 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
606 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
607 symtab.symoff = @intCast(u32, seg.inner.fileoff);
608440
609 var locals = std.ArrayList(macho.nlist_64).init(gpa);441 var locals = std.ArrayList(macho.nlist_64).init(gpa);
610 defer locals.deinit();442 defer locals.deinit();
...@@ -634,34 +466,36 @@ fn writeSymbolTable(self: *DebugSymbols) !void {...@@ -634,34 +466,36 @@ fn writeSymbolTable(self: *DebugSymbols) !void {
634466
635 const nlocals = locals.items.len;467 const nlocals = locals.items.len;
636 const nexports = exports.items.len;468 const nexports = exports.items.len;
637 const locals_off = symtab.symoff;469 const nsyms = nlocals + nexports;
638 const locals_size = nlocals * @sizeOf(macho.nlist_64);
639 const exports_off = locals_off + locals_size;
640 const exports_size = nexports * @sizeOf(macho.nlist_64);
641470
642 symtab.nsyms = @intCast(u32, nlocals + nexports);471 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
643 const needed_size = (nlocals + nexports) * @sizeOf(macho.nlist_64);472 const offset = mem.alignForwardGeneric(
473 u64,
474 seg.fileoff + seg.filesize,
475 @alignOf(macho.nlist_64),
476 );
477 const needed_size = nsyms * @sizeOf(macho.nlist_64);
644478
645 if (needed_size > seg.inner.filesize) {479 if (needed_size > seg.filesize) {
646 const aligned_size = mem.alignForwardGeneric(u64, needed_size, self.base.page_size);480 const aligned_size = mem.alignForwardGeneric(u64, needed_size, self.base.page_size);
647 const diff = @intCast(u32, aligned_size - seg.inner.filesize);481 const diff = @intCast(u32, aligned_size - seg.filesize);
648 const dwarf_seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;482 const dwarf_seg = &self.segments.items[self.dwarf_segment_cmd_index.?];
649 seg.inner.filesize = aligned_size;483 seg.filesize = aligned_size;
650484
651 try MachO.copyRangeAllOverlappingAlloc(485 try MachO.copyRangeAllOverlappingAlloc(
652 self.base.base.allocator,486 self.base.base.allocator,
653 self.file,487 self.file,
654 dwarf_seg.inner.fileoff,488 dwarf_seg.fileoff,
655 dwarf_seg.inner.fileoff + diff,489 dwarf_seg.fileoff + diff,
656 math.cast(usize, dwarf_seg.inner.filesize) orelse return error.Overflow,490 math.cast(usize, dwarf_seg.filesize) orelse return error.Overflow,
657 );491 );
658492
659 const old_seg_fileoff = dwarf_seg.inner.fileoff;493 const old_seg_fileoff = dwarf_seg.fileoff;
660 dwarf_seg.inner.fileoff += diff;494 dwarf_seg.fileoff += diff;
661495
662 log.debug(" (moving __DWARF segment from 0x{x} to 0x{x})", .{ old_seg_fileoff, dwarf_seg.inner.fileoff });496 log.debug(" (moving __DWARF segment from 0x{x} to 0x{x})", .{ old_seg_fileoff, dwarf_seg.fileoff });
663497
664 for (dwarf_seg.sections.items) |*sect| {498 for (self.sections.items) |*sect| {
665 const old_offset = sect.offset;499 const old_offset = sect.offset;
666 sect.offset += diff;500 sect.offset += diff;
667501
...@@ -674,47 +508,53 @@ fn writeSymbolTable(self: *DebugSymbols) !void {...@@ -674,47 +508,53 @@ fn writeSymbolTable(self: *DebugSymbols) !void {
674 }508 }
675 }509 }
676510
511 lc.symoff = @intCast(u32, offset);
512 lc.nsyms = @intCast(u32, nsyms);
513
514 const locals_off = lc.symoff;
515 const locals_size = nlocals * @sizeOf(macho.nlist_64);
516 const exports_off = locals_off + locals_size;
517 const exports_size = nexports * @sizeOf(macho.nlist_64);
518
677 log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });519 log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });
678 try self.file.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);520 try self.file.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);
679521
680 log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off });522 log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off });
681 try self.file.pwriteAll(mem.sliceAsBytes(exports.items), exports_off);523 try self.file.pwriteAll(mem.sliceAsBytes(exports.items), exports_off);
682
683 self.load_commands_dirty = true;
684}524}
685525
686fn writeStringTable(self: *DebugSymbols) !void {526fn writeStrtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
687 const tracy = trace(@src());527 const tracy = trace(@src());
688 defer tracy.end();528 defer tracy.end();
689529
690 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;530 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
691 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;531 const symtab_size = @intCast(u32, lc.nsyms * @sizeOf(macho.nlist_64));
692 const symtab_size = @intCast(u32, symtab.nsyms * @sizeOf(macho.nlist_64));532 const offset = mem.alignForwardGeneric(u64, lc.symoff + symtab_size, @alignOf(u64));
693 symtab.stroff = symtab.symoff + symtab_size;533 lc.stroff = @intCast(u32, offset);
694534
695 const needed_size = mem.alignForwardGeneric(u64, self.strtab.buffer.items.len, @alignOf(u64));535 const needed_size = mem.alignForwardGeneric(u64, self.strtab.buffer.items.len, @alignOf(u64));
696 symtab.strsize = @intCast(u32, needed_size);536 lc.strsize = @intCast(u32, needed_size);
697537
698 if (symtab_size + needed_size > seg.inner.filesize) {538 if (offset + needed_size > seg.filesize) {
699 const aligned_size = mem.alignForwardGeneric(u64, symtab_size + needed_size, self.base.page_size);539 const aligned_size = mem.alignForwardGeneric(u64, offset + needed_size, self.base.page_size);
700 const diff = @intCast(u32, aligned_size - seg.inner.filesize);540 const diff = @intCast(u32, aligned_size - seg.filesize);
701 const dwarf_seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;541 const dwarf_seg = &self.segments.items[self.dwarf_segment_cmd_index.?];
702 seg.inner.filesize = aligned_size;542 seg.filesize = aligned_size;
703543
704 try MachO.copyRangeAllOverlappingAlloc(544 try MachO.copyRangeAllOverlappingAlloc(
705 self.base.base.allocator,545 self.base.base.allocator,
706 self.file,546 self.file,
707 dwarf_seg.inner.fileoff,547 dwarf_seg.fileoff,
708 dwarf_seg.inner.fileoff + diff,548 dwarf_seg.fileoff + diff,
709 math.cast(usize, dwarf_seg.inner.filesize) orelse return error.Overflow,549 math.cast(usize, dwarf_seg.filesize) orelse return error.Overflow,
710 );550 );
711551
712 const old_seg_fileoff = dwarf_seg.inner.fileoff;552 const old_seg_fileoff = dwarf_seg.fileoff;
713 dwarf_seg.inner.fileoff += diff;553 dwarf_seg.fileoff += diff;
714554
715 log.debug(" (moving __DWARF segment from 0x{x} to 0x{x})", .{ old_seg_fileoff, dwarf_seg.inner.fileoff });555 log.debug(" (moving __DWARF segment from 0x{x} to 0x{x})", .{ old_seg_fileoff, dwarf_seg.fileoff });
716556
717 for (dwarf_seg.sections.items) |*sect| {557 for (self.sections.items) |*sect| {
718 const old_offset = sect.offset;558 const old_offset = sect.offset;
719 sect.offset += diff;559 sect.offset += diff;
720560
...@@ -727,9 +567,7 @@ fn writeStringTable(self: *DebugSymbols) !void {...@@ -727,9 +567,7 @@ fn writeStringTable(self: *DebugSymbols) !void {
727 }567 }
728 }568 }
729569
730 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });570 log.debug("writing string table from 0x{x} to 0x{x}", .{ lc.stroff, lc.stroff + lc.strsize });
731
732 try self.file.pwriteAll(self.strtab.buffer.items, symtab.stroff);
733571
734 self.load_commands_dirty = true;572 try self.file.pwriteAll(self.strtab.buffer.items, lc.stroff);
735}573}
src/link/MachO/Dylib.zig+53-106
...@@ -13,23 +13,9 @@ const fat = @import("fat.zig");...@@ -13,23 +13,9 @@ const fat = @import("fat.zig");
13const Allocator = mem.Allocator;13const Allocator = mem.Allocator;
14const CrossTarget = std.zig.CrossTarget;14const CrossTarget = std.zig.CrossTarget;
15const LibStub = @import("../tapi.zig").LibStub;15const LibStub = @import("../tapi.zig").LibStub;
16const LoadCommandIterator = macho.LoadCommandIterator;
16const MachO = @import("../MachO.zig");17const MachO = @import("../MachO.zig");
1718
18file: fs.File,
19name: []const u8,
20
21header: ?macho.mach_header_64 = null,
22
23// The actual dylib contents we care about linking with will be embedded at
24// an offset within a file if we are linking against a fat lib
25library_offset: u64 = 0,
26
27load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},
28
29symtab_cmd_index: ?u16 = null,
30dysymtab_cmd_index: ?u16 = null,
31id_cmd_index: ?u16 = null,
32
33id: ?Id = null,19id: ?Id = null,
34weak: bool = false,20weak: bool = false,
3521
...@@ -53,16 +39,12 @@ pub const Id = struct {...@@ -53,16 +39,12 @@ pub const Id = struct {
53 };39 };
54 }40 }
5541
56 pub fn fromLoadCommand(allocator: Allocator, lc: macho.GenericCommandWithData(macho.dylib_command)) !Id {42 pub fn fromLoadCommand(allocator: Allocator, lc: macho.dylib_command, name: []const u8) !Id {
57 const dylib = lc.inner.dylib;
58 const dylib_name = @ptrCast([*:0]const u8, lc.data[dylib.name - @sizeOf(macho.dylib_command) ..]);
59 const name = try allocator.dupe(u8, mem.sliceTo(dylib_name, 0));
60
61 return Id{43 return Id{
62 .name = name,44 .name = try allocator.dupe(u8, name),
63 .timestamp = dylib.timestamp,45 .timestamp = lc.dylib.timestamp,
64 .current_version = dylib.current_version,46 .current_version = lc.dylib.current_version,
65 .compatibility_version = dylib.compatibility_version,47 .compatibility_version = lc.dylib.compatibility_version,
66 };48 };
67 }49 }
6850
...@@ -126,125 +108,89 @@ pub const Id = struct {...@@ -126,125 +108,89 @@ pub const Id = struct {
126};108};
127109
128pub fn deinit(self: *Dylib, allocator: Allocator) void {110pub fn deinit(self: *Dylib, allocator: Allocator) void {
129 for (self.load_commands.items) |*lc| {
130 lc.deinit(allocator);
131 }
132 self.load_commands.deinit(allocator);
133
134 for (self.symbols.keys()) |key| {111 for (self.symbols.keys()) |key| {
135 allocator.free(key);112 allocator.free(key);
136 }113 }
137 self.symbols.deinit(allocator);114 self.symbols.deinit(allocator);
138
139 allocator.free(self.name);
140
141 if (self.id) |*id| {115 if (self.id) |*id| {
142 id.deinit(allocator);116 id.deinit(allocator);
143 }117 }
144}118}
145119
146pub fn parse(120pub fn parseFromBinary(
147 self: *Dylib,121 self: *Dylib,
148 allocator: Allocator,122 allocator: Allocator,
149 cpu_arch: std.Target.Cpu.Arch,123 cpu_arch: std.Target.Cpu.Arch,
150 dylib_id: u16,124 dylib_id: u16,
151 dependent_libs: anytype,125 dependent_libs: anytype,
126 name: []const u8,
127 data: []align(@alignOf(u64)) const u8,
152) !void {128) !void {
153 log.debug("parsing shared library '{s}'", .{self.name});129 var stream = std.io.fixedBufferStream(data);
154130 const reader = stream.reader();
155 self.library_offset = try fat.getLibraryOffset(self.file.reader(), cpu_arch);
156131
157 try self.file.seekTo(self.library_offset);132 log.debug("parsing shared library '{s}'", .{name});
158133
159 var reader = self.file.reader();134 const header = try reader.readStruct(macho.mach_header_64);
160 self.header = try reader.readStruct(macho.mach_header_64);
161135
162 if (self.header.?.filetype != macho.MH_DYLIB) {136 if (header.filetype != macho.MH_DYLIB) {
163 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });137 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, header.filetype });
164 return error.NotDylib;138 return error.NotDylib;
165 }139 }
166140
167 const this_arch: std.Target.Cpu.Arch = try fat.decodeArch(self.header.?.cputype, true);141 const this_arch: std.Target.Cpu.Arch = try fat.decodeArch(header.cputype, true);
168142
169 if (this_arch != cpu_arch) {143 if (this_arch != cpu_arch) {
170 log.err("mismatched cpu architecture: expected {}, found {}", .{ cpu_arch, this_arch });144 log.err("mismatched cpu architecture: expected {s}, found {s}", .{
145 @tagName(cpu_arch),
146 @tagName(this_arch),
147 });
171 return error.MismatchedCpuArchitecture;148 return error.MismatchedCpuArchitecture;
172 }149 }
173150
174 try self.readLoadCommands(allocator, reader, dylib_id, dependent_libs);151 const should_lookup_reexports = header.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0;
175 try self.parseId(allocator);152 var it = LoadCommandIterator{
176 try self.parseSymbols(allocator);153 .ncmds = header.ncmds,
177}154 .buffer = data[@sizeOf(macho.mach_header_64)..][0..header.sizeofcmds],
178155 };
179fn readLoadCommands(156 while (it.next()) |cmd| {
180 self: *Dylib,
181 allocator: Allocator,
182 reader: anytype,
183 dylib_id: u16,
184 dependent_libs: anytype,
185) !void {
186 const should_lookup_reexports = self.header.?.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0;
187
188 try self.load_commands.ensureUnusedCapacity(allocator, self.header.?.ncmds);
189
190 var i: u16 = 0;
191 while (i < self.header.?.ncmds) : (i += 1) {
192 var cmd = try macho.LoadCommand.read(allocator, reader);
193 switch (cmd.cmd()) {157 switch (cmd.cmd()) {
194 .SYMTAB => {158 .SYMTAB => {
195 self.symtab_cmd_index = i;159 const symtab_cmd = cmd.cast(macho.symtab_command).?;
196 },160 const symtab = @ptrCast(
197 .DYSYMTAB => {161 [*]const macho.nlist_64,
198 self.dysymtab_cmd_index = i;162 @alignCast(@alignOf(macho.nlist_64), &data[symtab_cmd.symoff]),
163 )[0..symtab_cmd.nsyms];
164 const strtab = data[symtab_cmd.stroff..][0..symtab_cmd.strsize];
165
166 for (symtab) |sym| {
167 const add_to_symtab = sym.ext() and (sym.sect() or sym.indr());
168 if (!add_to_symtab) continue;
169
170 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);
171 try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, sym_name), {});
172 }
199 },173 },
200 .ID_DYLIB => {174 .ID_DYLIB => {
201 self.id_cmd_index = i;175 self.id = try Id.fromLoadCommand(
176 allocator,
177 cmd.cast(macho.dylib_command).?,
178 cmd.getDylibPathName(),
179 );
202 },180 },
203 .REEXPORT_DYLIB => {181 .REEXPORT_DYLIB => {
204 if (should_lookup_reexports) {182 if (should_lookup_reexports) {
205 // Parse install_name to dependent dylib.183 // Parse install_name to dependent dylib.
206 var id = try Id.fromLoadCommand(allocator, cmd.dylib);184 var id = try Id.fromLoadCommand(
185 allocator,
186 cmd.cast(macho.dylib_command).?,
187 cmd.getDylibPathName(),
188 );
207 try dependent_libs.writeItem(.{ .id = id, .parent = dylib_id });189 try dependent_libs.writeItem(.{ .id = id, .parent = dylib_id });
208 }190 }
209 },191 },
210 else => {192 else => {},
211 log.debug("Unknown load command detected: 0x{x}.", .{@enumToInt(cmd.cmd())});
212 },
213 }193 }
214 self.load_commands.appendAssumeCapacity(cmd);
215 }
216}
217
218fn parseId(self: *Dylib, allocator: Allocator) !void {
219 const index = self.id_cmd_index orelse {
220 log.debug("no LC_ID_DYLIB load command found; using hard-coded defaults...", .{});
221 self.id = try Id.default(allocator, self.name);
222 return;
223 };
224 self.id = try Id.fromLoadCommand(allocator, self.load_commands.items[index].dylib);
225}
226
227fn parseSymbols(self: *Dylib, allocator: Allocator) !void {
228 const index = self.symtab_cmd_index orelse return;
229 const symtab_cmd = self.load_commands.items[index].symtab;
230
231 const symtab = try allocator.alloc(u8, @sizeOf(macho.nlist_64) * symtab_cmd.nsyms);
232 defer allocator.free(symtab);
233 _ = try self.file.preadAll(symtab, symtab_cmd.symoff + self.library_offset);
234 const slice = @alignCast(@alignOf(macho.nlist_64), mem.bytesAsSlice(macho.nlist_64, symtab));
235
236 const strtab = try allocator.alloc(u8, symtab_cmd.strsize);
237 defer allocator.free(strtab);
238 _ = try self.file.preadAll(strtab, symtab_cmd.stroff + self.library_offset);
239
240 for (slice) |sym| {
241 const add_to_symtab = sym.ext() and (sym.sect() or sym.indr());
242
243 if (!add_to_symtab) continue;
244
245 const sym_name = mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx), 0);
246 const name = try allocator.dupe(u8, sym_name);
247 try self.symbols.putNoClobber(allocator, name, {});
248 }194 }
249}195}
250196
...@@ -356,10 +302,11 @@ pub fn parseFromStub(...@@ -356,10 +302,11 @@ pub fn parseFromStub(
356 lib_stub: LibStub,302 lib_stub: LibStub,
357 dylib_id: u16,303 dylib_id: u16,
358 dependent_libs: anytype,304 dependent_libs: anytype,
305 name: []const u8,
359) !void {306) !void {
360 if (lib_stub.inner.len == 0) return error.EmptyStubFile;307 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
361308
362 log.debug("parsing shared library from stub '{s}'", .{self.name});309 log.debug("parsing shared library from stub '{s}'", .{name});
363310
364 const umbrella_lib = lib_stub.inner[0];311 const umbrella_lib = lib_stub.inner[0];
365312
src/link/MachO/Object.zig+134-172
...@@ -3,6 +3,7 @@ const Object = @This();...@@ -3,6 +3,7 @@ const Object = @This();
3const std = @import("std");3const std = @import("std");
4const build_options = @import("build_options");4const build_options = @import("build_options");
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const dwarf = std.dwarf;
6const fs = std.fs;7const fs = std.fs;
7const io = std.io;8const io = std.io;
8const log = std.log.scoped(.link);9const log = std.log.scoped(.link);
...@@ -14,43 +15,20 @@ const trace = @import("../../tracy.zig").trace;...@@ -14,43 +15,20 @@ const trace = @import("../../tracy.zig").trace;
1415
15const Allocator = mem.Allocator;16const Allocator = mem.Allocator;
16const Atom = @import("Atom.zig");17const Atom = @import("Atom.zig");
18const LoadCommandIterator = macho.LoadCommandIterator;
17const MachO = @import("../MachO.zig");19const MachO = @import("../MachO.zig");
18const MatchingSection = MachO.MatchingSection;
19const SymbolWithLoc = MachO.SymbolWithLoc;20const SymbolWithLoc = MachO.SymbolWithLoc;
2021
21file: fs.File,
22name: []const u8,22name: []const u8,
23mtime: u64,23mtime: u64,
2424contents: []align(@alignOf(u64)) const u8,
25/// Data contents of the file. Includes sections, and data of load commands.
26/// Excludes the backing memory for the header and load commands.
27/// Initialized in `parse`.
28contents: []const u8 = undefined,
29
30file_offset: ?u32 = null,
3125
32header: macho.mach_header_64 = undefined,26header: macho.mach_header_64 = undefined,
3327in_symtab: []const macho.nlist_64 = undefined,
34load_commands: std.ArrayListUnmanaged(macho.LoadCommand) = .{},28in_strtab: []const u8 = undefined,
35
36segment_cmd_index: ?u16 = null,
37text_section_index: ?u16 = null,
38symtab_cmd_index: ?u16 = null,
39dysymtab_cmd_index: ?u16 = null,
40build_version_cmd_index: ?u16 = null,
41data_in_code_cmd_index: ?u16 = null,
42
43// __DWARF segment sections
44dwarf_debug_info_index: ?u16 = null,
45dwarf_debug_abbrev_index: ?u16 = null,
46dwarf_debug_str_index: ?u16 = null,
47dwarf_debug_line_index: ?u16 = null,
48dwarf_debug_line_str_index: ?u16 = null,
49dwarf_debug_ranges_index: ?u16 = null,
5029
51symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},30symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
52strtab: []const u8 = &.{},31sections: std.ArrayListUnmanaged(macho.section_64) = .{},
53data_in_code_entries: []const macho.data_in_code_entry = &.{},
5432
55sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{},33sections_as_symbols: std.AutoHashMapUnmanaged(u16, u32) = .{},
5634
...@@ -61,12 +39,8 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},...@@ -61,12 +39,8 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
61atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},39atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
6240
63pub fn deinit(self: *Object, gpa: Allocator) void {41pub fn deinit(self: *Object, gpa: Allocator) void {
64 for (self.load_commands.items) |*lc| {
65 lc.deinit(gpa);
66 }
67 self.load_commands.deinit(gpa);
68 gpa.free(self.contents);
69 self.symtab.deinit(gpa);42 self.symtab.deinit(gpa);
43 self.sections.deinit(gpa);
70 self.sections_as_symbols.deinit(gpa);44 self.sections_as_symbols.deinit(gpa);
71 self.atom_by_index_table.deinit(gpa);45 self.atom_by_index_table.deinit(gpa);
7246
...@@ -77,22 +51,15 @@ pub fn deinit(self: *Object, gpa: Allocator) void {...@@ -77,22 +51,15 @@ pub fn deinit(self: *Object, gpa: Allocator) void {
77 self.managed_atoms.deinit(gpa);51 self.managed_atoms.deinit(gpa);
7852
79 gpa.free(self.name);53 gpa.free(self.name);
54 gpa.free(self.contents);
80}55}
8156
82pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) !void {57pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) !void {
83 const file_stat = try self.file.stat();
84 const file_size = math.cast(usize, file_stat.size) orelse return error.Overflow;
85 self.contents = try self.file.readToEndAlloc(allocator, file_size);
86
87 var stream = std.io.fixedBufferStream(self.contents);58 var stream = std.io.fixedBufferStream(self.contents);
88 const reader = stream.reader();59 const reader = stream.reader();
8960
90 const file_offset = self.file_offset orelse 0;
91 if (file_offset > 0) {
92 try reader.context.seekTo(file_offset);
93 }
94
95 self.header = try reader.readStruct(macho.mach_header_64);61 self.header = try reader.readStruct(macho.mach_header_64);
62
96 if (self.header.filetype != macho.MH_OBJECT) {63 if (self.header.filetype != macho.MH_OBJECT) {
97 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{64 log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{
98 macho.MH_OBJECT,65 macho.MH_OBJECT,
...@@ -110,92 +77,54 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)...@@ -110,92 +77,54 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
110 },77 },
111 };78 };
112 if (this_arch != cpu_arch) {79 if (this_arch != cpu_arch) {
113 log.err("mismatched cpu architecture: expected {}, found {}", .{ cpu_arch, this_arch });80 log.err("mismatched cpu architecture: expected {s}, found {s}", .{
81 @tagName(cpu_arch),
82 @tagName(this_arch),
83 });
114 return error.MismatchedCpuArchitecture;84 return error.MismatchedCpuArchitecture;
115 }85 }
11686
117 try self.load_commands.ensureUnusedCapacity(allocator, self.header.ncmds);87 var it = LoadCommandIterator{
11888 .ncmds = self.header.ncmds,
119 var i: u16 = 0;89 .buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
120 while (i < self.header.ncmds) : (i += 1) {90 };
121 var cmd = try macho.LoadCommand.read(allocator, reader);91 while (it.next()) |cmd| {
122 switch (cmd.cmd()) {92 switch (cmd.cmd()) {
123 .SEGMENT_64 => {93 .SEGMENT_64 => {
124 self.segment_cmd_index = i;94 const segment = cmd.cast(macho.segment_command_64).?;
125 var seg = cmd.segment;95 try self.sections.ensureUnusedCapacity(allocator, segment.nsects);
126 for (seg.sections.items) |*sect, j| {96 for (cmd.getSections()) |sect| {
127 const index = @intCast(u16, j);97 self.sections.appendAssumeCapacity(sect);
128 const segname = sect.segName();
129 const sectname = sect.sectName();
130 if (mem.eql(u8, segname, "__DWARF")) {
131 if (mem.eql(u8, sectname, "__debug_info")) {
132 self.dwarf_debug_info_index = index;
133 } else if (mem.eql(u8, sectname, "__debug_abbrev")) {
134 self.dwarf_debug_abbrev_index = index;
135 } else if (mem.eql(u8, sectname, "__debug_str")) {
136 self.dwarf_debug_str_index = index;
137 } else if (mem.eql(u8, sectname, "__debug_line")) {
138 self.dwarf_debug_line_index = index;
139 } else if (mem.eql(u8, sectname, "__debug_line_str")) {
140 self.dwarf_debug_line_str_index = index;
141 } else if (mem.eql(u8, sectname, "__debug_ranges")) {
142 self.dwarf_debug_ranges_index = index;
143 }
144 } else if (mem.eql(u8, segname, "__TEXT")) {
145 if (mem.eql(u8, sectname, "__text")) {
146 self.text_section_index = index;
147 }
148 }
149
150 sect.offset += file_offset;
151 if (sect.reloff > 0) {
152 sect.reloff += file_offset;
153 }
154 }98 }
155
156 seg.inner.fileoff += file_offset;
157 },99 },
158 .SYMTAB => {100 .SYMTAB => {
159 self.symtab_cmd_index = i;101 const symtab = cmd.cast(macho.symtab_command).?;
160 cmd.symtab.symoff += file_offset;102 self.in_symtab = @ptrCast(
161 cmd.symtab.stroff += file_offset;103 [*]const macho.nlist_64,
162 },104 @alignCast(@alignOf(macho.nlist_64), &self.contents[symtab.symoff]),
163 .DYSYMTAB => {105 )[0..symtab.nsyms];
164 self.dysymtab_cmd_index = i;106 self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize];
165 },107 try self.symtab.appendSlice(allocator, self.in_symtab);
166 .BUILD_VERSION => {
167 self.build_version_cmd_index = i;
168 },
169 .DATA_IN_CODE => {
170 self.data_in_code_cmd_index = i;
171 cmd.linkedit_data.dataoff += file_offset;
172 },
173 else => {
174 log.debug("Unknown load command detected: 0x{x}.", .{@enumToInt(cmd.cmd())});
175 },108 },
109 else => {},
176 }110 }
177 self.load_commands.appendAssumeCapacity(cmd);
178 }111 }
179
180 try self.parseSymtab(allocator);
181}112}
182113
183const Context = struct {114const Context = struct {
184 symtab: []const macho.nlist_64,115 object: *const Object,
185 strtab: []const u8,
186};116};
187117
188const SymbolAtIndex = struct {118const SymbolAtIndex = struct {
189 index: u32,119 index: u32,
190120
191 fn getSymbol(self: SymbolAtIndex, ctx: Context) macho.nlist_64 {121 fn getSymbol(self: SymbolAtIndex, ctx: Context) macho.nlist_64 {
192 return ctx.symtab[self.index];122 return ctx.object.getSourceSymbol(self.index).?;
193 }123 }
194124
195 fn getSymbolName(self: SymbolAtIndex, ctx: Context) []const u8 {125 fn getSymbolName(self: SymbolAtIndex, ctx: Context) []const u8 {
196 const sym = self.getSymbol(ctx);126 const sym = self.getSymbol(ctx);
197 assert(sym.n_strx < ctx.strtab.len);127 return ctx.object.getString(sym.n_strx);
198 return mem.sliceTo(@ptrCast([*:0]const u8, ctx.strtab.ptr + sym.n_strx), 0);
199 }128 }
200129
201 /// Returns whether lhs is less than rhs by allocated address in object file.130 /// Returns whether lhs is less than rhs by allocated address in object file.
...@@ -293,7 +222,6 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -293,7 +222,6 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
293 defer tracy.end();222 defer tracy.end();
294223
295 const gpa = macho_file.base.allocator;224 const gpa = macho_file.base.allocator;
296 const seg = self.load_commands.items[self.segment_cmd_index.?].segment;
297225
298 log.debug("splitting object({d}, {s}) into atoms: one-shot mode", .{ object_id, self.name });226 log.debug("splitting object({d}, {s}) into atoms: one-shot mode", .{ object_id, self.name });
299227
...@@ -302,13 +230,12 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -302,13 +230,12 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
302 // the GO compiler does not necessarily respect that therefore we sort immediately by type230 // the GO compiler does not necessarily respect that therefore we sort immediately by type
303 // and address within.231 // and address within.
304 const context = Context{232 const context = Context{
305 .symtab = self.getSourceSymtab(),233 .object = self,
306 .strtab = self.strtab,
307 };234 };
308 var sorted_all_syms = try std.ArrayList(SymbolAtIndex).initCapacity(gpa, context.symtab.len);235 var sorted_all_syms = try std.ArrayList(SymbolAtIndex).initCapacity(gpa, self.in_symtab.len);
309 defer sorted_all_syms.deinit();236 defer sorted_all_syms.deinit();
310237
311 for (context.symtab) |_, index| {238 for (self.in_symtab) |_, index| {
312 sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) });239 sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) });
313 }240 }
314241
...@@ -320,36 +247,36 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -320,36 +247,36 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
320247
321 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we248 // Well, shit, sometimes compilers skip the dysymtab load command altogether, meaning we
322 // have to infer the start of undef section in the symtab ourselves.249 // have to infer the start of undef section in the symtab ourselves.
323 const iundefsym = if (self.dysymtab_cmd_index) |cmd_index| blk: {250 const iundefsym = blk: {
324 const dysymtab = self.load_commands.items[cmd_index].dysymtab;251 const dysymtab = self.parseDysymtab() orelse {
252 var iundefsym: usize = sorted_all_syms.items.len;
253 while (iundefsym > 0) : (iundefsym -= 1) {
254 const sym = sorted_all_syms.items[iundefsym - 1].getSymbol(context);
255 if (sym.sect()) break;
256 }
257 break :blk iundefsym;
258 };
325 break :blk dysymtab.iundefsym;259 break :blk dysymtab.iundefsym;
326 } else blk: {
327 var iundefsym: usize = sorted_all_syms.items.len;
328 while (iundefsym > 0) : (iundefsym -= 1) {
329 const sym = sorted_all_syms.items[iundefsym - 1].getSymbol(context);
330 if (sym.sect()) break;
331 }
332 break :blk iundefsym;
333 };260 };
334261
335 // We only care about defined symbols, so filter every other out.262 // We only care about defined symbols, so filter every other out.
336 const sorted_syms = sorted_all_syms.items[0..iundefsym];263 const sorted_syms = sorted_all_syms.items[0..iundefsym];
337 const subsections_via_symbols = self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;264 const subsections_via_symbols = self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
338265
339 for (seg.sections.items) |sect, id| {266 for (self.sections.items) |sect, id| {
340 const sect_id = @intCast(u8, id);267 const sect_id = @intCast(u8, id);
341 log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() });268 log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() });
342269
343 // Get matching segment/section in the final artifact.270 // Get matching segment/section in the final artifact.
344 const match = (try macho_file.getMatchingSection(sect)) orelse {271 const match = (try macho_file.getOutputSection(sect)) orelse {
345 log.debug(" unhandled section", .{});272 log.debug(" unhandled section", .{});
346 continue;273 continue;
347 };274 };
348275
349 log.debug(" output sect({d}, '{s},{s}')", .{276 log.debug(" output sect({d}, '{s},{s}')", .{
350 macho_file.getSectionOrdinal(match),277 match + 1,
351 macho_file.getSection(match).segName(),278 macho_file.sections.items(.header)[match].segName(),
352 macho_file.getSection(match).sectName(),279 macho_file.sections.items(.header)[match].sectName(),
353 });280 });
354281
355 const cpu_arch = macho_file.base.options.target.cpu.arch;282 const cpu_arch = macho_file.base.options.target.cpu.arch;
...@@ -359,14 +286,13 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -359,14 +286,13 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
359 };286 };
360287
361 // Read section's code288 // Read section's code
362 const code: ?[]const u8 = if (!is_zerofill) try self.getSectionContents(sect_id) else null;289 const code: ?[]const u8 = if (!is_zerofill) try self.getSectionContents(sect) else null;
363290
364 // Read section's list of relocations291 // Read section's list of relocations
365 const raw_relocs = self.contents[sect.reloff..][0 .. sect.nreloc * @sizeOf(macho.relocation_info)];292 const relocs = @ptrCast(
366 const relocs = mem.bytesAsSlice(293 [*]const macho.relocation_info,
367 macho.relocation_info,294 @alignCast(@alignOf(macho.relocation_info), &self.contents[sect.reloff]),
368 @alignCast(@alignOf(macho.relocation_info), raw_relocs),295 )[0..sect.nreloc];
369 );
370296
371 // Symbols within this section only.297 // Symbols within this section only.
372 const filtered_syms = filterSymbolsByAddress(298 const filtered_syms = filterSymbolsByAddress(
...@@ -387,7 +313,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -387,7 +313,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
387 try self.symtab.append(gpa, .{313 try self.symtab.append(gpa, .{
388 .n_strx = 0,314 .n_strx = 0,
389 .n_type = macho.N_SECT,315 .n_type = macho.N_SECT,
390 .n_sect = macho_file.getSectionOrdinal(match),316 .n_sect = match + 1,
391 .n_desc = 0,317 .n_desc = 0,
392 .n_value = sect.addr,318 .n_value = sect.addr,
393 });319 });
...@@ -476,7 +402,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -476,7 +402,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
476 try self.symtab.append(gpa, .{402 try self.symtab.append(gpa, .{
477 .n_strx = 0,403 .n_strx = 0,
478 .n_type = macho.N_SECT,404 .n_type = macho.N_SECT,
479 .n_sect = macho_file.getSectionOrdinal(match),405 .n_sect = match + 1,
480 .n_desc = 0,406 .n_desc = 0,
481 .n_value = addr,407 .n_value = addr,
482 });408 });
...@@ -501,7 +427,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -501,7 +427,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
501 try self.symtab.append(gpa, .{427 try self.symtab.append(gpa, .{
502 .n_strx = 0,428 .n_strx = 0,
503 .n_type = macho.N_SECT,429 .n_type = macho.N_SECT,
504 .n_sect = macho_file.getSectionOrdinal(match),430 .n_sect = match + 1,
505 .n_desc = 0,431 .n_desc = 0,
506 .n_value = sect.addr,432 .n_value = sect.addr,
507 });433 });
...@@ -535,21 +461,21 @@ fn createAtomFromSubsection(...@@ -535,21 +461,21 @@ fn createAtomFromSubsection(
535 code: ?[]const u8,461 code: ?[]const u8,
536 relocs: []const macho.relocation_info,462 relocs: []const macho.relocation_info,
537 indexes: []const SymbolAtIndex,463 indexes: []const SymbolAtIndex,
538 match: MatchingSection,464 match: u8,
539 sect: macho.section_64,465 sect: macho.section_64,
540) !*Atom {466) !*Atom {
541 const gpa = macho_file.base.allocator;467 const gpa = macho_file.base.allocator;
542 const sym = self.symtab.items[sym_index];468 const sym = self.symtab.items[sym_index];
543 const atom = try MachO.createEmptyAtom(gpa, sym_index, size, alignment);469 const atom = try MachO.createEmptyAtom(gpa, sym_index, size, alignment);
544 atom.file = object_id;470 atom.file = object_id;
545 self.symtab.items[sym_index].n_sect = macho_file.getSectionOrdinal(match);471 self.symtab.items[sym_index].n_sect = match + 1;
546472
547 log.debug("creating ATOM(%{d}, '{s}') in sect({d}, '{s},{s}') in object({d})", .{473 log.debug("creating ATOM(%{d}, '{s}') in sect({d}, '{s},{s}') in object({d})", .{
548 sym_index,474 sym_index,
549 self.getString(sym.n_strx),475 self.getString(sym.n_strx),
550 macho_file.getSectionOrdinal(match),476 match + 1,
551 macho_file.getSection(match).segName(),477 macho_file.sections.items(.header)[match].segName(),
552 macho_file.getSection(match).sectName(),478 macho_file.sections.items(.header)[match].sectName(),
553 object_id,479 object_id,
554 });480 });
555481
...@@ -577,7 +503,7 @@ fn createAtomFromSubsection(...@@ -577,7 +503,7 @@ fn createAtomFromSubsection(
577 try atom.contained.ensureTotalCapacity(gpa, indexes.len);503 try atom.contained.ensureTotalCapacity(gpa, indexes.len);
578 for (indexes) |inner_sym_index| {504 for (indexes) |inner_sym_index| {
579 const inner_sym = &self.symtab.items[inner_sym_index.index];505 const inner_sym = &self.symtab.items[inner_sym_index.index];
580 inner_sym.n_sect = macho_file.getSectionOrdinal(match);506 inner_sym.n_sect = match + 1;
581 atom.contained.appendAssumeCapacity(.{507 atom.contained.appendAssumeCapacity(.{
582 .sym_index = inner_sym_index.index,508 .sym_index = inner_sym_index.index,
583 .offset = inner_sym.n_value - sym.n_value,509 .offset = inner_sym.n_value - sym.n_value,
...@@ -589,48 +515,84 @@ fn createAtomFromSubsection(...@@ -589,48 +515,84 @@ fn createAtomFromSubsection(
589 return atom;515 return atom;
590}516}
591517
592fn parseSymtab(self: *Object, allocator: Allocator) !void {518pub fn getSourceSymbol(self: Object, index: u32) ?macho.nlist_64 {
593 const index = self.symtab_cmd_index orelse return;519 if (index >= self.in_symtab.len) return null;
594 const symtab = self.load_commands.items[index].symtab;520 return self.in_symtab[index];
595 try self.symtab.appendSlice(allocator, self.getSourceSymtab());
596 self.strtab = self.contents[symtab.stroff..][0..symtab.strsize];
597}521}
598522
599pub fn getSourceSymtab(self: Object) []const macho.nlist_64 {523pub fn getSourceSection(self: Object, index: u16) macho.section_64 {
600 const index = self.symtab_cmd_index orelse return &[0]macho.nlist_64{};524 assert(index < self.sections.items.len);
601 const symtab = self.load_commands.items[index].symtab;525 return self.sections.items[index];
602 const symtab_size = @sizeOf(macho.nlist_64) * symtab.nsyms;
603 const raw_symtab = self.contents[symtab.symoff..][0..symtab_size];
604 return mem.bytesAsSlice(
605 macho.nlist_64,
606 @alignCast(@alignOf(macho.nlist_64), raw_symtab),
607 );
608}526}
609527
610pub fn getSourceSymbol(self: Object, index: u32) ?macho.nlist_64 {528pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry {
611 const symtab = self.getSourceSymtab();529 var it = LoadCommandIterator{
612 if (index >= symtab.len) return null;530 .ncmds = self.header.ncmds,
613 return symtab[index];531 .buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
532 };
533 while (it.next()) |cmd| {
534 switch (cmd.cmd()) {
535 .DATA_IN_CODE => {
536 const dice = cmd.cast(macho.linkedit_data_command).?;
537 const ndice = @divExact(dice.datasize, @sizeOf(macho.data_in_code_entry));
538 return @ptrCast(
539 [*]const macho.data_in_code_entry,
540 @alignCast(@alignOf(macho.data_in_code_entry), &self.contents[dice.dataoff]),
541 )[0..ndice];
542 },
543 else => {},
544 }
545 } else return null;
614}546}
615547
616pub fn getSourceSection(self: Object, index: u16) macho.section_64 {548fn parseDysymtab(self: Object) ?macho.dysymtab_command {
617 const seg = self.load_commands.items[self.segment_cmd_index.?].segment;549 var it = LoadCommandIterator{
618 assert(index < seg.sections.items.len);550 .ncmds = self.header.ncmds,
619 return seg.sections.items[index];551 .buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
552 };
553 while (it.next()) |cmd| {
554 switch (cmd.cmd()) {
555 .DYSYMTAB => {
556 return cmd.cast(macho.dysymtab_command).?;
557 },
558 else => {},
559 }
560 } else return null;
620}561}
621562
622pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry {563pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {
623 const index = self.data_in_code_cmd_index orelse return null;564 var di = dwarf.DwarfInfo{
624 const data_in_code = self.load_commands.items[index].linkedit_data;565 .endian = .Little,
625 const raw_dice = self.contents[data_in_code.dataoff..][0..data_in_code.datasize];566 .debug_info = &[0]u8{},
626 return mem.bytesAsSlice(567 .debug_abbrev = &[0]u8{},
627 macho.data_in_code_entry,568 .debug_str = &[0]u8{},
628 @alignCast(@alignOf(macho.data_in_code_entry), raw_dice),569 .debug_line = &[0]u8{},
629 );570 .debug_line_str = &[0]u8{},
571 .debug_ranges = &[0]u8{},
572 };
573 for (self.sections.items) |sect| {
574 const segname = sect.segName();
575 const sectname = sect.sectName();
576 if (mem.eql(u8, segname, "__DWARF")) {
577 if (mem.eql(u8, sectname, "__debug_info")) {
578 di.debug_info = try self.getSectionContents(sect);
579 } else if (mem.eql(u8, sectname, "__debug_abbrev")) {
580 di.debug_abbrev = try self.getSectionContents(sect);
581 } else if (mem.eql(u8, sectname, "__debug_str")) {
582 di.debug_str = try self.getSectionContents(sect);
583 } else if (mem.eql(u8, sectname, "__debug_line")) {
584 di.debug_line = try self.getSectionContents(sect);
585 } else if (mem.eql(u8, sectname, "__debug_line_str")) {
586 di.debug_line_str = try self.getSectionContents(sect);
587 } else if (mem.eql(u8, sectname, "__debug_ranges")) {
588 di.debug_ranges = try self.getSectionContents(sect);
589 }
590 }
591 }
592 return di;
630}593}
631594
632pub fn getSectionContents(self: Object, index: u16) error{Overflow}![]const u8 {595pub fn getSectionContents(self: Object, sect: macho.section_64) error{Overflow}![]const u8 {
633 const sect = self.getSourceSection(index);
634 const size = math.cast(usize, sect.size) orelse return error.Overflow;596 const size = math.cast(usize, sect.size) orelse return error.Overflow;
635 log.debug("getting {s},{s} data at 0x{x} - 0x{x}", .{597 log.debug("getting {s},{s} data at 0x{x} - 0x{x}", .{
636 sect.segName(),598 sect.segName(),
...@@ -642,8 +604,8 @@ pub fn getSectionContents(self: Object, index: u16) error{Overflow}![]const u8 {...@@ -642,8 +604,8 @@ pub fn getSectionContents(self: Object, index: u16) error{Overflow}![]const u8 {
642}604}
643605
644pub fn getString(self: Object, off: u32) []const u8 {606pub fn getString(self: Object, off: u32) []const u8 {
645 assert(off < self.strtab.len);607 assert(off < self.in_strtab.len);
646 return mem.sliceTo(@ptrCast([*:0]const u8, self.strtab.ptr + off), 0);608 return mem.sliceTo(@ptrCast([*:0]const u8, self.in_strtab.ptr + off), 0);
647}609}
648610
649pub fn getAtomForSymbol(self: Object, sym_index: u32) ?*Atom {611pub fn getAtomForSymbol(self: Object, sym_index: u32) ?*Atom {
src/link/MachO/dead_strip.zig+25-23
...@@ -8,7 +8,6 @@ const mem = std.mem;...@@ -8,7 +8,6 @@ const mem = std.mem;
8const Allocator = mem.Allocator;8const Allocator = mem.Allocator;
9const Atom = @import("Atom.zig");9const Atom = @import("Atom.zig");
10const MachO = @import("../MachO.zig");10const MachO = @import("../MachO.zig");
11const MatchingSection = MachO.MatchingSection;
1211
13pub fn gcAtoms(macho_file: *MachO) !void {12pub fn gcAtoms(macho_file: *MachO) !void {
14 const gpa = macho_file.base.allocator;13 const gpa = macho_file.base.allocator;
...@@ -25,12 +24,12 @@ pub fn gcAtoms(macho_file: *MachO) !void {...@@ -25,12 +24,12 @@ pub fn gcAtoms(macho_file: *MachO) !void {
25 try prune(arena, alive, macho_file);24 try prune(arena, alive, macho_file);
26}25}
2726
28fn removeAtomFromSection(atom: *Atom, match: MatchingSection, macho_file: *MachO) void {27fn removeAtomFromSection(atom: *Atom, match: u8, macho_file: *MachO) void {
29 const sect = macho_file.getSectionPtr(match);28 var section = macho_file.sections.get(match);
3029
31 // If we want to enable GC for incremental codepath, we need to take into30 // If we want to enable GC for incremental codepath, we need to take into
32 // account any padding that might have been left here.31 // account any padding that might have been left here.
33 sect.size -= atom.size;32 section.header.size -= atom.size;
3433
35 if (atom.prev) |prev| {34 if (atom.prev) |prev| {
36 prev.next = atom.next;35 prev.next = atom.next;
...@@ -38,15 +37,16 @@ fn removeAtomFromSection(atom: *Atom, match: MatchingSection, macho_file: *MachO...@@ -38,15 +37,16 @@ fn removeAtomFromSection(atom: *Atom, match: MatchingSection, macho_file: *MachO
38 if (atom.next) |next| {37 if (atom.next) |next| {
39 next.prev = atom.prev;38 next.prev = atom.prev;
40 } else {39 } else {
41 const last = macho_file.atoms.getPtr(match).?;
42 if (atom.prev) |prev| {40 if (atom.prev) |prev| {
43 last.* = prev;41 section.last_atom = prev;
44 } else {42 } else {
45 // The section will be GCed in the next step.43 // The section will be GCed in the next step.
46 last.* = undefined;44 section.last_atom = null;
47 sect.size = 0;45 section.header.size = 0;
48 }46 }
49 }47 }
48
49 macho_file.sections.set(match, section);
50}50}
5151
52fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void {52fn collectRoots(roots: *std.AutoHashMap(*Atom, void), macho_file: *MachO) !void {
...@@ -173,19 +173,19 @@ fn mark(...@@ -173,19 +173,19 @@ fn mark(
173fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *MachO) !void {173fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *MachO) !void {
174 // Any section that ends up here will be updated, that is,174 // Any section that ends up here will be updated, that is,
175 // its size and alignment recalculated.175 // its size and alignment recalculated.
176 var gc_sections = std.AutoHashMap(MatchingSection, void).init(arena);176 var gc_sections = std.AutoHashMap(u8, void).init(arena);
177 var loop: bool = true;177 var loop: bool = true;
178 while (loop) {178 while (loop) {
179 loop = false;179 loop = false;
180180
181 for (macho_file.objects.items) |object| {181 for (macho_file.objects.items) |object| {
182 for (object.getSourceSymtab()) |_, source_index| {182 for (object.in_symtab) |_, source_index| {
183 const atom = object.getAtomForSymbol(@intCast(u32, source_index)) orelse continue;183 const atom = object.getAtomForSymbol(@intCast(u32, source_index)) orelse continue;
184 if (alive.contains(atom)) continue;184 if (alive.contains(atom)) continue;
185185
186 const global = atom.getSymbolWithLoc();186 const global = atom.getSymbolWithLoc();
187 const sym = atom.getSymbolPtr(macho_file);187 const sym = atom.getSymbolPtr(macho_file);
188 const match = macho_file.getMatchingSectionFromOrdinal(sym.n_sect);188 const match = sym.n_sect - 1;
189189
190 if (sym.n_desc == MachO.N_DESC_GCED) continue;190 if (sym.n_desc == MachO.N_DESC_GCED) continue;
191 if (!sym.ext() and !refersDead(atom, macho_file)) continue;191 if (!sym.ext() and !refersDead(atom, macho_file)) continue;
...@@ -232,7 +232,7 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac...@@ -232,7 +232,7 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac
232232
233 // TODO tombstone233 // TODO tombstone
234 const atom = entry.getAtom(macho_file);234 const atom = entry.getAtom(macho_file);
235 const match = macho_file.getMatchingSectionFromOrdinal(sym.n_sect);235 const match = sym.n_sect - 1;
236 removeAtomFromSection(atom, match, macho_file);236 removeAtomFromSection(atom, match, macho_file);
237 _ = try gc_sections.put(match, {});237 _ = try gc_sections.put(match, {});
238 _ = macho_file.got_entries_table.remove(entry.target);238 _ = macho_file.got_entries_table.remove(entry.target);
...@@ -244,7 +244,7 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac...@@ -244,7 +244,7 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac
244244
245 // TODO tombstone245 // TODO tombstone
246 const atom = entry.getAtom(macho_file);246 const atom = entry.getAtom(macho_file);
247 const match = macho_file.getMatchingSectionFromOrdinal(sym.n_sect);247 const match = sym.n_sect - 1;
248 removeAtomFromSection(atom, match, macho_file);248 removeAtomFromSection(atom, match, macho_file);
249 _ = try gc_sections.put(match, {});249 _ = try gc_sections.put(match, {});
250 _ = macho_file.stubs_table.remove(entry.target);250 _ = macho_file.stubs_table.remove(entry.target);
...@@ -256,7 +256,7 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac...@@ -256,7 +256,7 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac
256256
257 // TODO tombstone257 // TODO tombstone
258 const atom = entry.getAtom(macho_file);258 const atom = entry.getAtom(macho_file);
259 const match = macho_file.getMatchingSectionFromOrdinal(sym.n_sect);259 const match = sym.n_sect - 1;
260 removeAtomFromSection(atom, match, macho_file);260 removeAtomFromSection(atom, match, macho_file);
261 _ = try gc_sections.put(match, {});261 _ = try gc_sections.put(match, {});
262 _ = macho_file.tlv_ptr_entries_table.remove(entry.target);262 _ = macho_file.tlv_ptr_entries_table.remove(entry.target);
...@@ -265,13 +265,13 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac...@@ -265,13 +265,13 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac
265 var gc_sections_it = gc_sections.iterator();265 var gc_sections_it = gc_sections.iterator();
266 while (gc_sections_it.next()) |entry| {266 while (gc_sections_it.next()) |entry| {
267 const match = entry.key_ptr.*;267 const match = entry.key_ptr.*;
268 const sect = macho_file.getSectionPtr(match);268 var section = macho_file.sections.get(match);
269 if (sect.size == 0) continue; // Pruning happens automatically in next step.269 if (section.header.size == 0) continue; // Pruning happens automatically in next step.
270270
271 sect.@"align" = 0;271 section.header.@"align" = 0;
272 sect.size = 0;272 section.header.size = 0;
273273
274 var atom = macho_file.atoms.get(match).?;274 var atom = section.last_atom.?;
275275
276 while (atom.prev) |prev| {276 while (atom.prev) |prev| {
277 atom = prev;277 atom = prev;
...@@ -279,14 +279,16 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac...@@ -279,14 +279,16 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac
279279
280 while (true) {280 while (true) {
281 const atom_alignment = try math.powi(u32, 2, atom.alignment);281 const atom_alignment = try math.powi(u32, 2, atom.alignment);
282 const aligned_end_addr = mem.alignForwardGeneric(u64, sect.size, atom_alignment);282 const aligned_end_addr = mem.alignForwardGeneric(u64, section.header.size, atom_alignment);
283 const padding = aligned_end_addr - sect.size;283 const padding = aligned_end_addr - section.header.size;
284 sect.size += padding + atom.size;284 section.header.size += padding + atom.size;
285 sect.@"align" = @maximum(sect.@"align", atom.alignment);285 section.header.@"align" = @maximum(section.header.@"align", atom.alignment);
286286
287 if (atom.next) |next| {287 if (atom.next) |next| {
288 atom = next;288 atom = next;
289 } else break;289 } else break;
290 }290 }
291
292 macho_file.sections.set(match, section);
291 }293 }
292}294}
src/link/MachO/fat.zig+3-1
...@@ -46,7 +46,9 @@ pub fn getLibraryOffset(reader: anytype, cpu_arch: std.Target.Cpu.Arch) !u64 {...@@ -46,7 +46,9 @@ pub fn getLibraryOffset(reader: anytype, cpu_arch: std.Target.Cpu.Arch) !u64 {
46 return fat_arch.offset;46 return fat_arch.offset;
47 }47 }
48 } else {48 } else {
49 log.err("Could not find matching cpu architecture in fat library: expected {}", .{cpu_arch});49 log.err("Could not find matching cpu architecture in fat library: expected {s}", .{
50 @tagName(cpu_arch),
51 });
50 return error.MismatchedCpuArchitecture;52 return error.MismatchedCpuArchitecture;
51 }53 }
52}54}