authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-10 11:46:44+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-10 11:56:51+01:00
log81e7d8505c086a93accb74e9f1a84abb8ff7cf24
tree9f4a8814448537da53d2eeab838672401a024eb5
parent77836e08a2384450b5e7933094511b61e3c22140

macho: move helper functions to libstd

Helper functions such as `commands.sectionName`, etc. should really belong in `std.macho.section_64` extern struct.

6 files changed, 86 insertions(+), 117 deletions(-)

lib/std/macho.zig+52-8
......@@ -1,3 +1,5 @@
1const std = @import("std");
2
13pub const mach_header = extern struct {
24 magic: u32,
35 cputype: cpu_type_t,
......@@ -9,14 +11,14 @@ pub const mach_header = extern struct {
911};
1012
1113pub const mach_header_64 = extern struct {
12 magic: u32,
13 cputype: cpu_type_t,
14 cpusubtype: cpu_subtype_t,
15 filetype: u32,
16 ncmds: u32,
17 sizeofcmds: u32,
18 flags: u32,
19 reserved: u32,
14 magic: u32 = MH_MAGIC_64,
15 cputype: cpu_type_t = 0,
16 cpusubtype: cpu_subtype_t = 0,
17 filetype: u32 = 0,
18 ncmds: u32 = 0,
19 sizeofcmds: u32 = 0,
20 flags: u32 = 0,
21 reserved: u32 = 0,
2022};
2123
2224pub const fat_header = extern struct {
......@@ -630,6 +632,10 @@ pub const segment_command_64 = extern struct {
630632 /// number of sections in segment
631633 nsects: u32 = 0,
632634 flags: u32 = 0,
635
636 pub fn segName(seg: segment_command_64) []const u8 {
637 return parseName(&seg.segname);
638 }
633639};
634640
635641/// 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 {
728734
729735 /// reserved
730736 reserved3: u32 = 0,
737
738 pub fn sectName(sect: section_64) []const u8 {
739 return parseName(&sect.sectname);
740 }
741
742 pub fn segName(sect: section_64) []const u8 {
743 return parseName(&sect.segname);
744 }
745
746 pub fn type_(sect: section_64) u8 {
747 return @truncate(u8, sect.flags & 0xff);
748 }
749
750 pub fn attrs(sect: section_64) u32 {
751 return sect.flags & 0xffffff00;
752 }
753
754 pub fn isCode(sect: section_64) bool {
755 const attr = sect.attrs();
756 return attr & S_ATTR_PURE_INSTRUCTIONS != 0 or attr & S_ATTR_SOME_INSTRUCTIONS != 0;
757 }
758
759 pub fn isDebug(sect: section_64) bool {
760 return sect.attrs() & S_ATTR_DEBUG != 0;
761 }
762
763 pub fn isDontDeadStrip(sect: section_64) bool {
764 return sect.attrs() & S_ATTR_NO_DEAD_STRIP != 0;
765 }
766
767 pub fn isDontDeadStripIfReferencesLive(sect: section_64) bool {
768 return sect.attrs() & S_ATTR_LIVE_SUPPORT != 0;
769 }
731770};
732771
772fn parseName(name: *const [16]u8) []const u8 {
773 const len = std.mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
774 return name[0..len];
775}
776
733777pub const nlist = extern struct {
734778 n_strx: u32,
735779 n_type: u8,
src/link/MachO.zig+23-30
......@@ -1324,10 +1324,10 @@ pub const MatchingSection = struct {
13241324};
13251325
13261326pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSection {
1327 const segname = commands.segmentName(sect);
1328 const sectname = commands.sectionName(sect);
1327 const segname = sect.segName();
1328 const sectname = sect.sectName();
13291329 const res: ?MatchingSection = blk: {
1330 switch (commands.sectionType(sect)) {
1330 switch (sect.type_()) {
13311331 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
13321332 if (self.text_const_section_index == null) {
13331333 self.text_const_section_index = try self.initSection(
......@@ -1579,7 +1579,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15791579 };
15801580 },
15811581 macho.S_REGULAR => {
1582 if (commands.sectionIsCode(sect)) {
1582 if (sect.isCode()) {
15831583 if (self.text_section_index == null) {
15841584 self.text_section_index = try self.initSection(
15851585 self.text_segment_cmd_index.?,
......@@ -1599,7 +1599,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15991599 .sect = self.text_section_index.?,
16001600 };
16011601 }
1602 if (commands.sectionIsDebug(sect)) {
1602 if (sect.isDebug()) {
16031603 // TODO debug attributes
16041604 if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) {
16051605 log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{
......@@ -1889,10 +1889,7 @@ fn allocateLocals(self: *MachO) !void {
18891889 const sect = seg.sections.items[match.sect];
18901890 var base_vaddr = sect.addr;
18911891
1892 log.debug("allocating local symbols in {s},{s}", .{
1893 commands.segmentName(sect),
1894 commands.sectionName(sect),
1895 });
1892 log.debug("allocating local symbols in {s},{s}", .{ sect.segName(), sect.sectName() });
18961893
18971894 while (true) {
18981895 const alignment = try math.powi(u32, 2, atom.alignment);
......@@ -1987,7 +1984,7 @@ fn writeAllAtoms(self: *MachO) !void {
19871984 defer buffer.deinit();
19881985 try buffer.ensureTotalCapacity(try math.cast(usize, sect.size));
19891986
1990 log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
1987 log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() });
19911988
19921989 while (atom.prev) |prev| {
19931990 atom = prev;
......@@ -2035,7 +2032,7 @@ fn writeAtoms(self: *MachO) !void {
20352032 const sect = seg.sections.items[match.sect];
20362033 var atom: *Atom = entry.value_ptr.*;
20372034
2038 log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
2035 log.debug("writing atoms in {s},{s}", .{ sect.segName(), sect.sectName() });
20392036
20402037 while (atom.prev) |prev| {
20412038 atom = prev;
......@@ -3005,7 +3002,7 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
30053002 };
30063003 }
30073004
3008 log.debug("{s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
3005 log.debug("{s},{s}", .{ sect.segName(), sect.sectName() });
30093006
30103007 while (true) {
30113008 const alignment = try math.powi(u32, 2, atom.alignment);
......@@ -3049,8 +3046,8 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
30493046 const seg = &self.load_commands.items[match.seg].Segment;
30503047 const sect = &seg.sections.items[match.sect];
30513048 log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{
3052 commands.segmentName(sect.*),
3053 commands.sectionName(sect.*),
3049 sect.segName(),
3050 sect.sectName(),
30543051 metadata.size,
30553052 metadata.alignment,
30563053 });
......@@ -4507,8 +4504,8 @@ fn initSection(
45074504 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;
45084505 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
45094506 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
4510 commands.segmentName(sect),
4511 commands.sectionName(sect),
4507 sect.segName(),
4508 sect.sectName(),
45124509 off,
45134510 off + size,
45144511 });
......@@ -4596,8 +4593,8 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
45964593 moved_sect.addr += offset_amt;
45974594
45984595 log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
4599 commands.segmentName(moved_sect.*),
4600 commands.sectionName(moved_sect.*),
4596 moved_sect.segName(),
4597 moved_sect.sectName(),
46014598 moved_sect.offset,
46024599 moved_sect.offset + moved_sect.size,
46034600 moved_sect.addr,
......@@ -4670,8 +4667,8 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
46704667 moved_sect.addr += offset_amt;
46714668
46724669 log.debug(" (new {s},{s} file offsets from 0x{x} to 0x{x} (in memory 0x{x} to 0x{x}))", .{
4673 commands.segmentName(moved_sect.*),
4674 commands.sectionName(moved_sect.*),
4670 moved_sect.segName(),
4671 moved_sect.sectName(),
46754672 moved_sect.offset,
46764673 moved_sect.offset + moved_sect.size,
46774674 moved_sect.addr,
......@@ -5784,9 +5781,8 @@ fn writeLoadCommands(self: *MachO) !void {
57845781
57855782/// Writes Mach-O file header.
57865783fn writeHeader(self: *MachO) !void {
5787 var header = commands.emptyHeader(.{
5788 .flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL,
5789 });
5784 var header: macho.mach_header_64 = .{};
5785 header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL;
57905786
57915787 switch (self.base.options.target.cpu.arch) {
57925788 .aarch64 => {
......@@ -5961,10 +5957,7 @@ fn snapshotState(self: *MachO) !void {
59615957 for (self.section_ordinals.keys()) |key| {
59625958 const seg = self.load_commands.items[key.seg].Segment;
59635959 const sect = seg.sections.items[key.sect];
5964 const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{
5965 commands.segmentName(sect),
5966 commands.sectionName(sect),
5967 });
5960 const sect_name = try std.fmt.allocPrint(arena, "{s},{s}", .{ sect.segName(), sect.sectName() });
59685961 try nodes.append(.{
59695962 .address = sect.addr,
59705963 .tag = .section_start,
......@@ -6037,7 +6030,7 @@ fn snapshotState(self: *MachO) !void {
60376030 const match = self.section_ordinals.keys()[source_sym.n_sect - 1];
60386031 const match_seg = self.load_commands.items[match.seg].Segment;
60396032 const match_sect = match_seg.sections.items[match.sect];
6040 break :is_tlv commands.sectionType(match_sect) == macho.S_THREAD_LOCAL_VARIABLES;
6033 break :is_tlv match_sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
60416034 };
60426035 if (is_tlv) {
60436036 const match_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
......@@ -6206,8 +6199,8 @@ fn logSectionOrdinals(self: MachO) void {
62066199 i + 1,
62076200 match.seg,
62086201 match.sect,
6209 commands.segmentName(sect),
6210 commands.sectionName(sect),
6202 sect.segName(),
6203 sect.sectName(),
62116204 });
62126205 }
62136206}
src/link/MachO/Atom.zig+2-3
......@@ -4,7 +4,6 @@ const std = @import("std");
44const build_options = @import("build_options");
55const aarch64 = @import("../../arch/aarch64/bits.zig");
66const assert = std.debug.assert;
7const commands = @import("commands.zig");
87const log = std.log.scoped(.link);
98const macho = std.macho;
109const math = std.math;
......@@ -492,7 +491,7 @@ fn addPtrBindingOrRebase(
492491 const match = context.macho_file.section_ordinals.keys()[source_sym.n_sect - 1];
493492 const seg = context.macho_file.load_commands.items[match.seg].Segment;
494493 const sect = seg.sections.items[match.sect];
495 const sect_type = commands.sectionType(sect);
494 const sect_type = sect.type_();
496495
497496 const should_rebase = rebase: {
498497 if (rel.r_length != 3) break :rebase false;
......@@ -707,7 +706,7 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
707706 const match = macho_file.section_ordinals.keys()[source_sym.n_sect - 1];
708707 const seg = macho_file.load_commands.items[match.seg].Segment;
709708 const sect = seg.sections.items[match.sect];
710 break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES;
709 break :is_tlv sect.type_() == macho.S_THREAD_LOCAL_VARIABLES;
711710 };
712711 if (is_tlv) {
713712 // For TLV relocations, the value specified as a relocation is the displacement from the
src/link/MachO/DebugSymbols.zig+4-5
......@@ -241,8 +241,8 @@ fn allocateSection(self: *DebugSymbols, sectname: []const u8, size: u64, alignme
241241 assert(off + size <= seg.inner.fileoff + seg.inner.filesize); // TODO expand
242242
243243 log.debug("found {s},{s} section free space 0x{x} to 0x{x}", .{
244 commands.segmentName(sect),
245 commands.sectionName(sect),
244 sect.segName(),
245 sect.sectName(),
246246 off,
247247 off + size,
248248 });
......@@ -670,9 +670,8 @@ fn writeLoadCommands(self: *DebugSymbols, allocator: Allocator) !void {
670670}
671671
672672fn writeHeader(self: *DebugSymbols) !void {
673 var header = commands.emptyHeader(.{
674 .filetype = macho.MH_DSYM,
675 });
673 var header: macho.mach_header_64 = .{};
674 header.filetype = macho.MH_DSYM;
676675
677676 switch (self.base.base.options.target.cpu.arch) {
678677 .aarch64 => {
src/link/MachO/Object.zig+5-11
......@@ -11,14 +11,11 @@ const macho = std.macho;
1111const math = std.math;
1212const mem = std.mem;
1313const sort = std.sort;
14const commands = @import("commands.zig");
15const segmentName = commands.segmentName;
16const sectionName = commands.sectionName;
1714const trace = @import("../../tracy.zig").trace;
1815
1916const Allocator = mem.Allocator;
2017const Atom = @import("Atom.zig");
21const LoadCommand = commands.LoadCommand;
18const LoadCommand = @import("commands.zig").LoadCommand;
2219const MachO = @import("../MachO.zig");
2320
2421file: fs.File,
......@@ -278,8 +275,8 @@ pub fn readLoadCommands(self: *Object, allocator: Allocator, reader: anytype) !v
278275 var seg = cmd.Segment;
279276 for (seg.sections.items) |*sect, j| {
280277 const index = @intCast(u16, j);
281 const segname = segmentName(sect.*);
282 const sectname = sectionName(sect.*);
278 const segname = sect.segName();
279 const sectname = sect.sectName();
283280 if (mem.eql(u8, segname, "__DWARF")) {
284281 if (mem.eql(u8, sectname, "__debug_info")) {
285282 self.dwarf_debug_info_index = index;
......@@ -424,10 +421,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
424421
425422 for (seg.sections.items) |sect, id| {
426423 const sect_id = @intCast(u8, id);
427 log.debug("putting section '{s},{s}' as an Atom", .{
428 segmentName(sect),
429 sectionName(sect),
430 });
424 log.debug("putting section '{s},{s}' as an Atom", .{ sect.segName(), sect.sectName() });
431425
432426 // Get matching segment/section in the final artifact.
433427 const match = (try macho_file.getMatchingSection(sect)) orelse {
......@@ -479,7 +473,7 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
479473 const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align");
480474
481475 const is_zerofill = blk: {
482 const section_type = commands.sectionType(sect);
476 const section_type = sect.type_();
483477 break :blk section_type == macho.S_ZEROFILL or section_type == macho.S_THREAD_LOCAL_ZEROFILL;
484478 };
485479 if (!is_zerofill) {
src/link/MachO/commands.zig-60
......@@ -12,28 +12,6 @@ const MachO = @import("../MachO.zig");
1212const makeStaticString = MachO.makeStaticString;
1313const padToIdeal = MachO.padToIdeal;
1414
15pub const HeaderArgs = struct {
16 magic: u32 = macho.MH_MAGIC_64,
17 cputype: macho.cpu_type_t = 0,
18 cpusubtype: macho.cpu_subtype_t = 0,
19 filetype: u32 = 0,
20 flags: u32 = 0,
21 reserved: u32 = 0,
22};
23
24pub fn emptyHeader(args: HeaderArgs) macho.mach_header_64 {
25 return .{
26 .magic = args.magic,
27 .cputype = args.cputype,
28 .cpusubtype = args.cpusubtype,
29 .filetype = args.filetype,
30 .ncmds = 0,
31 .sizeofcmds = 0,
32 .flags = args.flags,
33 .reserved = args.reserved,
34 };
35}
36
3715pub const LoadCommand = union(enum) {
3816 Segment: SegmentCommand,
3917 DyldInfoOnly: macho.dyld_info_command,
......@@ -357,44 +335,6 @@ pub fn createLoadDylibCommand(
357335 return dylib_cmd;
358336}
359337
360fn parseName(name: *const [16]u8) []const u8 {
361 const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
362 return name[0..len];
363}
364
365pub fn segmentName(sect: macho.section_64) []const u8 {
366 return parseName(&sect.segname);
367}
368
369pub fn sectionName(sect: macho.section_64) []const u8 {
370 return parseName(&sect.sectname);
371}
372
373pub fn sectionType(sect: macho.section_64) u8 {
374 return @truncate(u8, sect.flags & 0xff);
375}
376
377pub fn sectionAttrs(sect: macho.section_64) u32 {
378 return sect.flags & 0xffffff00;
379}
380
381pub fn sectionIsCode(sect: macho.section_64) bool {
382 const attr = sectionAttrs(sect);
383 return attr & macho.S_ATTR_PURE_INSTRUCTIONS != 0 or attr & macho.S_ATTR_SOME_INSTRUCTIONS != 0;
384}
385
386pub fn sectionIsDebug(sect: macho.section_64) bool {
387 return sectionAttrs(sect) & macho.S_ATTR_DEBUG != 0;
388}
389
390pub fn sectionIsDontDeadStrip(sect: macho.section_64) bool {
391 return sectionAttrs(sect) & macho.S_ATTR_NO_DEAD_STRIP != 0;
392}
393
394pub fn sectionIsDontDeadStripIfReferencesLive(sect: macho.section_64) bool {
395 return sectionAttrs(sect) & macho.S_ATTR_LIVE_SUPPORT != 0;
396}
397
398338fn testRead(allocator: Allocator, buffer: []const u8, expected: anytype) !void {
399339 var stream = io.fixedBufferStream(buffer);
400340 var given = try LoadCommand.read(allocator, stream.reader());