【发布时间】:2019-02-06 14:36:33
【问题描述】:
在 C 中我有:
struct segv_ctrl {
_Bool volatile*volatile rfaulted_eh_ptr;
_Bool volatile*volatile wfaulted_eh_ptr;
};
_Thread_local struct segv_ctrl segv_ctrl;
_Bool rfaulted_eh(char volatile*Ptr)
{
_Bool volatile faulted=0;
char c; _Bool r;
segv_ctrl.rfaulted_eh_ptr = &faulted;
#if 1
c=*Ptr;
r = faulted;
#else
//I'd like this to produce the same code as the #if block above
//but I obviously have no idea what I'm doing :D
__asm__ __volatile__ (
"mov (%2),%0;\n"
"mov %3,%1;\n"
: "=r"(c), "=r"(r)
: "r" (Ptr), "r"(faulted)
);
#endif
return r;
}
_Bool wfaulted_eh(char volatile*Ptr)
{
_Bool volatile faulted=0;
_Bool r;
segv_ctrl.wfaulted_eh_ptr = &faulted;
#if 1
*Ptr=0;
r = faulted;
#else
#endif
return r;
}
在 x86-64 上使用 clang -O1 到 -O3 它非常可靠地生成:
c.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <rfaulted_eh>:
0: c6 44 24 ff 00 movb $0x0,-0x1(%rsp)
5: 48 8d 44 24 ff lea -0x1(%rsp),%rax
a: 64 48 89 04 25 00 00 mov %rax,%fs:0x0
11: 00 00
13: 8a 07 mov (%rdi),%al
15: 8a 44 24 ff mov -0x1(%rsp),%al
19: c3 retq
1a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000000020 <wfaulted_eh>:
20: c6 44 24 ff 00 movb $0x0,-0x1(%rsp)
25: 48 8d 44 24 ff lea -0x1(%rsp),%rax
2a: 64 48 89 04 25 00 00 mov %rax,%fs:0x0
31: 00 00
33: c6 07 00 movb $0x0,(%rdi)
36: 8a 44 24 ff mov -0x1(%rsp),%al
3a: c3 retq
我想参加
mov (%rdi),%al
mov -0x1(%rsp),%al
部分和
movb $0x0,(%rdi)
mov -0x1(%rsp),%al
part 并将它们变成可重用、可内联的程序集 sn-ps。
我非常不成功的尝试显示在上面省略的#if 块中。 您能否解释一下为什么它是错误的,并且可以通过内联汇编来实现这一点?
(我用它来廉价地检测段错误(如果没有段错误的话)。如果我知道可能的段错误指令的长度,我可以在我的 SIGSEGV 处理程序中跳过它而不必做一个相对昂贵的 sigsetjmp,但 gcc 不能生成如此可靠的代码,所以我想强制它。)
【问题讨论】:
-
如何在不知道长度的情况下跳过错误指令? FWIW 我试图弄清楚你在这里做什么。但是我很难说我已经习惯了英特尔组装(-masm=intel)。另外,您是否考虑过在汇编中简单地编写整个函数?
-
@Micrified 你不能。这就是我尝试生成已知指令的原因。
-
(实际上你可以通过反汇编 sigsegv 处理程序中的当前指令来做到这一点——我以前做过的事情:))。
-
@Micrified 这绝对是一个足够且易于实施的解决方案,但我会尝试弄清楚如何使用内联汇编来做到这一点。现在阅读更多内容。
-
@Micrified 有趣的方法。
标签: c gcc assembly clang x86-64