带有反汇编分析的 Linux 最小可运行示例
由于这是标准未指定的实现细节,让我们看看编译器在特定实现上做了什么。
在这个答案中,我将链接到进行分析的特定答案,或者直接在此处提供分析,并在此处总结所有结果。
所有这些都在不同的 Ubuntu / GCC 版本中,并且跨版本的结果可能相当稳定,但如果我们发现任何变化,让我们指定更精确的版本。
函数内部的局部变量
无论是它main
还是任何其他功能:
void f(void) {
int my_local_var;
}
如图:gdb中<value优化输出>是什么意思?
-O0
: 堆
-O3
: 如果它们不溢出则注册,否则堆栈
有关堆栈存在的动机,请参见:x86 汇编中寄存器上使用的 push/pop 指令的功能是什么?
全局变量和static
函数变量
/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;
/* DATA */
int my_global_implicit_explicit_1 = 1;
void f(void) {
/* BSS */
static int my_static_local_var_implicit;
static int my_static_local_var_explicit_0 = 0;
/* DATA */
static int my_static_local_var_explicit_1 = 1;
}
char *
和char c[]
如图:C和C++中的静态变量存储在哪里?
void f(void) {
/* RODATA / TEXT */
char *a = "abc";
/* Stack. */
char b[] = "abc";
char c[] = {'a', 'b', 'c', '\0'};
}
TODO 是否也会将非常大的字符串文字放入堆栈?或者.data
?还是编译失败?
函数参数
void f(int i, int j);
必须通过相关的调用约定,例如:https ://en.wikipedia.org/wiki/X86_calling_conventions for X86,它为每个变量指定特定的寄存器或堆栈位置。
然后如What does <value optimize out> mean in gdb 所示?,-O0
然后将所有内容都放入堆栈中,同时-O3
尝试尽可能多地使用寄存器。
但是,如果函数被内联,它们将被视为普通本地人。
const
我相信这没有什么区别,因为您可以将其排版。
相反,如果编译器能够确定某些数据永远不会被写入,那么理论上它可以将其放入,.rodata
即使不是 const。
待办事项分析。
指针
它们是变量(包含地址,即数字),与其他所有变量一样 :-)
malloc
这个问题对 没有多大意义malloc
,因为malloc
它是一个函数,并且在:
int *i = malloc(sizeof(int));
*i
是一个包含地址的变量,所以属于上述情况。
至于 malloc 在内部是如何工作的,当你调用它时,Linux 内核在其内部数据结构上将某些地址标记为可写,并且当它们最初被程序触及时,会发生错误,内核启用页表,从而允许访问没有 segfaul 发生:x86 分页如何工作?
但是请注意,这基本上正是exec
系统调用在您尝试运行可执行文件时所做的事情:它标记要加载到的页面,并将程序写入那里,另请参见:内核如何获取运行的可执行二进制文件linux?除了exec
对加载到哪里有一些额外的限制(例如,代码是不可重定位的)。
用于现代 2020 实现的确切系统调用malloc
,mmap
过去brk
曾使用过:malloc() 使用 brk() 还是 mmap()?
动态库
基本上得到mmap
记忆:https ://unix.stackexchange.com/questions/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710
环境变量main
和argv
初始堆栈上方:https : //unix.stackexchange.com/questions/75939/where-is-the-environment-string-actual-stored TODO 为什么不在 .data 中?