从 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
我生成的一个函数没有计算它应该计算的内容,我正在尝试单独调试它。我有它的汇编程序,我尝试从精简的 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