将生成的程序集重写为GCC内联程序集
在C中,我有:将生成的程序集重写为GCC内联程序集,c,gcc,assembly,clang,x86-64,C,Gcc,Assembly,Clang,X86 64,在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
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上的-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
部分及
movb $0x0,(%rdi)
mov -0x1(%rsp),%al
并将它们转换为可重用的、可内联的程序集片段
我非常不成功的尝试显示在上面的省略的#if块中。
您能解释一下为什么它是错误的,并且可以通过内联汇编实现这一点吗
(我用它来廉价地检测segfault(如果没有segfault的话)。如果我知道可能的segfaulting指令的长度,我可以在我的SIGSEGV处理程序中跳过它,而不必制作相对昂贵的sigsetjmp,但gcc不会生成如此可靠的代码,所以我想强制它。)第二行只是从堆栈中加载出现故障的
,asm中不需要它,它也不会出现故障(假设之前的初始化没有故障)。你可以用
"mov (%1), %0" : "=a" (c) : "D" (Ptr)
及
其中,
a
是rax
的适当大小的子寄存器,它是8位的al
D
是rdi
寄存器<代码>=表示输出m
是一个通用内存操作数,用于告诉编译器asm正在*Ptr
处写入内存。这里可以省略,因为您的Ptr
是易失性的
,因此编译器不会缓存该值,但不会造成伤害。在不知道长度的情况下,如何跳过错误指令?我想知道你在这里干什么。但考虑到我已经习惯英特尔汇编(-masm=Intel),我很难做到这一点。另外,您是否考虑过简单地在汇编中编写整个函数?@Micrified您不能。这就是我试图生成已知指令的原因。(实际上,您可以通过在sigsegv处理程序中反汇编当前指令来完成此操作-这是我以前做过的:)@Micrified这绝对是一个充分且易于实现的解决方案,但我想我会尝试并找出如何使用内联汇编来完成此操作。“现在读更多关于它的内容。”Michrified有趣的方法。
"mov (%1), %0" : "=a" (c) : "D" (Ptr)
"movb $0, (%1)" : "=m" (*Ptr): "D" (Ptr)