简体   繁体   中英

Rewriting generated assembly into GCC inline assembly

In CI 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.)

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM