authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-07-27 07:21:30+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-07-27 07:21:30+02:00
log91a29d7074a61ba192fcefb351a10a26d60b85c8
tree952c66662f1c2334ec08a00aab5b499d8cb640ff
parent2aa8f3d3f5bf98d1a6a7396c608e24203cf094be
parent72e09893686613bd65369faf9272171d272fbee3

Merge pull request '`link.MachO`: add `LC_ENCRYPTION_INFO_64` for non-sim ios/tvos/visionos/watchos' (#36308) from alexrp/zig:macho-encryption-info into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36308

3 files changed, 64 insertions(+), 8 deletions(-)

lib/std/macho.zig+19
......@@ -588,6 +588,25 @@ pub const rpath_command = extern struct {
588588 path: u32,
589589};
590590
591pub const encryption_info_command = extern struct {
592 cmd: LC = .ENCRYPTION_INFO,
593 cmdsize: u32 = @sizeOf(encryption_info_command),
594
595 cryptoff: u32,
596 cryptsize: u32,
597 cryptid: u32 = 0,
598};
599
600pub const encryption_info_command_64 = extern struct {
601 cmd: LC = .ENCRYPTION_INFO_64,
602 cmdsize: u32 = @sizeOf(encryption_info_command_64),
603
604 cryptoff: u32,
605 cryptsize: u32,
606 cryptid: u32 = 0,
607 _pad: u32 = 0,
608};
609
591610/// The segment load command indicates that a part of this file is to be
592611/// mapped into the task's address space. The size of this segment in memory,
593612/// vmsize, maybe equal to or larger than the amount to map from this file,
src/link/MachO.zig+23-3
......@@ -24,6 +24,8 @@ dylibs: std.ArrayList(File.Index) = .empty,
2424
2525segments: std.ArrayList(macho.segment_command_64) = .empty,
2626sections: std.MultiArrayList(Section) = .{},
27/// Populated by `allocateSections`.
28header_size: ?u32 = null,
2729
2830resolver: SymbolResolver = .{},
2931/// This table will be populated after `scanRelocs` has run.
......@@ -2209,13 +2211,14 @@ fn initSegments(self: *MachO) !void {
22092211}
22102212
22112213fn allocateSections(self: *MachO) !void {
2212 const headerpad = try load_commands.calcMinHeaderPadSize(self);
2214 const header_size = try load_commands.calcMinHeaderSize(self);
2215 self.header_size = header_size;
22132216 var vmaddr: u64 = if (self.pagezero_seg_index) |index|
22142217 self.segments.items[index].vmaddr + self.segments.items[index].vmsize
22152218 else
22162219 0;
2217 vmaddr += headerpad;
2218 var fileoff = headerpad;
2220 vmaddr += header_size;
2221 var fileoff = header_size;
22192222 var prev_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0;
22202223
22212224 const page_size = self.getPageSize();
......@@ -2895,6 +2898,11 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
28952898 ncmds += 1;
28962899 }
28972900
2901 if (self.needsEncryptionInfo()) {
2902 try load_commands.writeEncryptionInfoLC(self, &writer);
2903 ncmds += 1;
2904 }
2905
28982906 for (self.rpath_list) |rpath| {
28992907 try load_commands.writeRpathLC(rpath, &writer);
29002908 ncmds += 1;
......@@ -5410,6 +5418,18 @@ pub fn alignPow(macho_file: *MachO, x: u32) error{AlreadyReported}!u32 {
54105418 return result;
54115419}
54125420
5421pub fn needsEncryptionInfo(macho_file: *MachO) bool {
5422 const target = macho_file.getTarget();
5423 return switch (target.os.tag) {
5424 .ios,
5425 .tvos,
5426 .visionos,
5427 .watchos,
5428 => target.abi != .simulator,
5429 else => false,
5430 };
5431}
5432
54135433/// Branch instruction has 26 bits immediate but is 4 byte aligned.
54145434const jump_bits = @bitSizeOf(i28);
54155435const max_distance = (1 << (jump_bits - 1));
src/link/MachO/load_commands.zig+22-5
......@@ -62,6 +62,10 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
6262 assume_max_path_len,
6363 );
6464 }
65 // LC_ENCRYPTION_INFO_64
66 if (macho_file.needsEncryptionInfo()) {
67 sizeofcmds += @sizeOf(macho.encryption_info_command_64);
68 }
6569 // LC_RPATH
6670 {
6771 for (macho_file.rpath_list) |rpath| {
......@@ -163,23 +167,29 @@ pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {
163167 return @as(u32, @intCast(sizeofcmds));
164168}
165169
166pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
170pub fn calcMinHeaderSize(macho_file: *MachO) !u32 {
167171 var padding: u32 = (try calcLoadCommandsSize(macho_file, false)) +
168172 (macho_file.headerpad_size orelse MachO.default_headerpad_size);
169 log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});
173 log.debug("minimum requested header + padding size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});
170174
171175 if (macho_file.headerpad_max_install_names) {
172176 const min_headerpad_size: u32 = try calcLoadCommandsSize(macho_file, true);
173 log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{
177 log.debug("headerpad_max_install_names minimum header + padding size 0x{x}", .{
174178 min_headerpad_size + @sizeOf(macho.mach_header_64),
175179 });
176180 padding = @max(padding, min_headerpad_size);
177181 }
178182
179183 const offset = @sizeOf(macho.mach_header_64) + padding;
180 log.debug("actual headerpad size 0x{x}", .{offset});
184 log.debug("actual header + padding size 0x{x}", .{offset});
181185
182 return offset;
186 // Encryption is done at page granularity, so if the output needs a load
187 // command for encryption info, ensure that the header + load commands have
188 // at least one full, unencrypted page.
189 return if (macho_file.needsEncryptionInfo())
190 mem.alignForward(u32, offset, macho_file.getPageSize())
191 else
192 offset;
183193}
184194
185195pub fn writeDylinkerLC(writer: *Writer) !void {
......@@ -260,6 +270,13 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: *Writer) !void {
260270 }, writer);
261271}
262272
273pub fn writeEncryptionInfoLC(macho_file: *MachO, writer: *Writer) !void {
274 try writer.writeAll(mem.asBytes(&macho.encryption_info_command_64{
275 .cryptoff = macho_file.header_size.?,
276 .cryptsize = @as(u32, @intCast(macho_file.getTextSegment().filesize)) - macho_file.header_size.?,
277 }));
278}
279
263280pub fn writeRpathLC(rpath: []const u8, writer: *Writer) !void {
264281 const rpath_len = rpath.len + 1;
265282 const cmdsize = @as(u32, @intCast(mem.alignForward(