diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-03-16 23:00:10 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-03-17 12:10:39 +0100 |
| commit | 643b4898f592c7193402dcf9a7ca465edb2d430a (patch) | |
| tree | 4942cc983e5517664d32d0d254c2c522f3f220bd /src | |
| parent | 3019676440c5ea30be8a9a185fb1346622f7cbdb (diff) | |
| download | zig-643b4898f592c7193402dcf9a7ca465edb2d430a.tar.gz zig-643b4898f592c7193402dcf9a7ca465edb2d430a.zip | |
macho: handle all jumps in stubs on aarch64
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 55 |
1 files changed, 48 insertions, 7 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 1240ae8481..a69ce31b85 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -1597,7 +1597,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { }; const stub_size: u4 = switch (self.base.options.target.cpu.arch) { .x86_64 => 6, - .aarch64 => 2 * @sizeOf(u32), + .aarch64 => 3 * @sizeOf(u32), else => unreachable, // unhandled architecture type }; const flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; @@ -2525,9 +2525,12 @@ fn writeStub(self: *MachO, index: u32) !void { const stub_off = stubs.offset + index * stubs.reserved2; const stub_addr = stubs.addr + index * stubs.reserved2; const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); + log.debug("writing stub at 0x{x}", .{stub_off}); + var code = try self.base.allocator.alloc(u8, stubs.reserved2); defer self.base.allocator.free(code); + switch (self.base.options.target.cpu.arch) { .x86_64 => { assert(la_ptr_addr >= stub_addr + stubs.reserved2); @@ -2539,12 +2542,50 @@ fn writeStub(self: *MachO, index: u32) !void { }, .aarch64 => { assert(la_ptr_addr >= stub_addr); - const displacement = try math.divExact(u64, la_ptr_addr - stub_addr, 4); - const literal = try math.cast(u19, displacement); - mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ - .literal = literal, - }).toU32()); - mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.br(.x16).toU32()); + outer: { + const this_addr = stub_addr; + const target_addr = la_ptr_addr; + inner: { + const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :inner; + const literal = math.cast(u18, displacement) catch |_| break :inner; + // ldr x16, literal + mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ + .literal = literal, + }).toU32()); + // nop + mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); + break :outer; + } + inner: { + const new_this_addr = this_addr + @sizeOf(u32); + const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :inner; + const literal = math.cast(u18, displacement) catch |_| break :inner; + // nop + mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); + // ldr x16, literal + mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{ + .literal = literal, + }).toU32()); + break :outer; + } + // Use adrp followed by ldr(register). + const this_page = @intCast(i32, this_addr >> 12); + const target_page = @intCast(i32, target_addr >> 12); + const pages = @intCast(i21, target_page - this_page); + // adrp x16, pages + mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x16, pages).toU32()); + const narrowed = @truncate(u12, target_addr); + const offset = try math.divExact(u12, narrowed, 8); + // ldr x16, x16, offset + mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{ + .register = .{ + .rn = .x16, + .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), + }, + }).toU32()); + } + // br x16 + mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); }, else => unreachable, } |
