c - 与 gcc 相比,为什么 clang 对寄存器变量的行为很奇怪?

标签 c assembly clang

背景:

我需要在c代码中获取寄存器值,所以我在gcc usage中找到了这个.我使用以下代码获取 ebp 值。

   register int ebp asm("ebp");
   printf("currently ebp is %08x\n", ebp);
   // then some code use the value

在我将程序的编译器更改为 clang 之前,一切似乎都还不错。在 gcc 中,它通常会打印类似于 0x7f1284978 的内容,绝对是一个类似于值的指针。

但是当使用 clang 时,输出变得奇怪,它打印出一个像 0x9 这样的值。 ebp 一定不能有这样的值。

问题:

  • clang 不支持这种寄存器变量的使用吗?
  • 为什么不支持这个特性(用下面的代码编译)却没有报警告或错误?

    #include <stdio.h>
    
    static size_t vfp = 0x233;
    
    int main(void) {
        register int ebp asm("ebp");
        vfp = (size_t) ebp;
        printf("vfp value is 0x%lx\n", vfp);
        return 0;
    }
    

最佳答案

长话短说:

Clang 目前不支持显式寄存器变量。

详细信息:

参见 clang documentation

clang only supports global register variables when the register specified is non-allocatable (e.g. the stack pointer). Support for general global register variables is unlikely to be implemented soon because it requires additional LLVM backend support.

在我的机器上(x86_64 ubuntu 16.04),如果我用 Clang-5.0 编译,我得到的程序集是:

 08048410 <main>:
 8048410:       55                      push   %ebp
 8048411:       89 e5                   mov    %esp,%ebp
 8048413:       83 ec 18                sub    $0x18,%esp
 8048416:       8d 05 c0 84 04 08       lea    0x80484c0,%eax
 804841c:       8b 4d fc                mov    -0x4(%ebp),%ecx ;this line is wrong, the behavior is meaningless
 804841f:       89 0d 1c a0 04 08       mov    %ecx,0x804a01c
 8048425:       8b 0d 1c a0 04 08       mov    0x804a01c,%ecx
 804842b:       89 04 24                mov    %eax,(%esp)
 804842e:       89 4c 24 04             mov    %ecx,0x4(%esp)
 8048432:       e8 89 fe ff ff          call   80482c0 <printf@plt>
 8048437:       89 45 f8                mov    %eax,-0x8(%ebp)
 804843a:       83 c4 18                add    $0x18,%esp
 804843d:       5d                      pop    %ebp
 804843e:       c3                      ret
 804843f:       90                      nop

如果我用 GCC-5.5.0 编译,这是我得到的程序集:

0000051d <main>:


 51d:   8d 4c 24 04             lea    0x4(%esp),%ecx
 521:   83 e4 f0                and    $0xfffffff0,%esp
 524:   ff 71 fc                pushl  -0x4(%ecx)
 527:   55                      push   %ebp
 528:   89 e5                   mov    %esp,%ebp
 52a:   53                      push   %ebx
 52b:   51                      push   %ecx
 52c:   e8 33 00 00 00          call   564 <__x86.get_pc_thunk.ax>
 531:   05 a7 1a 00 00          add    $0x1aa7,%eax
 536:   89 ea                   mov    %ebp,%edx ; this is the correct location to get the value of ebp
 538:   89 90 30 00 00 00       mov    %edx,0x30(%eax)
 53e:   8b 90 30 00 00 00       mov    0x30(%eax),%edx
 544:   83 ec 08                sub    $0x8,%esp
 547:   52                      push   %edx
 548:   8d 90 18 e6 ff ff       lea    -0x19e8(%eax),%edx
 54e:   52                      push   %edx
 54f:   89 c3                   mov    %eax,%ebx
 551:   e8 5a fe ff ff          call   3b0 <printf@plt>
 556:   83 c4 10                add    $0x10,%esp
 559:   90                      nop
 55a:   8d 65 f8                lea    -0x8(%ebp),%esp
 55d:   59                      pop    %ecx
 55e:   5b                      pop    %ebx
 55f:   5d                      pop    %ebp
 560:   8d 61 fc                lea    -0x4(%ecx),%esp
 563:   c3                      ret

我们可以看到,GCC 一般支持显式寄存器值访问,而 Clang 不支持。

解决方案:

如果你想使用 Clang 来访问 ebp 值,你可以使用内联汇编,像这样:asm("\t movl %%ebp,%0": "=r"(vfp));

关于c - 与 gcc 相比,为什么 clang 对寄存器变量的行为很奇怪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55648274/

相关文章:

c - MPI 总运行时间

sorting - 重叠寄存器错误

linux - 了解 ASM 中的输入和输出

c - 在没有双重评估的情况下在 Clang 中实现 min() 和 max()

c - 为什么使用返回值时将0移入堆栈?

c - 多个值的 OpenMP argmin 缩减

c - 套接字发送()和接收()不工作

c++ - 如何使用 ODBC 处理长字符串?

assembly - 在汇编中跳转后返回调用

c++ - 如何在C中自定义编译指示?