| ... | ... | @@ -808,17 +808,23 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 808 | 808 | sect.size -= atom.size; |
| 809 | 809 | } |
| 810 | 810 | for (self.stubs.items) |_| { |
| 811 | | const stub_atom = try self.createStubHelperAtom(); |
| 812 | | try self.allocateAtomStage1(stub_atom, .{ |
| 811 | const stub_helper_atom = try self.createStubHelperAtom(); |
| 812 | try self.allocateAtomStage1(stub_helper_atom, .{ |
| 813 | 813 | .seg = self.text_segment_cmd_index.?, |
| 814 | 814 | .sect = self.stub_helper_section_index.?, |
| 815 | 815 | }); |
| 816 | 816 | |
| 817 | | const laptr_atom = try self.createLazyPointerAtom(stub_atom.local_sym_index); |
| 817 | const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.local_sym_index); |
| 818 | 818 | try self.allocateAtomStage1(laptr_atom, .{ |
| 819 | 819 | .seg = self.data_segment_cmd_index.?, |
| 820 | 820 | .sect = self.la_symbol_ptr_section_index.?, |
| 821 | 821 | }); |
| 822 | |
| 823 | const stub_atom = try self.createStubAtom(laptr_atom.local_sym_index); |
| 824 | try self.allocateAtomStage1(stub_atom, .{ |
| 825 | .seg = self.text_segment_cmd_index.?, |
| 826 | .sect = self.stubs_section_index.?, |
| 827 | }); |
| 822 | 828 | } |
| 823 | 829 | try self.allocateTextSegment(); |
| 824 | 830 | try self.allocateDataConstSegment(); |
| ... | ... | @@ -1715,16 +1721,10 @@ fn sortSections(self: *MachO) !void { |
| 1715 | 1721 | |
| 1716 | 1722 | fn allocateTextSegment(self: *MachO) !void { |
| 1717 | 1723 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1718 | | const nstubs = @intCast(u32, self.stubs.items.len); |
| 1719 | | |
| 1720 | 1724 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; |
| 1721 | 1725 | seg.inner.fileoff = 0; |
| 1722 | 1726 | seg.inner.vmaddr = base_vmaddr; |
| 1723 | 1727 | |
| 1724 | | // Set stubs sizes |
| 1725 | | const stubs = &seg.sections.items[self.stubs_section_index.?]; |
| 1726 | | stubs.size += nstubs * stubs.reserved2; |
| 1727 | | |
| 1728 | 1728 | var sizeofcmds: u64 = 0; |
| 1729 | 1729 | for (self.load_commands.items) |lc| { |
| 1730 | 1730 | sizeofcmds += lc.cmdsize(); |
| ... | ... | @@ -2274,6 +2274,86 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32) !*TextBlock { |
| 2274 | 2274 | return atom; |
| 2275 | 2275 | } |
| 2276 | 2276 | |
| 2277 | fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock { |
| 2278 | const arch = self.base.options.target.cpu.arch; |
| 2279 | const alignment: u2 = switch (arch) { |
| 2280 | .x86_64 => 0, |
| 2281 | .aarch64 => 2, |
| 2282 | else => unreachable, // unhandled architecture type |
| 2283 | }; |
| 2284 | const stub_size: u4 = switch (arch) { |
| 2285 | .x86_64 => 6, |
| 2286 | .aarch64 => 3 * @sizeOf(u32), |
| 2287 | else => unreachable, // unhandled architecture type |
| 2288 | }; |
| 2289 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2290 | try self.locals.append(self.base.allocator, .{ |
| 2291 | .n_strx = try self.makeString("stub"), |
| 2292 | .n_type = macho.N_SECT, |
| 2293 | .n_sect = 0, |
| 2294 | .n_desc = 0, |
| 2295 | .n_value = 0, |
| 2296 | }); |
| 2297 | const atom = try self.createEmptyAtom(.{ |
| 2298 | .seg = self.text_segment_cmd_index.?, |
| 2299 | .sect = self.stubs_section_index.?, |
| 2300 | }, local_sym_index, stub_size, alignment); |
| 2301 | switch (arch) { |
| 2302 | .x86_64 => { |
| 2303 | // jmp |
| 2304 | atom.code.items[0] = 0xff; |
| 2305 | atom.code.items[1] = 0x25; |
| 2306 | try atom.relocs.append(self.base.allocator, .{ |
| 2307 | .offset = 2, |
| 2308 | .where = .local, |
| 2309 | .where_index = laptr_sym_index, |
| 2310 | .payload = .{ |
| 2311 | .branch = .{ .arch = arch }, |
| 2312 | }, |
| 2313 | }); |
| 2314 | }, |
| 2315 | .aarch64 => { |
| 2316 | try atom.relocs.ensureTotalCapacity(self.base.allocator, 2); |
| 2317 | // adrp x16, pages |
| 2318 | mem.writeIntLittle(u32, atom.code.items[0..4], aarch64.Instruction.adrp(.x16, 0).toU32()); |
| 2319 | atom.relocs.appendAssumeCapacity(.{ |
| 2320 | .offset = 0, |
| 2321 | .where = .local, |
| 2322 | .where_index = laptr_sym_index, |
| 2323 | .payload = .{ |
| 2324 | .page = .{ |
| 2325 | .kind = .page, |
| 2326 | .addend = 0, |
| 2327 | }, |
| 2328 | }, |
| 2329 | }); |
| 2330 | // ldr x16, x16, offset |
| 2331 | mem.writeIntLittle(u32, atom.code.items[4..8], aarch64.Instruction.ldr(.x16, .{ |
| 2332 | .register = .{ |
| 2333 | .rn = .x16, |
| 2334 | .offset = aarch64.Instruction.LoadStoreOffset.imm(0), |
| 2335 | }, |
| 2336 | }).toU32()); |
| 2337 | atom.relocs.appendAssumeCapacity(.{ |
| 2338 | .offset = 4, |
| 2339 | .where = .local, |
| 2340 | .where_index = laptr_sym_index, |
| 2341 | .payload = .{ |
| 2342 | .page_off = .{ |
| 2343 | .kind = .page, |
| 2344 | .addend = 0, |
| 2345 | .op_kind = .load, |
| 2346 | }, |
| 2347 | }, |
| 2348 | }); |
| 2349 | // br x16 |
| 2350 | mem.writeIntLittle(u32, atom.code.items[8..12], aarch64.Instruction.br(.x16).toU32()); |
| 2351 | }, |
| 2352 | else => unreachable, |
| 2353 | } |
| 2354 | return atom; |
| 2355 | } |
| 2356 | |
| 2277 | 2357 | fn resolveSymbolsInObject( |
| 2278 | 2358 | self: *MachO, |
| 2279 | 2359 | object_id: u16, |
| ... | ... | @@ -2761,12 +2841,6 @@ fn addLoadDylibLCs(self: *MachO) !void { |
| 2761 | 2841 | fn flushZld(self: *MachO) !void { |
| 2762 | 2842 | try self.writeTextBlocks(); |
| 2763 | 2843 | |
| 2764 | | for (self.stubs.items) |_, i| { |
| 2765 | | const index = @intCast(u32, i); |
| 2766 | | // TODO weak bound pointers |
| 2767 | | try self.writeStub(index); |
| 2768 | | } |
| 2769 | | |
| 2770 | 2844 | if (self.common_section_index) |index| { |
| 2771 | 2845 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2772 | 2846 | const sect = &seg.sections.items[index]; |
| ... | ... | @@ -4665,82 +4739,6 @@ fn writeGotEntry(self: *MachO, index: usize) !void { |
| 4665 | 4739 | try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off); |
| 4666 | 4740 | } |
| 4667 | 4741 | |
| 4668 | | fn writeStub(self: *MachO, index: u32) !void { |
| 4669 | | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4670 | | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |
| 4671 | | const data_segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 4672 | | const la_symbol_ptr = data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 4673 | | |
| 4674 | | const stub_off = stubs.offset + index * stubs.reserved2; |
| 4675 | | const stub_addr = stubs.addr + index * stubs.reserved2; |
| 4676 | | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); |
| 4677 | | |
| 4678 | | log.debug("writing stub at 0x{x}", .{stub_off}); |
| 4679 | | |
| 4680 | | var code = try self.base.allocator.alloc(u8, stubs.reserved2); |
| 4681 | | defer self.base.allocator.free(code); |
| 4682 | | |
| 4683 | | switch (self.base.options.target.cpu.arch) { |
| 4684 | | .x86_64 => { |
| 4685 | | assert(la_ptr_addr >= stub_addr + stubs.reserved2); |
| 4686 | | const displacement = try math.cast(u32, la_ptr_addr - stub_addr - stubs.reserved2); |
| 4687 | | // jmp |
| 4688 | | code[0] = 0xff; |
| 4689 | | code[1] = 0x25; |
| 4690 | | mem.writeIntLittle(u32, code[2..][0..4], displacement); |
| 4691 | | }, |
| 4692 | | .aarch64 => { |
| 4693 | | assert(la_ptr_addr >= stub_addr); |
| 4694 | | outer: { |
| 4695 | | const this_addr = stub_addr; |
| 4696 | | const target_addr = la_ptr_addr; |
| 4697 | | inner: { |
| 4698 | | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch break :inner; |
| 4699 | | const literal = math.cast(u18, displacement) catch break :inner; |
| 4700 | | // ldr x16, literal |
| 4701 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ |
| 4702 | | .literal = literal, |
| 4703 | | }).toU32()); |
| 4704 | | // nop |
| 4705 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| 4706 | | break :outer; |
| 4707 | | } |
| 4708 | | inner: { |
| 4709 | | const new_this_addr = this_addr + @sizeOf(u32); |
| 4710 | | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch break :inner; |
| 4711 | | const literal = math.cast(u18, displacement) catch break :inner; |
| 4712 | | // nop |
| 4713 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| 4714 | | // ldr x16, literal |
| 4715 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{ |
| 4716 | | .literal = literal, |
| 4717 | | }).toU32()); |
| 4718 | | break :outer; |
| 4719 | | } |
| 4720 | | // Use adrp followed by ldr(register). |
| 4721 | | const this_page = @intCast(i32, this_addr >> 12); |
| 4722 | | const target_page = @intCast(i32, target_addr >> 12); |
| 4723 | | const pages = @intCast(i21, target_page - this_page); |
| 4724 | | // adrp x16, pages |
| 4725 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| 4726 | | const narrowed = @truncate(u12, target_addr); |
| 4727 | | const offset = try math.divExact(u12, narrowed, 8); |
| 4728 | | // ldr x16, x16, offset |
| 4729 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{ |
| 4730 | | .register = .{ |
| 4731 | | .rn = .x16, |
| 4732 | | .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| 4733 | | }, |
| 4734 | | }).toU32()); |
| 4735 | | } |
| 4736 | | // br x16 |
| 4737 | | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); |
| 4738 | | }, |
| 4739 | | else => unreachable, |
| 4740 | | } |
| 4741 | | try self.base.file.?.pwriteAll(code, stub_off); |
| 4742 | | } |
| 4743 | | |
| 4744 | 4742 | fn relocateSymbolTable(self: *MachO) !void { |
| 4745 | 4743 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 4746 | 4744 | const nlocals = self.locals.items.len; |