linux 读取信号处理程序中的SSE寄存器(XMM、YMM)

gcuhipw9  于 2023-08-03  发布在  Linux
关注(0)|答案(1)|浏览(186)

我有一个x86_64指令"vgatherqpd %ymm7,(%r9,%ymm1,8),%ymm3",我需要在Linux的信号处理程序中构建运行时的内存地址。信号处理程序ucontext uc_mcontext.gregs[XED_REG_R9]给出了%r9中包含的值。
但是,如何获得%ymm1中包含的值?Linux似乎有一个sys/ucontext.h文件,其中有struct _libc_fpxreg_libc_xmmreg字段,但我不确定如何理解它们。此外,没有reg_ymm。
感谢帮助解决这个问题。

zpqajqem

zpqajqem1#

在信号处理程序中获取avx寄存器

内核通过信号处理程序的第三个参数使所有寄存器对用户空间可用。然而,它并不像阅读结构字段那样清晰,主要是因为struct _libc_fpxreg是一个转移注意力的信息。
由于我们对YMM寄存器感兴趣,这意味着我们运行的cpu将具有xsave,这是内核将用来存储FPU上下文的。下面我将集中讨论这一点,请记住,如果你想在旧的cpu上尝试这一点,你必须修改代码一点。

xsave

xsave由多个块组成,每个块对应于它所处理的特定cpu功能,具体取决于cpu。第一个块包含良好的旧x87 FPU堆栈和XMM寄存器,长度为512个字节。在块的末尾有一个保留空间,内核用它来跟踪缓冲区的大小和有效性,您也可以用它来验证它。请参阅struct _fpx_sw_bytes
下一个块是一个头,后面是扩展,首先是ymm扩展,它存储ymm寄存器的高半部分(低半部分存储在第一块的xmm部分,就像它们共享处理器上的空间一样。
您可以在我之前链接的结构下面的结构中看到详细信息,但是架构编程手册(至少来自AMD)中没有确切描述。因此,我认为最好不要去管它的结构,而是使用cpu指令xrstor来读取它--毕竟它最清楚里面有什么。

缓冲区位于何处

因为cpu要求xsave缓冲区是64字节对齐的,所以它最好不要是ucontext_t这样的另一个结构的一部分。内核使用一些动态填充在堆栈上为它分配对齐的存储空间,并将指向它的指针存储到ucontext_t结构(即uc_mcontext.fpregs)。有关填充指针的分配和其他函数,请参见get_sigframe()
但这还不是全部。如果您在64位模式下,此指针实际上就是您所需要的全部。在32位模式下,此指针指向传统的x87 fsave缓冲区(与struct _libc_fpxreg相同),xsave缓冲区紧随其后。因此,必须将其大小添加到值中。
代码
最后,从被中断的代码中获取ymm0如下所示:

#ifdef i386
#define XSAVE_POINTER(p) ((char*)(p)+sizeof(struct _libc_fpstate))
#else
#define XSAVE_POINTER(p) (p)
#endif

typedef int __v8si __attribute__ ((vector_size (32)));
void sighandler(int sig, siginfo_t* info, void* v_context)
{
    ucontext_t* context = v_context;
    /* this will be our memory to put the values to */
    char values[32] __attribute__((aligned(32)));

    /* get ymm registers from the context */
    __builtin_ia32_xrstor(XSAVE_POINTER(context->uc_mcontext.fpregs), 7);

    /* move ymm0 to memory so we can print it out */
    __asm__("vmovdqa %%ymm0, %0"
            : "=m"(values));

字符串

相关问题