authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-24 00:03:51+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-24 00:03:51+02:00
log91c0552cfcb727dd6c2e6aa402112145993fac5b
treec07187d22e26203d0aa083cffd9545d1305e550c
parent876071b50b1d23a59b3d3e5acedf4161029f5f2b

macho: add routine for creating stubs in __stubs section


1 files changed, 89 insertions(+), 91 deletions(-)

src/link/MachO.zig+89-91
......@@ -808,17 +808,23 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
808808 sect.size -= atom.size;
809809 }
810810 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, .{
813813 .seg = self.text_segment_cmd_index.?,
814814 .sect = self.stub_helper_section_index.?,
815815 });
816816
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);
818818 try self.allocateAtomStage1(laptr_atom, .{
819819 .seg = self.data_segment_cmd_index.?,
820820 .sect = self.la_symbol_ptr_section_index.?,
821821 });
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 });
822828 }
823829 try self.allocateTextSegment();
824830 try self.allocateDataConstSegment();
......@@ -1715,16 +1721,10 @@ fn sortSections(self: *MachO) !void {
17151721
17161722fn allocateTextSegment(self: *MachO) !void {
17171723 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1718 const nstubs = @intCast(u32, self.stubs.items.len);
1719
17201724 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
17211725 seg.inner.fileoff = 0;
17221726 seg.inner.vmaddr = base_vmaddr;
17231727
1724 // Set stubs sizes
1725 const stubs = &seg.sections.items[self.stubs_section_index.?];
1726 stubs.size += nstubs * stubs.reserved2;
1727
17281728 var sizeofcmds: u64 = 0;
17291729 for (self.load_commands.items) |lc| {
17301730 sizeofcmds += lc.cmdsize();
......@@ -2274,6 +2274,86 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32) !*TextBlock {
22742274 return atom;
22752275}
22762276
2277fn 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
22772357fn resolveSymbolsInObject(
22782358 self: *MachO,
22792359 object_id: u16,
......@@ -2761,12 +2841,6 @@ fn addLoadDylibLCs(self: *MachO) !void {
27612841fn flushZld(self: *MachO) !void {
27622842 try self.writeTextBlocks();
27632843
2764 for (self.stubs.items) |_, i| {
2765 const index = @intCast(u32, i);
2766 // TODO weak bound pointers
2767 try self.writeStub(index);
2768 }
2769
27702844 if (self.common_section_index) |index| {
27712845 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
27722846 const sect = &seg.sections.items[index];
......@@ -4665,82 +4739,6 @@ fn writeGotEntry(self: *MachO, index: usize) !void {
46654739 try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off);
46664740}
46674741
4668fn 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
47444742fn relocateSymbolTable(self: *MachO) !void {
47454743 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
47464744 const nlocals = self.locals.items.len;