一些編譯器,如舊的 gcc 或 egcs,對單個檔案中的靜態函式應用 ABI 破壞優化,例如傳遞引數或使用任意暫存器回傳結果。
考慮一些源代碼,例如:
// Original foobar.c
// This example targets MIPS o32 ABI.
// Shared subroutine
// Compiler decided to use $16, $17 to pass a0 and a1 to minimize stack usage and move between registers.
static void __bar(int a0, int a1) {
// Something very complicated
}
// ...
void foo(int a0, int a1) {
// ...
/*
This call was compiled to something like:
ori $16, $0, 0x1
jal __bar
ori $17, $0, 0x1
*/
__bar(1, 1);
// ...
}
// ...
假設有人想從已編譯的程式集中恢復/重新實作 foobar.c 而無需訪問原始源。
有人可能想先反編譯/重寫某些部分,例如從 foo() 或其他標準函式開始。但是,為了測驗實作的正確性,必須處理對非標準 ABI 例程的呼叫。
一個簡單的方法是使用 gcc / clang 提供的全域暫存器變數來解決:
// Restoration of foobar.c
// void __bar(int asm("s0"), int asm("s1"))
// External function in assembly, says foobar.s, which is from compiled original foobar.c.
void __bar();
volatile register int s0 asm ("s0"); // $16 = s0
volatile register int s1 asm ("s1"); // $17 = s1
// ...
void foo(int a0, int a1) {
// ...
// __bar(1, 1);
s0 = 1; s1 = 1;
__bar();
// ...
}
// ...
問題是:
- gcc / clang 是否支持為某些特定功能自定義呼叫約定?
- 有什么方法可以更優雅地處理非標準 ABI 呼叫?
uj5u.com熱心網友回復:
- gcc / clang 是否支持為某些特定功能自定義呼叫約定?
您可以做的最好的事情是選擇一種特定的支持呼叫約定,例如其中一種用于 x86。如果有static問題的功能不符合其中任何一個,那么你就卡住了。
- 有什么方法可以更優雅地處理非標準 ABI 呼叫?
沒有什么真正優雅的。如果沒有任何受支持的呼叫約定適用,則您會遇到以下任何一種情況:
- 反轉和重建整個事物(因此它可以正常編譯而不依賴于原始二進制檔案),或者至少足以讓您完全替換符合 ABI 的函式及其所有依賴項,或者
- 從程式集中呼叫它,根據編譯函式的非標準呼叫約定顯式傳遞引數。
#2 是最優雅解決方案的基礎,它基本上是在匯編中撰寫一個包裝函式,它接收引數并根據 ABI 回傳值,否則什么都不做,只是重新排列它們以傳遞給它的非標準函式換行(如果沒有按照正常規則回傳,則可能修復回傳值)。您撰寫了一次包裝器,現在您的其余代碼可以用 C 撰寫,呼叫遵循 ABI 的包裝器函式并且幸福地不知道幕后的怪異。
同樣,如果您嘗試用另一個替換現有的非標準函式,您將在匯編中撰寫不符合要求的包裝器,然后用純 C 撰寫替換函式并讓包裝器呼叫它,然后交換您的包裝器在原始二進制檔案和新代碼的混合中。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/487811.html
下一篇:C系統()函式
