Linux命令行参数在栈中的分布
lxg@2015-03-18
-
Linux命令行参数在栈中的分布
图1:分布示意图
上图是linux中32位ELF程序加载之后,命令行参数在stack中的分布示意图。
从上面来看argv(envp)参数的组织有点像一个链表一样,首先是char *argv[]这个指向指针的数组,然后通过argv[0]找到第一个命令行参数的指针(地址),最后再根据指针找到真正的参数字符串。envp也是类似。
-
通过gdb查看Linux命令行参数在栈中的分布
上文中通过图例的形式描述了命令行参数在栈中的分布情况,下面将通过gdb来近一步的查看真实运行环境中的情况。
/** * * Author: liuxingen@nsfocus.com * * Created Time: Mon 16 Mar 2015 10:08:26 PM GMT-8 * * FileName: hello.c * * Description: * **/
#include <stdio.h> int main(int argc,char*argv[],char*envp[]){ printf("Hello,world!\n"); }
|
Hello.c
.file “hello.c” .section .rodata .LC0: .string“Hello,world!” .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $16, %esp movl $.LC0,(%esp) call puts leave ret .size main, .-main .ident “GCC: (Gentoo 4.4.5 p1.3, pie-0.4.5) 4.4.5” .section .note.GNU-stack,””,@progbits
|
Hello.s
上面是一个简单的输出”Hello,world!”的程序,hello.s是” gcc -Shello.c”的结果,通过” gcc hello.s -o hello -gstabs”生成可执行文件hello。
liuxingen@remoter ~/station/asm $ gdb -q hello Reading symbols from hello...done. (gdb) b main Breakpoint 1 at 0x80483e7: file hello.s, line 11. (gdb) run 1 2 3 4 Starting program: /home/liuxingen/station/asm/hello 1 2 3 4
Breakpoint 1, main () at hello.s:11 11 andl$-16, %esp (gdb) l 6 .globl main 7 .type main, @function 8 main: 9 pushl %ebp 10 movl %esp, %ebp 11 andl$-16, %esp 12 subl $16, %esp 13 movl $.LC0, (%esp) 14 call puts 15 leave (gdb) x/5aw $esp 0xbffff608: 0xbffff688 0xb7e8fcc6 <__libc_start_main+230> 0x5 0xbffff6b4 0xbffff618: 0xbffff6cc |
这是gdb的部分输出,跟图1有一点不相同的地方,堆栈指针esp目前不是指向main的返回值,因为这是我们b main的时候其实断点是设在了第11行,在第9行已经把ebp入栈了。除了第一个0xbffff688输出以外,其它的4个输出分别对应了”main返回值”、”argc”、”char **argv”、”char **envp”。
(gdb) x/6wa 0xbffff6b4 0xbffff6b4: 0xbffff828 0xbffff84a 0xbffff850 0xbffff857 0xbffff6c4: 0xbffff85d 0x0 (gdb) x/s 0xbffff828 0xbffff828: "/home/liuxingen/station/asm/hello" (gdb) x/s 0xbffff84a 0xbffff84a: "first" (gdb) x/s 0xbffff850 0xbffff850: "second" (gdb) x/s 0xbffff857 0xbffff857: "third" (gdb) x/s 0xbffff85d 0xbffff85d: "fourth" |
上面是argv[]数组的输出,argv[]后面紧接着就是一个NULL。
(gdb) x/3wa 0xbffff6cc 0xbffff6cc: 0xbffff864 0xbffff930 0xbffff940 (gdb) x/s 0xbffff864 0xbffff864: "MANPATH=/usr/local/share/man:/usr/share/man:/usr/share/binutils-data/i686-pc-linux-gnu/2.21.1/man:/usr/share/gcc-data/i686-pc-linux-gnu/4.4.5/man:/usr/share/postgresql/man/:/usr/share/postgresql-9.0/m"... (gdb) x/s 0xbffff930 0xbffff930: "SHELL=/bin/bash" (gdb) x/s 0xbffff940 0xbffff940: "TERM=xterm" |
上面是envp[]数组的部分输出。
(gdb) x/s 0xbffffffc 0xbffffffc:"" (gdb) x/s 0xbffffff6 0xbffffff6: "hello" |
上面是栈底的最后两个数据,一个是NULL,一个是程序的名称。Linux的32位系统中栈底的位置固定为0xc0000000。