預告
今天的文章主要是延續之前有關呼叫約定的主題,接下來我們要講述的內容,對於我們後面的一些討論議題會比較有幫助。有個需要注意的地方是:在眾多的硬體平臺上,只有8086和x86平臺存在多個呼叫約定,其他的平臺都只有一個。我們接下來會深入到有關32位呼叫約定的細節,也許很多人都不太關心這個,但是還是值得講一講。
All
在這篇文章裡列出的所有的處理器都是RISC型別,這意味著:處理器上有搭載很多暫存器,這些暫存器都提供通用的功能,而不是某些定製化的功能。這裡有個例外:零值暫存器是直接硬體連線實現的。掛接到暫存器上的功能都受到呼叫約定的影響。
在處理器的早期階段,呼叫指令call會儲存返回地址到一個暫存器,而不是儲存在堆疊上。這其實也是一件好事,因為處理器根本不需要了解堆疊的細節資訊,這個資訊由呼叫約定來指明。
和之前一樣,暫存器或者棧空間被用來傳遞引數和返回值。
你可以注意到,所有針對RISC處理器的呼叫約定基本都是差不多的。但是對於8086和x86平臺來說,它的呼叫約定確實是比較奇怪。
Alpha AXP
Alpha AXP(“AXP”是一個人造的首字母縮寫單詞,實際上它沒有什麼特別的意思),這款處理器搭載了一系列的32位暫存器,其中有一個硬連線的零值暫存器。根據慣例,這些暫存器中有一個是”棧幀”暫存器,還有一個是”返回地址”暫存器,還有另外兩個是和引數傳遞無關的特殊功能暫存器。
當傳遞引數的時候,前面6個引數使用暫存器來傳遞,而剩下的則是透過堆疊來傳遞。如果是一個可變引數,則所有的引數都會使用堆疊來傳遞,這樣它們就可以使用陣列的方式來訪問。
剩下的幾個暫存器都是被保留的,其中一個用來返回值,剩下的13個Scratch暫存器。總的來說,32個暫存器被分類為:1個零值暫存器,1個棧幀暫存器,1個返回值暫存器,2個特殊功能暫存器,6個引數傳遞暫存器,7個保留暫存器,1個返回值暫存器和13個Scratch暫存器。
另外請注意:在Alpha AXP處理器上的函式名稱都是完全未修飾(undecorated)的。
MIPS R4000
前4個引數都透過暫存器a0, a1, a2和a3來傳遞,剩下的則透過堆疊傳遞。更進一步地,在堆疊上還有4個所謂的”死區”,這這個區域可以用來模擬這4個暫存器引數從堆疊來傳遞。它們主要被用在被呼叫函式中,用來將暫存器引數傳遞到堆疊上,這個對於可變引數十分方便。
在MIPS R4000處理器上的函式名稱都是完全未修飾(undecorated)的。
PowerPC
前8個引數透過r3-R10暫存器來傳遞,返回值則透過手動的方式進行管理。至於其他的引數如何,我就記不太清了。在PowerPC處理器上的函式名稱都是修飾(decorated)的。
總結
關於MIPS和PPC這兩種處理器,我不是很熟悉,所以上面有關它們的討論可能不是特別準確,但是我想基本原理的講述應該還是沒啥問題的。
最後
Raymond Chen的《The Old New Thing》是我非常喜歡的部落格之一,裡面有很多關於Windows的小知識,對於廣大Windows平臺開發者來說,確實十分有幫助。本文來自:《The history of calling conventions, part 2》
【來源:漫漫開發路】
宣告:轉載此文是出於傳遞更多資訊之目的。若有來源標註錯誤或侵犯了您的合法權益,請作者持權屬證明與本網聯絡,我們將及時更正、刪除,謝謝。 郵箱地址:[email protected]