C ++ предотвращает обнуление регистров с плавающей запятой в обработчике ошибок страницы - PullRequest
0 голосов
/ 25 апреля 2019

Я пишу программу, которая требует, чтобы регистры с плавающей запятой ([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.

1 Ответ

1 голос
/ 25 апреля 2019

Регистры FP (и все состояние процессора pre-AVX) доступны через третий параметр для handle в структуре ucontext_t.См. Документацию для функций sigaction (2) и sigreturn (2) .Однако регистры YMM явно не включены в это.

Состояние fps, сохраненное в ucontext_t, происходит из инструкции CPU FXSAVE.Это включает в себя регистры XMM (которые также являются нижней половиной регистров YMM).Полное состояние ЦП сохраняется с помощью инструкции XSAVE или одного из ее вариантов.Если включены соответствующие наборы функций ЦП, расширенное состояние, сохраненное XSAVE, будет включать верхнюю половину регистров YMM в дополнительные данные.

Старшая половина регистров YMM будет сохраняться со смещением, заданныминструкция CPUID (EAX = 0Dh, ECX = 2) в регистре EBX (в настоящее время это 576).Длина данных YMM указана в регистре EAX после этого CPUID (в настоящее время это 128).

Чтобы определить значения отдельных регистров YMM, вам необходимо склеить две половины вместе.

Существует PDF версия слайд-колоды, которая дает обзор всего этого процесса.

...