authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-02-21 14:27:07+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 19:56:55+01:00
log0b7af25637ce88f79461e6b855a8d59318b942ce
treed1b40ada5599451599e3444f37296fb9a2738db5
parent955fd65cb1705d8279eb195bdbc69810df1b1d98

MachO: fix `calcLoadCommandsSize` computation

Closes #19026

6 files changed, 34 insertions(+), 45 deletions(-)

src/link/MachO.zig+5-6
...@@ -2250,7 +2250,7 @@ fn initSegments(self: *MachO) !void {...@@ -2250,7 +2250,7 @@ fn initSegments(self: *MachO) !void {
2250}2250}
22512251
2252fn allocateSections(self: *MachO) !void {2252fn allocateSections(self: *MachO) !void {
2253 const headerpad = load_commands.calcMinHeaderPadSize(self);2253 const headerpad = try load_commands.calcMinHeaderPadSize(self);
2254 var vmaddr: u64 = if (self.pagezero_seg_index) |index|2254 var vmaddr: u64 = if (self.pagezero_seg_index) |index|
2255 self.segments.items[index].vmaddr + self.segments.items[index].vmsize2255 self.segments.items[index].vmaddr + self.segments.items[index].vmsize
2256 else2256 else
...@@ -2904,13 +2904,12 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 {...@@ -2904,13 +2904,12 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 {
29042904
2905fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {2905fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2906 const gpa = self.base.comp.gpa;2906 const gpa = self.base.comp.gpa;
2907 const needed_size = load_commands.calcLoadCommandsSize(self, false);2907 const needed_size = try load_commands.calcLoadCommandsSize(self, false);
2908 const buffer = try gpa.alloc(u8, needed_size);2908 const buffer = try gpa.alloc(u8, needed_size);
2909 defer gpa.free(buffer);2909 defer gpa.free(buffer);
29102910
2911 var stream = std.io.fixedBufferStream(buffer);2911 var stream = std.io.fixedBufferStream(buffer);
2912 var cwriter = std.io.countingWriter(stream.writer());2912 const writer = stream.writer();
2913 const writer = cwriter.writer();
29142913
2915 var ncmds: usize = 0;2914 var ncmds: usize = 0;
29162915
...@@ -2974,7 +2973,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2974,7 +2973,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2974 ncmds += 1;2973 ncmds += 1;
2975 }2974 }
29762975
2977 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + cwriter.bytes_written;2976 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;
2978 try writer.writeStruct(self.uuid_cmd);2977 try writer.writeStruct(self.uuid_cmd);
2979 ncmds += 1;2978 ncmds += 1;
29802979
...@@ -3002,7 +3001,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -3002,7 +3001,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
3002 ncmds += 1;3001 ncmds += 1;
3003 }3002 }
30043003
3005 assert(cwriter.bytes_written == needed_size);3004 assert(stream.pos == needed_size);
30063005
3007 try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));3006 try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
30083007
src/link/MachO/DebugSymbols.zig+2-3
...@@ -269,8 +269,7 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -269,8 +269,7 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
269 defer gpa.free(buffer);269 defer gpa.free(buffer);
270270
271 var stream = std.io.fixedBufferStream(buffer);271 var stream = std.io.fixedBufferStream(buffer);
272 var cwriter = std.io.countingWriter(stream.writer());272 const writer = stream.writer();
273 const writer = cwriter.writer();
274273
275 var ncmds: usize = 0;274 var ncmds: usize = 0;
276275
...@@ -314,7 +313,7 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -314,7 +313,7 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
314 try writer.writeStruct(self.symtab_cmd);313 try writer.writeStruct(self.symtab_cmd);
315 ncmds += 1;314 ncmds += 1;
316315
317 assert(cwriter.bytes_written == needed_size);316 assert(stream.pos == needed_size);
318317
319 try self.file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));318 try self.file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
320319
src/link/MachO/UnwindInfo.zig+4-9
...@@ -271,8 +271,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -271,8 +271,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
271 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];271 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];
272272
273 var stream = std.io.fixedBufferStream(buffer);273 var stream = std.io.fixedBufferStream(buffer);
274 var cwriter = std.io.countingWriter(stream.writer());274 const writer = stream.writer();
275 const writer = cwriter.writer();
276275
277 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);276 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
278 const common_encodings_count: u32 = info.common_encodings_count;277 const common_encodings_count: u32 = info.common_encodings_count;
...@@ -329,20 +328,16 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -329,20 +328,16 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
329 }328 }
330329
331 for (info.pages.items) |page| {330 for (info.pages.items) |page| {
332 const start = cwriter.bytes_written;331 const start = stream.pos;
333 try page.write(info, macho_file, writer);332 try page.write(info, macho_file, writer);
334 const nwritten = cwriter.bytes_written - start;333 const nwritten = stream.pos - start;
335 if (nwritten < second_level_page_bytes) {334 if (nwritten < second_level_page_bytes) {
336 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;335 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
337 try writer.writeByteNTimes(0, padding);336 try writer.writeByteNTimes(0, padding);
338 }337 }
339 }338 }
340339
341 const padding = buffer.len - cwriter.bytes_written;340 @memset(buffer[stream.pos..], 0);
342 if (padding > 0) {
343 const off = math.cast(usize, cwriter.bytes_written) orelse return error.Overflow;
344 @memset(buffer[off..], 0);
345 }
346}341}
347342
348fn getOrPutPersonalityFunction(info: *UnwindInfo, sym_index: Symbol.Index) error{TooManyPersonalities}!u2 {343fn getOrPutPersonalityFunction(info: *UnwindInfo, sym_index: Symbol.Index) error{TooManyPersonalities}!u2 {
src/link/MachO/dyld_info/bind.zig+7-11
...@@ -40,7 +40,7 @@ pub const Bind = struct {...@@ -40,7 +40,7 @@ pub const Bind = struct {
40 }40 }
4141
42 pub fn size(self: Self) u64 {42 pub fn size(self: Self) u64 {
43 return @as(u64, @intCast(self.buffer.items.len));43 return @intCast(self.buffer.items.len);
44 }44 }
4545
46 pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {46 pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
...@@ -124,7 +124,7 @@ pub const Bind = struct {...@@ -124,7 +124,7 @@ pub const Bind = struct {
124 switch (state) {124 switch (state) {
125 .start => {125 .start => {
126 if (current.offset < offset) {126 if (current.offset < offset) {
127 try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), writer);127 try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), writer);
128 offset = offset - (offset - current.offset);128 offset = offset - (offset - current.offset);
129 } else if (current.offset > offset) {129 } else if (current.offset > offset) {
130 const delta = current.offset - offset;130 const delta = current.offset - offset;
...@@ -195,7 +195,7 @@ pub const WeakBind = struct {...@@ -195,7 +195,7 @@ pub const WeakBind = struct {
195 }195 }
196196
197 pub fn size(self: Self) u64 {197 pub fn size(self: Self) u64 {
198 return @as(u64, @intCast(self.buffer.items.len));198 return @intCast(self.buffer.items.len);
199 }199 }
200200
201 pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {201 pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
...@@ -286,7 +286,7 @@ pub const WeakBind = struct {...@@ -286,7 +286,7 @@ pub const WeakBind = struct {
286 } else if (current.offset > offset) {286 } else if (current.offset > offset) {
287 const delta = current.offset - offset;287 const delta = current.offset - offset;
288 state = .bind_times_skip;288 state = .bind_times_skip;
289 skip = @as(u64, @intCast(delta));289 skip = @intCast(delta);
290 offset += skip;290 offset += skip;
291 } else unreachable;291 } else unreachable;
292 i -= 1;292 i -= 1;
...@@ -341,23 +341,20 @@ pub const LazyBind = struct {...@@ -341,23 +341,20 @@ pub const LazyBind = struct {
341 }341 }
342342
343 pub fn size(self: Self) u64 {343 pub fn size(self: Self) u64 {
344 return @as(u64, @intCast(self.buffer.items.len));344 return @intCast(self.buffer.items.len);
345 }345 }
346346
347 pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {347 pub fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
348 if (self.entries.items.len == 0) return;
349
350 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);348 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
351349
352 var cwriter = std.io.countingWriter(self.buffer.writer(gpa));350 const writer = self.buffer.writer(gpa);
353 const writer = cwriter.writer();
354351
355 log.debug("lazy bind opcodes", .{});352 log.debug("lazy bind opcodes", .{});
356353
357 var addend: i64 = 0;354 var addend: i64 = 0;
358355
359 for (self.entries.items) |entry| {356 for (self.entries.items) |entry| {
360 self.offsets.appendAssumeCapacity(@as(u32, @intCast(cwriter.bytes_written)));357 self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len));
361358
362 const sym = ctx.getSymbol(entry.target);359 const sym = ctx.getSymbol(entry.target);
363 const name = sym.getName(ctx);360 const name = sym.getName(ctx);
...@@ -388,7 +385,6 @@ pub const LazyBind = struct {...@@ -388,7 +385,6 @@ pub const LazyBind = struct {
388 }385 }
389386
390 pub fn write(self: Self, writer: anytype) !void {387 pub fn write(self: Self, writer: anytype) !void {
391 if (self.size() == 0) return;
392 try writer.writeAll(self.buffer.items);388 try writer.writeAll(self.buffer.items);
393 }389 }
394};390};
src/link/MachO/load_commands.zig+14-13
...@@ -17,7 +17,7 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool...@@ -17,7 +17,7 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool
17 return mem.alignForward(u64, cmd_size + name_len, @alignOf(u64));17 return mem.alignForward(u64, cmd_size + name_len, @alignOf(u64));
18}18}
1919
20pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {20pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 {
21 var sizeofcmds: u64 = 0;21 var sizeofcmds: u64 = 0;
2222
23 // LC_SEGMENT_6423 // LC_SEGMENT_64
...@@ -48,15 +48,16 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {...@@ -48,15 +48,16 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {
48 }48 }
49 // LC_ID_DYLIB49 // LC_ID_DYLIB
50 if (macho_file.base.isDynLib()) {50 if (macho_file.base.isDynLib()) {
51 sizeofcmds += blk: {51 const gpa = macho_file.base.comp.gpa;
52 const emit = macho_file.base.emit;52 const emit = macho_file.base.emit;
53 const install_name = macho_file.install_name orelse emit.sub_path;53 const install_name = macho_file.install_name orelse
54 break :blk calcInstallNameLen(54 try emit.directory.join(gpa, &.{emit.sub_path});
55 @sizeOf(macho.dylib_command),55 defer if (macho_file.install_name == null) gpa.free(install_name);
56 install_name,56 sizeofcmds += calcInstallNameLen(
57 assume_max_path_len,57 @sizeOf(macho.dylib_command),
58 );58 install_name,
59 };59 assume_max_path_len,
60 );
60 }61 }
61 // LC_RPATH62 // LC_RPATH
62 {63 {
...@@ -148,12 +149,12 @@ pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {...@@ -148,12 +149,12 @@ pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {
148 return @as(u32, @intCast(sizeofcmds));149 return @as(u32, @intCast(sizeofcmds));
149}150}
150151
151pub fn calcMinHeaderPadSize(macho_file: *MachO) u32 {152pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
152 var padding: u32 = calcLoadCommandsSize(macho_file, false) + (macho_file.headerpad_size orelse 0);153 var padding: u32 = (try calcLoadCommandsSize(macho_file, false)) + (macho_file.headerpad_size orelse 0);
153 log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});154 log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});
154155
155 if (macho_file.headerpad_max_install_names) {156 if (macho_file.headerpad_max_install_names) {
156 const min_headerpad_size: u32 = calcLoadCommandsSize(macho_file, true);157 const min_headerpad_size: u32 = try calcLoadCommandsSize(macho_file, true);
157 log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{158 log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{
158 min_headerpad_size + @sizeOf(macho.mach_header_64),159 min_headerpad_size + @sizeOf(macho.mach_header_64),
159 });160 });
src/link/MachO/relocatable.zig+2-3
...@@ -748,8 +748,7 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {...@@ -748,8 +748,7 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {
748 defer gpa.free(buffer);748 defer gpa.free(buffer);
749749
750 var stream = std.io.fixedBufferStream(buffer);750 var stream = std.io.fixedBufferStream(buffer);
751 var cwriter = std.io.countingWriter(stream.writer());751 const writer = stream.writer();
752 const writer = cwriter.writer();
753752
754 var ncmds: usize = 0;753 var ncmds: usize = 0;
755754
...@@ -779,7 +778,7 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {...@@ -779,7 +778,7 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {
779 ncmds += 1;778 ncmds += 1;
780 }779 }
781780
782 assert(cwriter.bytes_written == needed_size);781 assert(stream.pos == needed_size);
783782
784 try macho_file.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));783 try macho_file.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
785784