Skip to content

Commit 4497e42

Browse files
committed
macho: fix aligning linkedit sections
Align by file offsets and not file size.
1 parent ab8a670 commit 4497e42

File tree

1 file changed

+84
-68
lines changed

1 file changed

+84
-68
lines changed

src/link/MachO.zig

Lines changed: 84 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5715,43 +5715,62 @@ 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);
57435761

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

0 commit comments

Comments
 (0)