Commit 81e7d8505c
Changed files (6)
lib
std
src
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(§.sectname);
+ }
+
+ pub fn segName(sect: section_64) []const u8 {
+ return parseName(§.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(§.segname);
-}
-
-pub fn sectionName(sect: macho.section_64) []const u8 {
- return parseName(§.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(),
});
}
}