mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-27 04:29:39 +00:00
264 lines
8.4 KiB
C
264 lines
8.4 KiB
C
/****************************************************************************
|
|
* *
|
|
* GNAT COMPILER COMPONENTS *
|
|
* *
|
|
* S I G T R A M P *
|
|
* *
|
|
* Asm Implementation File *
|
|
* *
|
|
* Copyright (C) 2017-2019, 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 <ucontext.h>
|
|
|
|
#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 <tab>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));
|