【发布时间】:2013-12-10 20:28:47
【问题描述】:
我习惯于看到 (convention (A)) 引用的命令行参数:
pushl %ebp
movl %esp, %ebp
movl (%ebp), %eax # argc
movl 4(%ebp), %ebx # pointer to argv[0] string
movl 8($ebp), %ecx # pointer to argv[1] string
有时,我看到列表从偏移量 8 开始,这不是(主要)问题。我在一个程序中注意到的是这个我很困惑的翻译和参考,以获得argv[1](约定(B)):
movl 0xc(%ebp), %eax # pointer to a pointer to argv[0] (argc is at offset 8)
addl $0x4, %eax # argv[1] is a pointer at offset 4 from the pointer to argv[0]
movl (%eax), %eax # load where it points to, which is the argv[1] string
(在偏移量16(%ebp) 我看到一个指向环境变量的指针)
(1) 这种不同的约定有什么原因吗?
(2) 是否有编译器选项可以强制 gcc 使用我认为是上述标准约定 (A) 的内容?
(3) gcc 使用约定 (B) 有什么原因吗?
(4) 为什么要增加8的偏移量?
系统信息:
- Ubuntu 12.04
- gcc 4.6.3
- 使用 fno-stack-protector 编译
【问题讨论】:
-
您的约定 A 代码是从哪里获得的? AFAICT 这是不正确的,因为(在这种情况下)偏移量
4(%ebp)是argv本身,而不是argv[0]。在8(%ebp)是envp(环境块)。 -
另外(添加一个新注释,因为编辑看起来很无聊),偏移量 8 是因为在执行
movl %esp, %ebp时,堆栈上的前两项是%ebp和返回地址 - 每个都是 4 个字节,因此是 8 个字节的偏移量。 -
@Drew McGowen:约定 A 是您在任何组装教程/书籍/课程中都会看到的,当我使用执行 gcc 组装的 gas 编码时,它工作正常。至于8,如果这是main,为什么要存储一个ret地址? (推动 ebp 的 4 对我来说是愚蠢的,应该注意到)。
-
@gnometorule: 需要有来自
main()的返回地址,因为main()可以返回调用它的运行时。
标签: c gcc assembly command-line x86