乘法寄存器时汇编中的分段错误?

Segmentation fault in assembly when multiplying registers?

我试图将以下 C 代码转换为汇编代码。这是 C 代码:

typedef struct {
    int x;
    int y;
} point;


int square_distance( point * p ) {
    return p->x * p->x + p->y * p->y;  
}

我的汇编代码如下:

square_distance:

.LFB23:
    .cfi_startproc
    movl    (%edi), %edx
    imull   %edx, %edx
    movl    4(%edi), %eax
    imull   %eax, %eax
    addl    %edx, %eax
    ret
    .cfi_endproc

当我尝试 运行 这个程序时出现分段错误。有人可以解释为什么吗?谢谢!我将不胜感激!

您的代码是 32 位代码 (x86),但您应用了与 64 位代码 (x64) 一起使用的调用约定。这显然行不通。

x86 调用约定在堆栈上传递所有参数。

x64 调用约定在 rdi 中传递第一个参数,在 rsi 中传递第二个参数,在 rdx 中传递第三个参数,等等(我不确定哪些寄存器是如果参数超过 3 个则使用,这也可能取决于您的平台)。

你的代码大概对 x64 代码是正确的,就像这样:

square_distance:
    movl    (%rdi), %edx
    imull   %edx, %edx
    movl    4(%rdi), %eax
    imull   %eax, %eax
    addl    %edx, %eax
    ret

对于 x86 代码,参数在堆栈上传递,相应的正确代码如下所示:

square_distance:
    movl    4(%esp), edx
    movl    (%edx), eax
    imull   eax, eax
    movl    4(%edx), edx
    imull   edx, edx
    addl    edx, eax
    ret

总的来说,调用约定 主题非常广泛,根据平台还有其他调用约定,甚至在同一平台内,在某些情况下也可能存在不同的调用约定。

只是想补充一下。因为我的声望不够评论。

调用函数时传递参数的方式(也称为调用约定)与体系结构和操作系统不同(OS)。你可以从这个wiki

中找出许多常见的调用约定

从wiki上我们知道*nix上的x64调用约定是前六个参数通过RDI、RSI、RDX、RCX、R8、R9寄存器传递,其他的通过栈传递。