Chinaunix

标题: Linux 下程序启动时命令行参数的个数保存在哪里? [打印本页]

作者: superwujc    时间: 2013-09-11 18:23
标题: Linux 下程序启动时命令行参数的个数保存在哪里?
如题,请教各位:
《professional assembly language》中讲到,命令行参数的个数保存在ESP指针之后(向高地址方向)的位置,但小弟通过代码并未验证到这一点:
  1. root@c-dev:/cdev# vi memory_layout.c
复制代码
  1. int main (int argc, char *argv[])
  2. {
  3.     return 0;
  4. }
复制代码
  1. root@c-dev:/cdev# gcc -m32 -g memory_layout.c -o memory_layout
复制代码
  1. root@c-dev:/cdev# gdb --args memory_layout a bc def
  2. GNU gdb (GDB) 7.0.1-debian
  3. Copyright (C) 2009 Free Software Foundation, Inc.
  4. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
  5. This is free software: you are free to change and redistribute it.
  6. There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
  7. and "show warranty" for details.
  8. This GDB was configured as "x86_64-linux-gnu".
  9. For bug reporting instructions, please see:
  10. <http://www.gnu.org/software/gdb/bugs/>...
  11. Reading symbols from /cdev/memory_layout...done.
  12. (gdb) break main
  13. Breakpoint 1 at 0x8048397: file memory_layout.c, line 3.
  14. (gdb) run
  15. Starting program: /cdev/memory_layout a bc def

  16. Breakpoint 1, main (argc=4, argv=0xffffdd54) at memory_layout.c:3
  17. 3                return 0;
  18. (gdb) x/x 0xffffdd54
  19. 0xffffdd54:        0xffffde70
  20. (gdb) x/s 0xffffde70
  21. 0xffffde70:         "/cdev/memory_layout"
  22. (gdb) print argv[0]
  23. $1 = 0xffffde70 "/cdev/memory_layout"
  24. (gdb) print argv[1]
  25. $2 = 0xffffde84 "a"
  26. (gdb) print argv[2]
  27. $3 = 0xffffde86 "bc"
复制代码
自argv的内存地址开始向高地址方向,依次为各个命令行参数和环境变量,但通过怎样的方法才能找到保存命令行参数个数的内存地址呢?

请各位大神指点一下,小弟菜鸟,不甚感谢。


stack.png (37.65 KB, 下载次数: 43)

stack.png

作者: 井蛙夏虫    时间: 2013-09-11 21:48
回复 1# superwujc
  1. x /d $ebp+8
复制代码

作者: superwujc    时间: 2013-09-11 21:59
回复 2# 井蛙夏虫
可以得到结果,但请教为什么是$ebp+8呢?


   
作者: superwujc    时间: 2013-09-11 23:16
回复 2# 井蛙夏虫
已明了,多谢!

附上小弟的解释,请各位不吝拍砖
在C风格的函数调用中,stack首先保存被调函数的输入参数,然后是返回到主程序的地址
而为避免函数另包含其他压栈操作而改变esp的值(如嵌套调用函数),导致无法通过原来的esp间接寻址访问输入参数
因此在函数被调动时会将ebp压栈并将此时的esp值赋予ebp,使得ebp保存函数调用时的返回地址,之后esp指针可以随意向栈底移动,而不影响函数返回时执行清栈

由于32位系统上的地址为4 byte,因此
ebp保存的是函数被调用时的stack顶地址,ebp+4为被调函数的返回地址,ebp+8为被调函数的第一个参数
而对于main()函数,其输入参数有0或2个(int argc, char *argv[]),所以在gdb中,x/d $ebp+8命令将得到argc的值,即程序命令行参数的个数
完毕

   
作者: x5miao    时间: 2013-09-12 00:05
这个明显是体系架构相关的,看Linux内核中do_fork()的实现吧
作者: zhaohongjian000    时间: 2013-09-12 09:18
由于main函数也是被别的函数调用,所以这个问题就变成了函数的参数放在哪里。这就由体系结构的ABI来决定了。
作者: yulihua49    时间: 2013-09-12 13:20
superwujc 发表于 2013-09-11 18:23
如题,请教各位:
《professional assembly language》中讲到,命令行参数的个数保存在ESP指针之后(向高地 ...

那,argc是什么呢?
作者: myworkstation    时间: 2013-09-12 15:24
回复 4# superwujc


    你说的这部分内容实际上就是为函数调用生成堆栈框架,而现代的编译器基本上都提供不生产函数调用堆栈框架的优化功能。这个时候不存在ebp保存esp并使用esp的问题。这个优化使得ebp寄存器可以用于其它目的也加速的函数调用的性能。gcc用-fomit-frame-pointer,VC++用/Oy (Frame-Pointer Omission)。
作者: superwujc    时间: 2013-09-12 15:49
回复 8# myworkstation
太高深,不懂,小弟只是觉得用堆栈的观点可以解释这个问题,也便于自己理解
请教楼上几位该如何理解?

   




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2