Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 函数终止时的Segfault_C_Assembly_X86_64 Bit_Att - Fatal编程技术网

C 函数终止时的Segfault

C 函数终止时的Segfault,c,assembly,x86,64-bit,att,C,Assembly,X86,64 Bit,Att,我有一个用64位x86汇编(gcc和GAS的AT&T语法)编写的函数,它执行一些SSE2操作。我已经使用带反汇编的gdb检查了结果,并查看了寄存器值,因此我知道它产生了正确的结果。在retq指令之后,我得到一个分段错误。由于我是汇编新手(从未上过任何汇编课程),我猜我没有正确处理函数/主程序接口。该函数接受2个指针和一个int,并应返回一个float。 这是我在汇编函数中处理输入/输出的方式: float foo(float *x,float *y,unsigned int s) { _

我有一个用64位x86汇编(gcc和GAS的AT&T语法)编写的函数,它执行一些SSE2操作。我已经使用带反汇编的gdb检查了结果,并查看了寄存器值,因此我知道它产生了正确的结果。在retq指令之后,我得到一个分段错误。由于我是汇编新手(从未上过任何汇编课程),我猜我没有正确处理函数/主程序接口。该函数接受2个指针和一个int,并应返回一个float。 这是我在汇编函数中处理输入/输出的方式:

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"
    );
}
这是导致segfault的一行代码(这是拆解中ret之后的指令):

我不知道为什么在执行我的函数后,它会将rax低位的值添加回rax,但它似乎会使事情崩溃。我是不是不允许在我的汇编函数中使用rax,即使它是通用的,并且我声明它被破坏了

我不确定您是否需要查看这一部分,但这是gcc希望处理函数的方式;我已经包含了调用我的函数的行的反汇编:

    #asm dealing with function inputs
    callq  0x400520 <foo>
    movss  %xmm0,-0x48(%rbp)
    mov    -0x48(%rbp),%eax
    mov    %eax,-0x34(%rbp)
处理函数输入的asm callq 0x400520 movss%xmm0,-0x48(%rbp) mov-0x48(%rbp),%eax mov%eax,-0x34(%rbp)
这就引出了我的第二个问题,为什么它会任意地将xmm0中的值移动到两个位置?我应该让我的函数在xmm0中结束,还是这意味着我应该避免使用xmm0?我很困惑,希望能得到任何帮助。提前感谢所有花时间阅读我的noob帖子的人:)

您的问题是内联汇编并没有取代函数。您的函数编译为:

_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
retq
弹出堆栈的一个值,并跳转到它。如果一切正常,这是由
callq
推送的值
gcc
生成了一个函数序言(上面的前两条指令),包括
push%rbp
。因此,当您的
retq
运行时,它会弹出
rbp
(指向堆栈的指针),并跳转到它。这可能是由于堆栈不可执行而导致分段错误(也可能是因为%rax是无效指针,如果出于某种原因堆栈是可执行的)。它碰巧指向的堆栈上的值是
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;
}
另一个选项是始终将其写入程序集文件,并在以后将其与C代码链接

我希望这有点帮助,但如果它没有完全回答你的问题,我很抱歉


编辑:将代码更新为实际为我运行的代码。

我刚打印到一个.s文件,我想你是对的。让我试试你的建议,看看是否有效!到目前为止,我已经从函数中省略了ret,它不再崩溃。我应该指出,我认为您使用了错误的调用约定。您正在从堆栈中读取参数,而不是从寄存器中读取。在Linux/BSD/OSX上,它们将分别位于
rdi
rsi
rdx
,Windows使用
rcx
rdx
r8
。但据我所知,他们总是把它们按相反的顺序放在堆栈上;因此,如果我从那里而不是从寄存器中读取它们,它似乎更便于携带。当我尝试切换到您的扩展装配建议(我也是新手)时,我再次遇到了SEGFULTS。我现在要去睡觉了,但在我去之前,我想说,我真的很感谢你的回答和评论,道格尔:)你可能是对的,但没有任何理由继续这样做。我学习了一些SSE,并更新了一些在我的机器上实际运行的代码的答案中的示例,希望这会更有用。祝你好运:)
#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;
}
_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