C 为什么;mov%%rsp,%%rbp“;导致分割错误?

C 为什么;mov%%rsp,%%rbp“;导致分割错误?,c,segmentation-fault,x86-64,inline-assembly,C,Segmentation Fault,X86 64,Inline Assembly,我是内联汇编新手。我有以下带有内联汇编的C函数。我只是想看看push%%rbp和mov%%rsp、%%rbp是否实际运行正常。我的职能是: test_inlineAssemblyFunction(){ u64 base, rsp, base1, rsp1; asm volatile( "mov %%rbp, %0 \n" "mov %%rsp, %1 \n" &q

我是内联汇编新手。我有以下带有内联汇编的
C
函数。我只是想看看
push%%rbp
mov%%rsp、%%rbp
是否实际运行正常。我的职能是:

test_inlineAssemblyFunction(){

    u64 base, rsp, base1, rsp1;
    asm volatile(

            "mov %%rbp, %0 \n"
            "mov %%rsp, %1 \n"

            "push %%rbp \n"
            "mov %%rbp, %2 \n"

            "mov %%rsp, %%rbp \n" <--- this line is causing the problem
            "mov %%rbp, %3 \n"
            :"=r"(base), "=r"(rsp),"=r"(base1), "=r"(rsp1)
            :
            : "rax","rbx","rsp"
            );
    printf("Before: Base register %x\n", base);
    printf("Before: stack pointer register %x\n", rsp);
    printf("After: (Should be same as previous )Base register %x\n", base1);
    printf("After: (Actually %rsp-8)Base register %x\n", rsp1);

    
}
从输出中,我可以看到所有print语句都在打印所需的输出。但是分割错误。如果我的理解是正确的,则在尝试读取或写入非法内存位置时会出现分段错误。所以,在我的例子中,
“mov%%rsp,%%rbp\n”
导致了分段错误,所以我不允许从用户空间读取
rsp

更新:正如@Kuba没有忘记Monica所建议的,下面是
test\u inlineAssemblyFunction
函数的反汇编

(gdb) disas test_inlineAssemblyFunction
Dump of assembler code for function test_inlineAssemblyFunction:
0x0000000000007366 <+0>:    push   %rbp
0x0000000000007367 <+1>:    mov    %rsp,%rbp
0x000000000000736a <+4>:    push   %rbx
0x000000000000736b <+5>:    sub    $0x28,%rsp
0x000000000000736f <+9>:    mov    %rbp,%rdi
0x0000000000007372 <+12>:   mov    %rsp,%rsi
0x0000000000007375 <+15>:   push   %rbp
0x0000000000007376 <+16>:   mov    %rbp,%rcx
0x0000000000007379 <+19>:   mov    %rsp,%rbp
0x000000000000737c <+22>:   mov    %rax,%rdx
0x000000000000737f <+25>:   mov    %rdi,-0x30(%rbp)
0x0000000000007383 <+29>:   mov    %rsi,-0x28(%rbp)
0x0000000000007387 <+33>:   mov    %rcx,-0x20(%rbp)
0x000000000000738b <+37>:   mov    %rdx,-0x18(%rbp)
0x000000000000738f <+41>:   mov    -0x30(%rbp),%rax
0x0000000000007393 <+45>:   mov    %rax,%rsi
0x0000000000007396 <+48>:   lea    0x275ab(%rip),%rdi        # 0x2e948
0x000000000000739d <+55>:   mov    $0x0,%eax
0x00000000000073a2 <+60>:   callq  0x5570 <printf@plt>
0x00000000000073a7 <+65>:   mov    -0x28(%rbp),%rax
0x00000000000073ab <+69>:   mov    %rax,%rsi
0x00000000000073ae <+72>:   lea    0x275b3(%rip),%rdi        # 0x2e968
0x00000000000073b5 <+79>:   mov    $0x0,%eax
0x00000000000073ba <+84>:   callq  0x5570 <printf@plt>
0x00000000000073bf <+89>:   mov    -0x20(%rbp),%rax
0x00000000000073c3 <+93>:   mov    %rax,%rsi
0x00000000000073c6 <+96>:   lea    0x275c3(%rip),%rdi        # 0x2e990
0x00000000000073cd <+103>:  mov    $0x0,%eax
0x00000000000073d2 <+108>:  callq  0x5570 <printf@plt>
0x00000000000073d7 <+113>:  mov    -0x18(%rbp),%rax
0x00000000000073db <+117>:  mov    %rax,%rsi
0x00000000000073de <+120>:  lea    0x275e3(%rip),%rdi        # 0x2e9c8
0x00000000000073e5 <+127>:  mov    $0x0,%eax
0x00000000000073ea <+132>:  callq  0x5570 <printf@plt>
0x00000000000073ef <+137>:  nop
0x00000000000073f0 <+138>:  mov    -0x8(%rbp),%rbx
0x00000000000073f4 <+142>:  leaveq 
0x00000000000073f5 <+143>:  retq   
End of assembler dump.
(gdb)
(gdb)disas test\u inlineassembly函数
函数测试的汇编程序代码转储\u inlineAssemblyFunction:
0x0000000000007366:推送%rbp
0x0000000000007367:mov%rsp,%rbp
0x000000000000736a:推送%rbx
0x000000000000736b:子$0x28,%rsp
0x000000000000736f:mov%rbp,%rdi
0x0000000000007372:mov%rsp,%rsi
0x0000000000007375:推送%rbp
0x0000000000007376:mov%rbp,%rcx
0x0000000000007379:mov%rsp,%rbp
0x000000000000737c:mov%rax,%rdx
0x000000000000737f:mov%rdi,-0x30(%rbp)
0x0000000000007383:mov%rsi,-0x28(%rbp)
0x0000000000007387:mov%rcx,-0x20(%rbp)
0x000000000000738b:mov%rdx,-0x18(%rbp)
0x000000000000738f:mov-0x30(%rbp),%rax
0x0000000000007393:mov%rax,%rsi
0x0000000000007396:lea 0x275ab(%rip),%rdi#0x2e948
0x000000000000739d:mov$0x0,%eax
0x00000000000073a2:callq 0x5570
0x00000000000073a7:mov-0x28(%rbp),%rax
0x00000000000073ab:mov%rax,%rsi
0x00000000000073ae:lea 0x275b3(%rip),%rdi#0x2e968
0x00000000000073b5:mov$0x0,%eax
0x00000000000073ba:callq 0x5570
0x00000000000073bf:mov-0x20(%rbp),%rax
0x00000000000073c3:mov%rax,%rsi
0x00000000000073c6:lea 0x275c3(%rip),%rdi#0x2e990
0x00000000000073cd:mov$0x0,%eax
0x00000000000073d2:callq 0x5570
0x00000000000073d7:mov-0x18(%rbp),%rax
0x00000000000073db:mov%rax,%rsi
0x00000000000073de:lea 0x275e3(%rip),%rdi#0x2e9c8
0x00000000000073e5:mov$0x0,%eax
0x00000000000073ea:callq 0x5570
0x00000000000073ef:nop
0x00000000000073f0:mov-0x8(%rbp),%rbx
0x00000000000073f4:LEVEQ
0x00000000000073f5:retq
汇编程序转储结束。
(gdb)

没有任何东西可以保证编译代码的编译器以您暗示的方式使用这些寄存器。就这些。我不确定您是从哪里得到这样的想法的,即它应该是您暗示的方式,而不实际查看编译器生成的用于构建程序的汇编输出

当您在汇编中编写代码时,您正在与周围的所有汇编代码进行交互,因此我不明白您为什么要在黑暗中这样做。您必须做的第一件事是停止并找出如何从编译器获取程序集输出,即除了将目标代码保存到文件中之外,如何传递编译器希望将此类程序集输出保存到文件中的选项。然后重新编译程序,看看程序集如何与其余部分配合。提示:它不会:)


如果在您自己的系统上解决这个问题目前有点太分散注意力,那么您可以使用编写代码,选择一个gcc编译器,然后检查程序集输出并在云中运行程序并观察效果。你所需要的只是一个网络浏览器。没有其他东西需要在本地安装。

问题不在于您阅读了
rsp
。这是指您从asm块中删除了
rbp
(通过使用从
rsp
复制的值覆盖它)和
rsp
(通过执行
推送
,而不使用匹配的
pop
),而不通知编译器有关删除的信息。前者可以通过将
rbp
添加到clobber列表中来实现;后者根本不合法。

您是否尝试过查看编译器输出asm,看看您的asm与编译器的asm是如何混合的?取决于
-fomit frame pointer
与否,
“=m”
操作数将相对于RSP或RBP引用,因此在带内存操作数的asm语句中混用RSP和RBP似乎是个糟糕的主意。(此外,我认为RSP的打击手段实际上不起作用)。此外,内联asm在RSP下面的红色区域上进行操作是不安全的,但实际上,在非叶函数中这样做是安全的:gcc和clang不会使用res区域,因为您调用printf。读取
RSP
是可以的,但在内联程序集中修改
rbp
而不使用clobber是不安全的。由于红色区域,在x86-64内联asm中推送到堆栈也是不安全的。当然,在堆栈上留下东西是不安全的,因此堆栈指针的位置与它留下的位置不同(敲击
rsp
也无济于事)。@PeterCordes抱歉。我修正我的代码。我试着用
=r
&
=m
<代码>=m导致堆栈崩溃。并且
=r
导致分段错误您修改RSP而不还原,因此当函数尝试返回时,可能是RSP没有指向返回地址。
“rsp”
clobber不能保证安全;我很确定它是被支持的。再次,请查看编译器的整个asm输出,例如@NateEldredge。您能给出一个关于使用clobber修改
rbp
的示例吗?我添加了编译器生成的汇编代码。正如@Nate Eldredge所说,我面临的问题是由于修改了
rbp
。我已尝试将
rbp
替换为
rax
。函数运行时没有错误@
(gdb) disas test_inlineAssemblyFunction
Dump of assembler code for function test_inlineAssemblyFunction:
0x0000000000007366 <+0>:    push   %rbp
0x0000000000007367 <+1>:    mov    %rsp,%rbp
0x000000000000736a <+4>:    push   %rbx
0x000000000000736b <+5>:    sub    $0x28,%rsp
0x000000000000736f <+9>:    mov    %rbp,%rdi
0x0000000000007372 <+12>:   mov    %rsp,%rsi
0x0000000000007375 <+15>:   push   %rbp
0x0000000000007376 <+16>:   mov    %rbp,%rcx
0x0000000000007379 <+19>:   mov    %rsp,%rbp
0x000000000000737c <+22>:   mov    %rax,%rdx
0x000000000000737f <+25>:   mov    %rdi,-0x30(%rbp)
0x0000000000007383 <+29>:   mov    %rsi,-0x28(%rbp)
0x0000000000007387 <+33>:   mov    %rcx,-0x20(%rbp)
0x000000000000738b <+37>:   mov    %rdx,-0x18(%rbp)
0x000000000000738f <+41>:   mov    -0x30(%rbp),%rax
0x0000000000007393 <+45>:   mov    %rax,%rsi
0x0000000000007396 <+48>:   lea    0x275ab(%rip),%rdi        # 0x2e948
0x000000000000739d <+55>:   mov    $0x0,%eax
0x00000000000073a2 <+60>:   callq  0x5570 <printf@plt>
0x00000000000073a7 <+65>:   mov    -0x28(%rbp),%rax
0x00000000000073ab <+69>:   mov    %rax,%rsi
0x00000000000073ae <+72>:   lea    0x275b3(%rip),%rdi        # 0x2e968
0x00000000000073b5 <+79>:   mov    $0x0,%eax
0x00000000000073ba <+84>:   callq  0x5570 <printf@plt>
0x00000000000073bf <+89>:   mov    -0x20(%rbp),%rax
0x00000000000073c3 <+93>:   mov    %rax,%rsi
0x00000000000073c6 <+96>:   lea    0x275c3(%rip),%rdi        # 0x2e990
0x00000000000073cd <+103>:  mov    $0x0,%eax
0x00000000000073d2 <+108>:  callq  0x5570 <printf@plt>
0x00000000000073d7 <+113>:  mov    -0x18(%rbp),%rax
0x00000000000073db <+117>:  mov    %rax,%rsi
0x00000000000073de <+120>:  lea    0x275e3(%rip),%rdi        # 0x2e9c8
0x00000000000073e5 <+127>:  mov    $0x0,%eax
0x00000000000073ea <+132>:  callq  0x5570 <printf@plt>
0x00000000000073ef <+137>:  nop
0x00000000000073f0 <+138>:  mov    -0x8(%rbp),%rbx
0x00000000000073f4 <+142>:  leaveq 
0x00000000000073f5 <+143>:  retq   
End of assembler dump.
(gdb)