(一)main函式的argc argv實現本質

2021-06-19 02:11:28 字數 3962 閱讀 7552

對於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 視平台的不同而有不同的名字。程式的入口點實際上是乙個程式的初始化和結束部分,它往往是執行庫的一...