authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-03 17:12:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-03 17:12:39+02:00
log80e1c244b6c9d5f3e855878d92ecc09dc8eb970a
treeef93e21cde0713b0749e29951b2d54bfe000575d
parent1d2199b71c06e97be407c2bd0b05c07c8bd6cd2c

macho: dyld info subsections need to follow in strict order

MachO, why are doing this to me?

2 files changed, 115 insertions(+), 251 deletions(-)

src/link/MachO.zig+114-248
...@@ -162,10 +162,7 @@ stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{},...@@ -162,10 +162,7 @@ stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{},
162error_flags: File.ErrorFlags = File.ErrorFlags{},162error_flags: File.ErrorFlags = File.ErrorFlags{},
163163
164load_commands_dirty: bool = false,164load_commands_dirty: bool = false,
165rebase_info_dirty: bool = false,165dyld_info_dirty: bool = false,
166binding_info_dirty: bool = false,
167lazy_binding_info_dirty: bool = false,
168export_info_dirty: bool = false,
169166
170strtab_dirty: bool = false,167strtab_dirty: bool = false,
171strtab_needs_relocation: bool = false,168strtab_needs_relocation: bool = false,
...@@ -814,10 +811,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -814,10 +811,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
814 defer tracy.end();811 defer tracy.end();
815812
816 try self.setEntryPoint();813 try self.setEntryPoint();
817 try self.writeRebaseInfoTable();814 try self.writeDyldInfoData();
818 try self.writeBindInfoTable();
819 try self.writeLazyBindInfoTable();
820 try self.writeExportInfo();
821 try self.writeAllGlobalAndUndefSymbols();815 try self.writeAllGlobalAndUndefSymbols();
822 try self.writeIndirectSymbolTable();816 try self.writeIndirectSymbolTable();
823 try self.writeStringTable();817 try self.writeStringTable();
...@@ -849,10 +843,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -849,10 +843,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
849 }843 }
850844
851 assert(!self.load_commands_dirty);845 assert(!self.load_commands_dirty);
852 assert(!self.rebase_info_dirty);846 assert(!self.dyld_info_dirty);
853 assert(!self.binding_info_dirty);
854 assert(!self.lazy_binding_info_dirty);
855 assert(!self.export_info_dirty);
856 assert(!self.strtab_dirty);847 assert(!self.strtab_dirty);
857 assert(!self.strtab_needs_relocation);848 assert(!self.strtab_needs_relocation);
858849
...@@ -2111,7 +2102,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym...@@ -2111,7 +2102,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym
2111 .local_sym_index = lazy_binding_sym_index,2102 .local_sym_index = lazy_binding_sym_index,
2112 .offset = 0,2103 .offset = 0,
2113 });2104 });
2114 self.lazy_binding_info_dirty = true;2105 self.dyld_info_dirty = true;
2115 return atom;2106 return atom;
2116}2107}
21172108
...@@ -2312,7 +2303,7 @@ fn resolveSymbolsInObject(...@@ -2312,7 +2303,7 @@ fn resolveSymbolsInObject(
2312 .local_sym_index = local_sym_index,2303 .local_sym_index = local_sym_index,
2313 .file = object_id,2304 .file = object_id,
2314 };2305 };
2315 self.export_info_dirty = true;2306 self.dyld_info_dirty = true;
2316 } else if (symbolIsTentative(sym)) {2307 } else if (symbolIsTentative(sym)) {
2317 // Symbol is a tentative definition.2308 // Symbol is a tentative definition.
2318 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {2309 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
...@@ -2647,7 +2638,7 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2647,7 +2638,7 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2647 .sect = self.got_section_index.?,2638 .sect = self.got_section_index.?,
2648 };2639 };
2649 _ = try self.allocateAtom(atom, match);2640 _ = try self.allocateAtom(atom, match);
2650 self.binding_info_dirty = true;2641 self.dyld_info_dirty = true;
2651}2642}
26522643
2653fn parseTextBlocks(self: *MachO) !void {2644fn parseTextBlocks(self: *MachO) !void {
...@@ -2946,7 +2937,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -2946,7 +2937,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
2946 };2937 };
2947 const got_atom = try self.createGotAtom(key);2938 const got_atom = try self.createGotAtom(key);
2948 try self.got_entries_map.put(self.base.allocator, key, got_atom);2939 try self.got_entries_map.put(self.base.allocator, key, got_atom);
2949 self.rebase_info_dirty = true;2940 self.dyld_info_dirty = true;
2950}2941}
29512942
2952pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {2943pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
...@@ -3266,7 +3257,7 @@ pub fn updateDeclExports(...@@ -3266,7 +3257,7 @@ pub fn updateDeclExports(
3266 const name_str_index = try self.makeString(exp_name);3257 const name_str_index = try self.makeString(exp_name);
3267 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {3258 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {
3268 _ = self.globals.addOneAssumeCapacity();3259 _ = self.globals.addOneAssumeCapacity();
3269 self.export_info_dirty = true;3260 self.dyld_info_dirty = true;
3270 break :blk @intCast(u32, self.globals.items.len - 1);3261 break :blk @intCast(u32, self.globals.items.len - 1);
3271 };3262 };
3272 self.globals.items[i] = .{3263 self.globals.items[i] = .{
...@@ -3648,29 +3639,34 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3648,29 +3639,34 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3648 },3639 },
3649 });3640 });
36503641
3642 // Preallocate rebase, binding, lazy binding info, and export info.
3651 const dyld = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;3643 const dyld = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3644 const subsection_size = 128; // TODO this is totally random
3645 const needed_size = 4 * subsection_size;
3646 const offset = self.findFreeSpaceLinkedit(needed_size, 1, null);
3647
3648 const rebase_off = @intCast(u32, offset);
3649 log.debug("found rebase info free space 0x{x} to 0x{x}", .{ rebase_off, rebase_off + subsection_size });
3650 dyld.rebase_off = rebase_off;
3651 dyld.rebase_size = subsection_size;
3652
3653 const bind_off = rebase_off + subsection_size;
3654 log.debug("found binding info free space 0x{x} to 0x{x}", .{ bind_off, bind_off + subsection_size });
3655 dyld.bind_off = bind_off;
3656 dyld.bind_size = subsection_size;
3657
3658 const lazy_bind_off = bind_off + subsection_size;
3659 log.debug("found lazy binding info free space 0x{x} to 0x{x}", .{
3660 lazy_bind_off,
3661 lazy_bind_off + subsection_size,
3662 });
3663 dyld.lazy_bind_off = lazy_bind_off;
3664 dyld.lazy_bind_size = subsection_size;
36523665
3653 // Preallocate rebase, binding, lazy binding info, and export info.3666 const export_off = lazy_bind_off + subsection_size;
3654 const expected_size = 48; // TODO This is totally random.3667 log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + subsection_size });
3655 const rebase_off = self.findFreeSpaceLinkedit(expected_size, 1, null);3668 dyld.export_off = export_off;
3656 log.debug("found rebase info free space 0x{x} to 0x{x}", .{ rebase_off, rebase_off + expected_size });3669 dyld.export_size = subsection_size;
3657 dyld.rebase_off = @intCast(u32, rebase_off);
3658 dyld.rebase_size = expected_size;
3659
3660 const bind_off = self.findFreeSpaceLinkedit(expected_size, 1, null);
3661 log.debug("found binding info free space 0x{x} to 0x{x}", .{ bind_off, bind_off + expected_size });
3662 dyld.bind_off = @intCast(u32, bind_off);
3663 dyld.bind_size = expected_size;
3664
3665 const lazy_bind_off = self.findFreeSpaceLinkedit(expected_size, 1, null);
3666 log.debug("found lazy binding info free space 0x{x} to 0x{x}", .{ lazy_bind_off, lazy_bind_off + expected_size });
3667 dyld.lazy_bind_off = @intCast(u32, lazy_bind_off);
3668 dyld.lazy_bind_size = expected_size;
3669
3670 const export_off = self.findFreeSpaceLinkedit(expected_size, 1, null);
3671 log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + expected_size });
3672 dyld.export_off = @intCast(u32, export_off);
3673 dyld.export_size = expected_size;
36743670
3675 self.load_commands_dirty = true;3671 self.load_commands_dirty = true;
3676 }3672 }
...@@ -4097,10 +4093,6 @@ fn allocatedSizeLinkedit(self: *MachO, start: u64) u64 {...@@ -4097,10 +4093,6 @@ fn allocatedSizeLinkedit(self: *MachO, start: u64) u64 {
4097 if (self.dyld_info_cmd_index) |idx| {4093 if (self.dyld_info_cmd_index) |idx| {
4098 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;4094 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
4099 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;4095 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;
4100 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.bind_off;
4101 if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = dyld_info.weak_bind_off;
4102 if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = dyld_info.lazy_bind_off;
4103 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
4104 }4096 }
41054097
4106 if (self.function_starts_cmd_index) |idx| {4098 if (self.function_starts_cmd_index) |idx| {
...@@ -4141,27 +4133,14 @@ fn detectAllocCollisionLinkedit(self: *MachO, start: u64, size: u64) ?u64 {...@@ -4141,27 +4133,14 @@ fn detectAllocCollisionLinkedit(self: *MachO, start: u64, size: u64) ?u64 {
41414133
4142 // __LINKEDIT is a weird segment where sections get their own load commands so we4134 // __LINKEDIT is a weird segment where sections get their own load commands so we
4143 // special-case it.4135 // special-case it.
4144 if (self.dyld_info_cmd_index) |idx| outer: {4136 if (self.dyld_info_cmd_index) |idx| {
4145 if (self.load_commands.items.len == idx) break :outer;
4146 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;4137 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
4147 if (checkForCollision(start, end, dyld_info.rebase_off, dyld_info.rebase_size)) |pos| {4138 const offset = dyld_info.rebase_off;
4148 return pos;4139 const actual_size = dyld_info.export_off + dyld_info.export_size - offset;
4149 }4140 const increased_size = padToIdeal(actual_size);
4150 // Binding info4141 const test_end = offset + increased_size;
4151 if (checkForCollision(start, end, dyld_info.bind_off, dyld_info.bind_size)) |pos| {4142 if (end > offset and start < test_end) {
4152 return pos;4143 return test_end;
4153 }
4154 // Weak binding info
4155 if (checkForCollision(start, end, dyld_info.weak_bind_off, dyld_info.weak_bind_size)) |pos| {
4156 return pos;
4157 }
4158 // Lazy binding info
4159 if (checkForCollision(start, end, dyld_info.lazy_bind_off, dyld_info.lazy_bind_size)) |pos| {
4160 return pos;
4161 }
4162 // Export info
4163 if (checkForCollision(start, end, dyld_info.export_off, dyld_info.export_size)) |pos| {
4164 return pos;
4165 }4144 }
4166 }4145 }
41674146
...@@ -4483,145 +4462,53 @@ fn writeCodeSignature(self: *MachO) !void {...@@ -4483,145 +4462,53 @@ fn writeCodeSignature(self: *MachO) !void {
4483 try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);4462 try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);
4484}4463}
44854464
4486fn writeExportInfo(self: *MachO) !void {4465fn writeDyldInfoData(self: *MachO) !void {
4487 if (!self.export_info_dirty) return;4466 if (!self.dyld_info_dirty) return;
4488 if (self.globals.items.len == 0) return;
4489
4490 const tracy = trace(@src());
4491 defer tracy.end();
4492
4493 var trie: Trie = .{};
4494 defer trie.deinit(self.base.allocator);
4495
4496 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4497 const base_address = text_segment.inner.vmaddr;
4498
4499 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
4500 log.debug("writing export trie", .{});
4501
4502 for (self.globals.items) |sym| {
4503 const sym_name = self.getString(sym.n_strx);
4504 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
4505
4506 try trie.put(self.base.allocator, .{
4507 .name = sym_name,
4508 .vmaddr_offset = sym.n_value - base_address,
4509 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
4510 });
4511 }
4512 try trie.finalize(self.base.allocator);
4513
4514 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, trie.size));
4515 defer self.base.allocator.free(buffer);
4516 var stream = std.io.fixedBufferStream(buffer);
4517 const nwritten = try trie.write(stream.writer());
4518 assert(nwritten == trie.size);
4519
4520 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
4521 const allocated_size = self.allocatedSizeLinkedit(dyld_info.export_off);
4522 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
4523
4524 if (needed_size > allocated_size) {
4525 dyld_info.export_off = 0;
4526 dyld_info.export_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null));
4527 // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too.
4528 }
4529 dyld_info.export_size = @intCast(u32, needed_size);
4530 log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
4531
4532 try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
4533 self.load_commands_dirty = true;
4534 self.export_info_dirty = false;
4535}
4536
4537fn writeRebaseInfoTable(self: *MachO) !void {
4538 if (!self.rebase_info_dirty) return;
45394467
4540 const tracy = trace(@src());4468 const tracy = trace(@src());
4541 defer tracy.end();4469 defer tracy.end();
45424470
4543 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);4471 var rebase_pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
4544 defer pointers.deinit();4472 defer rebase_pointers.deinit();
4473 var bind_pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
4474 defer bind_pointers.deinit();
4475 var lazy_bind_pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
4476 defer lazy_bind_pointers.deinit();
45454477
4546 {4478 {
4547 var it = self.blocks.iterator();4479 var it = self.blocks.iterator();
4548 while (it.next()) |entry| {4480 while (it.next()) |entry| {
4549 const match = entry.key_ptr.*;4481 const match = entry.key_ptr.*;
4550 var block: *TextBlock = entry.value_ptr.*;4482 var atom: *TextBlock = entry.value_ptr.*;
45514483
4552 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable4484 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
45534485
4554 const seg = self.load_commands.items[match.seg].Segment;4486 const seg = self.load_commands.items[match.seg].Segment;
45554487
4556 while (true) {4488 while (true) {
4557 const sym = self.locals.items[block.local_sym_index];4489 const sym = self.locals.items[atom.local_sym_index];
4558 const base_offset = sym.n_value - seg.inner.vmaddr;4490 const base_offset = sym.n_value - seg.inner.vmaddr;
45594491
4560 for (block.rebases.items) |offset| {4492 for (atom.rebases.items) |offset| {
4561 try pointers.append(.{4493 try rebase_pointers.append(.{
4562 .offset = base_offset + offset,4494 .offset = base_offset + offset,
4563 .segment_id = match.seg,4495 .segment_id = match.seg,
4564 });4496 });
4565 }4497 }
45664498
4567 if (block.prev) |prev| {4499 for (atom.bindings.items) |binding| {
4568 block = prev;4500 const bind_sym = self.undefs.items[binding.local_sym_index];
4569 } else break;4501 try bind_pointers.append(.{
4570 }4502 .offset = binding.offset + base_offset,
4571 }4503 .segment_id = match.seg,
4572 }4504 .dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
45734505 .name = self.getString(bind_sym.n_strx),
4574 const size = try bind.rebaseInfoSize(pointers.items);4506 });
4575 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));4507 }
4576 defer self.base.allocator.free(buffer);
4577
4578 var stream = std.io.fixedBufferStream(buffer);
4579 try bind.writeRebaseInfo(pointers.items, stream.writer());
4580
4581 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
4582 const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off);
4583 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
4584
4585 if (needed_size > allocated_size) {
4586 dyld_info.rebase_off = 0;
4587 dyld_info.rebase_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null));
4588 // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too.
4589 }
4590
4591 dyld_info.rebase_size = @intCast(u32, needed_size);
4592 log.debug("writing rebase info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + dyld_info.rebase_size });
4593
4594 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
4595 self.load_commands_dirty = true;
4596 self.rebase_info_dirty = false;
4597}
4598
4599fn writeBindInfoTable(self: *MachO) !void {
4600 if (!self.binding_info_dirty) return;
4601
4602 const tracy = trace(@src());
4603 defer tracy.end();
4604
4605 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
4606 defer pointers.deinit();
4607
4608 {
4609 var it = self.blocks.iterator();
4610 while (it.next()) |entry| {
4611 const match = entry.key_ptr.*;
4612 var block: *TextBlock = entry.value_ptr.*;
4613
4614 if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable
4615
4616 const seg = self.load_commands.items[match.seg].Segment;
4617
4618 while (true) {
4619 const sym = self.locals.items[block.local_sym_index];
4620 const base_offset = sym.n_value - seg.inner.vmaddr;
46214508
4622 for (block.bindings.items) |binding| {4509 for (atom.lazy_bindings.items) |binding| {
4623 const bind_sym = self.undefs.items[binding.local_sym_index];4510 const bind_sym = self.undefs.items[binding.local_sym_index];
4624 try pointers.append(.{4511 try lazy_bind_pointers.append(.{
4625 .offset = binding.offset + base_offset,4512 .offset = binding.offset + base_offset,
4626 .segment_id = match.seg,4513 .segment_id = match.seg,
4627 .dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),4514 .dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
...@@ -4629,97 +4516,76 @@ fn writeBindInfoTable(self: *MachO) !void {...@@ -4629,97 +4516,76 @@ fn writeBindInfoTable(self: *MachO) !void {
4629 });4516 });
4630 }4517 }
46314518
4632 if (block.prev) |prev| {4519 if (atom.prev) |prev| {
4633 block = prev;4520 atom = prev;
4634 } else break;4521 } else break;
4635 }4522 }
4636 }4523 }
4637 }4524 }
46384525
4639 const size = try bind.bindInfoSize(pointers.items);4526 var trie: Trie = .{};
4640 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));4527 defer trie.deinit(self.base.allocator);
4641 defer self.base.allocator.free(buffer);
46424528
4643 var stream = std.io.fixedBufferStream(buffer);4529 {
4644 try bind.writeBindInfo(pointers.items, stream.writer());4530 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
4531 log.debug("writing export trie", .{});
4532 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4533 const base_address = text_segment.inner.vmaddr;
4534
4535 for (self.globals.items) |sym| {
4536 const sym_name = self.getString(sym.n_strx);
4537 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
4538
4539 try trie.put(self.base.allocator, .{
4540 .name = sym_name,
4541 .vmaddr_offset = sym.n_value - base_address,
4542 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
4543 });
4544 }
4545
4546 try trie.finalize(self.base.allocator);
4547 }
46454548
4646 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;4549 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
4647 const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off);4550 const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off);
4648 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));4551 const rebase_size = @intCast(u32, try bind.rebaseInfoSize(rebase_pointers.items));
4552 const bind_size = @intCast(u32, try bind.bindInfoSize(bind_pointers.items));
4553 const lazy_bind_size = @intCast(u32, try bind.lazyBindInfoSize(lazy_bind_pointers.items));
4554 const export_size = @intCast(u32, trie.size);
4555 const total_size = rebase_size + bind_size + lazy_bind_size + export_size;
4556 const needed_size = mem.alignForwardGeneric(u64, total_size, @alignOf(u64));
46494557
4650 if (needed_size > allocated_size) {4558 if (needed_size > allocated_size) {
4651 dyld_info.bind_off = 0;4559 dyld_info.rebase_off = 0;
4652 dyld_info.bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null));4560 dyld_info.rebase_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null));
4653 // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too.
4654 }4561 }
46554562
4656 dyld_info.bind_size = @intCast(u32, needed_size);4563 dyld_info.rebase_size = rebase_size;
4657 log.debug("writing binding info from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + dyld_info.bind_size });4564 dyld_info.bind_off = dyld_info.rebase_off + dyld_info.rebase_size;
4565 dyld_info.bind_size = bind_size;
4566 dyld_info.lazy_bind_off = dyld_info.bind_off + dyld_info.bind_size;
4567 dyld_info.lazy_bind_size = lazy_bind_size;
4568 dyld_info.export_off = dyld_info.lazy_bind_off + dyld_info.lazy_bind_size;
4569 dyld_info.export_size = export_size;
46584570
4659 try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off);4571 var buffer = try self.base.allocator.alloc(u8, needed_size);
4660 self.load_commands_dirty = true;
4661 self.binding_info_dirty = false;
4662}
4663
4664fn writeLazyBindInfoTable(self: *MachO) !void {
4665 if (!self.lazy_binding_info_dirty) return;
4666
4667 const tracy = trace(@src());
4668 defer tracy.end();
4669
4670 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
4671 defer pointers.deinit();
4672
4673 if (self.la_symbol_ptr_section_index) |sect| blk: {
4674 var atom = self.blocks.get(.{
4675 .seg = self.data_segment_cmd_index.?,
4676 .sect = sect,
4677 }) orelse break :blk;
4678 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4679
4680 while (true) {
4681 const sym = self.locals.items[atom.local_sym_index];
4682 const base_offset = sym.n_value - seg.inner.vmaddr;
4683
4684 for (atom.lazy_bindings.items) |binding| {
4685 const bind_sym = self.undefs.items[binding.local_sym_index];
4686 try pointers.append(.{
4687 .offset = binding.offset + base_offset,
4688 .segment_id = self.data_segment_cmd_index.?,
4689 .dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER),
4690 .name = self.getString(bind_sym.n_strx),
4691 });
4692 }
4693 if (atom.prev) |prev| {
4694 atom = prev;
4695 } else break;
4696 }
4697 }
4698
4699 const size = try bind.lazyBindInfoSize(pointers.items);
4700 var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size));
4701 defer self.base.allocator.free(buffer);4572 defer self.base.allocator.free(buffer);
4573 mem.set(u8, buffer, 0);
47024574
4703 var stream = std.io.fixedBufferStream(buffer);4575 var stream = std.io.fixedBufferStream(buffer);
4704 try bind.writeLazyBindInfo(pointers.items, stream.writer());4576 const writer = stream.writer();
47054577
4706 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;4578 try bind.writeRebaseInfo(rebase_pointers.items, writer);
4707 const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off);4579 try bind.writeBindInfo(bind_pointers.items, writer);
4708 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));4580 try bind.writeLazyBindInfo(lazy_bind_pointers.items, writer);
4581 _ = try trie.write(writer);
47094582
4710 if (needed_size > allocated_size) {4583 log.debug("writing dyld info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + needed_size });
4711 dyld_info.lazy_bind_off = 0;
4712 dyld_info.lazy_bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null));
4713 // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too.
4714 }
4715
4716 dyld_info.lazy_bind_size = @intCast(u32, needed_size);
4717 log.debug("writing lazy binding info from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size });
47184584
4719 try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off);4585 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
4720 try self.populateLazyBindOffsetsInStubHelper(buffer);4586 try self.populateLazyBindOffsetsInStubHelper(buffer[rebase_size + bind_size ..][0..lazy_bind_size]);
4721 self.load_commands_dirty = true;4587 self.load_commands_dirty = true;
4722 self.lazy_binding_info_dirty = false;4588 self.dyld_info_dirty = false;
4723}4589}
47244590
4725fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {4591fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
src/link/MachO/TextBlock.zig+1-3
...@@ -844,9 +844,7 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R...@@ -844,9 +844,7 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
844 .sect = context.macho_file.got_section_index.?,844 .sect = context.macho_file.got_section_index.?,
845 };845 };
846 _ = try context.macho_file.allocateAtom(atom, match);846 _ = try context.macho_file.allocateAtom(atom, match);
847 // TODO don't need both at once847 context.macho_file.dyld_info_dirty = true;
848 context.macho_file.rebase_info_dirty = true;
849 context.macho_file.binding_info_dirty = true;
850 } else if (parsed_rel.payload == .unsigned) {848 } else if (parsed_rel.payload == .unsigned) {
851 switch (parsed_rel.where) {849 switch (parsed_rel.where) {
852 .undef => {850 .undef => {