use*_*501 0 c linux gcc x86-64 calling-convention
我编写了一个最小函数来测试是否可以调用/链接 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;
}
Run Code Online (Sandbox Code Playgroud)
这是我的test.asm
section .text
global test
test:
mov ebx,2
add eax,ebx
ret
Run Code Online (Sandbox Code Playgroud)
我使用这个脚本构建了一个可执行文件
#!/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
Run Code Online (Sandbox Code Playgroud)
我写的时候test.asm并没有任何真正的线索我在做什么。然后我离开并做了一些阅读,现在我不明白我的代码是如何工作的,因为我说服自己它不应该这样。
以下是我认为这不起作用的原因列表:
eaxand传递的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
Run Code Online (Sandbox Code Playgroud)
我不保存或恢复基指针(设置堆栈帧)。我实际上不明白为什么需要这样做,但我看过的每个例子都是这样做的。
那是不需要的。尝试编译一些 C 代码-O3,然后您会发现它不会发生。
Linux 系统上 gcc 编译器的调用约定应该是通过堆栈传递参数。这里我假设参数是使用 eax 和 ebx 传递的。我认为这是不对的。
这部分工作只是因为侥幸。程序集恰好也按照您编译的方式10放入eax,但不能保证这种情况总是会发生。再次编译,-O3就不会了。
ret 可能希望从某个地方获取返回地址。我相当确定我没有提供这个。
这部分很好。返回地址由调用者提供。当你的函数被输入时,它总是位于堆栈的顶部。
甚至可能还有其他我不知道的原因。
是的,还有一个:ebx呼叫已保存,但你正在破坏它。如果调用函数(或堆栈中其上方的任何内容)使用了它,那么这会破坏它。
我所编写的内容产生正确的输出完全是侥幸吗?
是的,因为上面的第二点和第四点。
gcc作为参考,以下是在-O0(默认优化级别)下从 C 代码生成的程序集与-O3: https: //godbolt.org/z/7P13fbb1a
| 归档时间: |
|
| 查看次数: |
1196 次 |
| 最近记录: |