2010-09-13 137 views
5

目前我正在編寫一些彙編語言程序。正如一些約定所說的,當我想向調用者返回一些值時,比如說一個整數,我應該將它返回到EAX寄存器中。現在我想知道如果我想返回一個float,一個double,一個枚舉或者一個複雜的結構。如何返回這些類型的值?如何返回複雜的返回值?

我可以考慮在EAX中返回一個指向內存中真實值的地址。但它是標準的方式嗎?

非常感謝~~~

+2

如果你想知道「標準方式」,你需要指定你的平臺。你使用什麼硬件,操作系統和編譯器? – 2010-09-13 19:04:00

+0

@StephenCanon當我發佈這個問題時,我沒有意識到這些是相關的。謝謝。 – smwikipedia 2016-09-20 05:36:26

回答

10

如果調用者是您的代碼,則完全取決於您。如果調用者不受您的控制,您必須遵循現有的慣例或共同制定您自己的慣例。

例如,在x86平臺上,當FPU指令處理浮點運算時,函數的結果作爲FPU寄存器堆棧中的最高值返回。 (如果你知道,x86 FPU寄存器被組織成各種類型的「循環堆棧」)。此時,它既不是float也不是double,它是一個以內部FPU精度存儲的值(可能高於floatdouble),調用者有責任從FPU堆棧頂部檢索該值並將其轉換爲任意值鍵入它的願望。實際上,這就是典型的FPU指令的工作原理:它從FPU堆棧頂部獲取參數,並將結果返回到FPU堆棧。通過以相同的方式實現你的功能,你基本上用你的功能模擬了一個「複雜的」FPU指令 - 這是一種非常自然的方式。

當通過SSE指令處理浮點運算時,您可以選擇一些SSE寄存器用於相同目的(使用xmm0,就像整數使用EAX一樣)。

對於複雜的結構(即大於寄存器或寄存器對的結構),調用者通常會將指針傳遞給函數的保留緩衝區。該函數會將結果放入緩衝區。換句話說,在底層,函數不會真的「返回」大對象,而是將它們構造在調用者提供的內存緩衝區中。

當然,您可以使用此「內存緩衝區」方法來返回任何類型的值,但使用較小的值(即標量類型值)時,使用寄存器比內存位置更有效。這也適用於小型結構。

枚舉通常只是一些整數類型的概念包裝。所以,返回一個枚舉或一個整數沒有區別。

0

通常,您將使用堆棧

+1

使用C ABI您使用堆棧。在C++中,它是未定義的,因此允許編譯器製造商選擇更有效的機制(如果他們想要的話)。 – 2010-09-13 16:15:06

0

如果你打算用C或其他高級語言接口,通常你會接受一個內存緩衝區的地址一個參數給你的函數,並通過填充該緩衝區來返回你的複雜值。如果這只是程序集,那麼你可以使用你想要的任何寄存器來定義你自己的約定,但是如果你有特定的原因(例如性能),通常你只會這麼做。

6

應將雙精度值作爲堆棧中的第一項返回。

這裏是一個C++代碼示例(X86):

double sqrt(double n) 
{ 
    _asm fld n 
    _asm fsqrt 
} 

如果希望手動管理堆棧(節省一些CPU週期):

double inline __declspec (naked) __fastcall sqrt(double n) 
{ 
    _asm fld qword ptr [esp+4] 
    _asm fsqrt 
    _asm ret 8 
} 

對於複雜類型,你應該通過一個指針,或返回一個指針。

+0

如果您說您還需要指定編譯器(版本)和操作系統(使用版本),但您應該爲編譯器指定ABI文檔。這是因爲並非所有的C++編譯器都這樣做。所有的C編譯器都會因爲C ABI定義得很好。 – 2010-09-13 17:49:19

+0

對。它適用於Win32,VC++ 2008.但可能適用於所有VC版本。 – 2010-09-13 17:59:23

1

C99具有複雜的內置數據類型(_Complex)。所以,如果你有一個C99兼容的編譯器,你可以編譯一些函數來返回一個複合體並將其編譯成彙編器(通常使用-S選項)。在那裏你可以看到採取的慣例。

+0

也嘗試'-save-temps'。 – 2010-09-14 04:06:34

2

當您對調用約定或彙編語言有任何疑問時,請用高級語言編寫一個簡單函數(在單獨的文件中)。接下來,讓您的編譯器生成一個彙編語言列表或讓您的調試器顯示「交錯組件」。

不僅列表會告訴您編譯器如何實現代碼,還會顯示調用約定。比張貼到S.O更容易通常速度更快。 ;-)

1

這取決於ABI。例如,x86上的Linux使用Intel386 Architecture Processor Supplment, Fourth Edition中指定的Sys V ABI。

部分功能調用序列部分包含有關如何返回值的信息。簡單地說,在這個API:

  • 函數返回標量或沒有價值的使用%eax;
  • 返回浮點值的函數使用%st(0);
  • 對於返回structunion類型的函數,調用方爲返回值提供空間並將其地址作爲隱藏的第一個參數傳遞。被調用者在%eax中返回此地址。