對於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
.text
.global _start
_start:
nopnop
nopmovl $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>
eflags 0x212 [ af if ]
(gdb) x/6xw 0xbfd1dfe0 //讀取堆疊暫存器6個位元組(前5個位元組有效)
得出結論:傳入的命令列引數,會把引數個數、檔案名字所在位址、引數所在位址壓入堆疊esp。
2、實現彙編呼叫c語言函式,**彙編和c函式引數如何傳遞:
**:[root@localhost]# cat test.s
.text
.global _start
.global print_argv
_start:
nopmovl $2, %eax
pushl %eax //把2壓入棧
call main
movl $0, %ebx # 傳給_exit的引數
movl $1, %eax # 系統呼叫號,_exit
int $0x80
[root@localhost]# cat test.c
#include#includeint main(int argc,int argv)
編譯執行:
[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#includeint main(int argc,char *argv)
{ int i=0;
for(i=0;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函式的引數(一)
以下 全都在linux gcc上執行 在c語言程式設計中,函式非常常見。main 也是一種函式,而且c程式總是從main函式開始執行。為什麼呢?來看 unix環境高階程式設計 中的一段話 核心執行c程式時,在呼叫main前先呼叫乙個特殊的啟動例程。可執行程式檔案將此啟動例程指定為程式的起始位址 這是...
main函式的引數(一)
以下 全都在linux gcc上執行 在c語言程式設計中,函式非常常見。main 也是一種函式,而且c程式總是從main函式開始執行。為什麼呢?來看 unix環境高階程式設計 中的一段話 核心執行c程式時,在呼叫main前先呼叫乙個特殊的啟動例程。可執行程式檔案將此啟動例程指定為程式的起始位址 這是...
main函式的入口函式
作業系統裝載程式之後,首先執行的 並不是main的第一行,而是某些別的 這些 負責準備好main函式執行所需要的環境,並且負責呼叫main函式,執行這些 的函式稱為入口函式或入口點 entry point 視平台的不同而有不同的名字。程式的入口點實際上是乙個程式的初始化和結束部分,它往往是執行庫的一...