| ... | @@ -376,10 +376,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -376,10 +376,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 376 | try self.populateMissingMetadata(); | 376 | try self.populateMissingMetadata(); |
| 377 | try self.writeLocalSymbol(0); | 377 | try self.writeLocalSymbol(0); |
| 378 | | 378 | |
| 379 | if (self.stub_helper_stubs_start_off == null) { | | |
| 380 | try self.writeStubHelperPreamble(); | | |
| 381 | } | | |
| 382 | | | |
| 383 | if (self.d_sym) |*ds| { | 379 | if (self.d_sym) |*ds| { |
| 384 | try ds.populateMissingMetadata(allocator); | 380 | try ds.populateMissingMetadata(allocator); |
| 385 | try ds.writeLocalSymbol(0); | 381 | try ds.writeLocalSymbol(0); |
| ... | @@ -762,6 +758,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -762,6 +758,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 762 | try self.resolveSymbols(); | 758 | try self.resolveSymbols(); |
| 763 | try self.resolveDyldStubBinder(); | 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 | // Apply pending updates | 766 | // Apply pending updates |
| 766 | var still_pending = std.ArrayList(PendingUpdate).init(self.base.allocator); | 767 | var still_pending = std.ArrayList(PendingUpdate).init(self.base.allocator); |
| 767 | defer still_pending.deinit(); | 768 | defer still_pending.deinit(); |
| ... | @@ -824,6 +825,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -824,6 +825,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 824 | try self.allocateDataSegment(); | 825 | try self.allocateDataSegment(); |
| 825 | self.allocateLinkeditSegment(); | 826 | self.allocateLinkeditSegment(); |
| 826 | try self.allocateTextBlocks(); | 827 | try self.allocateTextBlocks(); |
| | 828 | try self.writeStubHelperPreamble(); |
| 827 | try self.flushZld(); | 829 | try self.flushZld(); |
| 828 | } else { | 830 | } else { |
| 829 | try self.flushModule(comp); | 831 | try self.flushModule(comp); |
| ... | @@ -1943,7 +1945,7 @@ fn writeTextBlocks(self: *MachO) !void { | ... | @@ -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 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1949 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1948 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | 1950 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| 1949 | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 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,14 +2076,6 @@ fn writeStubHelperCommon(self: *MachO) !void { |
| 2074 | else => unreachable, | 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 | fn resolveSymbolsInObject( | 2081 | fn resolveSymbolsInObject( |
| ... | @@ -2616,7 +2610,14 @@ fn addLoadDylibLCs(self: *MachO) !void { | ... | @@ -2616,7 +2610,14 @@ fn addLoadDylibLCs(self: *MachO) !void { |
| 2616 | | 2610 | |
| 2617 | fn flushZld(self: *MachO) !void { | 2611 | fn flushZld(self: *MachO) !void { |
| 2618 | try self.writeTextBlocks(); | 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 | if (self.common_section_index) |index| { | 2622 | if (self.common_section_index) |index| { |
| 2622 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 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,133 +4541,6 @@ fn writeLazySymbolPointer(self: *MachO, index: u32) !void { |
| 4540 | try self.base.file.?.pwriteAll(&buf, off); | 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 | fn writeStub(self: *MachO, index: u32) !void { | 4544 | fn writeStub(self: *MachO, index: u32) !void { |
| 4671 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 4545 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4672 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; | 4546 | const stubs = text_segment.sections.items[self.stubs_section_index.?]; |