![](/img/trans.png)
[英]How can I compile a hybrid (asm, C++) source code into a 32-bit program?
[英]Using 32-bit registers like EAX in Turbo C++ inline asm
我在 Turbo C++ 中寫了一個宏
零件 C++ 程序(僅限宏)
/* @intvar address=0x8f79fff4 */
{
-asm mov cx,08f7h
_asm mov es,cx
-asm mov ax,9000h
-asm mov ds,ax
-asm mov ax,0fff4h
-asm mov si,ax
/* -asm mov cl,0fh */
-asm mov eax,es
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm shl,eax,1
-asm add eax,ds[si]
-asm mov ah,9h
-asm mov al,[eax]
-asm mov bh,0h
-asm mov bl,0h
-asm mov cx,0h
-asm int 10h
}
-asm mov cl,0fh
行導致語法錯誤。
16 off -asm shl,eax,1
。 行-asm mov eax,es
導致錯誤“eax not recognized”
使用 32 位寄存器eax
的 TASM 指令.386P 將不起作用
為什么我不能將0fh
寫入cl
寄存器?
我從未使用過_asm
或-asm
(而且我認為-asm
無效),而是使用了這個:
asm{
// multi line
// assembly code
// in here
};
這在舊渦輪增壓器 C++ 和 Pascal 中也可以正常工作......所以只需擺脫所有-asm
和_asm
,只需將單個asm{
放在 asm 代碼的開頭和}
的末尾。
但是你的代碼有很多語法錯誤!!!
例如到底是什么:
shl,eax,1
它應該是:
shl eax,1
或者更好的是,您可以使用shl eax,16
指令。 立即移位是 186 中的新功能,使用 32 位寄存器的代碼只能在 386 或更高版本上運行。 或者使用 2x 16bit push
和 1x 32-bit pop
將es
移動到eax
的高 16 位,作為將兩個 16 位事物連接到 32 位寄存器中的一種方法。 (不過,在現代 CPU 上相當慢。)
另一個問題是 Turbo C++ 編譯器無法生成帶有 32 位寄存器的代碼,即使在 16 位模式下(至少我的)也是如此。 因此,您確實需要使用不同的編譯器才能使所有這些成為可能。
在項目選項中,您可以檢查 x386 和 x387 指令集,但這不適用於內聯匯編...具有 32 位寄存器的行將引發錯誤(未知eax
或類似的東西)所以您需要重寫代碼以使用16 位寄存器。
另一個問題是您使用了錯誤的十六進制數字格式。
在 C/C++ 中,您需要使用0x0
前綴而不是h
后綴。 所以例如9000h
應該是0x09000
!!!
另一個可能的問題是解決您使用
add eax,ds[si]
您在這里使用 16 位指針,但稍后使用 32 位[eax]
指針。 你確定那是你想要的嗎? 另外,您真的想要進行 32 位加載,而不是僅使用mov ax, [si]
將新的低 16 位合並到 EAX 中嗎? 不同之處在於加法的進位是否傳播到高位,或者該 memory 位置的雙字的上半部分是否非零。
此外,DS 是默認段(BP 或 ESP 除外),那么為什么要在此處明確指定 DS 而不是在[eax]
中? 您無法避免使用 32 位偏移量的 DS 基數。 格式也是這樣的:
add ax,[ds:si]
或者:
add eax,dword[ds:si]
取決於你想做什么。 asm
編譯器(TASM,NASM,...)之間的尋址格式不同,這很麻煩。
此外, asm mov ah,9
在您嘗試使用mov al,[eax]
將 EAX 作為指針取消引用之前修改 EAX 的第二個字節。 如果您在 EAX 中構造一個有效的偏移量(即seg:off
地址的低部分),那么以其他順序執行這兩條指令可能是有意義的。
最后但並非最不重要的一點是,您不保留注冊值,這簡直是個壞主意。 與 MSVC 不同,編譯器會確定您的 asm 使用哪些寄存器並為您保存/恢復它們,您必須將push/pop
語句添加到 asm 代碼的開始/結束,否則您可能會損壞 C/C++ 編譯器生成的寄存器值你的塊周圍的代碼取決於。
並非所有寄存器都需要保留(除非您編寫 ISR 代碼),但應恢復段和索引寄存器。 IIRC ax 保存 asm 函數的返回值(不確定是否也在 TC 中)。
(在 MSVC 中,您可以在 EAX 中保留一個值,然后讓執行從非 void function 的末尾(沒有return
),並且函數的返回值是您在 EAX 中留下的值。當內聯函數包含一個asm{}
塊,但如果這在 TC 中有效,那可能只是因為在 asm 塊之后沒有內聯並且沒有弄亂 AX。)
也看看這個:
在第一個項目符號中有使用 asm 的 TC++ 示例...
這是我剛剛在我的 TC 檔案中找到的另一個示例(使用 x387):
long sin(float a,long b)
{
long alfa=long(a*1000);
long far* ptr=(long far*)0xA000FA00;
ptr[0]=alfa;
ptr[1]=1000;
ptr[2]=b;
asm {
fninit
push es
push di
mov di,0xA000
mov es,di
mov di,0xFA00
fild dword[es:di]
fild dword[es:di+4]
fdivp st(1),st(0)
db 0xD9,0xFE
fild dword[es:di+8]
fmulp st(1),st(0);
fistp dword[es:di]
pop di
pop es
}
b=ptr[0];
return b;
}
我從中推斷出 TC 的尋址語法/格式,因為我根本不記得了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.