当前位置: 首页 > 知识库问答 >
问题:

程序集中的跟踪程序。

太叔涵亮
2023-03-14

我试图了解C程序在汇编级别上的样子,所以我运行gdb并在主get_input上使用反汇编。该程序很短,因此我可以更好地遵循它。有2行我不明白。在 main() 中的第一个是:

0x00000000004005a3

我们保存 rbp 的旧值,并将 rsp 的当前值保存到 rbp。该指令的目的是什么?

get_input()中的另一个是:

000000000400581 <+4>:   sub    $0x10,%rsp

在这里,我们也从保存rbp的旧值开始,将其推送到堆栈。然后给 rbp 提供 rsp 的当前值。然后从 rsp 中减去 16 个字节。我知道这是分配的空间,但为什么是16字节而不是8字节?我只使缓冲区为8个字节,其他8个字节的用途是什么?

#include <stdio.h>
void get_input()
{
    char buffer[8];

    gets(buffer);
    puts(buffer);
}

int main()
{
    get_input();
    return 0;
}

转储函数main的汇编代码:

   0x000000000040059f <+0>: push   %rbp
   0x00000000004005a0 <+1>: mov    %rsp,%rbp
   0x00000000004005a3 <+4>: mov    $0x0,%eax
   0x00000000004005a8 <+9>: callq  0x40057d <get_input>
   0x00000000004005ad <+14>:    mov    $0x0,%eax
   0x00000000004005b2 <+19>:    pop    %rbp
   0x00000000004005b3 <+20>:    retq   
End of assembler dump.

函数get_input的汇编代码转储:

   0x000000000040057d <+0>: push   %rbp
   0x000000000040057e <+1>: mov    %rsp,%rbp
   0x0000000000400581 <+4>: sub    $0x10,%rsp
   0x0000000000400585 <+8>: lea    -0x10(%rbp),%rax
   0x0000000000400589 <+12>:    mov    %rax,%rdi
   0x000000000040058c <+15>:    callq  0x400480 <gets@plt>
   0x0000000000400591 <+20>:    lea    -0x10(%rbp),%rax
   0x0000000000400595 <+24>:    mov    %rax,%rdi
   0x0000000000400598 <+27>:    callq  0x400450 <puts@plt>
   0x000000000040059d <+32>:    leaveq 
   0x000000000040059e <+33>:    retq 

共有2个答案

高宇定
2023-03-14

第二条指令sub$0x10,%rsp正在为系统调用分配内存并对齐堆栈。调用标准需要16字节对齐,而不是8字节对齐。

东门焕
2023-03-14

对于main()。。。

0x000000000040059f <+0>: push   %rbp

%RBP 的值推送到堆栈上。

0x00000000004005a0 <+1>: mov    %rsp,%rbp

%RSP的值复制到%RBP(创建一个新的堆栈帧)。

0x00000000004005a3 <+4>: mov    $0x0,%eax
0x00000000004005a8 <+9>: callq  0x40057d <get_input>

按下%RIP的值(可直接撤消),然后跳转到label/functionget_input()

0x00000000004005ad <+14>:    mov    $0x0,%eax

根据AMD64 System V ABI,函数的返回值存储在%RAX中(不考虑浮点和大型结构)。它还表示有两组寄存器:已保存的调用方和已保存的被调用方。调用函数时,不能期望调用方保存的寄存器保持不变,如果需要,必须自己将它们保存在堆栈中。同样,被调用的函数如果使用被调用方保存的寄存器,则必须保留这些寄存器。调用者保存的寄存器有%RAX%RDI%RSI%RDX%RCX、%R8%R9%R10。被叫方保存的寄存器有%RBX%RSP%RBP%R12>、<代码>%R13%R14%R15。

0x00000000004005b2 <+19>:    pop    %rbp

恢复主 () 的调用方的 %RBP,即销毁主 () 的堆栈帧。

0x00000000004005b3 <+20>:    retq   

main()返回,返回值为0

然后,我们有get_input()...

0x000000000040057d <+0>: push   %rbp

%RBP 的值推送到堆栈上。

0x000000000040057e <+1>: mov    %rsp,%rbp

%RSP的值复制到%RBP(创建一个新的堆栈帧)。

0x0000000000400581 <+4>: sub    $0x10,%rsp

%RSP中减去16(为当前帧保留16字节的临时存储)。

0x0000000000400585 <+8>: lea    -0x10(%rbp),%rax

