我正在尝试阅读一本使用 Visual C++ 和 Visual Studio 中的示例编写的关于 X86 的书。我正在尝试将示例转换为与 gcc 一起使用。在遇到一些问题之后,我终于得到了至少可以编译的代码,但现在我遇到了段错误。这是代码:
程序集.s:
.intel_syntax noprefix
.section .text
.globl CalcSum
.type CalcSum, @function
// extern "C" int CalcSum_(int a, int b, int c)
CalcSum:
// Initialize a stack frame pointer
pushq rbp
mov ebp,esp
// Load the argument values
mov eax,[ebp+8]
mov ecx,[ebp+12]
mov edx,[ebp+16]
// Calculate the sum
add eax, ecx
add eax, edx
// Restore the caller's stack frame pointer
popq rbp
ret
测试.c:
#include <stdio.h>
extern int CalcSum(int a, int b, int c);
int main() {
int sum = CalcSum(5,6,7);
printf(" result: %d\n",sum);
return 0;
}
我正在使用 gcc -o execute test.c assembly.s
进行编译。如果我将所有 32 位指令更改为 64 位(即 ebp
到 rbp
),它将运行但给出完全随机的输出。谁能指出我在这里做错了什么?谢谢!
最佳答案
正如评论中所暗示的,这是调用约定的问题。 32 位 C 函数遵循 CDECL calling convention
在 Windows 和 Linux 中。在 64 位 Linux 中,您必须使用 System V AMD64 ABI
. 64-bit calling convention of Windows
是不同的。可能有使用操作系统功能的细节。
32 位 C (GCC):
.intel_syntax noprefix
.section .text
.globl CalcSum
.type CalcSum, @function
// extern "C" int CalcSum_(int a, int b, int c)
CalcSum: // with underscore in Windows: _CalcSum
// Initialize a stack frame pointer
push ebp
mov ebp,esp
// Load the argument values
mov eax,[ebp+8]
mov ecx,[ebp+12]
mov edx,[ebp+16]
// Calculate the sum
add eax, ecx
add eax, edx
// Restore the caller's stack frame pointer
pop ebp
ret
64 位 Linux (GCC):
.intel_syntax noprefix
.section .text
.globl CalcSum
.type CalcSum, @function
// extern "C" int CalcSum_(int a, int b, int c)
CalcSum:
// Load the argument values
mov rax, rdi
add rax, rsi
add rax, rdx
ret
64 位 Windows (MingW-GCC):
.intel_syntax noprefix
.section .text
.globl CalcSum
// .type CalcSum, @function
// extern "C" int CalcSum_(int a, int b, int c)
CalcSum:
// Load the argument values
mov rax, rcx
add rax, rdx
add rax, r8
ret
关于c - X86 汇编问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44348838/