我正在尝试使用BIOS中断来读取硬盘扇区,使用以下代码:
int readSec(char sector, unsigned char out[]) {
char error = 0;
int address = (int)out;
__asm__ __volatile__("xorw %ax, %ax;" //clear all registers
"xorw %bx, %bx;"
"xorw %cx, %cx;"
"xorw %dx, %dx;");
__asm__ __volatile__("movw $0x00, %%ax; movw %%ax,%%es;" //clear the memory location that the sector will be read into
"movw $0x0000, %%ax;"
"movw $512, %%cx;"
"movw %w0, %%di;"
"rep stosw;"::"b" (address));
__asm__ __volatile__(
"movb $0x02, %%ah;" //read the sector
"movb $0x01, %%al;"
"movw %w2, %%bx;"
"movb %b1, %%cl;"
"int $0x13;"
"sbb %w0, %w0;": "=r" (error): "m" (sector), "m" (address));
return error;
}
运行此代码时,没有任何反应。
为了调试代码,我查看了反汇编代码,令我惊讶的是,“address”变量从未被复制到
di
- 而是复制了一个空寄存器。以下是函数的反汇编(右侧)和函数本身(左侧):
如图所示,bx
寄存器被清零(就像在第一个汇编块中一样),然后在到达movw %w0, %%di
行时,它只是使用了被清零的bx
寄存器mov %bx,%di
。为什么GCC要这样做呢?显然,将空寄存器的值复制到di
中不会复制address
到其中...编辑:我正在使用GCC编译此代码,并在虚拟机中运行它。这不是所有的代码,我只想知道为什么要将空寄存器复制到
%di
中。编辑2:如nos建议,我已从
(int) & out;
中删除了&符号。
gcc -m32 -S
命令输出的代码,然后在16位模式下进行了组装。(32位指令有操作数大小和/或地址大小前缀,而16位指令则没有。)这种方法可能仍然有效,但默认栈宽度将无法匹配,因此函数将无法在正确的位置找到它们的参数。 - Peter Cordes