/**************************************************************************** * * * GNAT COMPILER COMPONENTS * * * * S I G T R A M P * * * * Asm Implementation File * * * * Copyright (C) 2017-2022, Free Software Foundation, Inc. * * * * GNAT is free software; you can redistribute it and/or modify it under * * terms of the GNU General Public License as published by the Free Soft- * * ware Foundation; either version 3, or (at your option) any later ver- * * sion. GNAT is distributed in the hope that it will be useful, but WITH- * * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * * or FITNESS FOR A PARTICULAR PURPOSE. * * * * As a special exception under Section 7 of GPL version 3, you are granted * * additional permissions described in the GCC Runtime Library Exception, * * version 3.1, as published by the Free Software Foundation. * * * * In particular, you can freely distribute your programs built with the * * GNAT Pro compiler, including any required library run-time units, using * * any licensing terms of your choosing. See the AdaCore Software License * * for full details. * * * * GNAT was originally developed by the GNAT team at New York University. * * Extensive contributions were provided by Ada Core Technologies Inc. * * * ****************************************************************************/ /********************************************** * QNX version of the __gnat_sigtramp service * **********************************************/ #include #include "sigtramp.h" /* See sigtramp.h for a general explanation of functionality. */ extern void __gnat_sigtramp_common (int signo, void *siginfo, void *sigcontext, __sigtramphandler_t * handler); void __gnat_sigtramp (int signo, void *si, void *sc, __sigtramphandler_t * handler) __attribute__((optimize(2))); void __gnat_sigtramp (int signo, void *si, void *ucontext, __sigtramphandler_t * handler) { struct sigcontext *mcontext = &((ucontext_t *) ucontext)->uc_mcontext; __gnat_sigtramp_common (signo, si, mcontext, handler); } /* asm string construction helpers. */ #define STR(TEXT) #TEXT /* stringify expanded TEXT, surrounding it with double quotes. */ #define S(E) STR(E) /* stringify E, which will resolve as text but may contain macros still to be expanded. */ /* asm (TEXT) outputs TEXT. These facilitate the output of multiline contents: */ #define TAB(S) "\t" S #define CR(S) S "\n" #undef TCR #define TCR(S) TAB(CR(S)) /* Trampoline body block --------------------- */ #define COMMON_CFI(REG) \ ".cfi_offset " S(REGNO_##REG) "," S(REG_OFFSET_##REG) #ifdef __x86_64__ /***************************************** * x86-64 * *****************************************/ // CFI register numbers #define REGNO_RAX 0 #define REGNO_RDX 1 #define REGNO_RCX 2 #define REGNO_RBX 3 #define REGNO_RSI 4 #define REGNO_RDI 5 #define REGNO_RBP 6 #define REGNO_RSP 7 #define REGNO_R8 8 #define REGNO_R9 9 #define REGNO_R10 10 #define REGNO_R11 11 #define REGNO_R12 12 #define REGNO_R13 13 #define REGNO_R14 14 #define REGNO_R15 15 /* Used as CFA */ #define REGNO_RPC 16 /* aka %rip */ // Registers offset from the regset structure #define REG_OFFSET_RDI 0x00 #define REG_OFFSET_RSI 0x08 #define REG_OFFSET_RDX 0x10 #define REG_OFFSET_R10 0x18 #define REG_OFFSET_R8 0x20 #define REG_OFFSET_R9 0x28 #define REG_OFFSET_RAX 0x30 #define REG_OFFSET_RBX 0x38 #define REG_OFFSET_RBP 0x40 #define REG_OFFSET_RCX 0x48 #define REG_OFFSET_R11 0x50 #define REG_OFFSET_R12 0x58 #define REG_OFFSET_R13 0x60 #define REG_OFFSET_R14 0x68 #define REG_OFFSET_R15 0x70 #define REG_OFFSET_RPC 0x78 /* RIP */ #define REG_OFFSET_RSP 0x90 #define CFI_COMMON_REGS \ CR("# CFI for common registers\n") \ TCR(COMMON_CFI(RSP)) \ TCR(COMMON_CFI(R15)) \ TCR(COMMON_CFI(R14)) \ TCR(COMMON_CFI(R13)) \ TCR(COMMON_CFI(R12)) \ TCR(COMMON_CFI(R11)) \ TCR(COMMON_CFI(RCX)) \ TCR(COMMON_CFI(RBP)) \ TCR(COMMON_CFI(RBX)) \ TCR(COMMON_CFI(RAX)) \ TCR(COMMON_CFI(R9)) \ TCR(COMMON_CFI(R8)) \ TCR(COMMON_CFI(R10)) \ TCR(COMMON_CFI(RSI)) \ TCR(COMMON_CFI(RDI)) \ TCR(COMMON_CFI(RDX)) \ TCR(COMMON_CFI(RPC)) \ TCR(".cfi_return_column " S(REGNO_RPC)) #define SIGTRAMP_BODY \ TCR(".cfi_def_cfa 15, 0") \ CFI_COMMON_REGS \ CR("") \ TCR("# Allocate frame and save the non-volatile") \ TCR("# registers we're going to modify") \ TCR("subq $8, %rsp") \ TCR("# Setup CFA_REG = context, which we'll retrieve as our CFA value") \ TCR("movq %rdx, %r15") \ TCR("# Call the real handler. The signo, siginfo and sigcontext") \ TCR("# arguments are the same as those we received") \ TCR("call *%rcx") \ TCR("# This part should never be executed") \ TCR("addq $8, %rsp") \ TCR("ret") #endif #ifdef __aarch64__ /***************************************** * Aarch64 * *****************************************/ /* CFA reg: any callee saved register will do */ #define CFA_REG 19 /* General purpose registers */ #define REG_OFFSET_GR(n) (n * 8) #define REGNO_GR(n) n /* ELR value offset withing the mcontext registers list */ #define REG_OFFSET_ELR (32 * 8) /* The register used to hold the PC value to restore. We need a scratch register. */ #define REGNO_PC 9 #define CFI_DEF_CFA \ TCR(".cfi_def_cfa " S(CFA_REG) ", 0") /* This restores the callee-saved registers, the FP, the LR, and the SP. A scratch register is used as return column to indicate the new value for PC */ #define CFI_COMMON_REGS \ CR("# CFI for common registers\n") \ TCR(COMMON_CFI(GR(18))) \ TCR(COMMON_CFI(GR(19))) \ TCR(COMMON_CFI(GR(20))) \ TCR(COMMON_CFI(GR(21))) \ TCR(COMMON_CFI(GR(22))) \ TCR(COMMON_CFI(GR(23))) \ TCR(COMMON_CFI(GR(24))) \ TCR(COMMON_CFI(GR(25))) \ TCR(COMMON_CFI(GR(26))) \ TCR(COMMON_CFI(GR(27))) \ TCR(COMMON_CFI(GR(28))) \ TCR(COMMON_CFI(GR(29))) \ TCR(COMMON_CFI(GR(30))) \ TCR(COMMON_CFI(GR(31))) \ TCR(".cfi_offset " S(REGNO_PC) "," S(REG_OFFSET_ELR)) \ TCR(".cfi_return_column " S(REGNO_PC)) #define SIGTRAMP_BODY \ CFI_DEF_CFA \ CFI_COMMON_REGS \ TCR("# Allocate the frame (16bytes aligned) and push FP and LR") \ TCR("stp x29, x30, [sp, #-32]!") \ TCR("add x29, sp, 0") \ TCR("# Push register used to hold the CFA on stack") \ TCR("str x" S(CFA_REG) ", [sp, 16]") \ TCR("# Set the CFA: x2 value") \ TCR("mov x" S(CFA_REG) ", x2") \ TCR("# Call the handler") \ TCR("blr x3") \ TCR("# Release our frame and return (should never get here!).") \ TCR("ldr x" S(CFA_REG) ", [sp, 16]") \ TCR("ldp x29, x30, [sp], 32") \ TCR("ret") #endif /* AARCH64 */ /* Symbol definition block ----------------------- */ #if defined (__x86_64__) || defined (__aarch64__) #define FUNC_ALIGN TCR(".p2align 4,,15") #else #define FUNC_ALIGN #endif #define SIGTRAMP_START(SYM) \ CR("# " S(SYM) " cfi trampoline") \ TCR(".type " S(SYM) ", @function") \ CR("") \ FUNC_ALIGN \ CR(S(SYM) ":") \ TCR(".cfi_startproc") \ TCR(".cfi_signal_frame") /* Symbol termination block ------------------------ */ #define SIGTRAMP_END(SYM) \ CR(".cfi_endproc") \ TCR(".size " S(SYM) ", .-" S(SYM)) /*---------------------------- -- And now, the real code -- ---------------------------- */ /* Text section start. The compiler isn't aware of that switch. */ asm (".text\n" TCR(".align 2")); /* sigtramp stub for common registers. */ #define TRAMP_COMMON __gnat_sigtramp_common asm (SIGTRAMP_START(TRAMP_COMMON)); asm (SIGTRAMP_BODY); asm (SIGTRAMP_END(TRAMP_COMMON));