| ... | ... | @@ -162,10 +162,7 @@ stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{}, |
| 162 | 162 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 163 | 163 | |
| 164 | 164 | load_commands_dirty: bool = false, |
| 165 | | rebase_info_dirty: bool = false, |
| 166 | | binding_info_dirty: bool = false, |
| 167 | | lazy_binding_info_dirty: bool = false, |
| 168 | | export_info_dirty: bool = false, |
| 165 | dyld_info_dirty: bool = false, |
| 169 | 166 | |
| 170 | 167 | strtab_dirty: bool = false, |
| 171 | 168 | strtab_needs_relocation: bool = false, |
| ... | ... | @@ -814,10 +811,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 814 | 811 | defer tracy.end(); |
| 815 | 812 | |
| 816 | 813 | try self.setEntryPoint(); |
| 817 | | try self.writeRebaseInfoTable(); |
| 818 | | try self.writeBindInfoTable(); |
| 819 | | try self.writeLazyBindInfoTable(); |
| 820 | | try self.writeExportInfo(); |
| 814 | try self.writeDyldInfoData(); |
| 821 | 815 | try self.writeAllGlobalAndUndefSymbols(); |
| 822 | 816 | try self.writeIndirectSymbolTable(); |
| 823 | 817 | try self.writeStringTable(); |
| ... | ... | @@ -849,10 +843,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 849 | 843 | } |
| 850 | 844 | |
| 851 | 845 | assert(!self.load_commands_dirty); |
| 852 | | assert(!self.rebase_info_dirty); |
| 853 | | assert(!self.binding_info_dirty); |
| 854 | | assert(!self.lazy_binding_info_dirty); |
| 855 | | assert(!self.export_info_dirty); |
| 846 | assert(!self.dyld_info_dirty); |
| 856 | 847 | assert(!self.strtab_dirty); |
| 857 | 848 | assert(!self.strtab_needs_relocation); |
| 858 | 849 | |
| ... | ... | @@ -2111,7 +2102,7 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym |
| 2111 | 2102 | .local_sym_index = lazy_binding_sym_index, |
| 2112 | 2103 | .offset = 0, |
| 2113 | 2104 | }); |
| 2114 | | self.lazy_binding_info_dirty = true; |
| 2105 | self.dyld_info_dirty = true; |
| 2115 | 2106 | return atom; |
| 2116 | 2107 | } |
| 2117 | 2108 | |
| ... | ... | @@ -2312,7 +2303,7 @@ fn resolveSymbolsInObject( |
| 2312 | 2303 | .local_sym_index = local_sym_index, |
| 2313 | 2304 | .file = object_id, |
| 2314 | 2305 | }; |
| 2315 | | self.export_info_dirty = true; |
| 2306 | self.dyld_info_dirty = true; |
| 2316 | 2307 | } else if (symbolIsTentative(sym)) { |
| 2317 | 2308 | // Symbol is a tentative definition. |
| 2318 | 2309 | const resolv = self.symbol_resolver.getPtr(n_strx) orelse { |
| ... | ... | @@ -2647,7 +2638,7 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 2647 | 2638 | .sect = self.got_section_index.?, |
| 2648 | 2639 | }; |
| 2649 | 2640 | _ = try self.allocateAtom(atom, match); |
| 2650 | | self.binding_info_dirty = true; |
| 2641 | self.dyld_info_dirty = true; |
| 2651 | 2642 | } |
| 2652 | 2643 | |
| 2653 | 2644 | fn parseTextBlocks(self: *MachO) !void { |
| ... | ... | @@ -2946,7 +2937,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 2946 | 2937 | }; |
| 2947 | 2938 | const got_atom = try self.createGotAtom(key); |
| 2948 | 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 | } |
| 2951 | 2942 | |
| 2952 | 2943 | pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { |
| ... | ... | @@ -3266,7 +3257,7 @@ pub fn updateDeclExports( |
| 3266 | 3257 | const name_str_index = try self.makeString(exp_name); |
| 3267 | 3258 | const i = if (self.globals_free_list.popOrNull()) |i| i else blk: { |
| 3268 | 3259 | _ = self.globals.addOneAssumeCapacity(); |
| 3269 | | self.export_info_dirty = true; |
| 3260 | self.dyld_info_dirty = true; |
| 3270 | 3261 | break :blk @intCast(u32, self.globals.items.len - 1); |
| 3271 | 3262 | }; |
| 3272 | 3263 | self.globals.items[i] = .{ |
| ... | ... | @@ -3648,29 +3639,34 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3648 | 3639 | }, |
| 3649 | 3640 | }); |
| 3650 | 3641 | |
| 3642 | // Preallocate rebase, binding, lazy binding info, and export info. |
| 3651 | 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; |
| 3652 | 3665 | |
| 3653 | | // Preallocate rebase, binding, lazy binding info, and export info. |
| 3654 | | const expected_size = 48; // TODO This is totally random. |
| 3655 | | const rebase_off = self.findFreeSpaceLinkedit(expected_size, 1, null); |
| 3656 | | log.debug("found rebase info free space 0x{x} to 0x{x}", .{ rebase_off, rebase_off + expected_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; |
| 3666 | const export_off = lazy_bind_off + subsection_size; |
| 3667 | log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + subsection_size }); |
| 3668 | dyld.export_off = export_off; |
| 3669 | dyld.export_size = subsection_size; |
| 3674 | 3670 | |
| 3675 | 3671 | self.load_commands_dirty = true; |
| 3676 | 3672 | } |
| ... | ... | @@ -4097,10 +4093,6 @@ fn allocatedSizeLinkedit(self: *MachO, start: u64) u64 { |
| 4097 | 4093 | if (self.dyld_info_cmd_index) |idx| { |
| 4098 | 4094 | const dyld_info = self.load_commands.items[idx].DyldInfoOnly; |
| 4099 | 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 | } |
| 4105 | 4097 | |
| 4106 | 4098 | if (self.function_starts_cmd_index) |idx| { |
| ... | ... | @@ -4141,27 +4133,14 @@ fn detectAllocCollisionLinkedit(self: *MachO, start: u64, size: u64) ?u64 { |
| 4141 | 4133 | |
| 4142 | 4134 | // __LINKEDIT is a weird segment where sections get their own load commands so we |
| 4143 | 4135 | // special-case it. |
| 4144 | | if (self.dyld_info_cmd_index) |idx| outer: { |
| 4145 | | if (self.load_commands.items.len == idx) break :outer; |
| 4136 | if (self.dyld_info_cmd_index) |idx| { |
| 4146 | 4137 | const dyld_info = self.load_commands.items[idx].DyldInfoOnly; |
| 4147 | | if (checkForCollision(start, end, dyld_info.rebase_off, dyld_info.rebase_size)) |pos| { |
| 4148 | | return pos; |
| 4149 | | } |
| 4150 | | // Binding info |
| 4151 | | if (checkForCollision(start, end, dyld_info.bind_off, dyld_info.bind_size)) |pos| { |
| 4152 | | return pos; |
| 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; |
| 4138 | const offset = dyld_info.rebase_off; |
| 4139 | const actual_size = dyld_info.export_off + dyld_info.export_size - offset; |
| 4140 | const increased_size = padToIdeal(actual_size); |
| 4141 | const test_end = offset + increased_size; |
| 4142 | if (end > offset and start < test_end) { |
| 4143 | return test_end; |
| 4165 | 4144 | } |
| 4166 | 4145 | } |
| 4167 | 4146 | |
| ... | ... | @@ -4483,145 +4462,53 @@ fn writeCodeSignature(self: *MachO) !void { |
| 4483 | 4462 | try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); |
| 4484 | 4463 | } |
| 4485 | 4464 | |
| 4486 | | fn writeExportInfo(self: *MachO) !void { |
| 4487 | | if (!self.export_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 | | |
| 4537 | | fn writeRebaseInfoTable(self: *MachO) !void { |
| 4538 | | if (!self.rebase_info_dirty) return; |
| 4465 | fn writeDyldInfoData(self: *MachO) !void { |
| 4466 | if (!self.dyld_info_dirty) return; |
| 4539 | 4467 | |
| 4540 | 4468 | const tracy = trace(@src()); |
| 4541 | 4469 | defer tracy.end(); |
| 4542 | 4470 | |
| 4543 | | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 4544 | | defer pointers.deinit(); |
| 4471 | var rebase_pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 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(); |
| 4545 | 4477 | |
| 4546 | 4478 | { |
| 4547 | 4479 | var it = self.blocks.iterator(); |
| 4548 | 4480 | while (it.next()) |entry| { |
| 4549 | 4481 | const match = entry.key_ptr.*; |
| 4550 | | var block: *TextBlock = entry.value_ptr.*; |
| 4482 | var atom: *TextBlock = entry.value_ptr.*; |
| 4551 | 4483 | |
| 4552 | 4484 | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable |
| 4553 | 4485 | |
| 4554 | 4486 | const seg = self.load_commands.items[match.seg].Segment; |
| 4555 | 4487 | |
| 4556 | 4488 | while (true) { |
| 4557 | | const sym = self.locals.items[block.local_sym_index]; |
| 4489 | const sym = self.locals.items[atom.local_sym_index]; |
| 4558 | 4490 | const base_offset = sym.n_value - seg.inner.vmaddr; |
| 4559 | 4491 | |
| 4560 | | for (block.rebases.items) |offset| { |
| 4561 | | try pointers.append(.{ |
| 4492 | for (atom.rebases.items) |offset| { |
| 4493 | try rebase_pointers.append(.{ |
| 4562 | 4494 | .offset = base_offset + offset, |
| 4563 | 4495 | .segment_id = match.seg, |
| 4564 | 4496 | }); |
| 4565 | 4497 | } |
| 4566 | 4498 | |
| 4567 | | if (block.prev) |prev| { |
| 4568 | | block = prev; |
| 4569 | | } else break; |
| 4570 | | } |
| 4571 | | } |
| 4572 | | } |
| 4573 | | |
| 4574 | | const size = try bind.rebaseInfoSize(pointers.items); |
| 4575 | | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 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 | | |
| 4599 | | fn 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; |
| 4499 | for (atom.bindings.items) |binding| { |
| 4500 | const bind_sym = self.undefs.items[binding.local_sym_index]; |
| 4501 | try bind_pointers.append(.{ |
| 4502 | .offset = binding.offset + base_offset, |
| 4503 | .segment_id = match.seg, |
| 4504 | .dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER), |
| 4505 | .name = self.getString(bind_sym.n_strx), |
| 4506 | }); |
| 4507 | } |
| 4621 | 4508 | |
| 4622 | | for (block.bindings.items) |binding| { |
| 4509 | for (atom.lazy_bindings.items) |binding| { |
| 4623 | 4510 | const bind_sym = self.undefs.items[binding.local_sym_index]; |
| 4624 | | try pointers.append(.{ |
| 4511 | try lazy_bind_pointers.append(.{ |
| 4625 | 4512 | .offset = binding.offset + base_offset, |
| 4626 | 4513 | .segment_id = match.seg, |
| 4627 | 4514 | .dylib_ordinal = @divExact(bind_sym.n_desc, macho.N_SYMBOL_RESOLVER), |
| ... | ... | @@ -4629,97 +4516,76 @@ fn writeBindInfoTable(self: *MachO) !void { |
| 4629 | 4516 | }); |
| 4630 | 4517 | } |
| 4631 | 4518 | |
| 4632 | | if (block.prev) |prev| { |
| 4633 | | block = prev; |
| 4519 | if (atom.prev) |prev| { |
| 4520 | atom = prev; |
| 4634 | 4521 | } else break; |
| 4635 | 4522 | } |
| 4636 | 4523 | } |
| 4637 | 4524 | } |
| 4638 | 4525 | |
| 4639 | | const size = try bind.bindInfoSize(pointers.items); |
| 4640 | | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 4641 | | defer self.base.allocator.free(buffer); |
| 4526 | var trie: Trie = .{}; |
| 4527 | defer trie.deinit(self.base.allocator); |
| 4642 | 4528 | |
| 4643 | | var stream = std.io.fixedBufferStream(buffer); |
| 4644 | | try bind.writeBindInfo(pointers.items, stream.writer()); |
| 4529 | { |
| 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 | } |
| 4645 | 4548 | |
| 4646 | 4549 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 4647 | | const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off); |
| 4648 | | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| 4550 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off); |
| 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)); |
| 4649 | 4557 | |
| 4650 | 4558 | if (needed_size > allocated_size) { |
| 4651 | | dyld_info.bind_off = 0; |
| 4652 | | dyld_info.bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null)); |
| 4653 | | // TODO this might require relocating all following LC_DYLD_INFO_ONLY sections too. |
| 4559 | dyld_info.rebase_off = 0; |
| 4560 | dyld_info.rebase_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null)); |
| 4654 | 4561 | } |
| 4655 | 4562 | |
| 4656 | | dyld_info.bind_size = @intCast(u32, needed_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 }); |
| 4563 | dyld_info.rebase_size = rebase_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; |
| 4658 | 4570 | |
| 4659 | | try self.base.file.?.pwriteAll(buffer, dyld_info.bind_off); |
| 4660 | | self.load_commands_dirty = true; |
| 4661 | | self.binding_info_dirty = false; |
| 4662 | | } |
| 4663 | | |
| 4664 | | fn 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)); |
| 4571 | var buffer = try self.base.allocator.alloc(u8, needed_size); |
| 4701 | 4572 | defer self.base.allocator.free(buffer); |
| 4573 | mem.set(u8, buffer, 0); |
| 4702 | 4574 | |
| 4703 | 4575 | var stream = std.io.fixedBufferStream(buffer); |
| 4704 | | try bind.writeLazyBindInfo(pointers.items, stream.writer()); |
| 4576 | const writer = stream.writer(); |
| 4705 | 4577 | |
| 4706 | | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 4707 | | const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off); |
| 4708 | | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| 4578 | try bind.writeRebaseInfo(rebase_pointers.items, writer); |
| 4579 | try bind.writeBindInfo(bind_pointers.items, writer); |
| 4580 | try bind.writeLazyBindInfo(lazy_bind_pointers.items, writer); |
| 4581 | _ = try trie.write(writer); |
| 4709 | 4582 | |
| 4710 | | if (needed_size > allocated_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 }); |
| 4583 | log.debug("writing dyld info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + needed_size }); |
| 4718 | 4584 | |
| 4719 | | try self.base.file.?.pwriteAll(buffer, dyld_info.lazy_bind_off); |
| 4720 | | try self.populateLazyBindOffsetsInStubHelper(buffer); |
| 4585 | try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off); |
| 4586 | try self.populateLazyBindOffsetsInStubHelper(buffer[rebase_size + bind_size ..][0..lazy_bind_size]); |
| 4721 | 4587 | self.load_commands_dirty = true; |
| 4722 | | self.lazy_binding_info_dirty = false; |
| 4588 | self.dyld_info_dirty = false; |
| 4723 | 4589 | } |
| 4724 | 4590 | |
| 4725 | 4591 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |