2013-08-28 38 views
1

如果我有一個函數foo(arg1,arg2)。在IA32堆棧中,首先推入arg2,然後推入arg1,這樣被調用函數通過%ebp + 8訪問arg1並通過%ebp + 12訪問arg2,但是推回的原因是什麼? (我們的處理器提到了一些關於printf和count的內容,但我不太明白)。另外一般來說,調用函數從不傳遞參數的數量(有多少個參數),那麼被調用函數怎麼知道呢? 非常感謝!爲什麼在IA32堆棧過程中向後傳遞參數?

+1

這只是C調用約定。 C支持具有可變數量參數的函數,main()和printf()是常見的例子。通過將它們「向後」傳遞,第一個參數總是在已知位置。 –

+2

被調用者將「知道」有多少個參數,因爲*編譯器*在編譯時知道並且看到保留適當數量的堆棧空間並生成代碼來訪問這些值。任何數量的var-args都會隱式轉換爲單個*數組*(加上數組的長度),並作爲參考傳遞給被調用者。 – JimmyB

+0

而在C約定中,參數的可變數總是第一個?這是有道理的。然而,如果你按照正常順序推動它們,你也會知道「參數的數量」總是最後一個,對吧? – user1849043

回答

1

在彙編層面,如果您以書面或倒序的方式在堆棧上傳遞參數並不重要,但所選方法必須與被調用函數所使用的方法相同。 C通常以相反的順序推送值,因爲它需要支持varargs - 可變數量的參數。如果按照書面順序推送參數,那麼得到第一個參數並不容易。

像Java或C#(以及.NET一般)等現代語言可以正常推送值,因爲它們處理數組的附加參數(所以只有一個參數傳遞給被調用的函數 - 指向數組的指針)。

C的例子:

.data 
format: db "Your lucky number is %d", 0 
.... 

;code is equivalent to printf("Your lucky number is %d", 10); 
push dword 10 
push format 
call printf 

Java示例:

0: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
3: ldc   #3     // String Your lucky number is %d 
5: iconst_1 
6: anewarray  #4     // class java/lang/Object 
9: dup 
10: iconst_0 
11: bipush  10 
13: invokestatic #5     // Method java/lang/Integer.valueOf(I)Ljavava/lang/Integer; 
16: aastore 
17: invokevirtual #6     // Method java/io/PrintStream.printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; 
20: pop 
+0

「推10」從哪裏來? – user1849043

+0

這是要打印的號碼。 – user35443