【发布时间】:2019-12-23 16:41:00
【问题描述】:
我有一个小的源文件 m.c
extern void a(char *);
int main(int ac, char **av)
{
static char string[] = "Hello, world!\n";
a(string);
}
a 是一个外部函数。当我转储上述代码的反汇编时,它会发出以下输出:
m.o: file format elf32-i386
Disassembly of section .text:
00000000 <main>:
extern void a(char *);
int main(int ac, char **av)
{
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 10 sub $0x10,%esp
static char string[] = "Hello, world!\n";
a(string);
9: c7 04 24 00 00 00 00 movl $0x0,(%esp)
10: e8 fc ff ff ff call 11 <main+0x11>
}
15: c9 leave
16: c3 ret
我有两个问题:
既然有一个静态变量保存字符串,为什么我在这个反汇编代码中看不到
.data部分。这条指令的目的是什么:
movl $0x0,(%esp)。为什么我们在调用a之前将堆栈指针归零?
【问题讨论】:
-
该立即数受重定位的影响,由链接器填写。我建议您使用
-S选项指示编译器生成汇编文件,而不是反汇编目标文件。 -
只读常量数据进入
.rodata。并且 2:您正在查看带有占位符和重定位的未链接.o,但您忘记使用objdump -dr来显示它。此外,(%esp)是内存目标。它正在推动它,而不是写入%esp寄存器。 -
这不会将
esp归零,它会将零(稍后如其他提到的那样重新定位)写入堆栈,因为它是函数的参数。sub esp; mov [esp]本质上是一种推动。 -
objdump and resolving linkage of local function calls? 与
0重复。在其他地方可能还有另一个关于如何读取 AT&T 寻址模式的重复内容,%esp和(%esp)之间的区别。 -
为了让编译器、链接器和加载器(操作系统)生成的机器代码看起来更美观,请考虑在正在运行的程序上使用调试器。否则,您必须了解很多关于不同类型的元数据,这些元数据都告诉链接器和加载器该做什么来准备程序运行。在调试正在运行的程序时,您可以看到翻译成机器代码的努力的最终结果。您也可以单步查看它在做什么!
标签: c linux assembly att objdump