| ... | ... | @@ -376,10 +376,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 376 | 376 | try self.populateMissingMetadata(); |
| 377 | 377 | try self.writeLocalSymbol(0); |
| 378 | 378 | |
| 379 | | if (self.stub_helper_stubs_start_off == null) { |
| 380 | | try self.writeStubHelperPreamble(); |
| 381 | | } |
| 382 | | |
| 383 | 379 | if (self.d_sym) |*ds| { |
| 384 | 380 | try ds.populateMissingMetadata(allocator); |
| 385 | 381 | try ds.writeLocalSymbol(0); |
| ... | ... | @@ -762,6 +758,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 762 | 758 | try self.resolveSymbols(); |
| 763 | 759 | try self.resolveDyldStubBinder(); |
| 764 | 760 | |
| 761 | if (!use_stage1) { |
| 762 | // TODO this should be made common when I figure out how to prealloc space for traditional linker path. |
| 763 | try self.writeStubHelperPreamble(); |
| 764 | } |
| 765 | |
| 765 | 766 | // Apply pending updates |
| 766 | 767 | var still_pending = std.ArrayList(PendingUpdate).init(self.base.allocator); |
| 767 | 768 | defer still_pending.deinit(); |
| ... | ... | @@ -824,6 +825,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 824 | 825 | try self.allocateDataSegment(); |
| 825 | 826 | self.allocateLinkeditSegment(); |
| 826 | 827 | try self.allocateTextBlocks(); |
| 828 | try self.writeStubHelperPreamble(); |
| 827 | 829 | try self.flushZld(); |
| 828 | 830 | } else { |
| 829 | 831 | try self.flushModule(comp); |
| ... | ... | @@ -1943,7 +1945,7 @@ fn writeTextBlocks(self: *MachO) !void { |
| 1943 | 1945 | } |
| 1944 | 1946 | } |
| 1945 | 1947 | |
| 1946 | | fn writeStubHelperCommon(self: *MachO) !void { |
| 1948 | fn writeStubHelperPreamble(self: *MachO) !void { |
| 1947 | 1949 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1948 | 1950 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| 1949 | 1951 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| ... | ... | @@ -2074,14 +2076,6 @@ fn writeStubHelperCommon(self: *MachO) !void { |
| 2074 | 2076 | else => unreachable, |
| 2075 | 2077 | } |
| 2076 | 2078 | }; |
| 2077 | | |
| 2078 | | for (self.stubs.items) |_, i| { |
| 2079 | | const index = @intCast(u32, i); |
| 2080 | | // TODO weak bound pointers |
| 2081 | | try self.writeLazySymbolPointer(index); |
| 2082 | | try self.writeStub(index); |
| 2083 | | try self.writeStubInStubHelper(index); |
| 2084 | | } |
| 2085 | 2079 | } |
| 2086 | 2080 | |
| 2087 | 2081 | fn resolveSymbolsInObject( |
| ... | ... | @@ -2616,7 +2610,14 @@ fn addLoadDylibLCs(self: *MachO) !void { |
| 2616 | 2610 | |
| 2617 | 2611 | fn flushZld(self: *MachO) !void { |
| 2618 | 2612 | try self.writeTextBlocks(); |
| 2619 | | try self.writeStubHelperCommon(); |
| 2613 | |
| 2614 | for (self.stubs.items) |_, i| { |
| 2615 | const index = @intCast(u32, i); |
| 2616 | // TODO weak bound pointers |
| 2617 | try self.writeLazySymbolPointer(index); |
| 2618 | try self.writeStub(index); |
| 2619 | try self.writeStubInStubHelper(index); |
| 2620 | } |
| 2620 | 2621 | |
| 2621 | 2622 | if (self.common_section_index) |index| { |
| 2622 | 2623 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| ... | ... | @@ -4540,133 +4541,6 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| 4540 | 4541 | try self.base.file.?.pwriteAll(&buf, off); |
| 4541 | 4542 | } |
| 4542 | 4543 | |
| 4543 | | fn writeStubHelperPreamble(self: *MachO) !void { |
| 4544 | | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4545 | | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| 4546 | | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 4547 | | const got = &data_const_segment.sections.items[self.got_section_index.?]; |
| 4548 | | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 4549 | | const data = &data_segment.sections.items[self.data_section_index.?]; |
| 4550 | | |
| 4551 | | switch (self.base.options.target.cpu.arch) { |
| 4552 | | .x86_64 => { |
| 4553 | | const code_size = 15; |
| 4554 | | var code: [code_size]u8 = undefined; |
| 4555 | | // lea %r11, [rip + disp] |
| 4556 | | code[0] = 0x4c; |
| 4557 | | code[1] = 0x8d; |
| 4558 | | code[2] = 0x1d; |
| 4559 | | { |
| 4560 | | const target_addr = data.addr; |
| 4561 | | const displacement = try math.cast(u32, target_addr - stub_helper.addr - 7); |
| 4562 | | mem.writeIntLittle(u32, code[3..7], displacement); |
| 4563 | | } |
| 4564 | | // push %r11 |
| 4565 | | code[7] = 0x41; |
| 4566 | | code[8] = 0x53; |
| 4567 | | // jmp [rip + disp] |
| 4568 | | code[9] = 0xff; |
| 4569 | | code[10] = 0x25; |
| 4570 | | { |
| 4571 | | const displacement = try math.cast(u32, got.addr - stub_helper.addr - code_size); |
| 4572 | | mem.writeIntLittle(u32, code[11..], displacement); |
| 4573 | | } |
| 4574 | | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| 4575 | | self.stub_helper_stubs_start_off = stub_helper.offset + code_size; |
| 4576 | | }, |
| 4577 | | .aarch64 => { |
| 4578 | | var code: [6 * @sizeOf(u32)]u8 = undefined; |
| 4579 | | |
| 4580 | | data_blk_outer: { |
| 4581 | | const this_addr = stub_helper.addr; |
| 4582 | | const target_addr = data.addr; |
| 4583 | | data_blk: { |
| 4584 | | const displacement = math.cast(i21, target_addr - this_addr) catch break :data_blk; |
| 4585 | | // adr x17, disp |
| 4586 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| 4587 | | // nop |
| 4588 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| 4589 | | break :data_blk_outer; |
| 4590 | | } |
| 4591 | | data_blk: { |
| 4592 | | const new_this_addr = this_addr + @sizeOf(u32); |
| 4593 | | const displacement = math.cast(i21, target_addr - new_this_addr) catch break :data_blk; |
| 4594 | | // nop |
| 4595 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| 4596 | | // adr x17, disp |
| 4597 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| 4598 | | break :data_blk_outer; |
| 4599 | | } |
| 4600 | | // Jump is too big, replace adr with adrp and add. |
| 4601 | | const this_page = @intCast(i32, this_addr >> 12); |
| 4602 | | const target_page = @intCast(i32, target_addr >> 12); |
| 4603 | | const pages = @intCast(i21, target_page - this_page); |
| 4604 | | // adrp x17, pages |
| 4605 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32()); |
| 4606 | | const narrowed = @truncate(u12, target_addr); |
| 4607 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32()); |
| 4608 | | } |
| 4609 | | |
| 4610 | | // stp x16, x17, [sp, #-16]! |
| 4611 | | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.stp( |
| 4612 | | .x16, |
| 4613 | | .x17, |
| 4614 | | aarch64.Register.sp, |
| 4615 | | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), |
| 4616 | | ).toU32()); |
| 4617 | | |
| 4618 | | binder_blk_outer: { |
| 4619 | | const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| 4620 | | const target_addr = got.addr; |
| 4621 | | binder_blk: { |
| 4622 | | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch break :binder_blk; |
| 4623 | | const literal = math.cast(u18, displacement) catch break :binder_blk; |
| 4624 | | // ldr x16, label |
| 4625 | | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{ |
| 4626 | | .literal = literal, |
| 4627 | | }).toU32()); |
| 4628 | | // nop |
| 4629 | | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| 4630 | | break :binder_blk_outer; |
| 4631 | | } |
| 4632 | | binder_blk: { |
| 4633 | | const new_this_addr = this_addr + @sizeOf(u32); |
| 4634 | | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch break :binder_blk; |
| 4635 | | const literal = math.cast(u18, displacement) catch break :binder_blk; |
| 4636 | | // nop |
| 4637 | | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| 4638 | | // ldr x16, label |
| 4639 | | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| 4640 | | .literal = literal, |
| 4641 | | }).toU32()); |
| 4642 | | break :binder_blk_outer; |
| 4643 | | } |
| 4644 | | // Jump is too big, replace ldr with adrp and ldr(register). |
| 4645 | | const this_page = @intCast(i32, this_addr >> 12); |
| 4646 | | const target_page = @intCast(i32, target_addr >> 12); |
| 4647 | | const pages = @intCast(i21, target_page - this_page); |
| 4648 | | // adrp x16, pages |
| 4649 | | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| 4650 | | const narrowed = @truncate(u12, target_addr); |
| 4651 | | const offset = try math.divExact(u12, narrowed, 8); |
| 4652 | | // ldr x16, x16, offset |
| 4653 | | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| 4654 | | .register = .{ |
| 4655 | | .rn = .x16, |
| 4656 | | .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| 4657 | | }, |
| 4658 | | }).toU32()); |
| 4659 | | } |
| 4660 | | |
| 4661 | | // br x16 |
| 4662 | | mem.writeIntLittle(u32, code[20..24], aarch64.Instruction.br(.x16).toU32()); |
| 4663 | | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| 4664 | | self.stub_helper_stubs_start_off = stub_helper.offset + code.len; |
| 4665 | | }, |
| 4666 | | else => unreachable, |
| 4667 | | } |
| 4668 | | } |
| 4669 | | |
| 4670 | 4544 | fn writeStub(self: *MachO, index: u32) !void { |
| 4671 | 4545 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4672 | 4546 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |