2013-11-25 46 views
1

我看慣了的(約定(A))引用的命令行參數:GCC:在彙編代碼中引用不同的命令行參數

pushl %ebp 
movl %esp, %ebp 
movl (%ebp), %eax # argc 
movl 4(%ebp), %ebx # pointer to argv[0] string  
movl 8($ebp), %ecx # pointer to argv[1] string 

有時候,我見過的名單開始在偏移8,這不是(主要)問題。我也注意到程序是這樣的翻譯和參考,我感到困惑,讓argv[1](約定(B)):

movl 0xc(%ebp), %eax # pointer to a pointer to argv[0] (argc is at offset 8) 
addl $0x4, %eax # argv[1] is a pointer at offset 4 from the pointer to argv[0] 
movl (%eax), %eax # load where it points to, which is the argv[1] string 

(在offset 16(%ebp)我看到一個指向環境變量)

(1)這種不同的約定有什麼理由嗎?
(2)有沒有一個編譯器選項來強制gcc使用我認爲是上面的標準約定(A)?
(3)gcc使用約定(B)有什麼原因嗎?
(4)爲什麼8的附加偏移?

系統信息:
- Ubuntu的12.04
- GCC 4.6.3
- 與FNO堆棧保護器

+0

你從哪裏得到你的約定一個代碼? AFAICT這是不正確的,因爲(在這種情況下)偏移'4(%ebp)'是'argv'本身,而不是'argv [0]'。在'8(%ebp)'是'envp'(環境塊)。 –

+1

另外(增加一個新的註釋,因爲編輯看起來是bork'd),8的偏移量是因爲在執行'movl%esp,%ebp'時,堆棧中的前兩個項目是'%ebp',並且返回地址 - 每個是4個字節,因此是8個字節的偏移量。 –

+0

@德魯McGowen:約定A是你會看到在任何彙編教程/書/類,並且它工作正常,當我用gcc代碼組裝氣體。至於8,如果這是主要的,爲什麼要存儲一個ret地址? (推動ebp的4人對我來說很愚蠢,應該已經注意到了)。 – gnometorule

回答

1

如果你處理的是已被鏈接到C運行時程序編譯,那麼argcargv參數通過(假設x86)argcebp+8argvebp+12。這是因爲C運行時執行它自己的初始化並使用正常的C ABI將參數傳遞給main()

調用約定,你說你已經習慣了看到(在堆棧的頂部argc,其次是argv[0] .. argv[argc])是堆疊的由Linux系統調用設置的狀態開始新程序。

注意你的彙編代碼導向例如:

pushl %ebp 
movl %esp, %ebp 
movl (%ebp), %eax # argc 
movl 4(%ebp), %ebx # pointer to argv[0] string  
movl 8($ebp), %ecx # pointer to argv[1] string 

看起來是關閉的4對每個由於初始pushl指令的最後三行。

+0

感謝您澄清,如果我第一次pushl%ebp,那麼我輸入的內容就會失效。 – gnometorule

+0

最後一行不應該是'$'''是'%'嗎? – Addison

+0

哦,還有,這對64個ASM來說還是這樣嗎?或者'argc'在'rbp + 16','argv'在'rbp + 24'? – Addison