Reputation: 60056
In C I have:
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;
}
With clang -O1 to -O3 on x86-64 it very reliably generates:
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
I'd like to take the
mov (%rdi),%al
mov -0x1(%rsp),%al
part and the
movb $0x0,(%rdi)
mov -0x1(%rsp),%al
part and turn them into reusable, inlinable assembly snippets.
My very unsuccessful attempt is shown in the elided #if block above. Can you please explain why it's wrong and it's possible to make this work with inline assembly?
(I'm using this to detect segfaults cheaply (if there wouldn't be a segfault). If I know the length of the possibly segfaulting instruction, I can skip right past it in my SIGSEGV handler without having to have made a relatively expensive sigsetjmp, but gcc isn't generating such reliable code so I'd like to force it to.)
Upvotes: 1
Views: 82
Reputation: 58762
The second line is just loading the faulted
from the stack, you don't need that in asm and it won't ever fault (assuming the previous initialization didn't fault). You can use
"mov (%1), %0" : "=a" (c) : "D" (Ptr)
and
"movb $0, (%1)" : "=m" (*Ptr): "D" (Ptr)
where a
is the appropriately sized sub-register of rax
, which is al
for 8 bits. D
is the rdi
register. =
means output. m
is a generic memory operand used to tell the compiler the asm is writing into memory at *Ptr
. Could be omitted here since your Ptr
is volatile
so the compiler will not cache the value, but it doesn't hurt.
Upvotes: 2