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 {...@@ -5715,28 +5715,46 @@ fn writeDyldInfoData(self: *MachO) !void {
57155715
5716 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;5716 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5717 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].dyld_info_only;5717 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));
5718 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);5720 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
5719 const bind_size = try bind.bindInfoSize(bind_pointers.items);5721 dyld_info.rebase_off = @intCast(u32, rebase_off);
5720 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);5722 dyld_info.rebase_size = @intCast(u32, rebase_size);
5721 const export_size = trie.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);5728 const bind_off = mem.alignForwardGeneric(u64, dyld_info.rebase_off + dyld_info.rebase_size, @alignOf(u64));
5724 dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, rebase_size, @alignOf(u64)));5729 const bind_size = try bind.bindInfoSize(bind_pointers.items);
5725 seg.inner.filesize += dyld_info.rebase_size;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;5737 const lazy_bind_off = mem.alignForwardGeneric(u64, dyld_info.bind_off + dyld_info.bind_size, @alignOf(u64));
5728 dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, bind_size, @alignOf(u64)));5738 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
5729 seg.inner.filesize += dyld_info.bind_size;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;5746 const export_off = mem.alignForwardGeneric(u64, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size, @alignOf(u64));
5732 dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, lazy_bind_size, @alignOf(u64)));5747 const export_size = trie.size;
5733 seg.inner.filesize += dyld_info.lazy_bind_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;5755 seg.inner.filesize = dyld_info.export_off + dyld_info.export_size - seg.inner.fileoff;
5736 dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, export_size, @alignOf(u64)));
5737 seg.inner.filesize += dyld_info.export_size;
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;
5740 var buffer = try self.base.allocator.alloc(u8, needed_size);5758 var buffer = try self.base.allocator.alloc(u8, needed_size);
5741 defer self.base.allocator.free(buffer);5759 defer self.base.allocator.free(buffer);
5742 mem.set(u8, buffer, 0);5760 mem.set(u8, buffer, 0);
...@@ -5744,14 +5762,15 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5744,14 +5762,15 @@ fn writeDyldInfoData(self: *MachO) !void {
5744 var stream = std.io.fixedBufferStream(buffer);5762 var stream = std.io.fixedBufferStream(buffer);
5745 const writer = stream.writer();5763 const writer = stream.writer();
57465764
5765 const base_off = dyld_info.rebase_off;
5747 try bind.writeRebaseInfo(rebase_pointers.items, writer);5766 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
5750 try bind.writeBindInfo(bind_pointers.items, writer);5769 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
5753 try bind.writeLazyBindInfo(lazy_bind_pointers.items, writer);5772 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
5756 _ = try trie.write(writer);5775 _ = try trie.write(writer);
57575776
...@@ -5762,7 +5781,7 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -5762,7 +5781,7 @@ fn writeDyldInfoData(self: *MachO) !void {
57625781
5763 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);5782 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
5764 try self.populateLazyBindOffsetsInStubHelper(5783 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],
5766 );5785 );
5767 self.load_commands_dirty = true;5786 self.load_commands_dirty = true;
5768}5787}
...@@ -5932,32 +5951,31 @@ fn writeFunctionStarts(self: *MachO) !void {...@@ -5932,32 +5951,31 @@ fn writeFunctionStarts(self: *MachO) !void {
5932 } else break;5951 } else break;
5933 }5952 }
59345953
5935 const max_size = @intCast(usize, offsets.items.len * @sizeOf(u64));5954 var buffer = std.ArrayList(u8).init(self.base.allocator);
5936 var buffer = try self.base.allocator.alloc(u8, max_size);5955 defer buffer.deinit();
5937 defer self.base.allocator.free(buffer);
5938 mem.set(u8, buffer, 0);
59395956
5940 var stream = std.io.fixedBufferStream(buffer);5957 const max_size = @intCast(usize, offsets.items.len * @sizeOf(u64));
5941 const writer = stream.writer();5958 try buffer.ensureTotalCapacity(max_size);
59425959
5943 for (offsets.items) |offset| {5960 for (offsets.items) |offset| {
5944 try std.leb.writeULEB128(writer, offset);5961 try std.leb.writeULEB128(buffer.writer(), offset);
5945 }5962 }
59465963
5947 const needed_size = @intCast(u32, mem.alignForwardGeneric(u64, stream.pos, @sizeOf(u64)));
5948 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;5964 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
5949 const fn_cmd = &self.load_commands.items[self.function_starts_cmd_index.?].linkedit_data;5965 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);5967 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
5952 fn_cmd.datasize = needed_size;5968 const datasize = buffer.items.len;
5953 seg.inner.filesize += needed_size;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
5955 log.debug("writing function starts info from 0x{x} to 0x{x}", .{5973 log.debug("writing function starts info from 0x{x} to 0x{x}", .{
5956 fn_cmd.dataoff,5974 fn_cmd.dataoff,
5957 fn_cmd.dataoff + fn_cmd.datasize,5975 fn_cmd.dataoff + fn_cmd.datasize,
5958 });5976 });
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);
5961 self.load_commands_dirty = true;5979 self.load_commands_dirty = true;
5962}5980}
59635981
...@@ -6005,11 +6023,12 @@ fn writeDices(self: *MachO) !void {...@@ -6005,11 +6023,12 @@ fn writeDices(self: *MachO) !void {
60056023
6006 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;6024 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6007 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].linkedit_data;6025 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);6027 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
6011 dice_cmd.datasize = needed_size;6028 const datasize = buf.items.len;
6012 seg.inner.filesize += needed_size;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
6014 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{6033 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{
6015 dice_cmd.dataoff,6034 dice_cmd.dataoff,
...@@ -6026,7 +6045,8 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -6026,7 +6045,8 @@ fn writeSymbolTable(self: *MachO) !void {
60266045
6027 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;6046 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6028 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;6047 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
6031 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);6051 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
6032 defer locals.deinit();6052 defer locals.deinit();
...@@ -6126,7 +6146,7 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -6126,7 +6146,7 @@ fn writeSymbolTable(self: *MachO) !void {
6126 try self.base.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off);6146 try self.base.file.?.pwriteAll(mem.sliceAsBytes(undefs.items), undefs_off);
61276147
6128 symtab.nsyms = @intCast(u32, nlocals + nexports + nundefs);6148 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
6131 // Update dynamic symbol table.6151 // Update dynamic symbol table.
6132 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].dysymtab;6152 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].dysymtab;
...@@ -6146,22 +6166,21 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -6146,22 +6166,21 @@ fn writeSymbolTable(self: *MachO) !void {
6146 const nstubs = @intCast(u32, self.stubs_table.keys().len);6166 const nstubs = @intCast(u32, self.stubs_table.keys().len);
6147 const ngot_entries = @intCast(u32, self.got_entries_table.keys().len);6167 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);
6150 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;6171 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;
61516172
6152 const needed_size = dysymtab.nindirectsyms * @sizeOf(u32);6173 seg.inner.filesize = dysymtab.indirectsymoff + dysymtab.nindirectsyms * @sizeOf(u32) - seg.inner.fileoff;
6153 seg.inner.filesize += needed_size;
61546174
6155 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{6175 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{
6156 dysymtab.indirectsymoff,6176 dysymtab.indirectsymoff,
6157 dysymtab.indirectsymoff + needed_size,6177 dysymtab.indirectsymoff + dysymtab.nindirectsyms * @sizeOf(u32),
6158 });6178 });
61596179
6160 var buf = try self.base.allocator.alloc(u8, needed_size);6180 var buf = std.ArrayList(u8).init(self.base.allocator);
6161 defer self.base.allocator.free(buf);6181 defer buf.deinit();
61626182 try buf.ensureTotalCapacity(dysymtab.nindirectsyms * @sizeOf(u32));
6163 var stream = std.io.fixedBufferStream(buf);6183 const writer = buf.writer();
6164 var writer = stream.writer();
61656184
6166 stubs.reserved1 = 0;6185 stubs.reserved1 = 0;
6167 for (self.stubs_table.keys()) |key| {6186 for (self.stubs_table.keys()) |key| {
...@@ -6195,7 +6214,9 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -6195,7 +6214,9 @@ fn writeSymbolTable(self: *MachO) !void {
6195 }6214 }
6196 }6215 }
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);
6199 self.load_commands_dirty = true;6220 self.load_commands_dirty = true;
6200}6221}
62016222
...@@ -6205,18 +6226,16 @@ fn writeStringTable(self: *MachO) !void {...@@ -6205,18 +6226,16 @@ fn writeStringTable(self: *MachO) !void {
62056226
6206 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;6227 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;
6207 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;6228 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].symtab;
6208 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);6229 const stroff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64));
6209 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));6230 const strsize = self.strtab.items.len;
6210 seg.inner.filesize += symtab.strsize;6231 symtab.stroff = @intCast(u32, stroff);
6232 symtab.strsize = @intCast(u32, strsize);
6233 seg.inner.filesize = symtab.stroff + symtab.strsize - seg.inner.fileoff;
62116234
6212 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });6235 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
62136236
6214 try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);6237 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 }
6220 self.load_commands_dirty = true;6239 self.load_commands_dirty = true;
6221}6240}
62226241
...@@ -6240,25 +6259,22 @@ fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {...@@ -6240,25 +6259,22 @@ fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
6240 const tracy = trace(@src());6259 const tracy = trace(@src());
6241 defer tracy.end();6260 defer tracy.end();
62426261
6243 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment;6262 const seg = &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;6263 const cs_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data;
6245 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file6264 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
6246 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L2716265 // 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);6266 const dataoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, 16);
6248 const padding = fileoff - (linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize);6267 const datasize = code_sig.estimateSize(dataoff);
6249 const needed_size = code_sig.estimateSize(fileoff);6268 cs_cmd.dataoff = @intCast(u32, dataoff);
6250 code_sig_cmd.dataoff = @intCast(u32, fileoff);6269 cs_cmd.datasize = @intCast(u32, code_sig.estimateSize(dataoff));
6251 code_sig_cmd.datasize = needed_size;
62526270
6253 // Advance size of __LINKEDIT segment6271 // Advance size of __LINKEDIT segment
6254 linkedit_segment.inner.filesize += needed_size + padding;6272 seg.inner.filesize = cs_cmd.dataoff + cs_cmd.datasize - seg.inner.fileoff;
6255 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {6273 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size);
6256 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);6274 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ dataoff, dataoff + datasize });
6257 }
6258 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
6259 // Pad out the space. We need to do this to calculate valid hashes for everything in the file6275 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
6260 // except for code signature data.6276 // 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);
6262 self.load_commands_dirty = true;6278 self.load_commands_dirty = true;
6263}6279}
62646280