-
-
Save bczhc/fcd9eb01a29f1bfbd228708f19eeeead to your computer and use it in GitHub Desktop.
从除零错误中断中恢复
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define _GNU_SOURCE | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <signal.h> | |
| #include <ucontext.h> | |
| void handle_fpe(int sig, siginfo_t *info, void *ucontext) { | |
| printf("Caught SIGFPE! Attempting to skip the broken instruction...\n"); | |
| // 强制转换为 ucontext_t 结构体指针 | |
| ucontext_t *context = (ucontext_t *) ucontext; | |
| // REG_RIP 是 x86_64 的指令指针寄存器 | |
| // 注意:2 字节只是一个猜测,具体取决于编译器生成的指令 | |
| // 如果你的编译器生成的是 3 字节指令,这里需要 +3 | |
| context->uc_mcontext.gregs[REG_RAX] = 666; | |
| context->uc_mcontext.gregs[REG_RIP] += 2; | |
| } | |
| int main(int argc, char **argv) { | |
| struct sigaction sa; | |
| sa.sa_sigaction = handle_fpe; | |
| sa.sa_flags = SA_SIGINFO; // 必须开启这个标志才能拿到 ucontext | |
| sigemptyset(&sa.sa_mask); | |
| sigaction(SIGFPE, &sa, NULL); | |
| int d = 0; | |
| printf("Before division...\n"); | |
| // 这里故意制造除零 | |
| // 使用 asm 锁定指令长度,确保 idivl 占用 2 字节 (f7 f1) | |
| int r; | |
| int a = 10; | |
| asm volatile( | |
| "movl %1, %%eax\n\t" | |
| "cltd\n\t" | |
| "idivl %2\n\t" | |
| "movl %%eax, %0" | |
| : "=r"(r) | |
| : "r"(a), "r"(d) | |
| : "%eax", "%edx" | |
| ); | |
| printf("After division! We survived.\n"); | |
| printf("r = %d\n", r); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment