簡體   English   中英

在 Turbo C++ 內聯匯編中使用 32 位寄存器,如 EAX

[英]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 popes移動到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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM