C ++防止浮点寄存器在页面错误处理程序中被清零
C++ prevent floating point registers from being zeroed in page fault handler
我正在编写一个程序,要求浮点寄存器 ([xy]mm0-15) 在页面错误后不被覆盖。我编写了以下生成页面错误然后捕获它的示例代码:
#include <signal.h>
#include <iostream>
using namespace std;
void handle(int, siginfo_t*, void* vcontext);
// Page fault handler. When this is called the fp registers are all zeroed
void handle(int, siginfo_t*, void* vcontext) {
cout << "Get fp reg here";
exit(0);
}
main (int argc, char *argv[]) {
// Setup sigaction handler for page fault
struct sigaction act;
act.sa_sigaction = handle;
sigaction(SIGSEGV, &act, 0);
// Generate page fault
int i = 10;
int* iPtr = &i;
iPtr += 10000;
cout << *iPtr; // This line will generate a page fault, then sigaction will redirect the program to `handle`.
}
然后我将程序放入 GDB 中,一次单步执行一条指令。我发现在 cout << *iPtr;
和 cout << "Get fp reg here";
之间(在 handle()
中)所有 fp 寄存器值都设置为零。我需要的是保留寄存器值,以便我可以在 handle()
中使用它们
附带说明一下,我使用的是 Red Hat。
FP 寄存器(以及整个 AVX 之前的 CPU 状态)可通过 ucontext_t
结构中 handle
的第三个参数获得。请参阅 sigaction(2) and sigreturn(2) 函数的文档。但是,YMM 寄存器并未明确包含在其中。
ucontext_t
中存储的fpstate来自CPU的FXSAVE
指令。这包括 XMM 寄存器(也是 YMM 寄存器的下半部分)。完整的 CPU 状态使用 XSAVE
指令或其变体之一保存。当启用适当的 CPU 功能集时,XSAVE
保存的扩展状态将在额外数据中包含 YMM 寄存器的上半部分。
YMM 寄存器的高半部分将存储在 EBX 寄存器中由 CPUID 指令(EAX = 0Dh,ECX = 2)给出的偏移量(当前为 576)。 YMM数据的长度在EAX寄存器中CPUID之后(目前是128)。
要确定各个 YMM 寄存器值,您需要将两半粘合在一起。
有一个 PDF 版本的幻灯片可以概述整个过程。
我正在编写一个程序,要求浮点寄存器 ([xy]mm0-15) 在页面错误后不被覆盖。我编写了以下生成页面错误然后捕获它的示例代码:
#include <signal.h>
#include <iostream>
using namespace std;
void handle(int, siginfo_t*, void* vcontext);
// Page fault handler. When this is called the fp registers are all zeroed
void handle(int, siginfo_t*, void* vcontext) {
cout << "Get fp reg here";
exit(0);
}
main (int argc, char *argv[]) {
// Setup sigaction handler for page fault
struct sigaction act;
act.sa_sigaction = handle;
sigaction(SIGSEGV, &act, 0);
// Generate page fault
int i = 10;
int* iPtr = &i;
iPtr += 10000;
cout << *iPtr; // This line will generate a page fault, then sigaction will redirect the program to `handle`.
}
然后我将程序放入 GDB 中,一次单步执行一条指令。我发现在 cout << *iPtr;
和 cout << "Get fp reg here";
之间(在 handle()
中)所有 fp 寄存器值都设置为零。我需要的是保留寄存器值,以便我可以在 handle()
附带说明一下,我使用的是 Red Hat。
FP 寄存器(以及整个 AVX 之前的 CPU 状态)可通过 ucontext_t
结构中 handle
的第三个参数获得。请参阅 sigaction(2) and sigreturn(2) 函数的文档。但是,YMM 寄存器并未明确包含在其中。
ucontext_t
中存储的fpstate来自CPU的FXSAVE
指令。这包括 XMM 寄存器(也是 YMM 寄存器的下半部分)。完整的 CPU 状态使用 XSAVE
指令或其变体之一保存。当启用适当的 CPU 功能集时,XSAVE
保存的扩展状态将在额外数据中包含 YMM 寄存器的上半部分。
YMM 寄存器的高半部分将存储在 EBX 寄存器中由 CPUID 指令(EAX = 0Dh,ECX = 2)给出的偏移量(当前为 576)。 YMM数据的长度在EAX寄存器中CPUID之后(目前是128)。
要确定各个 YMM 寄存器值,您需要将两半粘合在一起。
有一个 PDF 版本的幻灯片可以概述整个过程。