c - x64 参数和返回值调用约定

标签 c assembly x86-64 calling-convention

我使用 -Os -march=haswell 调用 Clang 12.0.0 来编译以下 C 程序:

int bar(int);

int foo(int x) {
  const int b = bar(x);
  if (x || b) {
      return 123;
  }
  return 456;
}
生成以下程序集:
foo:                                    # @foo
        push    rbx
        mov     ebx, edi
        call    bar
        or      eax, ebx
        mov     ecx, 456
        mov     eax, 123
        cmove   eax, ecx
        pop     rbx
        ret
https://gcc.godbolt.org/z/WsGoM56Ez
据我了解,foo 的调用者在 RAX/EAX 中设置了 x。 foo 然后调用 bar,这不需要修改 RAX/EAX,因为 x 作为未修改的输入传递。or eax, ebx 指令似乎将输入 x 与 bar 的结果进行比较。这个结果如何在 EBX 中结束? mov ebx,edi 有什么用途?

最佳答案

恐怕你误会了:

  • 函数参数在 rdi 中传递,根据 x86-64 System V calling convention
  • 注册 rbx must not be modified by a function ; GCC 根据需要保存/恢复它,因此它可以在调用 x 的过程中保留 bar 的副本。
  • 函数返回值在 rax 中。 (实际上是eax;一个32位的int只使用了低半部分)

  • 您可以通过编译 int foo(int x){return x;} 之类的函数来验证基础知识 - 您只会看到 mov eax, edi
    这是一个评论版本:
    foo:                                    # @foo
            push    rbx           # save register rbx
            mov     ebx, edi      # save argument `x` in ebx
            call    bar           # a = bar()  (in eax)
            or      eax, ebx      # compute `x | a`, setting FLAGS
            mov     ecx, 456      # prepare 456 for conditional move
            mov     eax, 123      # eax = 123
            cmove   eax, ecx      # if `(x | a) == 0` set eax to 456
            pop     rbx           # restore register rbx
            ret                   # return value is in eax
    
    编译器将 x || b 优化为 (x | b) != 0,允许无分支代码生成。
    请注意,与大多数整数 ALU 指令不同, mov 不会修改 FLAGS。

    关于c - x64 参数和返回值调用约定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67477988/

    相关文章:

    Linux可执行文件.data节的默认行为在5.4和5.9之间更改?

    linux - 从 x86 中的特定位置读取文件

    assembly - 为什么我在 GDB 上出现断点问题? GDB 停止

    c - 数组充满了文件中的最后一个元素

    c - 在C中将数据以字节为单位从一个数组传输到另一个数组

    c - 对 c 内置函数 'pow' 的 undefined reference

    assembly - 指向不带 .data 部分的独立二进制代码中的字符串的指针

    c - 内联汇编 --> 错误 : internal_relocation (type: OFFSET_IMM) not fixed up

    assembly - 为什么由D编译的main()在64位计算机上具有32位返回值?

    assembly - PowerPC 上有屏蔽混合指令吗?