authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-16 23:00:10+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-17 12:10:39+01:00
log643b4898f592c7193402dcf9a7ca465edb2d430a
tree4942cc983e5517664d32d0d254c2c522f3f220bd
parent3019676440c5ea30be8a9a185fb1346622f7cbdb

macho: handle all jumps in stubs on aarch64


1 files changed, 48 insertions(+), 7 deletions(-)

src/link/MachO.zig+48-7
......@@ -1597,7 +1597,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15971597 };
15981598 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
15991599 .x86_64 => 6,
1600 .aarch64 => 2 * @sizeOf(u32),
1600 .aarch64 => 3 * @sizeOf(u32),
16011601 else => unreachable, // unhandled architecture type
16021602 };
16031603 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 {
25252525 const stub_off = stubs.offset + index * stubs.reserved2;
25262526 const stub_addr = stubs.addr + index * stubs.reserved2;
25272527 const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64);
2528
25282529 log.debug("writing stub at 0x{x}", .{stub_off});
2530
25292531 var code = try self.base.allocator.alloc(u8, stubs.reserved2);
25302532 defer self.base.allocator.free(code);
2533
25312534 switch (self.base.options.target.cpu.arch) {
25322535 .x86_64 => {
25332536 assert(la_ptr_addr >= stub_addr + stubs.reserved2);
......@@ -2539,12 +2542,50 @@ fn writeStub(self: *MachO, index: u32) !void {
25392542 },
25402543 .aarch64 => {
25412544 assert(la_ptr_addr >= stub_addr);
2542 const displacement = try math.divExact(u64, la_ptr_addr - stub_addr, 4);
2543 const literal = try math.cast(u19, displacement);
2544 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{
2545 .literal = literal,
2546 }).toU32());
2547 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.br(.x16).toU32());
2545 outer: {
2546 const this_addr = stub_addr;
2547 const target_addr = la_ptr_addr;
2548 inner: {
2549 const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :inner;
2550 const literal = math.cast(u18, displacement) catch |_| break :inner;
2551 // ldr x16, literal
2552 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{
2553 .literal = literal,
2554 }).toU32());
2555 // nop
2556 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32());
2557 break :outer;
2558 }
2559 inner: {
2560 const new_this_addr = this_addr + @sizeOf(u32);
2561 const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :inner;
2562 const literal = math.cast(u18, displacement) catch |_| break :inner;
2563 // nop
2564 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32());
2565 // ldr x16, literal
2566 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{
2567 .literal = literal,
2568 }).toU32());
2569 break :outer;
2570 }
2571 // Use adrp followed by ldr(register).
2572 const this_page = @intCast(i32, this_addr >> 12);
2573 const target_page = @intCast(i32, target_addr >> 12);
2574 const pages = @intCast(i21, target_page - this_page);
2575 // adrp x16, pages
2576 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x16, pages).toU32());
2577 const narrowed = @truncate(u12, target_addr);
2578 const offset = try math.divExact(u12, narrowed, 8);
2579 // ldr x16, x16, offset
2580 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{
2581 .register = .{
2582 .rn = .x16,
2583 .offset = aarch64.Instruction.LoadStoreOffset.imm(offset),
2584 },
2585 }).toU32());
2586 }
2587 // br x16
2588 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());
25482589 },
25492590 else => unreachable,
25502591 }