2011-04-05 57 views
1

在我的C代碼中有一些內聯程序集調用PCI BIOS服務。現在問題是其中一個結果返回%ah寄存器,但我找不到引用該寄存器的常量。任何約束來引用gcc內聯彙編中的寄存器的高一半?

我想要的是編寫類似以下內容:

asm("lcall *%[call_addr]" : "something here"(status) :); 

和可變status包含%ah寄存器的值。

如果我使用"=a"(status)並添加mov %%ah, %%al指令它會工作。但它看起來很醜。

有什麼建議嗎?

回答

0

我不認爲有一種方法可以在約束中指定%ah - GCC x86後端知道子寄存器包含值的特定部分,但並不真正將它們視爲獨立實體。

您的方法可行;另一種選擇是將status向內移入彙編程序外。例如這樣的:

unsigned int foo(void) 
{ 
    unsigned int status; 

    asm("movb $0x12, %%ah; movb $0x34, %%al" : "=a"(status) :); 
    return (status >> 8) & 0xff; 
} 

...實現(status >> 8) & 0xff作爲一個單一的movzbl %ah, %eax指令。

第三種選擇是使用一個小的結構:

unsigned int bar(void) 
{ 
    struct { uint8_t al; uint8_t ah; } status; 

    asm("movb $0x12, %%ah; movb $0x34, %%al" : "=a"(status) :); 
    return status.ah; 
} 

我不知道這是否是漂亮與否 - 它似乎多了幾分自我記錄,而是使用一個小的結構與寄存器約束看起來不太明顯正確。但是,它會生成與上面的foo()相同的代碼。

(免責聲明:代碼生成僅用gcc 4.3.2測試;結果可能在其他版本上有所不同)。

+0

感謝您的幫助。在這篇文章之前,我已經嘗試了兩種解決方案。對於你的第三個選擇,我使用了一個聯盟,我認爲它會有更好的外觀。這些解決方法的一個常見問題是它們需要額外的代碼,使封裝函數相當長。我認爲在找到更好的方法之前,必須保持現有的方法。 – hpsMouse 2011-04-08 11:00:28