我习惯看到(约定(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编译
答案 0 :(得分:1)
如果您正在处理已链接到C运行时的程序,则argc
和argv
参数将通过argc
传递(假设为x86){{1}在ebp+8
{}}和argv
。那是因为C运行时执行它自己的初始化并使用正常的C ABI将参数传递给ebp+12
。
你说你习惯看到的调用约定(在堆栈顶部有main()
,后跟argc
.. argv[0]
)是堆栈的状态由启动新程序的Linux系统调用设置。
请注意面向程序集的代码示例:
argv[argc]
由于最初的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
指令,对于最后三行中的每一行看起来都是4。