authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-23 11:31:02+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-23 13:16:00+02:00
log4497e422f0629ccbde699d7ecc900ab7e358caa2
treee27e137ddad673447aec4e58d33cfb961d4ce171
parentab8a670a571f6ae5edb77dba13f0e250c53d3742

macho: fix aligning linkedit sections

Align by file offsets and not file size.

1 files changed, 84 insertions(+), 68 deletions(-)

src/link/MachO.zig+84-68
......@@ -5715,28 +5715,46 @@ fn writeDyldInfoData(self: *MachO) !void {
57155715
57165716 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
57175717 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].dyld_info_only;
5718
5719 const rebase_off = mem.alignForwardGeneric(u64, seg.inner.fileoff, @alignOf(u64));
57185720 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
5719 const bind_size = try bind.bindInfoSize(bind_pointers.items);
5720 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
5721 const export_size = trie.size;
5721 dyld_info.rebase_off = @intCast(u32, rebase_off);
5722 dyld_info.rebase_size = @intCast(u32, rebase_size);
5723 log.debug("writing rebase info from 0x{x} to 0x{x}", .{
5724 dyld_info.rebase_off,
5725 dyld_info.rebase_off + dyld_info.rebase_size,
5726 });
57225727
5723 dyld_info.rebase_off = @intCast(u32, seg.inner.fileoff);
5724 dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, rebase_size, @alignOf(u64)));
5725 seg.inner.filesize += dyld_info.rebase_size;
5728 const bind_off = mem.alignForwardGeneric(u64, dyld_info.rebase_off + dyld_info.rebase_size, @alignOf(u64));
5729 const bind_size = try bind.bindInfoSize(bind_pointers.items);
5730 dyld_info.bind_off = @intCast(u32, bind_off);
5731 dyld_info.bind_size = @intCast(u32, bind_size);
5732 log.debug("writing bind info from 0x{x} to 0x{x}", .{
5733 dyld_info.bind_off,
5734 dyld_info.bind_off + dyld_info.bind_size,
5735 });
57265736
5727 dyld_info.bind_off = dyld_info.rebase_off + dyld_info.rebase_size;
5728 dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, bind_size, @alignOf(u64)));
5729 seg.inner.filesize += dyld_info.bind_size;
5737 const lazy_bind_off = mem.alignForwardGeneric(u64, dyld_info.bind_off + dyld_info.bind_size, @alignOf(u64));
5738 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
5739 dyld_info.lazy_bind_off = @intCast(u32, lazy_bind_off);
5740 dyld_info.lazy_bind_size = @intCast(u32, lazy_bind_size);
5741 log.debug("writing lazy bind info from 0x{x} to 0x{x}", .{
5742 dyld_info.lazy_bind_off,
5743 dyld_info.lazy_bind_off + dyld_info.lazy_bind_size,
5744 });
57305745
5731 dyld_info.lazy_bind_off = dyld_info.bind_off + dyld_info.bind_size;
5732 dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, lazy_bind_size, @alignOf(u64)));
5733 seg.inner.filesize += dyld_info.lazy_bind_size;
5746 const export_off = mem.alignForwardGeneric(u64, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size, @alignOf(u64));
5747 const export_size = trie.size;
5748 dyld_info.export_off = @intCast(u32, export_off);
5749 dyld_info.export_size = @intCast(u32, export_size);
5750 log.debug("writing export trie from 0x{x} to 0x{x}", .{
5751 dyld_info.export_off,
5752 dyld_info.export_off + dyld_info.export_size,
5753 });
57345754
5735 dyld_info.export_off = dyld_info.lazy_bind_off + dyld_info.lazy_bind_size;
5736 dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, export_size, @alignOf(u64)));
5737 seg.inner.filesize += dyld_info.export_size;
5755 seg.inner.filesize = dyld_info.export_off + dyld_info.export_size - seg.inner.fileoff;
57385756
5739 const needed_size = dyld_info.rebase_size + dyld_info.bind_size + dyld_info.lazy_bind_size + dyld_info.export_size;
5757 const needed_size = dyld_info.export_off + dyld_info.export_size - dyld_info.rebase_off;
57405758 var buffer = try self.base.allocator.alloc(u8, needed_size);
57415759 defer self.base.allocator.free(buffer);
57425760 mem.set(u8, buffer, 0);
......@@ -5744,14 +5762,15 @@ fn writeDyldInfoData(self: *MachO) !void {
57445762 var stream = std.io.fixedBufferStream(buffer);
57455763 const writer = stream.writer();
57465764
5765 const base_off = dyld_info.rebase_off;
57475766 try bind.writeRebaseInfo(rebase_pointers.items, writer);
5748 try stream.seekBy(@intCast(i64, dyld_info.rebase_size) - @intCast(i64, rebase_size));
5767 try stream.seekTo(dyld_info.bind_off - base_off);
57495768
57505769 try bind.writeBindInfo(bind_pointers.items, writer);
5751 try stream.seekBy(@intCast(i64, dyld_info.bind_size) - @intCast(i64, bind_size));
5770 try stream.seekTo(dyld_info.lazy_bind_off - base_off);
57525771
57535772 try bind.writeLazyBindInfo(lazy_bind_pointers.items, writer);
5754 try stream.seekBy(@intCast(i64, dyld_info.lazy_bind_size) - @intCast(i64, lazy_bind_size));
5773 try stream.seekTo(dyld_info.export_off - base_off);
57555774
57565775 _ = try trie.write(writer);
57575776
......@@ -5762,7 +5781,7 @@ fn writeDyldInfoData(self: *MachO) !void {
57625781
57635782 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
57645783 try self.populateLazyBindOffsetsInStubHelper(
5765 buffer[dyld_info.rebase_size + dyld_info.bind_size ..][0..dyld_info.lazy_bind_size],
5784 buffer[dyld_info.lazy_bind_off - base_off ..][0..dyld_info.lazy_bind_size],
57665785 );
57675786 self.load_commands_dirty = true;
57685787}
......@@ -5932,32 +5951,31 @@ fn writeFunctionStarts(self: *MachO) !void {
59325951 } else break;
59335952 }
59345953
5935 const max_size = @intCast(usize, offsets.items.len * @sizeOf(u64));
5936 var buffer = try self.base.allocator.alloc(u8, max_size);
5937 defer self.base.allocator.free(buffer);
5938 mem.set(u8, buffer, 0);
5954 var buffer = std.ArrayList(u8).init(self.base.allocator);
5955 defer buffer.deinit();
59395956
5940 var stream = std.io.fixedBufferStream(buffer);
5941 const writer = stream.writer();
5957 const max_size = @intCast(usize, offsets.items.len * @sizeOf(u64));
5958 try buffer.ensureTotalCapacity(max_size);
59425959
59435960 for (offsets.items) |offset| {
5944 try std.leb.writeULEB128(writer, offset);
5961 try std.leb.writeULEB128(buffer.writer(), offset);
59455962 }
59465963
5947 const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64)));
59485964 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
59495965 const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].linkedit_data;
59505966
5951 fn_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
5952 fn_cmd.datasize = needed_size;
5953 seg.inner.filesize += needed_size;
5967 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
5968 const datasize = buffer.items.len;
5969 fn_cmd.dataoff = @intCast(u32, dataoff);
5970 fn_cmd.datasize = @intCast(u32, datasize);
5971 seg.inner.filesize = fn_cmd.dataoff + fn_cmd.datasize - seg.inner.fileoff;
59545972
59555973 log.debug("writing function starts info from 0x{x} to 0x{x}", .{
59565974 fn_cmd.dataoff,
59575975 fn_cmd.dataoff + fn_cmd.datasize,
59585976 });
59595977
5960 try self.base.file.?.pwriteAll(buffer[0..needed_size], fn_cmd.dataoff);
5978 try self.base.file.?.pwriteAll(buffer.items, fn_cmd.dataoff);
59615979 self.load_commands_dirty = true;
59625980}
59635981
......@@ -6005,11 +6023,12 @@ fn writeDices(self: *MachO) !void {
60056023
60066024 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
60076025 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data;
6008 const needed_size = @intCast(u32, buf.items.len);
60096026
6010 dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
6011 dice_cmd.datasize = needed_size;
6012 seg.inner.filesize += needed_size;
6027 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
6028 const datasize = buf.items.len;
6029 dice_cmd.dataoff = @intCast(u32, dataoff);
6030 dice_cmd.datasize = @intCast(u32, datasize);
6031 seg.inner.filesize = dice_cmd.dataoff + dice_cmd.datasize - seg.inner.fileoff;
60136032
60146033 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{
60156034 dice_cmd.dataoff,
......@@ -6026,7 +6045,8 @@ fn writeSymbolTable(self: *MachO) !void {
60266045
60276046 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
60286047 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
6029 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
6048 const symoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(macho.nlist_64));
6049 symtab.symoff = @intCast(u32, symoff);
60306050
60316051 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
60326052 defer locals.deinit();
......@@ -6126,7 +6146,7 @@ fn writeSymbolTable(self: *MachO) !void {
61266146 try self.base.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off);
61276147
61286148 symtab.nsyms = @intCast(u32, nlocals + nexports + nundefs);
6129 seg.inner.filesize += locals_size + exports_size + undefs_size;
6149 seg.inner.filesize = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64) - seg.inner.fileoff;
61306150
61316151 // Update dynamic symbol table.
61326152 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].dysymtab;
......@@ -6146,22 +6166,21 @@ fn writeSymbolTable(self: *MachO) !void {
61466166 const nstubs = @intCast(u32, self.stubs_table.keys().len);
61476167 const ngot_entries = @intCast(u32, self.got_entries_table.keys().len);
61486168
6149 dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
6169 const indirectsymoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
6170 dysymtab.indirectsymoff = @intCast(u32, indirectsymoff);
61506171 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;
61516172
6152 const needed_size = dysymtab.nindirectsyms * @sizeOf(u32);
6153 seg.inner.filesize += needed_size;
6173 seg.inner.filesize = dysymtab.indirectsymoff + dysymtab.nindirectsyms * @sizeOf(u32) - seg.inner.fileoff;
61546174
61556175 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{
61566176 dysymtab.indirectsymoff,
6157 dysymtab.indirectsymoff + needed_size,
6177 dysymtab.indirectsymoff + dysymtab.nindirectsyms * @sizeOf(u32),
61586178 });
61596179
6160 var buf = try self.base.allocator.alloc(u8, needed_size);
6161 defer self.base.allocator.free(buf);
6162
6163 var stream = std.io.fixedBufferStream(buf);
6164 var writer = stream.writer();
6180 var buf = std.ArrayList(u8).init(self.base.allocator);
6181 defer buf.deinit();
6182 try buf.ensureTotalCapacity(dysymtab.nindirectsyms * @sizeOf(u32));
6183 const writer = buf.writer();
61656184
61666185 stubs.reserved1 = 0;
61676186 for (self.stubs_table.keys()) |key| {
......@@ -6195,7 +6214,9 @@ fn writeSymbolTable(self: *MachO) !void {
61956214 }
61966215 }
61976216
6198 try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
6217 assert(buf.items.len == dysymtab.nindirectsyms * @sizeOf(u32));
6218
6219 try self.base.file.?.pwriteAll(buf.items, dysymtab.indirectsymoff);
61996220 self.load_commands_dirty = true;
62006221}
62016222
......@@ -6205,18 +6226,16 @@ fn writeStringTable(self: *MachO) !void {
62056226
62066227 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
62076228 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
6208 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
6209 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
6210 seg.inner.filesize += symtab.strsize;
6229 const stroff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
6230 const strsize = self.strtab.items.len;
6231 symtab.stroff = @intCast(u32, stroff);
6232 symtab.strsize = @intCast(u32, strsize);
6233 seg.inner.filesize = symtab.stroff + symtab.strsize - seg.inner.fileoff;
62116234
62126235 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
62136236
62146237 try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
62156238
6216 if (symtab.strsize > self.strtab.items.len) {
6217 // This is potentially the last section, so we need to pad it out.
6218 try self.base.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
6219 }
62206239 self.load_commands_dirty = true;
62216240}
62226241
......@@ -6240,25 +6259,22 @@ fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
62406259 const tracy = trace(@src());
62416260 defer tracy.end();
62426261
6243 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6244 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
6262 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6263 const cs_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
62456264 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
62466265 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271
6247 const fileoff = mem.alignForwardGeneric(u64, linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize, 16);
6248 const padding = fileoff - (linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize);
6249 const needed_size = code_sig.estimateSize(fileoff);
6250 code_sig_cmd.dataoff = @intCast(u32, fileoff);
6251 code_sig_cmd.datasize = needed_size;
6266 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, 16);
6267 const datasize = code_sig.estimateSize(dataoff);
6268 cs_cmd.dataoff = @intCast(u32, dataoff);
6269 cs_cmd.datasize = @intCast(u32, code_sig.estimateSize(dataoff));
62526270
62536271 // Advance size of __LINKEDIT segment
6254 linkedit_segment.inner.filesize += needed_size + padding;
6255 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
6256 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
6257 }
6258 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
6272 seg.inner.filesize = cs_cmd.dataoff + cs_cmd.datasize - seg.inner.fileoff;
6273 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size);
6274 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ dataoff, dataoff + datasize });
62596275 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
62606276 // except for code signature data.
6261 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
6277 try self.base.file.?.pwriteAll(&[_]u8{0}, dataoff + datasize - 1);
62626278 self.load_commands_dirty = true;
62636279}
62646280