authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-27 21:39:05+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-12-27 21:39:05+01:00
log601ab9a251a7952026fa9c72427344126bf62730
treea111b9df535a32f13c584d78b6259812c960e7e8
parent19056cb6821dd03612628e9220595576878aafe7
parentc0c5acf074a9eba01e892184489ac3e837d739bc
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14086 from ziglang/issue-14082

macho: ensure LINKEDIT layout follows Apple strict validation rules

5 files changed, 197 insertions(+), 93 deletions(-)

lib/std/build/CheckObjectStep.zig+6-1
......@@ -126,7 +126,7 @@ const Action = struct {
126126 /// its reduced, computed value compares using `op` with the expected value, either
127127 /// a literal or another extracted variable.
128128 fn computeCmp(act: Action, gpa: Allocator, global_vars: anytype) !bool {
129 var op_stack = std.ArrayList(enum { add, sub, mod }).init(gpa);
129 var op_stack = std.ArrayList(enum { add, sub, mod, mul }).init(gpa);
130130 var values = std.ArrayList(u64).init(gpa);
131131
132132 var it = mem.tokenize(u8, act.phrase, " ");
......@@ -137,6 +137,8 @@ const Action = struct {
137137 try op_stack.append(.sub);
138138 } else if (mem.eql(u8, next, "%")) {
139139 try op_stack.append(.mod);
140 } else if (mem.eql(u8, next, "*")) {
141 try op_stack.append(.mul);
140142 } else {
141143 const val = std.fmt.parseInt(u64, next, 0) catch blk: {
142144 break :blk global_vars.get(next) orelse {
......@@ -167,6 +169,9 @@ const Action = struct {
167169 .mod => {
168170 reduced %= other;
169171 },
172 .mul => {
173 reduced *= other;
174 },
170175 }
171176 op_i += 1;
172177 }
src/link/MachO.zig+52-30
......@@ -3358,27 +3358,36 @@ fn writeDyldInfoData(self: *MachO) !void {
33583358 try self.collectExportData(&trie);
33593359
33603360 const link_seg = self.getLinkeditSegmentPtr();
3361 const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64));
3362 assert(rebase_off == link_seg.fileoff);
3361 assert(mem.isAlignedGeneric(u64, link_seg.fileoff, @alignOf(u64)));
3362 const rebase_off = link_seg.fileoff;
33633363 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
3364 log.debug("writing rebase info from 0x{x} to 0x{x}", .{ rebase_off, rebase_off + rebase_size });
3364 const rebase_size_aligned = mem.alignForwardGeneric(u64, rebase_size, @alignOf(u64));
3365 log.debug("writing rebase info from 0x{x} to 0x{x}", .{ rebase_off, rebase_off + rebase_size_aligned });
33653366
3366 const bind_off = mem.alignForwardGeneric(u64, rebase_off + rebase_size, @alignOf(u64));
3367 const bind_off = rebase_off + rebase_size_aligned;
33673368 const bind_size = try bind.bindInfoSize(bind_pointers.items);
3368 log.debug("writing bind info from 0x{x} to 0x{x}", .{ bind_off, bind_off + bind_size });
3369 const bind_size_aligned = mem.alignForwardGeneric(u64, bind_size, @alignOf(u64));
3370 log.debug("writing bind info from 0x{x} to 0x{x}", .{ bind_off, bind_off + bind_size_aligned });
33693371
3370 const lazy_bind_off = mem.alignForwardGeneric(u64, bind_off + bind_size, @alignOf(u64));
3372 const lazy_bind_off = bind_off + bind_size_aligned;
33713373 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
3372 log.debug("writing lazy bind info from 0x{x} to 0x{x}", .{ lazy_bind_off, lazy_bind_off + lazy_bind_size });
3374 const lazy_bind_size_aligned = mem.alignForwardGeneric(u64, lazy_bind_size, @alignOf(u64));
3375 log.debug("writing lazy bind info from 0x{x} to 0x{x}", .{
3376 lazy_bind_off,
3377 lazy_bind_off + lazy_bind_size_aligned,
3378 });
33733379
3374 const export_off = mem.alignForwardGeneric(u64, lazy_bind_off + lazy_bind_size, @alignOf(u64));
3380 const export_off = lazy_bind_off + lazy_bind_size_aligned;
33753381 const export_size = trie.size;
3376 log.debug("writing export trie from 0x{x} to 0x{x}", .{ export_off, export_off + export_size });
3382 const export_size_aligned = mem.alignForwardGeneric(u64, export_size, @alignOf(u64));
3383 log.debug("writing export trie from 0x{x} to 0x{x}", .{ export_off, export_off + export_size_aligned });
33773384
3378 const needed_size = export_off + export_size - rebase_off;
3385 const needed_size = math.cast(usize, export_off + export_size_aligned - rebase_off) orelse
3386 return error.Overflow;
33793387 link_seg.filesize = needed_size;
3388 assert(mem.isAlignedGeneric(u64, link_seg.fileoff + link_seg.filesize, @alignOf(u64)));
33803389
3381 var buffer = try gpa.alloc(u8, math.cast(usize, needed_size) orelse return error.Overflow);
3390 var buffer = try gpa.alloc(u8, needed_size);
33823391 defer gpa.free(buffer);
33833392 mem.set(u8, buffer, 0);
33843393
......@@ -3407,13 +3416,13 @@ fn writeDyldInfoData(self: *MachO) !void {
34073416 try self.populateLazyBindOffsetsInStubHelper(buffer[start..end]);
34083417
34093418 self.dyld_info_cmd.rebase_off = @intCast(u32, rebase_off);
3410 self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size);
3419 self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size_aligned);
34113420 self.dyld_info_cmd.bind_off = @intCast(u32, bind_off);
3412 self.dyld_info_cmd.bind_size = @intCast(u32, bind_size);
3421 self.dyld_info_cmd.bind_size = @intCast(u32, bind_size_aligned);
34133422 self.dyld_info_cmd.lazy_bind_off = @intCast(u32, lazy_bind_off);
3414 self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size);
3423 self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size_aligned);
34153424 self.dyld_info_cmd.export_off = @intCast(u32, export_off);
3416 self.dyld_info_cmd.export_size = @intCast(u32, export_size);
3425 self.dyld_info_cmd.export_size = @intCast(u32, export_size_aligned);
34173426}
34183427
34193428fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
......@@ -3569,13 +3578,11 @@ fn writeSymtab(self: *MachO) !SymtabCtx {
35693578 const nsyms = nlocals + nexports + nimports;
35703579
35713580 const seg = self.getLinkeditSegmentPtr();
3572 const offset = mem.alignForwardGeneric(
3573 u64,
3574 seg.fileoff + seg.filesize,
3575 @alignOf(macho.nlist_64),
3576 );
3581 const offset = seg.fileoff + seg.filesize;
3582 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
35773583 const needed_size = nsyms * @sizeOf(macho.nlist_64);
35783584 seg.filesize = offset + needed_size - seg.fileoff;
3585 assert(mem.isAlignedGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64)));
35793586
35803587 var buffer = std.ArrayList(u8).init(gpa);
35813588 defer buffer.deinit();
......@@ -3599,17 +3606,25 @@ fn writeSymtab(self: *MachO) !SymtabCtx {
35993606}
36003607
36013608fn writeStrtab(self: *MachO) !void {
3609 const gpa = self.base.allocator;
36023610 const seg = self.getLinkeditSegmentPtr();
3603 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
3611 const offset = seg.fileoff + seg.filesize;
3612 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
36043613 const needed_size = self.strtab.buffer.items.len;
3605 seg.filesize = offset + needed_size - seg.fileoff;
3614 const needed_size_aligned = mem.alignForwardGeneric(u64, needed_size, @alignOf(u64));
3615 seg.filesize = offset + needed_size_aligned - seg.fileoff;
36063616
3607 log.debug("writing string table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
3617 log.debug("writing string table from 0x{x} to 0x{x}", .{ offset, offset + needed_size_aligned });
36083618
3609 try self.base.file.?.pwriteAll(self.strtab.buffer.items, offset);
3619 const buffer = try gpa.alloc(u8, math.cast(usize, needed_size_aligned) orelse return error.Overflow);
3620 defer gpa.free(buffer);
3621 mem.set(u8, buffer, 0);
3622 mem.copy(u8, buffer, self.strtab.buffer.items);
3623
3624 try self.base.file.?.pwriteAll(buffer, offset);
36103625
36113626 self.symtab_cmd.stroff = @intCast(u32, offset);
3612 self.symtab_cmd.strsize = @intCast(u32, needed_size);
3627 self.symtab_cmd.strsize = @intCast(u32, needed_size_aligned);
36133628}
36143629
36153630const SymtabCtx = struct {
......@@ -3628,15 +3643,17 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
36283643 const iundefsym = iextdefsym + ctx.nextdefsym;
36293644
36303645 const seg = self.getLinkeditSegmentPtr();
3631 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
3646 const offset = seg.fileoff + seg.filesize;
3647 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
36323648 const needed_size = nindirectsyms * @sizeOf(u32);
3633 seg.filesize = offset + needed_size - seg.fileoff;
3649 const needed_size_aligned = mem.alignForwardGeneric(u64, needed_size, @alignOf(u64));
3650 seg.filesize = offset + needed_size_aligned - seg.fileoff;
36343651
3635 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
3652 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ offset, offset + needed_size_aligned });
36363653
36373654 var buf = std.ArrayList(u8).init(gpa);
36383655 defer buf.deinit();
3639 try buf.ensureTotalCapacity(needed_size);
3656 try buf.ensureTotalCapacity(math.cast(usize, needed_size_aligned) orelse return error.Overflow);
36403657 const writer = buf.writer();
36413658
36423659 if (self.stubs_section_index) |sect_id| {
......@@ -3675,7 +3692,12 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
36753692 }
36763693 }
36773694
3678 assert(buf.items.len == needed_size);
3695 const padding = math.cast(usize, needed_size_aligned - needed_size) orelse return error.Overflow;
3696 if (padding > 0) {
3697 buf.appendNTimesAssumeCapacity(0, padding);
3698 }
3699
3700 assert(buf.items.len == needed_size_aligned);
36793701 try self.base.file.?.pwriteAll(buf.items, offset);
36803702
36813703 self.dysymtab_cmd.nlocalsym = ctx.nlocalsym;
src/link/MachO/zld.zig+75-39
......@@ -2178,25 +2178,34 @@ pub const Zld = struct {
21782178 try self.collectExportData(&trie);
21792179
21802180 const link_seg = self.getLinkeditSegmentPtr();
2181 const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64));
2182 assert(rebase_off == link_seg.fileoff);
2181 assert(mem.isAlignedGeneric(u64, link_seg.fileoff, @alignOf(u64)));
2182 const rebase_off = link_seg.fileoff;
21832183 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
2184 log.debug("writing rebase info from 0x{x} to 0x{x}", .{ rebase_off, rebase_off + rebase_size });
2184 const rebase_size_aligned = mem.alignForwardGeneric(u64, rebase_size, @alignOf(u64));
2185 log.debug("writing rebase info from 0x{x} to 0x{x}", .{ rebase_off, rebase_off + rebase_size_aligned });
21852186
2186 const bind_off = mem.alignForwardGeneric(u64, rebase_off + rebase_size, @alignOf(u64));
2187 const bind_off = rebase_off + rebase_size_aligned;
21872188 const bind_size = try bind.bindInfoSize(bind_pointers.items);
2188 log.debug("writing bind info from 0x{x} to 0x{x}", .{ bind_off, bind_off + bind_size });
2189 const bind_size_aligned = mem.alignForwardGeneric(u64, bind_size, @alignOf(u64));
2190 log.debug("writing bind info from 0x{x} to 0x{x}", .{ bind_off, bind_off + bind_size_aligned });
21892191
2190 const lazy_bind_off = mem.alignForwardGeneric(u64, bind_off + bind_size, @alignOf(u64));
2192 const lazy_bind_off = bind_off + bind_size_aligned;
21912193 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
2192 log.debug("writing lazy bind info from 0x{x} to 0x{x}", .{ lazy_bind_off, lazy_bind_off + lazy_bind_size });
2194 const lazy_bind_size_aligned = mem.alignForwardGeneric(u64, lazy_bind_size, @alignOf(u64));
2195 log.debug("writing lazy bind info from 0x{x} to 0x{x}", .{
2196 lazy_bind_off,
2197 lazy_bind_off + lazy_bind_size_aligned,
2198 });
21932199
2194 const export_off = mem.alignForwardGeneric(u64, lazy_bind_off + lazy_bind_size, @alignOf(u64));
2200 const export_off = lazy_bind_off + lazy_bind_size_aligned;
21952201 const export_size = trie.size;
2196 log.debug("writing export trie from 0x{x} to 0x{x}", .{ export_off, export_off + export_size });
2202 const export_size_aligned = mem.alignForwardGeneric(u64, export_size, @alignOf(u64));
2203 log.debug("writing export trie from 0x{x} to 0x{x}", .{ export_off, export_off + export_size_aligned });
21972204
2198 const needed_size = math.cast(usize, export_off + export_size - rebase_off) orelse return error.Overflow;
2205 const needed_size = math.cast(usize, export_off + export_size_aligned - rebase_off) orelse
2206 return error.Overflow;
21992207 link_seg.filesize = needed_size;
2208 assert(mem.isAlignedGeneric(u64, link_seg.fileoff + link_seg.filesize, @alignOf(u64)));
22002209
22012210 var buffer = try gpa.alloc(u8, needed_size);
22022211 defer gpa.free(buffer);
......@@ -2228,13 +2237,13 @@ pub const Zld = struct {
22282237 try self.populateLazyBindOffsetsInStubHelper(buffer[offset..][0..size]);
22292238
22302239 self.dyld_info_cmd.rebase_off = @intCast(u32, rebase_off);
2231 self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size);
2240 self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size_aligned);
22322241 self.dyld_info_cmd.bind_off = @intCast(u32, bind_off);
2233 self.dyld_info_cmd.bind_size = @intCast(u32, bind_size);
2242 self.dyld_info_cmd.bind_size = @intCast(u32, bind_size_aligned);
22342243 self.dyld_info_cmd.lazy_bind_off = @intCast(u32, lazy_bind_off);
2235 self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size);
2244 self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size_aligned);
22362245 self.dyld_info_cmd.export_off = @intCast(u32, export_off);
2237 self.dyld_info_cmd.export_size = @intCast(u32, export_size);
2246 self.dyld_info_cmd.export_size = @intCast(u32, export_size_aligned);
22382247 }
22392248
22402249 fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
......@@ -2403,16 +2412,23 @@ pub const Zld = struct {
24032412 }
24042413
24052414 const link_seg = self.getLinkeditSegmentPtr();
2406 const offset = mem.alignForwardGeneric(u64, link_seg.fileoff + link_seg.filesize, @alignOf(u64));
2415 const offset = link_seg.fileoff + link_seg.filesize;
2416 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
24072417 const needed_size = buffer.items.len;
2408 link_seg.filesize = offset + needed_size - link_seg.fileoff;
2418 const needed_size_aligned = mem.alignForwardGeneric(u64, needed_size, @alignOf(u64));
2419 const padding = math.cast(usize, needed_size_aligned - needed_size) orelse return error.Overflow;
2420 if (padding > 0) {
2421 try buffer.ensureUnusedCapacity(padding);
2422 buffer.appendNTimesAssumeCapacity(0, padding);
2423 }
2424 link_seg.filesize = offset + needed_size_aligned - link_seg.fileoff;
24092425
2410 log.debug("writing function starts info from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
2426 log.debug("writing function starts info from 0x{x} to 0x{x}", .{ offset, offset + needed_size_aligned });
24112427
24122428 try self.file.pwriteAll(buffer.items, offset);
24132429
24142430 self.function_starts_cmd.dataoff = @intCast(u32, offset);
2415 self.function_starts_cmd.datasize = @intCast(u32, needed_size);
2431 self.function_starts_cmd.datasize = @intCast(u32, needed_size_aligned);
24162432 }
24172433
24182434 fn filterDataInCode(
......@@ -2477,16 +2493,23 @@ pub const Zld = struct {
24772493 }
24782494
24792495 const seg = self.getLinkeditSegmentPtr();
2480 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
2496 const offset = seg.fileoff + seg.filesize;
2497 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
24812498 const needed_size = out_dice.items.len * @sizeOf(macho.data_in_code_entry);
2482 seg.filesize = offset + needed_size - seg.fileoff;
2499 const needed_size_aligned = mem.alignForwardGeneric(u64, needed_size, @alignOf(u64));
2500 seg.filesize = offset + needed_size_aligned - seg.fileoff;
2501
2502 const buffer = try self.gpa.alloc(u8, math.cast(usize, needed_size_aligned) orelse return error.Overflow);
2503 defer self.gpa.free(buffer);
2504 mem.set(u8, buffer, 0);
2505 mem.copy(u8, buffer, mem.sliceAsBytes(out_dice.items));
24832506
2484 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
2507 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ offset, offset + needed_size_aligned });
24852508
2486 try self.file.pwriteAll(mem.sliceAsBytes(out_dice.items), offset);
2509 try self.file.pwriteAll(buffer, offset);
24872510
24882511 self.data_in_code_cmd.dataoff = @intCast(u32, offset);
2489 self.data_in_code_cmd.datasize = @intCast(u32, needed_size);
2512 self.data_in_code_cmd.datasize = @intCast(u32, needed_size_aligned);
24902513 }
24912514
24922515 fn writeSymtabs(self: *Zld) !void {
......@@ -2561,13 +2584,11 @@ pub const Zld = struct {
25612584 const nsyms = nlocals + nexports + nimports;
25622585
25632586 const seg = self.getLinkeditSegmentPtr();
2564 const offset = mem.alignForwardGeneric(
2565 u64,
2566 seg.fileoff + seg.filesize,
2567 @alignOf(macho.nlist_64),
2568 );
2587 const offset = seg.fileoff + seg.filesize;
2588 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
25692589 const needed_size = nsyms * @sizeOf(macho.nlist_64);
25702590 seg.filesize = offset + needed_size - seg.fileoff;
2591 assert(mem.isAlignedGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64)));
25712592
25722593 var buffer = std.ArrayList(u8).init(gpa);
25732594 defer buffer.deinit();
......@@ -2592,16 +2613,23 @@ pub const Zld = struct {
25922613
25932614 fn writeStrtab(self: *Zld) !void {
25942615 const seg = self.getLinkeditSegmentPtr();
2595 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
2616 const offset = seg.fileoff + seg.filesize;
2617 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
25962618 const needed_size = self.strtab.buffer.items.len;
2597 seg.filesize = offset + needed_size - seg.fileoff;
2619 const needed_size_aligned = mem.alignForwardGeneric(u64, needed_size, @alignOf(u64));
2620 seg.filesize = offset + needed_size_aligned - seg.fileoff;
2621
2622 log.debug("writing string table from 0x{x} to 0x{x}", .{ offset, offset + needed_size_aligned });
25982623
2599 log.debug("writing string table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
2624 const buffer = try self.gpa.alloc(u8, math.cast(usize, needed_size_aligned) orelse return error.Overflow);
2625 defer self.gpa.free(buffer);
2626 mem.set(u8, buffer, 0);
2627 mem.copy(u8, buffer, self.strtab.buffer.items);
26002628
2601 try self.file.pwriteAll(self.strtab.buffer.items, offset);
2629 try self.file.pwriteAll(buffer, offset);
26022630
26032631 self.symtab_cmd.stroff = @intCast(u32, offset);
2604 self.symtab_cmd.strsize = @intCast(u32, needed_size);
2632 self.symtab_cmd.strsize = @intCast(u32, needed_size_aligned);
26052633 }
26062634
26072635 const SymtabCtx = struct {
......@@ -2620,15 +2648,17 @@ pub const Zld = struct {
26202648 const iundefsym = iextdefsym + ctx.nextdefsym;
26212649
26222650 const seg = self.getLinkeditSegmentPtr();
2623 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
2651 const offset = seg.fileoff + seg.filesize;
2652 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
26242653 const needed_size = nindirectsyms * @sizeOf(u32);
2625 seg.filesize = offset + needed_size - seg.fileoff;
2654 const needed_size_aligned = mem.alignForwardGeneric(u64, needed_size, @alignOf(u64));
2655 seg.filesize = offset + needed_size_aligned - seg.fileoff;
26262656
2627 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
2657 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ offset, offset + needed_size_aligned });
26282658
26292659 var buf = std.ArrayList(u8).init(gpa);
26302660 defer buf.deinit();
2631 try buf.ensureTotalCapacity(needed_size);
2661 try buf.ensureTotalCapacityPrecise(math.cast(usize, needed_size_aligned) orelse return error.Overflow);
26322662 const writer = buf.writer();
26332663
26342664 if (self.getSectionByName("__TEXT", "__stubs")) |sect_id| {
......@@ -2664,7 +2694,12 @@ pub const Zld = struct {
26642694 }
26652695 }
26662696
2667 assert(buf.items.len == needed_size);
2697 const padding = math.cast(usize, needed_size_aligned - needed_size) orelse return error.Overflow;
2698 if (padding > 0) {
2699 buf.appendNTimesAssumeCapacity(0, padding);
2700 }
2701
2702 assert(buf.items.len == needed_size_aligned);
26682703 try self.file.pwriteAll(buf.items, offset);
26692704
26702705 self.dysymtab_cmd.nlocalsym = ctx.nlocalsym;
......@@ -2692,7 +2727,8 @@ pub const Zld = struct {
26922727 conformUuid(&self.uuid_cmd.uuid);
26932728 },
26942729 else => {
2695 const max_file_end = self.symtab_cmd.stroff + self.symtab_cmd.strsize;
2730 // We set the max file size to the actual strtab buffer length to exclude any strtab padding.
2731 const max_file_end = @intCast(u32, self.symtab_cmd.stroff + self.strtab.buffer.items.len);
26962732
26972733 const FileSubsection = struct {
26982734 start: u32,
test/link/macho/strict_validation/build.zig+34-15
......@@ -32,13 +32,23 @@ pub fn build(b: *Builder) void {
3232 check_exe.checkNext("exportoff {exportoff}");
3333 check_exe.checkNext("exportsize {exportsize}");
3434
35 check_exe.checkStart("cmd FUNCTION_STARTS");
36 check_exe.checkNext("dataoff {fstartoff}");
37 check_exe.checkNext("datasize {fstartsize}");
38
39 check_exe.checkStart("cmd DATA_IN_CODE");
40 check_exe.checkNext("dataoff {diceoff}");
41 check_exe.checkNext("datasize {dicesize}");
42
3543 check_exe.checkStart("cmd SYMTAB");
3644 check_exe.checkNext("symoff {symoff}");
45 check_exe.checkNext("nsyms {symnsyms}");
3746 check_exe.checkNext("stroff {stroff}");
3847 check_exe.checkNext("strsize {strsize}");
3948
4049 check_exe.checkStart("cmd DYSYMTAB");
4150 check_exe.checkNext("indirectsymoff {dysymoff}");
51 check_exe.checkNext("nindirectsyms {dysymnsyms}");
4252
4353 switch (builtin.cpu.arch) {
4454 .aarch64 => {
......@@ -50,42 +60,51 @@ pub fn build(b: *Builder) void {
5060 else => unreachable,
5161 }
5262
53 // Next check: DYLD_INFO_ONLY subsections are in order: rebase < bind < lazy < export
54 check_exe.checkComputeCompare("rebaseoff ", .{ .op = .lt, .value = .{ .variable = "bindoff" } });
55 check_exe.checkComputeCompare("bindoff", .{ .op = .lt, .value = .{ .variable = "lazybindoff" } });
56 check_exe.checkComputeCompare("lazybindoff", .{ .op = .lt, .value = .{ .variable = "exportoff" } });
63 // DYLD_INFO_ONLY subsections are in order: rebase < bind < lazy < export,
64 // and there are no gaps between them
65 check_exe.checkComputeCompare("rebaseoff rebasesize +", .{ .op = .eq, .value = .{ .variable = "bindoff" } });
66 check_exe.checkComputeCompare("bindoff bindsize +", .{ .op = .eq, .value = .{ .variable = "lazybindoff" } });
67 check_exe.checkComputeCompare("lazybindoff lazybindsize +", .{ .op = .eq, .value = .{ .variable = "exportoff" } });
68
69 // FUNCTION_STARTS directly follows DYLD_INFO_ONLY (no gap)
70 check_exe.checkComputeCompare("exportoff exportsize +", .{ .op = .eq, .value = .{ .variable = "fstartoff" } });
71
72 // DATA_IN_CODE directly follows FUNCTION_STARTS (no gap)
73 check_exe.checkComputeCompare("fstartoff fstartsize +", .{ .op = .eq, .value = .{ .variable = "diceoff" } });
74
75 // SYMTAB directly follows DATA_IN_CODE (no gap)
76 check_exe.checkComputeCompare("diceoff dicesize +", .{ .op = .eq, .value = .{ .variable = "symoff" } });
5777
58 // Next check: DYLD_INFO_ONLY subsections do not overlap
59 check_exe.checkComputeCompare("rebaseoff rebasesize +", .{ .op = .lte, .value = .{ .variable = "bindoff" } });
60 check_exe.checkComputeCompare("bindoff bindsize +", .{ .op = .lte, .value = .{ .variable = "lazybindoff" } });
61 check_exe.checkComputeCompare("lazybindoff lazybindsize +", .{ .op = .lte, .value = .{ .variable = "exportoff" } });
78 // DYSYMTAB directly follows SYMTAB (no gap)
79 check_exe.checkComputeCompare("symnsyms 16 symoff * +", .{ .op = .eq, .value = .{ .variable = "dysymoff" } });
6280
63 // Next check: we maintain order: symtab < dysymtab < strtab
64 check_exe.checkComputeCompare("symoff", .{ .op = .lt, .value = .{ .variable = "dysymoff" } });
65 check_exe.checkComputeCompare("dysymoff", .{ .op = .lt, .value = .{ .variable = "stroff" } });
81 // STRTAB follows DYSYMTAB with possible gap
82 check_exe.checkComputeCompare("dysymnsyms 4 dysymoff * +", .{ .op = .lte, .value = .{ .variable = "stroff" } });
6683
67 // Next check: all LINKEDIT sections apart from CODE_SIGNATURE are 8-bytes aligned
84 // all LINKEDIT sections apart from CODE_SIGNATURE are 8-bytes aligned
6885 check_exe.checkComputeCompare("rebaseoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
6986 check_exe.checkComputeCompare("bindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
7087 check_exe.checkComputeCompare("lazybindoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
7188 check_exe.checkComputeCompare("exportoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
89 check_exe.checkComputeCompare("fstartoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
90 check_exe.checkComputeCompare("diceoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
7291 check_exe.checkComputeCompare("symoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
7392 check_exe.checkComputeCompare("stroff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
7493 check_exe.checkComputeCompare("dysymoff 8 %", .{ .op = .eq, .value = .{ .literal = 0 } });
7594
7695 switch (builtin.cpu.arch) {
7796 .aarch64 => {
78 // Next check: LINKEDIT segment does not extend beyond, or does not include, CODE_SIGNATURE data
97 // LINKEDIT segment does not extend beyond, or does not include, CODE_SIGNATURE data
7998 check_exe.checkComputeCompare("fileoff filesz codesigoff codesigsize + - -", .{
8099 .op = .eq,
81100 .value = .{ .literal = 0 },
82101 });
83102
84 // Next check: CODE_SIGNATURE data offset is 16-bytes aligned
103 // CODE_SIGNATURE data offset is 16-bytes aligned
85104 check_exe.checkComputeCompare("codesigoff 16 %", .{ .op = .eq, .value = .{ .literal = 0 } });
86105 },
87106 .x86_64 => {
88 // Next check: LINKEDIT segment does not extend beyond, or does not include, strtab data
107 // LINKEDIT segment does not extend beyond, or does not include, strtab data
89108 check_exe.checkComputeCompare("fileoff filesz stroff strsize + - -", .{
90109 .op = .eq,
91110 .value = .{ .literal = 0 },
test/link/macho/uuid/build.zig+30-8
......@@ -5,23 +5,45 @@ const LibExeObjectStep = std.build.LibExeObjStep;
55pub fn build(b: *Builder) void {
66 const test_step = b.step("test", "Test");
77 test_step.dependOn(b.getInstallStep());
8 testUuid(b, test_step, .ReleaseSafe, "eb1203019e453d808d4f1e71053af9af");
9 testUuid(b, test_step, .ReleaseFast, "eb1203019e453d808d4f1e71053af9af");
10 testUuid(b, test_step, .ReleaseSmall, "eb1203019e453d808d4f1e71053af9af");
8
9 // We force cross-compilation to ensure we always pick a generic CPU with constant set of CPU features.
10 const aarch64_macos = std.zig.CrossTarget{
11 .cpu_arch = .aarch64,
12 .os_tag = .macos,
13 };
14
15 testUuid(b, test_step, .ReleaseSafe, aarch64_macos, "46b333df88f5314686fc0cba3b939ca8");
16 testUuid(b, test_step, .ReleaseFast, aarch64_macos, "46b333df88f5314686fc0cba3b939ca8");
17 testUuid(b, test_step, .ReleaseSmall, aarch64_macos, "46b333df88f5314686fc0cba3b939ca8");
18
19 const x86_64_macos = std.zig.CrossTarget{
20 .cpu_arch = .x86_64,
21 .os_tag = .macos,
22 };
23
24 testUuid(b, test_step, .ReleaseSafe, x86_64_macos, "342ac765194131e1bad5692b9e0e54a4");
25 testUuid(b, test_step, .ReleaseFast, x86_64_macos, "342ac765194131e1bad5692b9e0e54a4");
26 testUuid(b, test_step, .ReleaseSmall, x86_64_macos, "f119310e24773ecf8ec42e09d0379dad");
1127}
1228
13fn testUuid(b: *Builder, test_step: *std.build.Step, mode: std.builtin.Mode, comptime exp: []const u8) void {
29fn testUuid(
30 b: *Builder,
31 test_step: *std.build.Step,
32 mode: std.builtin.Mode,
33 target: std.zig.CrossTarget,
34 comptime exp: []const u8,
35) void {
1436 // The calculated UUID value is independent of debug info and so it should
1537 // stay the same across builds.
1638 {
17 const dylib = simpleDylib(b, mode);
39 const dylib = simpleDylib(b, mode, target);
1840 const check_dylib = dylib.checkObject(.macho);
1941 check_dylib.checkStart("cmd UUID");
2042 check_dylib.checkNext("uuid " ++ exp);
2143 test_step.dependOn(&check_dylib.step);
2244 }
2345 {
24 const dylib = simpleDylib(b, mode);
46 const dylib = simpleDylib(b, mode, target);
2547 dylib.strip = true;
2648 const check_dylib = dylib.checkObject(.macho);
2749 check_dylib.checkStart("cmd UUID");
......@@ -30,10 +52,10 @@ fn testUuid(b: *Builder, test_step: *std.build.Step, mode: std.builtin.Mode, com
3052 }
3153}
3254
33fn simpleDylib(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {
55fn simpleDylib(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
3456 const dylib = b.addSharedLibrary("test", null, b.version(1, 0, 0));
57 dylib.setTarget(target);
3558 dylib.setBuildMode(mode);
36 dylib.setTarget(.{ .cpu_arch = .aarch64, .os_tag = .macos });
3759 dylib.addCSourceFile("test.c", &.{});
3860 dylib.linkLibC();
3961 return dylib;