| ... | @@ -808,17 +808,23 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -808,17 +808,23 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 808 | sect.size -= atom.size; | 808 | sect.size -= atom.size; |
| 809 | } | 809 | } |
| 810 | for (self.stubs.items) |_| { | 810 | for (self.stubs.items) |_| { |
| 811 | const stub_atom = try self.createStubHelperAtom(); | 811 | const stub_helper_atom = try self.createStubHelperAtom(); |
| 812 | try self.allocateAtomStage1(stub_atom, .{ | 812 | try self.allocateAtomStage1(stub_helper_atom, .{ |
| 813 | .seg = self.text_segment_cmd_index.?, | 813 | .seg = self.text_segment_cmd_index.?, |
| 814 | .sect = self.stub_helper_section_index.?, | 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 | try self.allocateAtomStage1(laptr_atom, .{ | 818 | try self.allocateAtomStage1(laptr_atom, .{ |
| 819 | .seg = self.data_segment_cmd_index.?, | 819 | .seg = self.data_segment_cmd_index.?, |
| 820 | .sect = self.la_symbol_ptr_section_index.?, | 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 | try self.allocateTextSegment(); | 829 | try self.allocateTextSegment(); |
| 824 | try self.allocateDataConstSegment(); | 830 | try self.allocateDataConstSegment(); |
| ... | @@ -1715,16 +1721,10 @@ fn sortSections(self: *MachO) !void { | ... | @@ -1715,16 +1721,10 @@ fn sortSections(self: *MachO) !void { |
| 1715 | | 1721 | |
| 1716 | fn allocateTextSegment(self: *MachO) !void { | 1722 | fn allocateTextSegment(self: *MachO) !void { |
| 1717 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1723 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1718 | const nstubs = @intCast(u32, self.stubs.items.len); | | |
| 1719 | | | |
| 1720 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; | 1724 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; |
| 1721 | seg.inner.fileoff = 0; | 1725 | seg.inner.fileoff = 0; |
| 1722 | seg.inner.vmaddr = base_vmaddr; | 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 | var sizeofcmds: u64 = 0; | 1728 | var sizeofcmds: u64 = 0; |
| 1729 | for (self.load_commands.items) |lc| { | 1729 | for (self.load_commands.items) |lc| { |
| 1730 | sizeofcmds += lc.cmdsize(); | 1730 | sizeofcmds += lc.cmdsize(); |
| ... | @@ -2274,6 +2274,86 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32) !*TextBlock { | ... | @@ -2274,6 +2274,86 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32) !*TextBlock { |
| 2274 | return atom; | 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 | fn resolveSymbolsInObject( | 2357 | fn resolveSymbolsInObject( |
| 2278 | self: *MachO, | 2358 | self: *MachO, |
| 2279 | object_id: u16, | 2359 | object_id: u16, |
| ... | @@ -2761,12 +2841,6 @@ fn addLoadDylibLCs(self: *MachO) !void { | ... | @@ -2761,12 +2841,6 @@ fn addLoadDylibLCs(self: *MachO) !void { |
| 2761 | fn flushZld(self: *MachO) !void { | 2841 | fn flushZld(self: *MachO) !void { |
| 2762 | try self.writeTextBlocks(); | 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 | if (self.common_section_index) |index| { | 2844 | if (self.common_section_index) |index| { |
| 2771 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 2845 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2772 | const sect = &seg.sections.items[index]; | 2846 | const sect = &seg.sections.items[index]; |
| ... | @@ -4665,82 +4739,6 @@ fn writeGotEntry(self: *MachO, index: usize) !void { | ... | @@ -4665,82 +4739,6 @@ fn writeGotEntry(self: *MachO, index: usize) !void { |
| 4665 | try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off); | 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 | fn relocateSymbolTable(self: *MachO) !void { | 4742 | fn relocateSymbolTable(self: *MachO) !void { |
| 4745 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 4743 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 4746 | const nlocals = self.locals.items.len; | 4744 | const nlocals = self.locals.items.len; |