authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-09 00:01:20+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-09 00:01:22+02:00
log8378cde74369ddb1cc618d444970e963a4ab1110
tree62bec6ea56c64a96c13ba304d35320b80184d013
parent0ae2ea671b867e5ecd0bc779405c175f33316559

macho: prefill any space between __DATA and __LINKEDIT with 0s if required

If there are zerofill sections, the loader may copy the contents of the physical space in file directly into memory and attach that to the zerofill section. This is a performance optimisation in the loader but requires us, the linker, to properly zero-out any space between __DATA and __LINKEDIT segments in file. This is of course completely skipped if there are no zerofill sections present.

1 files changed, 26 insertions(+), 2 deletions(-)

src/link/MachO.zig+26-2
...@@ -1157,6 +1157,28 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -1157,6 +1157,28 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
1157 var ncmds: u32 = 0;1157 var ncmds: u32 = 0;
11581158
1159 try self.writeLinkeditSegmentData(&ncmds, lc_writer);1159 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
1160
1161 // If the last section of __DATA segment is zerofill section, we need to ensure
1162 // that the free space between the end of the last non-zerofill section of __DATA
1163 // segment and the beginning of __LINKEDIT segment is zerofilled as the loader will
1164 // copy-paste this space into memory for quicker zerofill operation.
1165 if (self.data_segment_cmd_index) |data_seg_id| blk: {
1166 var physical_zerofill_start: u64 = 0;
1167 const section_indexes = self.getSectionIndexes(data_seg_id);
1168 for (self.sections.items(.header)[section_indexes.start..section_indexes.end]) |header| {
1169 if (header.isZerofill() and header.size > 0) break;
1170 physical_zerofill_start = header.offset + header.size;
1171 } else break :blk;
1172 const linkedit = self.segments.items[self.linkedit_segment_cmd_index.?];
1173 const physical_zerofill_size = linkedit.fileoff - physical_zerofill_start;
1174 if (physical_zerofill_size > 0) {
1175 var padding = try self.base.allocator.alloc(u8, physical_zerofill_size);
1176 defer self.base.allocator.free(padding);
1177 mem.set(u8, padding, 0);
1178 try self.base.file.?.pwriteAll(padding, physical_zerofill_start);
1179 }
1180 }
1181
1160 try writeDylinkerLC(&ncmds, lc_writer);1182 try writeDylinkerLC(&ncmds, lc_writer);
1161 try self.writeMainLC(&ncmds, lc_writer);1183 try self.writeMainLC(&ncmds, lc_writer);
1162 try self.writeDylibIdLC(&ncmds, lc_writer);1184 try self.writeDylibIdLC(&ncmds, lc_writer);
...@@ -5690,8 +5712,10 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {...@@ -5690,8 +5712,10 @@ fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void {
5690 else => unreachable,5712 else => unreachable,
5691 }5713 }
56925714
5693 if (self.getSectionByName("__DATA", "__thread_vars")) |_| {5715 if (self.getSectionByName("__DATA", "__thread_vars")) |sect_id| {
5694 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;5716 if (self.sections.items(.header)[sect_id].size > 0) {
5717 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;
5718 }
5695 }5719 }
56965720
5697 header.ncmds = ncmds;5721 header.ncmds = ncmds;