authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-16 12:31:02+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-18 10:00:04+02:00
log275abf7c5712e572c96db825cc4a0e46a4890250
treee3f3d3c8f4ff8f9a533f3eb1116196c9966e87f1
parent66942cbc1a42b8d959da657bf0c2b192a3726719

macho: fix overlapping segments in file offset


1 files changed, 42 insertions(+), 33 deletions(-)

src/link/MachO.zig+42-33
...@@ -1137,11 +1137,10 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {...@@ -1137,11 +1137,10 @@ pub fn allocateSpecialSymbols(self: *MachO) !void {
1137 const global = self.getGlobal(name) orelse continue;1137 const global = self.getGlobal(name) orelse continue;
1138 if (global.file != null) continue;1138 if (global.file != null) continue;
1139 const sym = self.getSymbolPtr(global);1139 const sym = self.getSymbolPtr(global);
1140 const seg_id = switch (self.mode) {1140 const seg = switch (self.mode) {
1141 .incremental => self.sections.items(.segment_index)[self.text_section_index.?],1141 .incremental => self.getSegment(self.text_section_index.?),
1142 .one_shot => self.text_segment_cmd_index.?,1142 .one_shot => self.segments.items[self.text_segment_cmd_index.?],
1143 };1143 };
1144 const seg = self.segments.items[seg_id];
1145 sym.n_sect = 1;1144 sym.n_sect = 1;
1146 sym.n_value = seg.vmaddr;1145 sym.n_value = seg.vmaddr;
11471146
...@@ -2239,7 +2238,6 @@ pub fn writeMainLC(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -2239,7 +2238,6 @@ pub fn writeMainLC(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
2239 if (self.base.options.output_mode != .Exe) return;2238 if (self.base.options.output_mode != .Exe) return;
2240 const seg_id = switch (self.mode) {2239 const seg_id = switch (self.mode) {
2241 .incremental => self.header_segment_cmd_index.?,2240 .incremental => self.header_segment_cmd_index.?,
2242 // .incremental => self.sections.items(.segment_index)[self.text_section_index.?],
2243 .one_shot => self.text_segment_cmd_index.?,2241 .one_shot => self.text_segment_cmd_index.?,
2244 };2242 };
2245 const seg = self.segments.items[seg_id];2243 const seg = self.segments.items[seg_id];
...@@ -3713,9 +3711,9 @@ fn allocateSection(self: *MachO, segname: []const u8, sectname: []const u8, opts...@@ -3713,9 +3711,9 @@ fn allocateSection(self: *MachO, segname: []const u8, sectname: []const u8, opts
3713 return section_id;3711 return section_id;
3714}3712}
37153713
3716fn moveSectionInVirtualMemory(self: *MachO, sect_id: u32, needed_size: u64) !void {3714fn moveSectionInVirtualMemory(self: *MachO, sect_id: u8, needed_size: u64) !void {
3717 const header = &self.sections.items(.header)[sect_id];3715 const header = &self.sections.items(.header)[sect_id];
3718 const segment = &self.segments.items[self.sections.items(.segment_index)[sect_id]];3716 const segment = self.getSegmentPtr(sect_id);
3719 const increased_size = padToIdeal(needed_size);3717 const increased_size = padToIdeal(needed_size);
3720 const old_aligned_end = segment.vmaddr + segment.vmsize;3718 const old_aligned_end = segment.vmaddr + segment.vmsize;
3721 const new_aligned_end = segment.vmaddr + mem.alignForwardGeneric(u64, increased_size, self.page_size);3719 const new_aligned_end = segment.vmaddr + mem.alignForwardGeneric(u64, increased_size, self.page_size);
...@@ -3728,9 +3726,9 @@ fn moveSectionInVirtualMemory(self: *MachO, sect_id: u32, needed_size: u64) !voi...@@ -3728,9 +3726,9 @@ fn moveSectionInVirtualMemory(self: *MachO, sect_id: u32, needed_size: u64) !voi
37283726
3729 // TODO: enforce order by increasing VM addresses in self.sections container.3727 // TODO: enforce order by increasing VM addresses in self.sections container.
3730 for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| {3728 for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| {
3731 const index = sect_id + 1 + next_sect_id;3729 const index = @intCast(u8, sect_id + 1 + next_sect_id);
3732 const maybe_last_atom = &self.sections.items(.last_atom)[index];3730 const maybe_last_atom = &self.sections.items(.last_atom)[index];
3733 const next_segment = &self.segments.items[self.sections.items(.segment_index)[index]];3731 const next_segment = self.getSegmentPtr(index);
3734 next_header.addr += diff;3732 next_header.addr += diff;
3735 next_segment.vmaddr += diff;3733 next_segment.vmaddr += diff;
37363734
...@@ -3753,7 +3751,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !...@@ -3753,7 +3751,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !
3753 defer tracy.end();3751 defer tracy.end();
37543752
3755 const sect_id = atom.getSymbol(self).n_sect - 1;3753 const sect_id = atom.getSymbol(self).n_sect - 1;
3756 const segment = &self.segments.items[self.sections.items(.segment_index)[sect_id]];3754 const segment = self.getSegmentPtr(sect_id);
3757 const header = &self.sections.items(.header)[sect_id];3755 const header = &self.sections.items(.header)[sect_id];
3758 const free_list = &self.sections.items(.free_list)[sect_id];3756 const free_list = &self.sections.items(.free_list)[sect_id];
3759 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];3757 const maybe_last_atom = &self.sections.items(.last_atom)[sect_id];
...@@ -4017,7 +4015,7 @@ fn writeSegmentHeaders(self: *MachO, ncmds: *u32, writer: anytype) !void {...@@ -4017,7 +4015,7 @@ fn writeSegmentHeaders(self: *MachO, ncmds: *u32, writer: anytype) !void {
4017}4015}
40184016
4019fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {4017fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
4020 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];4018 const seg = self.getLinkeditSegmentPtr();
4021 seg.filesize = 0;4019 seg.filesize = 0;
4022 seg.vmsize = 0;4020 seg.vmsize = 0;
40234021
...@@ -4061,15 +4059,14 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -4061,15 +4059,14 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
4061 const slice = self.sections.slice();4059 const slice = self.sections.slice();
4062 for (slice.items(.last_atom)) |last_atom, sect_id| {4060 for (slice.items(.last_atom)) |last_atom, sect_id| {
4063 var atom = last_atom orelse continue;4061 var atom = last_atom orelse continue;
4064 const segment_index = slice.items(.segment_index)[sect_id];
4065 const header = slice.items(.header)[sect_id];4062 const header = slice.items(.header)[sect_id];
4063 const segment_index = slice.items(.segment_index)[sect_id];
4064 const seg = self.getSegment(@intCast(u8, sect_id));
40664065
4067 if (mem.eql(u8, header.segName(), "__TEXT")) continue; // __TEXT is non-writable4066 if (mem.eql(u8, header.segName(), "__TEXT")) continue; // __TEXT is non-writable
40684067
4069 log.debug("dyld info for {s},{s}", .{ header.segName(), header.sectName() });4068 log.debug("dyld info for {s},{s}", .{ header.segName(), header.sectName() });
40704069
4071 const seg = self.segments.items[segment_index];
4072
4073 while (true) {4070 while (true) {
4074 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });4071 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) });
4075 const sym = atom.getSymbol(self);4072 const sym = atom.getSymbol(self);
...@@ -4193,7 +4190,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -4193,7 +4190,7 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
4193 try trie.finalize(gpa);4190 try trie.finalize(gpa);
4194 }4191 }
41954192
4196 const link_seg = &self.segments.items[self.linkedit_segment_cmd_index.?];4193 const link_seg = self.getLinkeditSegmentPtr();
4197 const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64));4194 const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64));
4198 assert(rebase_off == link_seg.fileoff);4195 assert(rebase_off == link_seg.fileoff);
4199 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);4196 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
...@@ -4275,11 +4272,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -4275,11 +4272,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
4275 {4272 {
4276 var stub_atom = last_atom;4273 var stub_atom = last_atom;
4277 var laptr_atom = self.sections.items(.last_atom)[self.la_symbol_ptr_section_index.?].?;4274 var laptr_atom = self.sections.items(.last_atom)[self.la_symbol_ptr_section_index.?].?;
4278 const base_addr = blk: {4275 const base_addr = self.getSegment(self.la_symbol_ptr_section_index.?).vmaddr;
4279 const seg_id = self.sections.items(.segment_index)[self.la_symbol_ptr_section_index.?];
4280 const seg = self.segments.items[seg_id];
4281 break :blk seg.vmaddr;
4282 };
42834276
4284 while (true) {4277 while (true) {
4285 const laptr_off = blk: {4278 const laptr_off = blk: {
...@@ -4461,7 +4454,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -4461,7 +4454,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
4461 const nimports = @intCast(u32, imports.items.len);4454 const nimports = @intCast(u32, imports.items.len);
4462 const nsyms = nlocals + nexports + nimports;4455 const nsyms = nlocals + nexports + nimports;
44634456
4464 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];4457 const seg = self.getLinkeditSegmentPtr();
4465 const offset = mem.alignForwardGeneric(4458 const offset = mem.alignForwardGeneric(
4466 u64,4459 u64,
4467 seg.fileoff + seg.filesize,4460 seg.fileoff + seg.filesize,
...@@ -4492,7 +4485,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -4492,7 +4485,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
4492}4485}
44934486
4494fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {4487fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {
4495 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];4488 const seg = self.getLinkeditSegmentPtr();
4496 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));4489 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
4497 const needed_size = self.strtab.buffer.items.len;4490 const needed_size = self.strtab.buffer.items.len;
4498 seg.filesize = offset + needed_size - seg.fileoff;4491 seg.filesize = offset + needed_size - seg.fileoff;
...@@ -4520,7 +4513,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx, lc: *macho.dysymtab_command) !voi...@@ -4520,7 +4513,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx, lc: *macho.dysymtab_command) !voi
4520 const iextdefsym = ctx.nlocalsym;4513 const iextdefsym = ctx.nlocalsym;
4521 const iundefsym = iextdefsym + ctx.nextdefsym;4514 const iundefsym = iextdefsym + ctx.nextdefsym;
45224515
4523 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];4516 const seg = self.getLinkeditSegmentPtr();
4524 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));4517 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
4525 const needed_size = nindirectsyms * @sizeOf(u32);4518 const needed_size = nindirectsyms * @sizeOf(u32);
4526 seg.filesize = offset + needed_size - seg.fileoff;4519 seg.filesize = offset + needed_size - seg.fileoff;
...@@ -4592,7 +4585,7 @@ fn writeCodeSignaturePadding(...@@ -4592,7 +4585,7 @@ fn writeCodeSignaturePadding(
4592 ncmds: *u32,4585 ncmds: *u32,
4593 lc_writer: anytype,4586 lc_writer: anytype,
4594) !u32 {4587) !u32 {
4595 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];4588 const seg = self.getLinkeditSegmentPtr();
4596 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file4589 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
4597 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L2714590 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271
4598 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, 16);4591 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, 16);
...@@ -4616,8 +4609,7 @@ fn writeCodeSignaturePadding(...@@ -4616,8 +4609,7 @@ fn writeCodeSignaturePadding(
4616}4609}
46174610
4618fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature, offset: u32) !void {4611fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature, offset: u32) !void {
4619 const seg_id = self.sections.items(.segment_index)[self.text_section_index.?];4612 const seg = self.getSegment(self.text_section_index.?);
4620 const seg = self.segments.items[seg_id];
46214613
4622 var buffer = std.ArrayList(u8).init(self.base.allocator);4614 var buffer = std.ArrayList(u8).init(self.base.allocator);
4623 defer buffer.deinit();4615 defer buffer.deinit();
...@@ -4696,11 +4688,12 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {...@@ -4696,11 +4688,12 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
46964688
4697 const end = start + padToIdeal(size);4689 const end = start + padToIdeal(size);
46984690
4699 for (self.sections.items(.header)) |header| {4691 for (self.sections.items(.segment_index)) |segment_index| {
4700 const tight_size = header.size;4692 const segment = self.segments.items[segment_index];
4693 const tight_size = segment.filesize;
4701 const increased_size = padToIdeal(tight_size);4694 const increased_size = padToIdeal(tight_size);
4702 const test_end = header.offset + increased_size;4695 const test_end = segment.fileoff + increased_size;
4703 if (end > header.offset and start < test_end) {4696 if (end > segment.fileoff and start < test_end) {
4704 return test_end;4697 return test_end;
4705 }4698 }
4706 }4699 }
...@@ -4712,9 +4705,10 @@ fn allocatedSize(self: *MachO, start: u64) u64 {...@@ -4712,9 +4705,10 @@ fn allocatedSize(self: *MachO, start: u64) u64 {
4712 if (start == 0)4705 if (start == 0)
4713 return 0;4706 return 0;
4714 var min_pos: u64 = std.math.maxInt(u64);4707 var min_pos: u64 = std.math.maxInt(u64);
4715 for (self.sections.items(.header)) |header| {4708 for (self.sections.items(.segment_index)) |segment_index| {
4716 if (header.offset <= start) continue;4709 const segment = self.segments.items[segment_index];
4717 if (header.offset < min_pos) min_pos = header.offset;4710 if (segment.fileoff <= start) continue;
4711 if (segment.fileoff < min_pos) min_pos = segment.fileoff;
4718 }4712 }
4719 return min_pos - start;4713 return min_pos - start;
4720}4714}
...@@ -4752,6 +4746,21 @@ fn getSegmentByName(self: MachO, segname: []const u8) ?u8 {...@@ -4752,6 +4746,21 @@ fn getSegmentByName(self: MachO, segname: []const u8) ?u8 {
4752 } else return null;4746 } else return null;
4753}4747}
47544748
4749pub fn getSegment(self: MachO, sect_id: u8) macho.segment_command_64 {
4750 const index = self.sections.items(.segment_index)[sect_id];
4751 return self.segments.items[index];
4752}
4753
4754pub fn getSegmentPtr(self: *MachO, sect_id: u8) *macho.segment_command_64 {
4755 const index = self.sections.items(.segment_index)[sect_id];
4756 return &self.segments.items[index];
4757}
4758
4759pub fn getLinkeditSegmentPtr(self: *MachO) *macho.segment_command_64 {
4760 const index = self.linkedit_segment_cmd_index.?;
4761 return &self.segments.items[index];
4762}
4763
4755pub fn getSectionByName(self: MachO, segname: []const u8, sectname: []const u8) ?u8 {4764pub fn getSectionByName(self: MachO, segname: []const u8, sectname: []const u8) ?u8 {
4756 // TODO investigate caching with a hashmap4765 // TODO investigate caching with a hashmap
4757 for (self.sections.items(.header)) |header, i| {4766 for (self.sections.items(.header)) |header, i| {