2017-09-10 254 views
0

我在寫一個內聯彙編代碼來讀取實時時鐘。我正在加載寄存器編號(4)以讀取到'dl'並將其加載到端口0x70。我正在嘗試將這個寄存器值(4)讀入al。欲瞭解更多信息 - RTCGNU彙編語法

asm(
"mov $4, %%dl;" 
"out 0x70, %%dl;" 
"in %%al, 0x71;" 
: 
: 
:"%al","%dl" 
); 

我正在上編譯包含該代碼的C文件下面的錯誤消息。

Assembler messages:

Error: operand size mismatch for 'out'

Error: operand size mismatch for `in'

彙編器版本:使用BFD版(GNU Binutils的Ubuntu的)GNU彙編版本2.26.1下(x86_64-Linux的GNU)2.26.1

是否有人可以指出的問題?

+3

根據猜測,錯誤信息是由於在常量前沒有'$'。也就是說,如果你想讓你的asm輸出一個值,你需要有一個輸出參數(在第一個冒號後面)。如果在運行Ubuntu時可以使用'in'或'out',我會感到很驚訝。在閱讀RTC之前,你不應該「cli」嗎?如果你正在構建16位代碼,我不確定使用64位編譯器是否可行。如果你想在啓動時讀取RTC,那麼[this](https://stackoverflow.com/q/46074535/2189500)。 –

+2

AT&T語法通常在右側有目的地。我希望對於IN和OUT指令也是如此。 IN 0x71,%% al'? –

+0

@DavidWohlferd在給予自己使用'iopl()'或'ioperm()'系統調用的權利後,你可以使用'in'和'out'。 – fuz

回答

4

存在一些問題。首先,inout都只能在A寄存器(al,ax,eax,rax)上運行。其次,操作數順序是錯誤的,第三,立即數必須以AT & T語法中的$作爲前綴。在普通的裝配,你的代碼應該是這樣的:

mov $4,%al 
out %al,$0x70 
in $0x71,%al 

所以,你糾正裝配將

asm(
"movb $4, %%al;" 
"outb %%al, $0x70;" 
"inb $0x71, %%al;" 
: 
: 
:"%al" 
); 

請注意,我已經加入明確的大小後綴,以幫助鐺組裝此代碼。我建議你進一步改變該代碼使用正確的擴展內聯彙編:

unsigned char result; 
volatile asm("outb %1,$0x70; inb $0x71, %0" : "=a"(result) : "a"((char)4)); 

這可能使GCC產生稍微好一點的代碼。例如,它允許gcc內聯這些代碼。此外,你可以考慮使用來自<sys/io.h>inb()outb()宏來完全避免內聯彙編。這通常是一件很好的事情。

+0

謝謝你的詳細解答。你能指點我一個關於內聯彙編的AT&T語法的綜合指南,以便避免這種語法錯誤嗎? – SilentMonk

+0

@SilentMonk閱讀GNU彙編程序的手冊。 – fuz

+0

您還應該獲得一個很好的指令集引用,它會告訴您沒有dl作爲源的out指令。我使用英特爾手冊(https://software.intel.com/zh-cn/articles/intel-sdm)。 – prl