使用者程式函式呼叫過程中的引數傳遞方式
阿新 • • 發佈:2019-01-27
在C語言中,在呼叫一個函式func()時,如果func()接受不超過4個的引數,則呼叫者直接將實參從左到右依次賦值給r0, r1, r2, r3暫存器(如果是指標則傳入地址),然後呼叫func()。
進入func()函式後,func()將自己的棧緊接著caller的棧頂向下擴充套件,從r0, r1, r2, r3暫存器中拿引數,然後開始做事。
而如果func()有超過4個引數,例如:
int func(int a, int *b, int c, int d, struct sh_info * e, int f) {}
則前4個引數仍然通過暫存器傳遞,其餘引數e和f則放在棧裡面讓func()來取。就如下圖:
也就是說,caller函式在呼叫func()之前,將引數e和f放到自己棧頂的位置。在編譯階段caller函式知道在函式棧裡為這兩個引數留出空間,而func()也根據自己引數列表的數量知道有8bytes的arg要從棧裡面去拿。
所以存放參數的棧空間是由caller函式開闢的,因為caller才知道自己是如何傳參的,尤其對於可變長引數的函式,如printf,caller函式將所有引數入棧,callee函式通過格式化字串或va_arg來判斷需要處理的引數個數。
雖然引數在caller的棧空間,但由於緊挨著func()的棧底,所以通過fp+4和fp+8就能獲取e和f兩個引數存放的位置。
引數壓棧順序是按引數列表從右至左(也可以這樣記,如果按順序e和f用r4, r5存放,也符合ARM中壓棧時大數值暫存器位於高地址的規律)。
-