从 C 调用汇编函数

Calling an assembly function from C

我生成的一个函数没有计算它应该计算的内容,我正在尝试单独调试它。我有它的汇编程序,我尝试从精简的 C 程序中调用它。但是,由于某种原因,我最终在函数中遇到段错误(因此,调用函数似乎有效,但执行失败)。传递参数可能有问题..

函数签名是

void func(int, int, float*, float*, float*);

该函数忽略前两个参数并接收 3 个数组,每个数组包含 32 个浮点数。它将按元素添加后两个并将结果按元素存储到第一个数组中。但是,它会以一种奇怪的顺序执行此操作(与线性流式传输相反,这样做的原因不在这个 SO 问题的范围内)。这就是 offset_arrays 在汇编代码中的作用。

我检查了 x86 调用约定(这是我正在使用的体系结构),前六个整数或指针参数在寄存器 RDI、RSI、RDX、RCX、R8 和 R9 中传递。

这里是函数实现:

    .text
    .globl  func
    .align  16, 0x90
    .type   func,@function
func:
    .cfi_startproc
    xorl    %eax, %eax
    movabsq $offset_array1, %r9
    movabsq $offset_array, %r10
    xorl    %esi, %esi
    .align  16, 0x90
.LBB0_1:
    movq    (%r9,%rax), %r11
    movq    (%r10,%rax), %rdi
    movss   (%r8,%rdi,4), %xmm0
    addss   (%rcx,%rdi,4), %xmm0
    movss   %xmm0, (%rdx,%r11,4)
    incq    %rsi
    addq    , %rax
    cmpq    , %rsi
    jb  .LBB0_1
    retq
.Ltmp0:
    .size   func, .Ltmp0-func
    .cfi_endproc

    .type   offset_array,@object
    .section    .rodata,"a",@progbits
    .align  16
offset_array:
    .quad   0
    .quad   16
    .quad   1
    .quad   17
    .quad   2
    .quad   18
    .quad   3
    .quad   19
    .quad   4
    .quad   20
    .quad   5
    .quad   21
    .quad   6
    .quad   22
    .quad   7
    .quad   23
    .quad   8
    .quad   24
    .quad   9
    .quad   25
    .quad   10
    .quad   26
    .quad   11
    .quad   27
    .quad   12
    .quad   28
    .quad   13
    .quad   29
    .quad   14
    .quad   30
    .quad   15
    .quad   31
    .size   offset_array, 256

    .type   offset_array1,@object
    .align  16
offset_array1:
    .quad   0
    .quad   16
    .quad   1
    .quad   17
    .quad   2
    .quad   18
    .quad   3
    .quad   19
    .quad   4
    .quad   20
    .quad   5
    .quad   21
    .quad   6
    .quad   22
    .quad   7
    .quad   23
    .quad   8
    .quad   24
    .quad   9
    .quad   25
    .quad   10
    .quad   26
    .quad   11
    .quad   27
    .quad   12
    .quad   28
    .quad   13
    .quad   29
    .quad   14
    .quad   30
    .quad   15
    .quad   31
    .size   offset_array1, 256


    .section    ".note.GNU-stack","",@progbits

我尝试从这个 C 代码调用函数:

float f0[32];
float f1[32];
float f2[32];

extern void func(int i0,int i1,float* dest,float* src0,float* src1);

int main(int argc, char *argv[])
{
  func(0,0,f0,f1,f2);
}

编译并链接

gcc -o f.o -c -g f.S
gcc -g -o test_f test_f.c f.o

和 运行 虽然 gdb 结果是

Program received signal SIGSEGV, Segmentation fault.
func () at f.S:17
17      movss   %xmm0, (%rdx,%r11,4)

所以,这显然是对内存的写入,即对第一个数组的写入。为什么会出现段错误以及如何正确调用此函数(不更改汇编代码)?

数组的大小是 32,但在函数中,%rsi 从 0 递增到 33,后面是 jb。这是错误的,访问这部分静态内存(未分配)会引发分段错误。应该改为32。在ubuntu.

测试
func:
    .cfi_startproc
    xorl    %eax, %eax
    movabsq $offset_array1, %r9
    movabsq $offset_array, %r10
    xorl    %esi, %esi
    .align  16, 0x90
.LBB0_1:
    movq    (%r9,%rax), %r11
    movq    (%r10,%rax), %rdi
    movss   (%r8,%rdi,4), %xmm0
    addss   (%rcx,%rdi,4), %xmm0
    movss   %xmm0, (%rdx,%r11,4)
    incq    %rsi
    addq    , %rax
    cmpq    , %rsi
    jb  .LBB0_1

问题出在这一行

cmpq    , %rsi

应该是

cmpq    , %rsi

您在 .quad 31 之后访问内存中的垃圾并将其粘贴到 movq (%r9,%rax), %r11

处的 r11