(一)main函数的argc、argv实现本质
2013-11-09 15:16
351 查看
对于main函数的argc和argv作用:
[root@localhost valgrind_test]# ./test a b
则argc=2,argv[0]="./test ",argv[1]="a",argv[2]="b"
现在讨论这个实现原理:分为几步骤分析:
1、首先编写一个什么事情都不做的汇编文件,看看传入的命令行参数对于汇编而言是如何处理的:
[root@localhost]# cat test.s
编译文件:
[root@localhost ]# as -g -o test.o test.s
[root@localhost]# ld -o test test.o
调试文件:
root@localhost]# gdb test
得出结论:传入的命令行参数,会把参数个数、文件名字所在地址、参数所在地址压入堆栈esp。
2、实现汇编调用C语言函数,探讨汇编和C函数参数如何传递:
代码:
[root@localhost]# cat test.s
[root@localhost]# cat test.c
编译运行:
[root@localhost]# gcc -nostartfiles -o test test.c test.s
[root@localhost]# ./test 2 2 2
0x2,0x4
得出结论:调用C函数,实际传入的实参就是esp堆栈出栈得到的。
3、实现main的argc和argv:
[root@localhost]# cat test.s
[root@localhost valgrind_test]# cat test.c
编译运行:
[root@localhost]# gcc -nostartfiles -o test test.c test.s
[root@localhost valgrind_test]# ./test 2 2 2
[0]:./test
[1]:2
[2]:2
[3]:2
示意图:
最后一个问题,实际gcc编译一个C文件的时候,都是把包含main的C文件编译为.o文件,然后和其他文件的.o进行链接,其中就包括类似前面汇编功能的文件,所以实际argc和argv的功能实现是在编译器帮我们完成了。
[root@localhost valgrind_test]# ./test a b
则argc=2,argv[0]="./test ",argv[1]="a",argv[2]="b"
现在讨论这个实现原理:分为几步骤分析:
1、首先编写一个什么事情都不做的汇编文件,看看传入的命令行参数对于汇编而言是如何处理的:
[root@localhost]# cat test.s
.text .global _start _start: nop nop nop movl $0, %ebx # 传给_exit的参数 movl $1, %eax # 系统调用号,_exit int $0x80
编译文件:
[root@localhost ]# as -g -o test.o test.s
[root@localhost]# ld -o test test.o
调试文件:
root@localhost]# gdb test
(gdb) b 7 //设置断点,在nop语句 Breakpoint 1 at 0x8048056: file test.s, line 7. (gdb) r 2 2 2 //命令行参数,相当于./test 2 2 2 Starting program: /home/long/valgrind_test/test 2 2 2 //注意,这里是绝对路径!不是相对路径(不是./test) Breakpoint 1, _start () at test.s:7 7 nop Current language: auto; currently asm (gdb) i r //打印寄存器的值 eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbfd1dfe0 0xbfd1dfe0 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048056 0x8048056 <_start+2> eflags 0x212 [ AF IF ] (gdb) x/6xw 0xbfd1dfe0 //读取堆栈寄存器6个字节(前5个字节有效) 0xbfd1dfe0: 0x00000004 0xbfd1fbd2 0xbfd1fbf0 0xbfd1fbf2 0xbfd1dff0: 0xbfd1fbf4 0x00000000 (gdb) x/40c 0xbfd1fbd2 //堆栈第一个字节存放命令行参数的个数(包括文件名字),这里是4。接下来的字节就是这些参数的存放的地址,包括:"/home/long/valgrind_test/test"、"2"、"2"存放的地址: 0xbfd1fbd2: 47 '/' 104 'h' 111 'o' 109 'm' 101 'e' 47 '/' 108 'l' 111 'o' 0xbfd1fbda: 110 'n' 103 'g' 47 '/' 118 'v' 97 'a' 108 'l' 103 'g' 114 'r' 0xbfd1fbe2: 105 'i' 110 'n' 100 'd' 95 '_' 116 't' 101 'e' 115 's' 116 't' 0xbfd1fbea: 47 '/' 116 't' 101 'e' 115 's' 116 't' 0 '\0' 50 '2' 0 '\0' 0xbfd1fbf2: 50 '2' 0 '\0' 50 '2' 0 '\0' 72 'H' 79 'O' 83 'S' 84 'T'
得出结论:传入的命令行参数,会把参数个数、文件名字所在地址、参数所在地址压入堆栈esp。
2、实现汇编调用C语言函数,探讨汇编和C函数参数如何传递:
代码:
[root@localhost]# cat test.s
.text .global _start .global print_argv _start: nop movl $2, %eax pushl %eax //把2压入栈 call main movl $0, %ebx # 传给_exit的参数 movl $1, %eax # 系统调用号,_exit int $0x80
[root@localhost]# cat test.c
#include<stdio.h> #include<stdlib.h> int main(int argc,int argv) { printf("0x%x,0x%x\n",argc,argv); return 0; }
编译运行:
[root@localhost]# gcc -nostartfiles -o test test.c test.s
[root@localhost]# ./test 2 2 2
0x2,0x4
得出结论:调用C函数,实际传入的实参就是esp堆栈出栈得到的。
3、实现main的argc和argv:
[root@localhost]# cat test.s
.text .global _start .global print_argv .type _start,@function _start: movl %esp, %eax //得到栈顶地址 addl $4, %eax //栈顶地址+4,也就是栈的第二个元素地址,也就是上图0xbfd1fbd2存放地址(&argv[0]) pushl %eax //压栈 movl 4(%esp),%eax //栈顶地址+4的内容压栈,也就是argc的值 pushl %eax call main movl $0, %ebx # 传给_exit的参数 movl $1, %eax # 系统调用号,_exit int $0x80
[root@localhost valgrind_test]# cat test.c
#include<stdio.h> #include<stdlib.h> int main(int argc,char *argv[]) { int i=0; for(i=0;i<argc;i++) printf("[%d]:%s\n",i,argv[i]); }
编译运行:
[root@localhost]# gcc -nostartfiles -o test test.c test.s
[root@localhost valgrind_test]# ./test 2 2 2
[0]:./test
[1]:2
[2]:2
[3]:2
示意图:
最后一个问题,实际gcc编译一个C文件的时候,都是把包含main的C文件编译为.o文件,然后和其他文件的.o进行链接,其中就包括类似前面汇编功能的文件,所以实际argc和argv的功能实现是在编译器帮我们完成了。
相关文章推荐
- main函数的参数:argc和argv
- main函数中argc,argv作用
- 关于main函数中argc和argv的简单介绍
- main函数中argc,argv说明
- main函数中的argc和argv是什么意思?
- main函数,输入参数argc,argv
- Main函数中的argc和argv应用举例
- C++ main函数中参数argc和argv含义及用法
- main函数中argc的区别argv
- 关于main函数中argc和argv的简单介绍
- Main函数中的argc和argv应用举例
- main函数中的argc和argv
- main函数的参数(argc和argv)
- 深入Main函数中的参数argc,argv的使用详解
- 关于main函数的argc和argv参数
- 如何在main函数外获取main函数的参数(argc、argv)
- argc和argv在main函数中的应用,及unistd.h
- main函数中argc和argv含义
- Main函数中的参数argc,argv的使用详解