将有效地址 -0x10 (%RBP) 加载到 %RAX 中。也就是说,它将从 %RBP 的值中减去 16 的结果加载到 %RAX 中。这意味着 %RAX 现在指向本地临时存储的第一个字节。

0x0000000000400589 <+12>:    mov    %rax,%rdi

根据ABI,函数的第一个参数在%RDI上给出,第二个参数在%RSI上给出,等等…在这种情况下,%RAX的值作为要调用的函数的第一个参数给出。

0x000000000040058c <+15>:    callq  0x400480 <gets@plt>

调用函数< code>gets()

0x0000000000400591 <+20>:    lea    -0x10(%rbp),%rax

同上。

0x0000000000400595 <+24>:    mov    %rax,%rdi

%RAX作为第一个参数传递。

0x0000000000400598 <+27>:    callq  0x400450 <puts@plt>

调用函数 put()

0x000000000040059d <+32>:    leaveq

相当于MOV%RBP,%RSP然后POP%RBP,即破坏堆栈帧。

0x000000000040059e <+33>:    retq

从函数get_input()返回,但没有正确的返回值。

现在

该指令的第二个html" target="_blank">实例非常重要,因为它设置了 main() 的返回值。但是,第一个实际上是多余的。您可能在编译器上禁用了优化。

然后从rsp中减去16个字节。我知道这是分配的空间,但为什么是16字节而不是8字节?我只做了8个字节的缓冲区,其他8个字节的目的是什么?

ABI要求%RSP在每次函数调用之前位于16字节边界上。顺便说一句,您应该远离静态大小的缓冲区和get()

 类似资料:
  • 我知道Java中内存分配的基本原理——应用程序占用的大部分内存都分配在堆上,堆由所有线程共享,因此没有线程拥有对象的概念,您无法轻松计算线程使用它拥有的所有对象占用了多少内存。 但我想知道是否有任何方法可以计算和汇总从特定线程触发的分配?内存分配发生在堆上,但它总是由想要创建对象的线程触发,所以我想知道是否可以以某种方式分析这种关系? 我的想法是,一个典型的Spring Boot应用程序将引导,从

  • 问题内容: 我在Linux中玩ptrace。我正在尝试使用/ proc / pid / mem接口编写跟踪进程的内存。 我用来完成此任务的功能是: 但是我总是会得到错误:编写:错误的文件描述符。 是否可以使用此方法编写跟踪过程? 问题答案: 您正在以只读模式()打开文件。我建议改用: 但是,从目前尚不清楚这是否可行: memory through open(2), read(2), and lse

  • 问题内容: 在不让父进程等待子进程被杀死的情况下,我如何跟踪子进程的死亡? 我正在尝试一个客户端-服务器方案,其中服务器从客户端接受连接,并为它接受的每个连接派生一个新进程。 我忽略了SIGCHLD信号以防止僵尸创建。 上述情况下的问题是,如果子进程在函数中被杀死,则全局变量不会递减。 注意: 我正在寻找不使用SIGCHLD信号的解决方案…如果可能 问题答案: 通常,您编写一个调用pid 的处理程

  • 关于Clojure中第一个UI程序的SO问题,我创建了一个新的应用程序项目: 线程“Awt-EventQueue-0”java.lang.IllegalArgumentException中出现异常:没有匹配子句:在a_ui_app.core处的157$FN__16$FN__21$FN__22处的Invoke(core.clj:19)在clojure.lang.afn.call(afn.java:1

  • 我看到了这个Python问题:应用引擎延迟:跟踪内存泄漏 ...同样,我也遇到了这个可怕的错误: 在为总共384个请求提供服务后,超过了128 MB的软专用内存限制 ... 处理此请求后,发现处理此请求的进程占用了太多内存,因此被终止。这可能会导致应用程序的下一个请求使用新进程。如果经常看到此消息,则应用程序中可能存在内存泄漏。 根据另一个问题,可能是“实例类”太小,无法运行这个应用程序,但是在增

  • 我知道Java中内存分配的基本原理-应用程序占用的大部分内存都是在堆上分配的,堆由所有线程共享,因此没有线程拥有的对象的概念,并且您无法轻松计算线程拥有的所有对象占用了多少内存。 但我想知道是否有任何方法可以计算和汇总从特定线程触发的分配?内存分配发生在堆上,但它总是由想要创建对象的线程触发,所以我想知道是否可以以某种方式分析这种关系? 我的想法是,一个典型的Spring Boot应用程序将引导,