x86_64 Linux 系统的 GCC 调用约定

问题描述 投票:0回答:2

我编写了一个最小函数来测试是否可以调用/链接 C 和 x86_64 汇编代码。

这是我的

main.c

#include <stdio.h>

extern int test(int);

int main(int argc, char* argv[])
{

    int a = 10;
    
    int b = test(a);

    printf("b=%d\n", b);

    return 0;
}

这是我的

test.asm

section .text
    global test

test:
    mov ebx,2
    add eax,ebx
    ret

我使用此脚本构建了一个可执行文件

#!/usr/bin/env bash

nasm -f elf64 test.asm -o test.o

gcc -c main.c -o main.o

gcc main.o test.o -o a.out

我写了

test.asm
,但没有任何真正的线索我在做什么。然后我离开并做了一些阅读,现在我不明白我的代码似乎是如何工作的,因为我说服自己它不应该这样。

以下列出了我认为这不起作用的原因:

  • 我不保存或恢复基指针(设置堆栈帧)。我实际上不明白为什么需要这样做,但我看过的每个例子都是这样做的。
  • Linux系统上gcc编译器的调用约定应该是通过堆栈传递参数。这里我假设参数是使用
    eax
    ebx
    传递的。我认为这是不对的。
  • ret
    可能希望从某个地方获取回邮地址。我相当确定我没有提供这个。
  • 甚至可能还有其他我不知道的原因。

我所编写的内容产生正确的输出完全是侥幸吗?

我对此完全陌生。虽然我顺便听说过一些 x86 概念,但这是我第一次真正尝试编写一些概念。必须从某个地方开始吗?

编辑:供将来参考,这里是更正的代码

test:
                    ; save old base pointer
    push rbp        ; sub rsp, 8; mov [rsp] rbp
    mov rbp, rsp    ; mov rbp, rsp ;; rbp = rsp
                    ; initializes new stack frame

    add rdi, 2      ; add 2 to the first argument passed to this function
    mov rax, rdi    ; return value passed via rax

                    ; did not allocate any local variables, nothing to add to
                    ; stack pointer
                    ; the stack pointer is unchanged

    pop rbp         ; restore old base pointer

    ret             ; pop the return address off the stack and jump
                    ; call and ret modify or save the rip instruction pointer
c linux gcc x86-64 calling-convention
2个回答
5
投票

我不保存或恢复基指针(设置堆栈帧)。我实际上不明白为什么需要这样做,但我看过的每个例子都是这样做的。

那是不需要的。尝试用

-O3
编译一些 C 代码,你会发现它不会发生。

Linux系统上gcc编译器的调用约定应该是通过堆栈传递参数。这里我假设参数是使用 eax 和 ebx 传递的。我认为这是不对的。

那部分之所以起作用只是因为侥幸。程序集碰巧也按照您编译的方式将

10
放入
eax
中,但不能保证这种情况总会发生。再次用
-O3
编译就不会了。

ret 可能希望从某个地方获取返回地址。我相当确定我没有提供这个。

这部分很好。返回地址由调用者提供。当你的函数被输入时,它总是位于堆栈的顶部。

甚至可能还有其他我不知道的原因。

是的,还有一个:

ebx
已通话保存,但你正在破坏它。如果调用函数(或堆栈中其上方的任何内容)使用了它,那么这会破坏它。

我所编写的内容产生正确的输出完全是侥幸吗?

是的,因为上面的第二点和第四点。

作为参考,以下是

gcc
-O0
(默认优化级别)和
-O3
下从 C 代码生成的程序集的比较: https://godbolt.org/z/7P13fbb1a


0
投票

无符号长测试(无符号长c){返回++c; }

gcc-12 与 -O3:

0000000000400540 <teste>:
  400540:       48 8d 47 01             lea    rax,[rdi+0x1]
  400544:       c3                      ret

如果你没有任何自动变量,你就不需要搞乱 bp。 使用 -O3 如果函数从未被调用,则可以将其从代码中完全删除。

© www.soinside.com 2019 - 2024. All rights reserved.