Commit 81e7d8505c

Jakub Konka <kubkon@jakubkonka.com>
2021-12-10 11:46:44
macho: move helper functions to libstd
Helper functions such as `commands.sectionName`, etc. should really belong in `std.macho.section_64` extern struct.
1 parent 77836e0
lib/std/macho.zig
@@ -1,3 +1,5 @@
+const std = @import("std");
+
 pub const mach_header = extern struct {
     magic: u32,
     cputype: cpu_type_t,
@@ -9,14 +11,14 @@ pub const mach_header = extern struct {
 };
 
 pub const mach_header_64 = extern struct {
-    magic: u32,
-    cputype: cpu_type_t,
-    cpusubtype: cpu_subtype_t,
-    filetype: u32,
-    ncmds: u32,
-    sizeofcmds: u32,
-    flags: u32,
-    reserved: u32,
+    magic: u32 = MH_MAGIC_64,
+    cputype: cpu_type_t = 0,
+    cpusubtype: cpu_subtype_t = 0,
+    filetype: u32 = 0,
+    ncmds: u32 = 0,
+    sizeofcmds: u32 = 0,
+    flags: u32 = 0,
+    reserved: u32 = 0,
 };
 
 pub const fat_header = extern struct {
@@ -630,6 +632,10 @@ pub const segment_command_64 = extern struct {
     /// number of sections in segment
     nsects: u32 = 0,
     flags: u32 = 0,
+
+    pub fn segName(seg: segment_command_64) []const u8 {
+        return parseName(&seg.segname);
+    }
 };
 
 /// A segment is made up of zero or more sections.  Non-MH_OBJECT files have
@@ -728,8 +734,46 @@ pub const section_64 = extern struct {
 
     /// reserved
     reserved3: u32 = 0,
+
+    pub fn sectName(sect: section_64) []const u8 {
+        return parseName(&sect.sectname);
+    }
+
+    pub fn segName(sect: section_64) []const u8 {
+        return parseName(&sect.segname);
+    }
+
+    pub fn type_(sect: section_64) u8 {
+        return @truncate(u8, sect.flags & 0xff);
+    }
+
+    pub fn attrs(sect: section_64) u32 {
+        return sect.flags & 0xffffff00;
+    }
+
+    pub fn isCode(sect: section_64) bool {
+        const attr = sect.attrs();
+        return attr & S_ATTR_PURE_INSTRUCTIONS != 0 or attr & S_ATTR_SOME_INSTRUCTIONS != 0;
+    }
+
+    pub fn isDebug(sect: section_64) bool {
+        return sect.attrs() & S_ATTR_DEBUG != 0;
+    }
+
+    pub fn isDontDeadStrip(sect: section_64) bool {
+        return sect.attrs() & S_ATTR_NO_DEAD_STRIP != 0;
+    }
+
+    pub fn isDontDeadStripIfReferencesLive(sect: section_64) bool {
+        return sect.attrs() & S_ATTR_LIVE_SUPPORT != 0;
+    }
 };
 
+fn parseName(name: *const [16]u8) []const u8 {
+    const len = std.mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
+    return name[0..len];
+}
+
 pub const nlist = extern struct {
     n_strx: u32,
     n_type: u8,
src/link/MachO/Atom.zig
@@ -4,7 +4,6 @@ const std = @import("std");
 const build_options = @import("build_options");
 const aarch64 = @import("../../arch/aarch64/bits.zig");
 const assert = std.debug.assert;
-const commands = @import("commands.zig");
 const log = std.log.scoped(.link);
 const macho = std.macho;
 const math = std.math;
@@ -492,7 +491,7 @@ fn addPtrBindingOrRebase(
             const match = context.macho_file.section_ordinals.keys()[source_sym.n_sect - 1];
             const seg = context.macho_file.load_commands.items[match.seg].Segment;
             const sect = seg.sections.items[match.sect];
-            const sect_type = commands.sectionType(sect);
+            const sect_type = sect.type_();
 
             const should_rebase = rebase: {
                 if (rel.r_length != 3) break :rebase false;
@@ -707,7 +706,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
                         const match = macho_file.section_ordinals.keys()[source_sym.n_sect - 1];
                         const seg = macho_file.load_commands.items[match.seg].Segment;
                         const sect = seg.sections.items[match.sect];
-                        break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
+                        break :is_tlv sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
                     };
                     if (is_tlv) {
                         // For TLV relocations, the value specified as a relocation is the displacement from the
src/link/MachO/commands.zig
@@ -12,28 +12,6 @@ const MachO = @import("../MachO.zig");
 const makeStaticString = MachO.makeStaticString;
 const padToIdeal = MachO.padToIdeal;
 
-pub const HeaderArgs = struct {
-    magic: u32 = macho.MH_MAGIC_64,
-    cputype: macho.cpu_type_t = 0,
-    cpusubtype: macho.cpu_subtype_t = 0,
-    filetype: u32 = 0,
-    flags: u32 = 0,
-    reserved: u32 = 0,
-};
-
-pub fn emptyHeader(args: HeaderArgs) macho.mach_header_64 {
-    return .{
-        .magic = args.magic,
-        .cputype = args.cputype,
-        .cpusubtype = args.cpusubtype,
-        .filetype = args.filetype,
-        .ncmds = 0,
-        .sizeofcmds = 0,
-        .flags = args.flags,
-        .reserved = args.reserved,
-    };
-}
-
 pub const LoadCommand = union(enum) {
     Segment: SegmentCommand,
     DyldInfoOnly: macho.dyld_info_command,
@@ -357,44 +335,6 @@ pub fn createLoadDylibCommand(
     return dylib_cmd;
 }
 
-fn parseName(name: *const [16]u8) []const u8 {
-    const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
-    return name[0..len];
-}
-
-pub fn segmentName(sect: macho.section_64) []const u8 {
-    return parseName(&sect.segname);
-}
-
-pub fn sectionName(sect: macho.section_64) []const u8 {
-    return parseName(&sect.sectname);
-}
-
-pub fn sectionType(sect: macho.section_64) u8 {
-    return @truncate(u8, sect.flags & 0xff);
-}
-
-pub fn sectionAttrs(sect: macho.section_64) u32 {
-    return sect.flags & 0xffffff00;
-}
-
-pub fn sectionIsCode(sect: macho.section_64) bool {
-    const attr = sectionAttrs(sect);
-    return attr & macho.S_ATTR_PURE_INSTRUCTIONS != 0 or attr & macho.S_ATTR_SOME_INSTRUCTIONS != 0;
-}
-
-pub fn sectionIsDebug(sect: macho.section_64) bool {
-    return sectionAttrs(sect) & macho.S_ATTR_DEBUG != 0;
-}
-
-pub fn sectionIsDontDeadStrip(sect: macho.section_64) bool {
-    return sectionAttrs(sect) & macho.S_ATTR_NO_DEAD_STRIP != 0;
-}
-
-pub fn sectionIsDontDeadStripIfReferencesLive(sect: macho.section_64) bool {
-    return sectionAttrs(sect) & macho.S_ATTR_LIVE_SUPPORT != 0;
-}
-
 fn testRead(allocator: Allocator, buffer: []const u8, expected: anytype) !void {
     var stream = io.fixedBufferStream(buffer);
     var given = try LoadCommand.read(allocator, stream.reader());
src/link/MachO/DebugSymbols.zig
@@ -241,8 +241,8 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
     assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand
 
     log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{
-        commands.segmentName(sect),
-        commands.sectionName(sect),
+        sect.segName(),
+        sect.sectName(),
         off,
         off + size,
     });
@@ -670,9 +670,8 @@ fn writeLoadCommands(self: *DebugSymbols, allocator: Allocator) !void {
 }
 
 fn writeHeader(self: *DebugSymbols) !void {
-    var header = commands.emptyHeader(.{
-        .filetype = macho.MH_DSYM,
-    });
+    var header: macho.mach_header_64 = .{};
+    header.filetype = macho.MH_DSYM;
 
     switch (self.base.base.options.target.cpu.arch) {
         .aarch64 => {
src/link/MachO/Object.zig
@@ -11,14 +11,11 @@ const macho = std.macho;
 const math = std.math;
 const mem = std.mem;
 const sort = std.sort;
-const commands = @import("commands.zig");
-const segmentName = commands.segmentName;
-const sectionName = commands.sectionName;
 const trace = @import("../../tracy.zig").trace;
 
 const Allocator = mem.Allocator;
 const Atom = @import("Atom.zig");
-const LoadCommand = commands.LoadCommand;
+const LoadCommand = @import("commands.zig").LoadCommand;
 const MachO = @import("../MachO.zig");
 
 file: fs.File,
@@ -278,8 +275,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
                 var seg = cmd.Segment;
                 for (seg.sections.items) |*sect, j| {
                     const index = @intCast(u16, j);
-                    const segname = segmentName(sect.*);
-                    const sectname = sectionName(sect.*);
+                    const segname = sect.segName();
+                    const sectname = sect.sectName();
                     if (mem.eql(u8, segname, "__DWARF")) {
                         if (mem.eql(u8, sectname, "__debug_info")) {
                             self.dwarf_debug_info_index = index;
@@ -424,10 +421,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
 
     for (seg.sections.items) |sect, id| {
         const sect_id = @intCast(u8, id);
-        log.debug("putting section '{s},{s}' as an Atom", .{
-            segmentName(sect),
-            sectionName(sect),
-        });
+        log.debug("putting section '{s},{s}' as an Atom", .{ sect.segName(), sect.sectName() });
 
         // Get matching segment/section in the final artifact.
         const match = (try macho_file.getMatchingSection(sect)) orelse {
@@ -479,7 +473,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
         const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align");
 
         const is_zerofill = blk: {
-            const section_type = commands.sectionType(sect);
+            const section_type = sect.type_();
             break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL;
         };
         if (!is_zerofill) {
src/link/MachO.zig
@@ -1324,10 +1324,10 @@ pub const MatchingSection = struct {
 };
 
 pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSection {
-    const segname = commands.segmentName(sect);
-    const sectname = commands.sectionName(sect);
+    const segname = sect.segName();
+    const sectname = sect.sectName();
     const res: ?MatchingSection = blk: {
-        switch (commands.sectionType(sect)) {
+        switch (sect.type_()) {
             macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
                 if (self.text_const_section_index == null) {
                     self.text_const_section_index = try self.initSection(
@@ -1579,7 +1579,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
                 };
             },
             macho.S_REGULAR => {
-                if (commands.sectionIsCode(sect)) {
+                if (sect.isCode()) {
                     if (self.text_section_index == null) {
                         self.text_section_index = try self.initSection(
                             self.text_segment_cmd_index.?,
@@ -1599,7 +1599,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
                         .sect = self.text_section_index.?,
                     };
                 }
-                if (commands.sectionIsDebug(sect)) {
+                if (sect.isDebug()) {
                     // TODO debug attributes
                     if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) {
                         log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{
@@ -1889,10 +1889,7 @@ fn allocateLocals(self: *MachO) !void {
         const sect = seg.sections.items[match.sect];
         var base_vaddr = sect.addr;
 
-        log.debug("allocating local symbols in {s},{s}", .{
-            commands.segmentName(sect),
-            commands.sectionName(sect),
-        });
+        log.debug("allocating local symbols in {s},{s}", .{ sect.segName(), sect.sectName() });
 
         while (true) {
             const alignment = try math.powi(u32, 2, atom.alignment);
@@ -1987,7 +1984,7 @@ fn writeAllAtoms(self: *MachO) !void {
         defer buffer.deinit();
         try buffer.ensureTotalCapacity(try math.cast(usize, sect.size));
 
-        log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
+        log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() });
 
         while (atom.prev) |prev| {
             atom = prev;
@@ -2035,7 +2032,7 @@ fn writeAtoms(self: *MachO) !void {
         const sect = seg.sections.items[match.sect];
         var atom: *Atom = entry.value_ptr.*;
 
-        log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
+        log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() });
 
         while (atom.prev) |prev| {
             atom = prev;
@@ -3005,7 +3002,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
                 };
             }
 
-            log.debug("{s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
+            log.debug("{s},{s}", .{ sect.segName(), sect.sectName() });
 
             while (true) {
                 const alignment = try math.powi(u32, 2, atom.alignment);
@@ -3049,8 +3046,8 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
         const seg = &self.load_commands.items[match.seg].Segment;
         const sect = &seg.sections.items[match.sect];
         log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{
-            commands.segmentName(sect.*),
-            commands.sectionName(sect.*),
+            sect.segName(),
+            sect.sectName(),
             metadata.size,
             metadata.alignment,
         });
@@ -4507,8 +4504,8 @@ fn initSection(
         const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;
         const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
         log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
-            commands.segmentName(sect),
-            commands.sectionName(sect),
+            sect.segName(),
+            sect.sectName(),
             off,
             off + size,
         });
@@ -4596,8 +4593,8 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
             moved_sect.addr += offset_amt;
 
             log.debug("  (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
-                commands.segmentName(moved_sect.*),
-                commands.sectionName(moved_sect.*),
+                moved_sect.segName(),
+                moved_sect.sectName(),
                 moved_sect.offset,
                 moved_sect.offset + moved_sect.size,
                 moved_sect.addr,
@@ -4670,8 +4667,8 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
             moved_sect.addr += offset_amt;
 
             log.debug("  (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
-                commands.segmentName(moved_sect.*),
-                commands.sectionName(moved_sect.*),
+                moved_sect.segName(),
+                moved_sect.sectName(),
                 moved_sect.offset,
                 moved_sect.offset + moved_sect.size,
                 moved_sect.addr,
@@ -5784,9 +5781,8 @@ fn writeLoadCommands(self: *MachO) !void {
 
 /// Writes Mach-O file header.
 fn writeHeader(self: *MachO) !void {
-    var header = commands.emptyHeader(.{
-        .flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL,
-    });
+    var header: macho.mach_header_64 = .{};
+    header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
 
     switch (self.base.options.target.cpu.arch) {
         .aarch64 => {
@@ -5961,10 +5957,7 @@ fn snapshotState(self: *MachO) !void {
     for (self.section_ordinals.keys()) |key| {
         const seg = self.load_commands.items[key.seg].Segment;
         const sect = seg.sections.items[key.sect];
-        const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{
-            commands.segmentName(sect),
-            commands.sectionName(sect),
-        });
+        const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() });
         try nodes.append(.{
             .address = sect.addr,
             .tag = .section_start,
@@ -6037,7 +6030,7 @@ fn snapshotState(self: *MachO) !void {
                                 const match = self.section_ordinals.keys()[source_sym.n_sect - 1];
                                 const match_seg = self.load_commands.items[match.seg].Segment;
                                 const match_sect = match_seg.sections.items[match.sect];
-                                break :is_tlv commands.sectionType(match_sect) == macho.S_THREAD_LOCAL_VARIABLES;
+                                break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
                             };
                             if (is_tlv) {
                                 const match_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
@@ -6206,8 +6199,8 @@ fn logSectionOrdinals(self: MachO) void {
             i + 1,
             match.seg,
             match.sect,
-            commands.segmentName(sect),
-            commands.sectionName(sect),
+            sect.segName(),
+            sect.sectName(),
         });
     }
 }