[英]Convert inline assembly code to C++
我正在研究一個cpp項目。 該項目需要遷移到64位。 它包含一些無法在x64上編譯的內聯匯編代碼。 這是包含匯編代碼的函數:
void ExternalFunctionCall::callFunction(ArgType resultType, void* resultBuffer)
{
#if defined(_NT_) || defined(__OS2__)
// I386
// just copy the args buffer to the stack (it's already layed out correctly)
int* begin = m_argsBegin;
int* ptr = m_argsEnd;
int arr[1000], i=0;
while (ptr > begin) {
int val = *(--ptr);
__asm push val
}
void* functionAddress = m_functionAddress;
// call the function & handle the return value. use __stdcall calling convention
switch (resultType) {
case voidType:
__asm {
call functionAddress
}
break;
case pointerType:
case int32Type:
__asm {
call functionAddress
mov ebx, resultBuffer
mov dword ptr [ebx],eax
}
break;
case floatType:
__asm {
call functionAddress
mov ebx, resultBuffer
fstp dword ptr [ebx]
}
break;
case doubleType:
__asm {
call functionAddress
mov ebx, resultBuffer
fstp qword ptr [ebx]
}
break;
}
我使用stack,array來遷移這個“asm push val”但是沒有用。 雖然,它不會拋出任何編譯錯誤,但邏輯沒有奏效。
所以,我想問一下,我可以在C ++中使用什么而不是“__asm push val”。 任何幫助將不勝感激。
這個問題一般無法解決; 那是因為評論,
// call the function & handle the return value. use __stdcall calling convention
表示依賴於32位呼叫約定 。
在32位x86中, stdcall
意味着所有參數都以相反的順序傳遞給堆棧(即最后一個arg被推送。也就是說,如果arg[0]
在addr
然后是arg[1]
,無論它的類型是什么,在addr + sizeof(arg[0])
)。 這就是您的示例中以下代碼的原因:
// just copy the args buffer to the stack (it's already layed out correctly)
int* begin = m_argsBegin;
int* ptr = m_argsEnd;
int arr[1000], i=0;
while (ptr > begin) {
int val = *(--ptr);
__asm push val
}
實際上可以工作 - 因為它究竟是什么並不重要,參數是什么類型的; 所有相關的是它們中的每一個都在一個已知的存儲位置,並且已知在內存中是連續的。 如果你知道參數N
在addr
,那么你可以知道參數N+1
在addr + sizeof(arg[N])
。
這就是評論所說的“ 它已經正確布局 ” - 不幸的是,這在64位模式下並非如此。 因此代碼不能“移植”; 沒有相當於港口的。
調用至少部分基於寄存器的約定 - 就像x64(64位x86)上的Win64一樣,表現不同。 對於那些,它取決於被調用函數采用什么類型的參數(在Windows中,您可以在通用寄存器中傳遞四個整數類型的參數,在XMM
寄存器中傳遞一些浮點類型的參數)。 因此,您需要了解更多關於您調用的函數的簽名(原型),而不僅僅是“它需要N
參數”,以便能夠正確地編組來自“anycall”類型包裝器的args,如上所述。 在64位模式下,對於您希望通過包裝器調用的每個函數,您不僅需要知道總共有多少個args,還需要知道通用注冊中有多少個, XMM
多少個,以及如何很多在堆棧上。
“通過指針調用func並將返回值復制到已知位置”部分是可移植的,可以用普通的C / C ++表示。 但是,如上所述,獲得此參數的部分並沒有以任何直接的方式在32位stdcall
和我所知道的任何64位x86調用約定之間移植 (Win64 / x64和UN * X x86_64
約定都不允許預測兩者給定函數的所有參數的位置和總堆棧內存使用量,只給出了args的數量和類型,但沒有給出它們的順序)。
您需要做什么更多地取決於上述class ExternalFunctionCall
的調用者/用戶,而不是您所顯示的內聯匯編的小樣本。 特別需要知道如何初始化成員m_argsBegin
和m_argsEnd
以及在何處。 您能否提供一些關於類的外觀(所有成員變量/函數)的詳細信息,以及實際使用的示例?
有幾件事你需要解決。 (我在另一個問題上查找了你的代碼)。 據我所知,這段代碼是一個包裝器,用於調用位於指定地址的相當抽象的函數,該函數需要堆棧中的一定數量的數據,並且可以返回基於ArgType的不同內容。
如果你想通過普通的C包裝它,你必須定義幾個函數原型(基於返回值)然后在你的開關上使用,但是你必須解決另一個問題,這是更棘手的。
在C中移植這類東西的問題在於,您不必預先知道必須推入堆棧的參數(數據大小),因此您將難以定義原型。
假設func(char c)肯定會推入堆棧1字節(但由於數據對齊也不一定正確)..在你的情況下,你必須考慮解決方案,它將具有與數據大小相同的參數集你需要在堆棧上。 乍一看,你不能馬上做什么。
UPD。 你可以用func(char [] param)來做; 但它也有上面回答中解釋的問題。
我意識到這是一個有點老問題,但我偶然發現: xbyak 。
也許你在尋找什么?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.