Fre*_*ove 0 c 64-bit x86 assembly att
我有一个用64位x86汇编语言编写的函数(用于gcc和GAS的AT&T语法),它执行一些SSE2操作.我通过使用反汇编的gdb并查看寄存器值来检查结果,所以我知道它产生了正确的结果.在retq指令之后,我得到了一个segementation故障.因为我刚接触汇编(并且从未接受过任何类),我猜我没有正确处理函数/主程序接口.该函数接受2个指针和一个int,并期望返回一个浮点数.这就是我在汇编函数中处理输入/输出的方法:
float foo(float *x,float *y,unsigned int s)
{
__asm__ __volatile__(
"movl -0x14(%%rbp),%%ecx \n\t" //ecx = s
"movq -0x8(%%rbp),%%rax \n\t" //rax -> x
"movq -0x10(%%rbp),%%rdx \n\t" //rdx -> y
"subq $4,%%rsp \n\t" //function result
#sse2 operations that end up with the answer in xmm4...
"movss %%xmm4,(%%rsp) \n\t" //store result
"flds (%%rsp) \n\t" //load function result
"addq $4,%%rsp \n\t" //adjust stack
"ret \n\t"
:
:"g"(s)
:"%ecx","%rax","%rdx"
);
}
Run Code Online (Sandbox Code Playgroud)
这里的行似乎导致了segfault(在反汇编中ret之后的指令):
0x00007fffffffe0d0 in ?? ()
=> 0x00007fffffffe0d0: 00 00 add %al,(%rax)
Run Code Online (Sandbox Code Playgroud)
我不知道为什么它在执行我的函数后将rax的低位中的值添加回rax,但它似乎崩溃了.我不允许在我的汇编函数中使用rax,即使它是一般用途并且我宣布它被破坏了吗?
我不确定你是否需要看到这个部分,但这是gcc期望处理该功能的方式; 我已经包含了调用我的函数的行的反汇编:
#asm dealing with function inputs
callq 0x400520 <foo>
movss %xmm0,-0x48(%rbp)
mov -0x48(%rbp),%eax
mov %eax,-0x34(%rbp)
Run Code Online (Sandbox Code Playgroud)
这让我想到了第二个问题,为什么它会随意将xmm0中的值移动到两个位置?我应该让我的函数最终得到xmm0的结果,或者这是否意味着我应该避免使用xmm0?我很困惑,很感激任何帮助.提前感谢任何花时间阅读我的菜鸟帖的人:)
您的问题是内联汇编不会替换该函数.你的函数编译成这样:
_foo:
push %rbp ; function prologue
mov %rsp,%rbp
mov %rdi,-0x8(%rbp)
mov %rsi,-0x10(%rbp)
mov %edx,-0x14(%rbp)
mov -0x14(%rbp),%eax
mov %eax,-0x1c(%rbp)
mov -0x14(%rbp),%ecx ; your code
mov -0x8(%rbp),%rax
mov -0x10(%rbp),%rdx
sub $0x4,%rsp
movss %xmm4,(%rsp)
flds (%rsp)
add $0x4,%rsp
retq ; your return
movss -0x18(%rbp),%xmm0 ; function epilogue
pop %rbp
retq ; gcc's return
Run Code Online (Sandbox Code Playgroud)
retq弹出堆栈的值,然后跳转到它.如果一切顺利,那就是推动的价值callq.gcc生成一个函数序言(上面的前两个指令)包括push %rbp.因此,当您retq运行时,它会弹出rbp(指向堆栈的指针)并跳转到它.这可能导致分段错误,因为堆栈不可执行(也可能是因为%rax是无效指针,如果由于某种原因,您的堆栈是可执行的).它碰巧指向的堆栈上的值00 00(在内存中显示了很多,不足为奇)并巧合地反汇编add %al,(%rax).
现在,我是SSE的新手,我几次只使用GCC内联汇编,所以我不确定这是否是一个有效的解决方案.你真的不应该看堆栈或返回,因为不同的编译器会有不同的函数序言,代码运行时堆栈中参数的相对位置.
尝试类似的东西:
#include <stdio.h>
float foo(float *x,float *y,unsigned int s)
{
float result;
__asm__ __volatile__(
"movss (%%rax),%%xmm4 \n\t" // xmm4 = *x
"movss (%%rdx),%%xmm5 \n\t" // xmm5 = *y
"addss %%xmm5,%%xmm4 \n\t" // xmm4 += xmm5
"movss %%xmm4,(%%rbx) \n\t" // result = xmm4
:
:"c"(s), "a"(x), "d"(y), "b"(&result) // ecx = s, eax = x, edx = y, ebx = &result
:"memory", "cc"
);
return result;
}
int main() {
float x = 1.0, y = 2.0;
printf("%f", foo(&x, &y, 99));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
所有堆栈分配,参数处理和返回都在C中完成.它还传入一个用于存储浮点结果的指针.
这会生成以下程序集,大致与您的目的相同:
_foo:
push %rbp ; prologue
mov %rsp,%rbp
push %rbx
lea -0xc(%rbp),%rbx ; set up registers
mov %edx,%ecx
mov %rdi,%rax
mov %rsi,%rdx
movss (%rax),%xmm4 ; your code
movss (%rdx),%xmm5
addss %xmm5,%xmm4
movss %xmm4,(%rbx)
movss -0xc(%rbp),%xmm0 ; retrieve result to xmm0 (the return register)
pop %rbx ; epilogue
pop %rbp
retq
Run Code Online (Sandbox Code Playgroud)
另一个选项始终是将其写入汇编文件中,稍后将其与您的C代码链接.
我希望这有点帮助,但如果它没有完全回答你的问题,我很抱歉.
编辑:更新代码到实际运行的东西.