【问题标题】:Rewriting generated assembly into GCC inline assembly将生成的程序集重写为 GCC 内联程序集
【发布时间】: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


【解决方案1】:

第二行只是从堆栈中加载faulted,在 asm 中不需要它,它永远不会出错(假设之前的初始化没有出错)。你可以使用

"mov (%1), %0" : "=a" (c) : "D" (Ptr)

"movb $0, (%1)" : "=m" (*Ptr): "D" (Ptr)

其中arax 的适当大小的子寄存器,即al 8 位。 Drdi 寄存器。 = 表示输出。 m 是一个通用内存操作数,用于告诉编译器 asm 正在写入内存 *Ptr。此处可以省略,因为您的 Ptrvolatile,因此编译器不会缓存该值,但不会造成伤害。

【讨论】:

    猜你喜欢
    • 2017-04-29
    • 2010-11-20
    • 2011-02-26
    • 2013-07-05
    • 2019-01-28
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多