我试图了解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
第二条指令sub$0x10,%rsp
正在为系统调用分配内存并对齐堆栈。调用标准需要16字节对齐,而不是8字节对齐。
对于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应用程序将引导,