Как установить / снять флажок TF на процессоре Intel x86 IA32 в пользовательском режиме
Я хотел бы знать шаги для установки / очистки EFLAGS.TF в пользовательском режиме на x86 IA32 Intel CPU
попробовал ниже для очистки флага TF, но получаю ошибку ***** Unhandled interrupt vector *****
__asm__ volatile("pushl %eax\n\t"
"pushfl\n\t"
"popl %eax\n\t"
"xorl $0x0100, %eax\n\t"
"pushl %eax\n\t"
"popfl\n\t"
"popl %eax\n\t");
2 ответа
XOR слегка переворачивается вместо того, чтобы всегда очищать его. И это одна опция, BTR (бит-тест-сброс) это другая. BTR с назначением памяти действительно медленный с источником регистра, но это совсем не плохо с немедленным (только 2 мопа на Haswell, 3 на Skylake. Однако до 4 на AMD, где он стоит 2 мопа даже для btr $9, %eax
.)
popf
довольно медленный (9 моп, 1 на 20 циклов на Скайлэйке). Или на Ryzen, 35 мопов и один на 13 циклов. ( http://agner.org/optimize). Поэтому оптимизация окружающего кода не будет иметь большого значения, но интересно найти способ сохранить компактность размера кода.
Вам не нужно сохранять / восстанавливать EAX самостоятельно, просто скажите компилятору, что вы хотите его затереть : "eax"
в качестве списка clobber, или используйте фиктивный операнд вывода (обратите внимание, что я использую расширенный asm GNU C, а не basic).
static inline
void clear_tf(void) {
long dummy; // there's no type that's always 32-bit on 32-bit, and always 64 on 64-bit. x32 uses 32-bit pointers in long mode so uintptr_t or size_t doesn't work.
// if porting to x86-64 System V user-space: beware that push clobbers the red-zone
__asm__ volatile("pushf \n\t"
"pop %[tmp] \n\t"
"btr $9, %[tmp]\n\t" // reset bit 9
"push %[tmp] \n\t"
"popf"
: [tmp] "=r"(dummy)
: // no inputs
: // no clobbers. // "memory" // would block reordering with loads/stores.
);
}
Или просто не трогайте никакие регистры: это тоже очень эффективно, особенно на AMD Ryzen, где нет стеков с синхронизацией стека, а в качестве места назначения памяти AND используется однократная операция.
static inline
void clear_tf(void) {
// if porting to x86-64 System V user-space: beware that push clobbers the red-zone
__asm__ volatile("pushf \n\t"
"andl $0xFFFFFEFF, (%esp) \n\t" // 1 byte larger than the pop/btr/push version
"popf"
);
// Basic asm syntax: no clobbers.
}
Для меньшего размера кода, btrl $9, (%esp)
наверное хорошо. Все еще только 2 мопа на Haswell (3 на Skylake), но на 2 байта меньше, чем andl
, andb $0xfe, 1(%esp)
также имеет тот же размер, но вызывает остановку пересылки магазина и составляет 2 мопа + макс стека синхронизации при использовании после push
, pop %%eax; and $0xfe, %ah; push %eax
также имеет такой же размер, а также 3 мопа (плюс моп с частичным регистром, который выдает в цикле сам по себе на Haswell / SKL). Но это приятно на AMD.
портативность
Кстати, в коде пространства пользователя x86-64 System V вы не можете безопасно нажимать / выталкивать, не заглушая красную зону компилятора, так что вы, вероятно, захотите add $-128, %rsp
до push
и восстановить его после.
В коде ядра нет красной зоны, так что push/pop внутри встроенного asm отлично.
Windows использует другой ABI без красной зоны.
С кодом ниже он работал нормально. Спасибо
__asm__ volatile("pushl %eax;\
pushfl;\
popl %eax;\
andl $0xFFFFFEFF, %eax;\
pushl %eax;\
popfl;\
popl %eax;"
);