从程序集调用 c 函数的段错误

Segfault calling c function from assembly

我正在尝试在汇编程序中设置一些指针(AT&T 语法 运行 on x86_64 linux),然后将它们传递给 C 程序以基本上添加它们的值.当然,这不是实现最终结果的最有效方法,但我正在尝试了解如何实现这样的工作,以便进一步构建它。 C 程序如下所示:

#include <stdio.h>

extern void iplus(long *a, long *b, long *c){
  printf("Starting\n");
  long r= *a + *b;
  printf("R setup\n");
  *c=r;
  printf("Done\n");
}

这需要三个长指针,将前两个的值相加,然后将该值存储在第三个中。如上所示,它会在每个点打印一条有关其状态的消息,以跟踪发生分段错误的位置。

引用该函数的汇编程序如下:

.extern exit
.extern malloc
.data
vars: .zero 24 /*stores pointer addresses*/
.text
FORI: .ascii "%d[=11=]" /*format for printing integer*/
.global main
main:
and $~0xf, %rsp /*16-byte align the stack*/
movq ,%rdi
call malloc
movq %rax,(vars+0) /*allocate 8 bytes and put its address into the variable*/
movq ,%rdi
call malloc
movq %rax,(vars+8)
movq ,%rdi
call malloc
movq %rax,(vars+16)
movq ,((vars+0)) /*first addend 3*/
movq ,((vars+8)) /*second addend 7*/
movq [=11=],((vars+16))
movq (vars),%rdi
movq (vars+8),%rsi
movq (vars+16),%rdx
call iplus /*call the function with these values*/
movq $FORI,%rdi
movq ((vars+16)),%rsi
call printf /*print the sum, "10" expected*/
call exit

在执行上面的程序后,我得到了这个输出:

Starting
Segmentation fault (core dumped)

意味着该函数似乎已成功调用,但该函数中的第一个操作 long r = *a + *b; 或更早的仅在此时成为问题的某些内容导致了段错误。我期望发生的是,对于 24 字节 vars 持有的三个 8 字节值,malloc 返回的地址(每次分配 8 个字节)被存储。然后这个地址指向一个 8 字节的整数,分别设置为 3、7 和 0。这些整数的地址(即 vars 中保存的值)按顺序传递给 iplus对它们求和,然后使用 printf 打印总和。由于我无法确定的原因,这会导致段错误。

为什么会出现段错误?是否可以使用基本上仍在使用双指针结构的 C 函数调用来执行此加法?

您不能直接使用驻留在内存中的指针,您应该先将其加载到寄存器中。您放置的双括号将被忽略,因此:

movq ,((vars+0)) /*first addend 3*/
movq ,((vars+8)) /*second addend 7*/
movq [=10=],((vars+16))

与此相同:

movq ,(vars+0) /*first addend 3*/
movq ,(vars+8) /*second addend 7*/
movq [=11=],(vars+16)

相反,您需要执行(对于每个值):

movq (vars+0), %rax
movq , (%rax)