簡體   English   中英

GCC 內聯匯編 intel 語法“錯誤:寄存器使用無效”

[英]GCC inline assembly intel syntax “Error: invalid use of register”

我決定嘗試在 c 中為我的基本操作系統使用內聯匯編(使用 intel 語法,因為我習慣於使用 NASM)。 我遇到了一些我無法解決的問題,我試着到處尋找,但沒有任何效果。 在嘗試錯誤消息后顯示的代碼時,GCC 顯示以下消息:

main.c: Assembler messages:
main.c:8: Error: invalid use of register

代碼是:

int main(){
    asm("mov ah, 0x00\n\t");
    asm("mov al, 0x13\n\t");
    asm("int 0x10\n\t");
    asm("mov bx, 0xA000\n\t");
    asm("mov es, bx\n\t");
    asm("mov di, 0\n\t");
    asm("mov byte [es:di], 0x0f\n\t"); // Problem line of error.
    while(1){
        asm("nop");
    }
    return 0;
}

有人能幫我嗎?

關於這一點有很多要提到的。 首先,您使用的是 Intel 語法,這很好(至少對於 GCC,clang 更難)。 您可以在編譯時使用-masm=intel ,或者在 asm 模板中作為.intel_syntax noprefix的 hack 開關,然后在 asm 字符串的末尾切換回.att_syntax ,這樣編譯器代碼的 rest 仍然有效。 如何設置 gcc 永久使用 intel 語法?

接下來,你有很多asm()塊。 最好有一個,因此您可以為整個塊指定輸入/輸出/clobbers/goto。 這可以很容易地完成,因為 C 連接了相鄰的字符串。

您的代碼中有 NASM 風格的[es:di] 在 GAS 的 Intel 語法方言中,段名稱位於方括號之外: es:[di] 我還注意到,除非您使用 16 位架構,否則[di]並不合適。 方括號中的東西必須是平台上指針的大小......

...但是您也在使用int 0x10 ,這是一個 BIOS 中斷,所以我猜測 16 位實際上是您想要的。

盡管如此,您確實需要養成指定clobbers的習慣。 即指定你的代碼修改了哪些寄存器,是否修改了條件碼寄存器和memory。 編譯器正在決定將哪些變量保存在寄存器等中,並且不知道您的匯編代碼做了什么。 您必須告訴它您正在修改,例如ax ,所以它知道並可以保存/恢復它。

GCC 並不真正了解分段(它是一個便攜式編譯器,假定一個平坦的ds es ,不專門研究 x86 到 16 的不同基礎,所以不安全) 例如 GCC 可能會選擇使用rep stosd來初始化結構或數組。 這里很安全,因為您在 asm 之后的代碼很少。

這是我對您的代碼的重寫。

int main()
{
    asm volatile(
        ".intel_syntax noprefix\n\t"
        "mov ah, 0x00\n\t"
        "mov al, 0x13\n\t"
        "int 0x10\n\t"
        "mov bx, 0xA000\n\t"
        "mov es, bx\n\t"
        "mov di, 0x00\n\t"
        "mov byte ptr es:[di], 0x0f\n\t"
        ".att_syntax"                      // undo .intel_syntax
        : /* output operands */
        : /* input operands */
        : "ax","bx","di","cc", "memory" /* clobbers */
    );
    while(1){
        // asm("nop");  // unneeded: empty infinite loops are already legal in C.
    }
    return 0;
}

如果您的代碼修改甚至讀取了您也通過 C 指針訪問的 memory,那么您還將在 clobbers 行中包含"memory" 請參閱gcc 的內聯匯編文檔,以及如何指示可以使用內聯 ASM 參數指向的 memory *pointed*?

volatile在這里不是絕對必要的,因為沒有 output 操作數,asm 語句是隱式的volatile 但是最好包含volatile以明確(對人類讀者)存在可見的副作用(BIOS 調用和存儲到視頻內存)。 因此,如果您確實包含了 output 操作數,它就不會被優化掉。

附錄:一般情況下,使用-masm=intel進行編譯,而不是在清單中使用.intel_syntax 這讓編譯器在替換操作數時使用正確的語法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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