blob: e112ca6cf1fdd73be5f6b283c6110a13c615190d [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Google, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/*
* mcxtx_api.h
*
* Machine context struct. Included into two separate
* structs for internal and external use and so it has no include guard.
* Not meant to be directly includedt into an implementation file!
*
*/
/* clang-format off */
#if defined(AARCHXX)
/* We want to simplify things by keeping this in register lists order.
* We also want registers used by ibl to be placed together to fit on
* the same 32-byte cache line, whether on a 32-bit or 64-bit machine,
* or a 32-byte or 64-byte cache line.
* Any changes in order here must be mirrored in arch/arm.asm offsets.
*/
/* The stolen register slot only holds the app's value while in DR.
* While in the cache, the app's value is stored in TLS in
* dcontext->local_state->spill_space.reg_stolen, and the mcontext slot
* actually holds DR's TLS base just due to a quirk of how fcache_enter
* operates.
*/
reg_t r0; /**< The r0 register. */
reg_t r1; /**< The r1 register. */
reg_t r2; /**< The r2 register. */
reg_t r3; /**< The r3 register. */
reg_t r4; /**< The r4 register. */
reg_t r5; /**< The r5 register. */
reg_t r6; /**< The r6 register. */
reg_t r7; /**< The r7 register. */
reg_t r8; /**< The r8 register. */
reg_t r9; /**< The r9 register. */
reg_t r10; /**< The r10 register. */
reg_t r11; /**< The r11 register. */
reg_t r12; /**< The r12 register. */
# ifdef X64 /* 64-bit */
reg_t r13; /**< The r13 register. */
reg_t r14; /**< The r14 register. */
reg_t r15; /**< The r15 register. */
reg_t r16; /**< The r16 register. \note For 64-bit DR builds only. */
reg_t r17; /**< The r17 register. \note For 64-bit DR builds only. */
reg_t r18; /**< The r18 register. \note For 64-bit DR builds only. */
reg_t r19; /**< The r19 register. \note For 64-bit DR builds only. */
reg_t r20; /**< The r20 register. \note For 64-bit DR builds only. */
reg_t r21; /**< The r21 register. \note For 64-bit DR builds only. */
reg_t r22; /**< The r22 register. \note For 64-bit DR builds only. */
reg_t r23; /**< The r23 register. \note For 64-bit DR builds only. */
reg_t r24; /**< The r24 register. \note For 64-bit DR builds only. */
reg_t r25; /**< The r25 register. \note For 64-bit DR builds only. */
reg_t r26; /**< The r26 register. \note For 64-bit DR builds only. */
reg_t r27; /**< The r27 register. \note For 64-bit DR builds only. */
reg_t r28; /**< The r28 register. \note For 64-bit DR builds only. */
reg_t r29; /**< The r29 register. \note For 64-bit DR builds only. */
union {
reg_t r30; /**< The r30 register. \note For 64-bit DR builds only. */
reg_t lr; /**< The link register. */
}; /**< The anonymous union of alternative names for r30/lr register. */
union {
reg_t r31; /**< The r31 register. \note For 64-bit DR builds only. */
reg_t sp; /**< The stack pointer register. */
reg_t xsp; /**< The platform-independent name for the stack pointer register. */
}; /**< The anonymous union of alternative names for r31/sp register. */
/**
* The program counter.
* \note This field is not always set or read by all API routines.
*/
byte *pc;
union {
uint xflags; /**< The platform-independent name for condition flags. */
struct {
uint nzcv; /**< Condition flags (status register). */
uint fpcr; /**< Floating-Point Control Register. */
uint fpsr; /**< Floating-Point Status Register. */
}; /**< AArch64 flag registers. */
}; /**< The anonymous union of alternative names for flag registers. */
# else /* 32-bit */
union {
reg_t r13; /**< The r13 register. */
reg_t sp; /**< The stack pointer register.*/
reg_t xsp; /**< The platform-independent name for the stack pointer register. */
}; /**< The anonymous union of alternative names for r13/sp register. */
union {
reg_t r14; /**< The r14 register. */
reg_t lr; /**< The link register. */
}; /**< The anonymous union of alternative names for r14/lr register. */
/**
* The anonymous union of alternative names for r15/pc register.
* \note This field is not always set or read by all API routines.
*/
union {
reg_t r15; /**< The r15 register. */
byte *pc; /**< The program counter. */
};
union {
uint xflags; /**< The platform-independent name for full APSR register. */
uint apsr; /**< The application program status registers in AArch32. */
uint cpsr; /**< The current program status registers in AArch32. */
}; /**< The anonymous union of alternative names for apsr/cpsr register. */
# endif /* 64/32-bit */
# ifdef X64 /* 64-bit */
/**
* The Arm AArch64 SIMD (DR_REG_Q0->DR_REG_Q31) and Scalable Vector
* Extension (SVE) vector registers (DR_REG_Z0->DR_REG_Z31).
*/
dr_simd_t simd[MCXT_NUM_SIMD_SVE_SLOTS];
/**
* The Arm AArch64 Scalable Vector Extension (SVE) predicate registers
* DR_REG_P0 to DR_REG_P15.
*/
dr_svep_t svep[MCXT_NUM_SVEP_SLOTS];
/**
* The Arm AArch64 Scalable Vector Extension (SVE) first fault register
* DR_REG_FFR, for vector load instrcutions.
*/
dr_ffr_t ffr;
# else
/*
* For the Arm AArch32 SIMD registers, we would probably be ok if we did
* not preserve the callee-saved registers (q4-q7 == d8-d15) but to be safe
* we preserve them all. We do not need anything more than word alignment
* for OP_vldm/OP_vstm, and dr_simd_t has no fields larger than 32 bits, so
* we have no padding.
*/
/**
* The Arm AArch32 SIMD registers.
*/
dr_simd_t simd[MCXT_NUM_SIMD_SLOTS];
# endif
#elif defined(X86)
/* Our inlined ibl uses eax-edx, so we place them together to fit
* on the same 32-byte cache line; yet we also want to simplify
* things by keeping this in pusha order. Whether on a 32-bit or
* 64-bit machine, or a 32-byte or 64-byte cache line, they will
* still be on the same line, assuming this struct is
* cache-line-aligned (which it is if in dcontext).
* Any changes in order here must be mirrored in arch/x86.asm offsets.
* UPDATE: actually we now use TLS for scratch slots.
* See the list above of places that assume dr_mcxt_t layout.
*/
union {
reg_t xdi; /**< The platform-independent name for full rdi/edi register. */
reg_t IF_X64_ELSE(rdi, edi); /**< The platform-dependent name for
rdi/edi register. */
}; /**< The anonymous union of alternative names for rdi/edi register. */
union {
reg_t xsi; /**< The platform-independent name for full rsi/esi register. */
reg_t IF_X64_ELSE(rsi, esi); /**< The platform-dependent name for
rsi/esi register. */
}; /**< The anonymous union of alternative names for rsi/esi register. */
union {
reg_t xbp; /**< The platform-independent name for full rbp/ebp register. */
reg_t IF_X64_ELSE(rbp, ebp); /**< The platform-dependent name for
rbp/ebp register. */
}; /**< The anonymous union of alternative names for rbp/ebp register. */
union {
reg_t xsp; /**< The platform-independent name for full rsp/esp register. */
reg_t IF_X64_ELSE(rsp, esp); /**< The platform-dependent name for
rsp/esp register. */
}; /**< The anonymous union of alternative names for rsp/esp register. */
union {
reg_t xbx; /**< The platform-independent name for full rbx/ebx register. */
reg_t IF_X64_ELSE(rbx, ebx); /**< The platform-dependent name for
rbx/ebx register. */
}; /**< The anonymous union of alternative names for rbx/ebx register. */
union {
reg_t xdx; /**< The platform-independent name for full rdx/edx register. */
reg_t IF_X64_ELSE(rdx, edx); /**< The platform-dependent name for
rdx/edx register. */
}; /**< The anonymous union of alternative names for rdx/edx register. */
union {
reg_t xcx; /**< The platform-independent name for full rcx/ecx register. */
reg_t IF_X64_ELSE(rcx, ecx); /**< The platform-dependent name for
rcx/ecx register. */
}; /**< The anonymous union of alternative names for rcx/ecx register. */
union {
reg_t xax; /**< The platform-independent name for full rax/eax register. */
reg_t IF_X64_ELSE(rax, eax); /**< The platform-dependent name for
rax/eax register. */
}; /**< The anonymous union of alternative names for rax/eax register. */
# ifdef X64
reg_t r8; /**< The r8 register. \note For 64-bit DR builds only. */
reg_t r9; /**< The r9 register. \note For 64-bit DR builds only. */
reg_t r10; /**< The r10 register. \note For 64-bit DR builds only. */
reg_t r11; /**< The r11 register. \note For 64-bit DR builds only. */
reg_t r12; /**< The r12 register. \note For 64-bit DR builds only. */
reg_t r13; /**< The r13 register. \note For 64-bit DR builds only. */
reg_t r14; /**< The r14 register. \note For 64-bit DR builds only. */
reg_t r15; /**< The r15 register. \note For 64-bit DR builds only. */
# endif
union {
reg_t xflags; /**< The platform-independent name for
full rflags/eflags register. */
reg_t IF_X64_ELSE(rflags, eflags); /**< The platform-dependent name for
rflags/eflags register. */
}; /**< The anonymous union of alternative names for rflags/eflags register. */
/**
* Anonymous union of alternative names for the program counter /
* instruction pointer (eip/rip). \note This field is not always set or
* read by all API routines.
*/
union {
byte *xip; /**< The platform-independent name for full rip/eip register. */
byte *pc; /**< The platform-independent alt name for full rip/eip register. */
byte *IF_X64_ELSE(rip, eip); /**< The platform-dependent name for
rip/eip register. */
};
byte padding[PRE_XMM_PADDING]; /**< The padding to get zmm field 64-byte aligned. */
/**
* Anonymous union of alternative names for the simd structure in dr_mcontext_t. The
* deprecated name ymm is provided for backward compatibility.
*/
union {
/**
* The SSE registers xmm0-xmm5 (-xmm15 on Linux) are volatile
* (caller-saved) for 64-bit and WOW64, and are actually zeroed out on
* Windows system calls. These fields are ignored for 32-bit processes
* that are not WOW64, or if the underlying processor does not support
* SSE. Use dr_mcontext_xmm_fields_valid() to determine whether the
* fields are valid. Use dr_mcontext_zmm_fields_valid() to determine
* whether zmm registers are preserved.
*
* When the xmm fields are valid, on processors with AVX enabled (i.e.,
* proc_has_feature() with #FEATURE_AVX returns true), these fields will
* contain the full ymm register values; otherwise, the top 128
* bits of each slot will be undefined.
*
* When the zmm fields are valid, it implies that
* proc_has_feature() with #FEATURE_AVX512F is true. This is because DynamoRIO
* will not attempt to fill zmm fields w/o support by the processor and OS. The
* fields then will contain the full zmm register values.
*/
/* PR 264138: we must preserve xmm0-5 if on a 64-bit Windows kernel,
* and xmm0-15 if in a 64-bit Linux app (PR 302107). (Note that
* mmx0-7 are also caller-saved on linux but we assume they're not
* going to be used by DR, libc, or client routines: overlap w/
* floating point). For Windows we assume that none of our routines
* (or libc routines that we call, except the floating-point ones,
* where we explicitly save state) clobber beyond xmm0-5. Rather than
* have a separate WOW64 build, we have them in the struct but ignored
* for normal 32-bit.
* PR 306394: we preserve xmm0-7 for 32-bit linux too.
* DrMi#665: we now preserve all of the xmm registers.
*
* The size of mcontext's simd strucure has become a potential risk for
* DynamoRIO's stack- and signal stack size or for general memory usage becoming
* too large. Compared to AVX's ymm registers, the AVX-512 zmm register slots are
* adding 1536 bytes on 64-bit on Linux. On 32-bit Linux, it is adding 256 bytes.
* XXX i#1312: If this will become a problem, we may want to separate this out
* into a heap structure and only maintain a pointer on the stack. This would save
* space on memory constraint platforms as well as keep our signal stack size
* smaller.
* XXX i#1312: Currently, only 512 bytes are added on 64-bit until
* MCXT_NUM_SIMD_SLOTS will be 32. This excludes AVX-512 k mask registers, which
* will add another 64 bytes.
*/
dr_zmm_t simd[MCXT_NUM_SIMD_SLOTS];
/**
* \deprecated The ymm field is provided for backward compatibility and is an
* alias for the simd field.
*/
dr_zmm_t ymm[MCXT_NUM_SIMD_SLOTS];
};
/** Storage for #MCXT_NUM_OPMASK_SLOTS mask registers as part of AVX-512. */
dr_opmask_t opmask[MCXT_NUM_OPMASK_SLOTS];
#elif defined(RISCV64)
/* FIXME i#3544: add rest of machine context and register aliases. */
/* Any changes in order here must be mirrored in arch/riscv64.asm offsets.
*/
union {
/* FIXME i#3544: This is hard-wired to zero so could be removed */
reg_t x0; /**< The x0 register. */
reg_t zero; /**< The hard-wired zero register. */
}; /**< The anonymous union of alternative names for x0/zero register. */
union {
reg_t x1; /**< The x1 register. */
reg_t ra; /**< The return address register. */
}; /**< The anonymous union of alternative names for the x1/ra register. */
union {
reg_t x2; /**< The x2 register. */
reg_t sp; /**< The stack pointer register.*/
reg_t xsp; /**< The platform-independent name for the stack pointer register. */
}; /**< The anonymous union of alternative names for the x2/sp register. */
union {
reg_t x3; /**< The x3 register. */
reg_t gp; /**< The global pointer register. */
}; /**< The anonymous union of alternative names for the x3/gp register. */
union {
reg_t x4; /**< The x4 register. */
reg_t tp; /**< The thread pointer register. */
}; /**< The anonymous union of alternative names for the x4/tp register. */
union {
reg_t x5; /**< The x5 register. */
reg_t t0; /**< The 1st temporary register. */
}; /**< The anonymous union of alternative names for the x5/t0 register. */
union {
reg_t x6; /**< The x6 register. */
reg_t t1; /**< The 2nd temporary register. */
}; /**< The anonymous union of alternative names for the x6/t1 register. */
union {
reg_t x7; /**< The x7 register. */
reg_t t2; /**< The 3rd temporary register. */
}; /**< The anonymous union of alternative names for the x7/t2 register. */
union {
reg_t x8; /**< The x8 register. */
reg_t s0; /**< The 1st callee-saved register. */
reg_t fp; /**< The frame pointer register. */
}; /**< The anonymous union of alternative names for the x8/s0/fp register. */
union {
reg_t x9; /**< The x9 register. */
reg_t s1; /**< The 2nd callee-saved register. */
}; /**< The anonymous union of alternative names for the x9/s1 register. */
union {
reg_t x10; /**< The x10 register. */
reg_t a0; /**< The 1st argument/return value register. */
}; /**< The anonymous union of alternative names for the x10/a0 register. */
union {
reg_t x11; /**< The x11 register. */
reg_t a1; /**< The 2nd argument/return value register. */
}; /**< The anonymous union of alternative names for the x11/a1 register. */
union {
reg_t x12; /**< The x12 register. */
reg_t a2; /**< The 3rd argument register. */
}; /**< The anonymous union of alternative names for the x12/a2 register. */
union {
reg_t x13; /**< The x13 register. */
reg_t a3; /**< The 4th argument register. */
}; /**< The anonymous union of alternative names for the x13/a3 register. */
union {
reg_t x14; /**< The x14 register. */
reg_t a4; /**< The 5th argument register. */
}; /**< The anonymous union of alternative names for the x14/a4 register. */
union {
reg_t x15; /**< The x15 register. */
reg_t a5; /**< The 6th argument register. */
}; /**< The anonymous union of alternative names for the x15/a5 register. */
union {
reg_t x16; /**< The x16 register. */
reg_t a6; /**< The 7th argument register. */
}; /**< The anonymous union of alternative names for the x16/a6 register. */
union {
reg_t x17; /**< The x17 register. */
reg_t a7; /**< The 8th argument register. */
}; /**< The anonymous union of alternative names for the x17/a7 register. */
union {
reg_t x18; /**< The x18 register. */
reg_t s2; /**< The 3rd callee-saved register. */
}; /**< The anonymous union of alternative names for the x18/s2 register. */
union {
reg_t x19; /**< The x19 register. */
reg_t s3; /**< The 4th callee-saved register. */
}; /**< The anonymous union of alternative names for the x19/s3 register. */
union {
reg_t x20; /**< The x20 register. */
reg_t s4; /**< The 5th callee-saved register. */
}; /**< The anonymous union of alternative names for the x20/s4 register. */
union {
reg_t x21; /**< The x21 register. */
reg_t s5; /**< The 6th callee-saved register. */
}; /**< The anonymous union of alternative names for the x21/s5 register. */
union {
reg_t x22; /**< The x22 register. */
reg_t s6; /**< The 7th callee-saved register. */
}; /**< The anonymous union of alternative names for the x22/s6 register. */
union {
reg_t x23; /**< The x23 register. */
reg_t s7; /**< The 8th callee-saved register. */
}; /**< The anonymous union of alternative names for the x23/s7 register. */
union {
reg_t x24; /**< The x24 register. */
reg_t s8; /**< The 9th callee-saved register. */
}; /**< The anonymous union of alternative names for the x24/s8 register. */
union {
reg_t x25; /**< The x25 register. */
reg_t s9; /**< The 10th callee-saved register. */
}; /**< The anonymous union of alternative names for the x25/s9 register. */
union {
reg_t x26; /**< The x26 register. */
reg_t s10; /**< The 11th callee-saved register. */
}; /**< The anonymous union of alternative names for the x26/s10 register. */
union {
reg_t x27; /**< The x27 register. */
reg_t s11; /**< The 12th callee-saved register. */
}; /**< The anonymous union of alternative names for the x27/s11 register. */
union {
reg_t x28; /**< The x28 register. */
reg_t t3; /**< The 4th temporary register. */
}; /**< The anonymous union of alternative names for the s28/t3 register. */
union {
reg_t x29; /**< The x29 register. */
reg_t t4; /**< The 5th temporary register. */
}; /**< The anonymous union of alternative names for the x29/t4 register. */
union {
reg_t x30; /**< The x30 register. */
reg_t t5; /**< The 6th temporary register. */
}; /**< The anonymous union of alternative names for the x30/t5 register. */
union {
reg_t x31; /**< The x31 register. */
reg_t t6; /**< The 7th temporary register. */
}; /**< The anonymous union of alternative names for the x31/t6 register. */
/**
* The program counter.
* \note This field is not always set or read by all API routines.
*/
byte *pc;
union {
reg_t f0; /**< The f0 register. */
reg_t ft0; /**< The 1st temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f0/ft0 register. */
union {
reg_t f1; /**< The f1 register. */
reg_t ft1; /**< The 2nd temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f1/ft1 register. */
union {
reg_t f2; /**< The f2 register. */
reg_t ft2; /**< The 3rd temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f2/ft2 register. */
union {
reg_t f3; /**< The f3 register. */
reg_t ft3; /**< The 4th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f3/ft3 register. */
union {
reg_t f4; /**< The f4 register. */
reg_t ft4; /**< The 5th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f4/ft4 register. */
union {
reg_t f5; /**< The f5 register. */
reg_t ft5; /**< The 6th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f5/ft5 register. */
union {
reg_t f6; /**< The f6 register. */
reg_t ft6; /**< The 7th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f6/ft6 register. */
union {
reg_t f7; /**< The f7 register. */
reg_t ft7; /**< The 8th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f7/ft7 register. */
union {
reg_t f8; /**< The f8 register. */
reg_t fs0; /**< The 1st callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f8/fs0 register. */
union {
reg_t f9; /**< The f9 register. */
reg_t fs1; /**< The 2nd callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f9/fs1 register. */
union {
reg_t f10; /**< The f10 register. */
reg_t fa0; /**< The 1st argument/return value floating-point register. */
}; /**< The anonymous union of alternative names for the f10/fa0 register. */
union {
reg_t f11; /**< The f11 register. */
reg_t fa1; /**< The 2nd argument/return value floating-point register. */
}; /**< The anonymous union of alternative names for the f11/fa1 register. */
union {
reg_t f12; /**< The f12 register. */
reg_t fa2; /**< The 3rd argument floating-point register. */
}; /**< The anonymous union of alternative names for the f12/fa2 register. */
union {
reg_t f13; /**< The f13 register. */
reg_t fa3; /**< The 4th argument floating-point register. */
}; /**< The anonymous union of alternative names for the f13/fa3 register. */
union {
reg_t f14; /**< The f14 register. */
reg_t fa4; /**< The 5th argument floating-point register. */
}; /**< The anonymous union of alternative names for the f14/fa4 register. */
union {
reg_t f15; /**< The f15 register. */
reg_t fa5; /**< The 6th argument floating-point register. */
}; /**< The anonymous union of alternative names for the f15/fa5 register. */
union {
reg_t f16; /**< The f16 register. */
reg_t fa6; /**< The 7th argument floating-point register. */
}; /**< The anonymous union of alternative names for the f16/fa6 register. */
union {
reg_t f17; /**< The f17 register. */
reg_t fa7; /**< The 8th argument floating-point register. */
}; /**< The anonymous union of alternative names for the f17/fa7 register. */
union {
reg_t f18; /**< The f18 register. */
reg_t fs2; /**< The 3rd callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f18/fs2 register. */
union {
reg_t f19; /**< The f19 register. */
reg_t fs3; /**< The 4th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f19/fs3 register. */
union {
reg_t f20; /**< The f20 register. */
reg_t fs4; /**< The 5th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f20/fs4 register. */
union {
reg_t f21; /**< The f21 register. */
reg_t fs5; /**< The 6th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f21/fs5 register. */
union {
reg_t f22; /**< The f22 register. */
reg_t fs6; /**< The 7th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f22/fs6 register. */
union {
reg_t f23; /**< The f23 register. */
reg_t fs7; /**< The 8th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f23/fs7 register. */
union {
reg_t f24; /**< The f24 register. */
reg_t fs8; /**< The 9th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f24/fs8 register. */
union {
reg_t f25; /**< The f25 register. */
reg_t fs9; /**< The 10th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f25/fs9 register. */
union {
reg_t f26; /**< The f26 register. */
reg_t fs10; /**< The 11th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f26/fs10 register. */
union {
reg_t f27; /**< The f27 register. */
reg_t fs11; /**< The 12th callee-saved floating-point register. */
}; /**< The anonymous union of alternative names for the f27/fs11 register. */
union {
reg_t f28; /**< The f28 register. */
reg_t ft8; /**< The 9th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f28/ft8 register. */
union {
reg_t f29; /**< The f29 register. */
reg_t ft9; /**< The 10th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f29/ft9 register. */
union {
reg_t f30; /**< The f30 register. */
reg_t ft10; /**< The 11th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f30/ft10 register. */
union {
reg_t f31; /**< The f31 register. */
reg_t ft11; /**< The 12th temporary floating-point register. */
}; /**< The anonymous union of alternative names for the f31/ft11 register. */
reg_t fcsr; /**< Floating-Point Control Register. */
reg_t vstart; /**< Vector Start Index CSR. */
reg_t vcsr; /**< Vector Control and Status Register. */
/** The Vector registers. */
dr_simd_t simd[MCXT_NUM_SIMD_SLOTS];
#else /* RISCV64 */
#error Unsupported architecture
#endif