| ... | @@ -162,10 +162,7 @@ stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{}, | ... | @@ -162,10 +162,7 @@ stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{}, |
| 162 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 162 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 163 | | 163 | |
| 164 | load_commands_dirty: bool = false, | 164 | load_commands_dirty: bool = false, |
| 165 | rebase_info_dirty: bool = false, | 165 | dyld_info_dirty: bool = false, |
| 166 | binding_info_dirty: bool = false, | | |
| 167 | lazy_binding_info_dirty: bool = false, | | |
| 168 | export_info_dirty: bool = false, | | |
| 169 | | 166 | |
| 170 | strtab_dirty: bool = false, | 167 | strtab_dirty: bool = false, |
| 171 | strtab_needs_relocation: bool = false, | 168 | strtab_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(); |
| 815 | | 812 | |
| 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 | } |
| 850 | | 844 | |
| 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); |
| 858 | | 849 | |
| ... | @@ -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 | } |
| 2117 | | 2108 | |
| ... | @@ -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 | } |
| 2652 | | 2643 | |
| 2653 | fn parseTextBlocks(self: *MachO) !void { | 2644 | fn 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 | } |
| 2951 | | 2942 | |
| 2952 | pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 2943 | pub 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 | }); |
| 3650 | | 3641 | |
| | 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; |
| 3652 | | 3665 | |
| 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; | | |
| 3674 | | 3670 | |
| 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 | } |
| 4105 | | 4097 | |
| 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 { |
| 4141 | | 4133 | |
| 4142 | // __LINKEDIT is a weird segment where sections get their own load commands so we | 4134 | // __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 info | 4141 | 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 | } |
| 4167 | | 4146 | |
| ... | @@ -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 | } |
| 4485 | | 4464 | |
| 4486 | fn writeExportInfo(self: *MachO) !void { | 4465 | fn 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 | | | |
| 4537 | fn writeRebaseInfoTable(self: *MachO) !void { | | |
| 4538 | if (!self.rebase_info_dirty) return; | | |
| 4539 | | 4467 | |
| 4540 | const tracy = trace(@src()); | 4468 | const tracy = trace(@src()); |
| 4541 | defer tracy.end(); | 4469 | defer tracy.end(); |
| 4542 | | 4470 | |
| 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(); |
| 4545 | | 4477 | |
| 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.*; |
| 4551 | | 4483 | |
| 4552 | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable | 4484 | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable |
| 4553 | | 4485 | |
| 4554 | const seg = self.load_commands.items[match.seg].Segment; | 4486 | const seg = self.load_commands.items[match.seg].Segment; |
| 4555 | | 4487 | |
| 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; |
| 4559 | | 4491 | |
| 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 | } |
| 4566 | | 4498 | |
| 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), |
| 4573 | | 4505 | .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 | | | |
| 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; | | |
| 4621 | | 4508 | |
| 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 | } |
| 4631 | | 4518 | |
| 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 | } |
| 4638 | | 4525 | |
| 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); | | |
| 4642 | | 4528 | |
| 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 | } |
| 4645 | | 4548 | |
| 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)); |
| 4649 | | 4557 | |
| 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 | } |
| 4655 | | 4562 | |
| 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; |
| 4658 | | 4570 | |
| 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 | | | |
| 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)); | | |
| 4701 | defer self.base.allocator.free(buffer); | 4572 | defer self.base.allocator.free(buffer); |
| | 4573 | mem.set(u8, buffer, 0); |
| 4702 | | 4574 | |
| 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(); |
| 4705 | | 4577 | |
| 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); |
| 4709 | | 4582 | |
| 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 }); | | |
| 4718 | | 4584 | |
| 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 | } |
| 4724 | | 4590 | |
| 4725 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { | 4591 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |