From cc6d0fb858562a8b81880e02db0112c60a250e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Holz?= Date: Fri, 20 Jun 2025 00:33:25 +0200 Subject: [PATCH] LibC: Implement setjmp and longjmp for aarch64 This implementation is based on the riscv64 version. --- Userland/Libraries/LibC/arch/aarch64/setjmp.S | 73 +++++++++++++++++-- Userland/Libraries/LibC/setjmp.h | 8 +- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/Userland/Libraries/LibC/arch/aarch64/setjmp.S b/Userland/Libraries/LibC/arch/aarch64/setjmp.S index fe8f4c0cfb6..7dcd7138fdb 100644 --- a/Userland/Libraries/LibC/arch/aarch64/setjmp.S +++ b/Userland/Libraries/LibC/arch/aarch64/setjmp.S @@ -1,26 +1,83 @@ /* * Copyright (c) 2021, Nico Weber + * Copyright (c) 2025, Sönke Holz * * SPDX-License-Identifier: BSD-2-Clause */ +// +// /!\ Read setjmp.h before modifying this file! +// + +#define DID_SAVE_SIGNAL_MASK_SLOT (21 * 8) +#define SAVED_SIGNAL_MASK_SLOT (21 * 8 + 4) + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/setjmp.html +// int setjmp(jmp_buf env) +// int _setjmp(jmp_buf env) .global _setjmp .global setjmp _setjmp: setjmp: - # FIXME: Possibly incomplete. + mov x1, #0 // Set savemask argument to 0 + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsetjmp.html +// int sigsetjmp(sigjmp_buf env, int savemask) +.global sigsetjmp +sigsetjmp: + str w1, [x0, #DID_SAVE_SIGNAL_MASK_SLOT] // Store savemask into did_save_signal_mask + str wzr, [x0, #SAVED_SIGNAL_MASK_SLOT] // Clear saved_signal_mask + cbz w1, .Lsaveregs + + stp x0, lr, [sp, #-16]! // Prepare ABI-compliant call to sigprocmask + + add x2, x0, #SAVED_SIGNAL_MASK_SLOT // Set argument oldset + mov x1, #0 // Set argument set + mov x0, #0 // Set argument how + bl sigprocmask + + ldp x0, lr, [sp], #16 + +.Lsaveregs: + stp x19, x20, [x0, #(0 * 8)] // Save registers + stp x21, x22, [x0, #(2 * 8)] + stp x23, x24, [x0, #(4 * 8)] + stp x25, x26, [x0, #(6 * 8)] + stp x27, x28, [x0, #(8 * 8)] + stp x29, x30, [x0, #(10 * 8)] + + stp d8, d9, [x0, #(12 * 8)] + stp d10, d11, [x0, #(14 * 8)] + stp d12, d13, [x0, #(16 * 8)] + stp d14, d15, [x0, #(18 * 8)] + + mov x1, sp + str x1, [x0, #(20 * 8)] + + mov x0, #0 ret .global _longjmp .global longjmp _longjmp: longjmp: - # FIXME: Possibly incomplete. - ret + ldp x19, x20, [x0, #(0 * 8)] // Restore registers + ldp x21, x22, [x0, #(2 * 8)] + ldp x23, x24, [x0, #(4 * 8)] + ldp x25, x26, [x0, #(6 * 8)] + ldp x27, x28, [x0, #(8 * 8)] + ldp x29, x30, [x0, #(10 * 8)] -.global _sigsetjmp -.global sigsetjmp -_sigsetjmp: -sigsetjmp: - # FIXME: Possibly incomplete. + ldp d8, d9, [x0, #(12 * 8)] + ldp d10, d11, [x0, #(14 * 8)] + ldp d12, d13, [x0, #(16 * 8)] + ldp d14, d15, [x0, #(18 * 8)] + + ldr x2, [x0, #(20 * 8)] + mov sp, x2 + + mov x0, x1 + cbnz x0, .Lnonzero + mov x0, #1 +.Lnonzero: ret diff --git a/Userland/Libraries/LibC/setjmp.h b/Userland/Libraries/LibC/setjmp.h index a69a0adfe6b..a164a2f812f 100644 --- a/Userland/Libraries/LibC/setjmp.h +++ b/Userland/Libraries/LibC/setjmp.h @@ -29,8 +29,10 @@ struct __jmp_buf { uint64_t rsp; uint64_t rip; #elif defined(__aarch64__) - // FIXME: This is likely incorrect. - uint64_t regs[22]; + uint64_t x19_to_x29[11]; + uint64_t lr; + uint64_t d8_to_d15[8]; + uint64_t sp; #elif defined(__riscv) && __riscv_xlen == 64 uint64_t s[12]; uint64_t fs[12]; @@ -53,7 +55,7 @@ typedef struct __jmp_buf sigjmp_buf[1]; # if defined(__x86_64__) static_assert(sizeof(struct __jmp_buf) == 72, "struct __jmp_buf unsynchronized with x86_64/setjmp.S"); # elif defined(__aarch64__) -static_assert(sizeof(struct __jmp_buf) == 184, "struct __jmp_buf unsynchronized with aarch64/setjmp.S"); +static_assert(sizeof(struct __jmp_buf) == 176, "struct __jmp_buf unsynchronized with aarch64/setjmp.S"); # elif defined(__riscv) && __riscv_xlen == 64 static_assert(sizeof(struct __jmp_buf) == 216, "struct __jmp_buf unsynchronized with riscv64/setjmp.S"); # else