【发布时间】:2020-10-11 16:21:33
【问题描述】:
我正在使用i686-elf-gcc 交叉编译器生成代码以在实模式下运行。
我正在尝试从我的内核中读取一个扇区。我知道这是我的内核所在的位置,在第二扇区,第 0 个驱动器,第 0 个轨道。它构建得很好,但是在我调用 read 之后,sectors_read 仍然是 0。
u8 status;
u8 sectors_read;
read(1, 0, 1, 0, 0, status, sectors_read);
kprint("STATUS: ");
hex_to_ascii(status, num_str_buffer);
kprint(num_str_buffer);
kprint("\nSECTORS READ: ");
num_str_buffer[0] = '\0';
hex_to_ascii(sectors_read, num_str_buffer);
kprint(num_str_buffer);
void read(u8 sector_size, u8 track, u8 sector, u8 head, u8 drive, u8 status, u8 sectors_read)
{
asm volatile("mov $2, %AH");
asm volatile("mov %0, %%AL" : : "r"(sector_size) : );
asm volatile("mov %0, %%CH" : : "r"(track) : );
asm volatile("mov %0, %%CL" : : "r"(sector) : );
asm volatile("mov %0, %%DH" : : "r"(head));
asm volatile("mov %0, %%DL" : : "r"(drive));
asm volatile("int $0x13");
asm volatile("mov %%AH, %0":"=r"(status) : );
asm volatile("mov %%AL, %0":"=r"(sectors_read) : );
}
【问题讨论】:
-
在汇编中编写整个磁盘读取例程可能更容易。 E:这完全是个人喜好,但我发现内联汇编非常容易出错
-
您需要所有这些都成为 one asm 语句的一部分;零保证编译器不会为
"r"(track)操作数选择 AL,例如,覆盖您之前编写的 AL。您也没有告诉编译器您修改的寄存器(缺少一个clobber),所以它完全不安全。这与如何使用 GNU C 内联 asm、阅读教程 (stackoverflow.com/tags/inline-assembly/info) 和/或查看通过编译得到的编译器生成的 asm 正好相反。 -
另请注意,C 中的参数一如既往地按值传递。您似乎期望调用函数中
sectors_read的值将通过对read的调用而改变,但由于它是按值传递的,因此无法更改。因此,无论您在函数之后在其中看到什么值,都与之前在其中的未初始化垃圾值相同。你的编译器应该给你各种关于未初始化变量的警告(如果你打开警告和优化)——注意它! -
顺便说一句,您似乎没有提供将数据读入任何地方的缓冲区。您希望将数据读取到哪里?
-
我有一个小项目,它是一个在实模式下运行的 2 阶段引导加载程序(需要 386+ 才能运行)。 github.com/mpetch/OSDev/blob/master/examples/… 。 biosdsk.h 有一个可能有用的内联代码示例。我实现了一些功能,例如磁盘读取(重试)和磁盘重置。我通过结构指针传递磁盘数据,以节省必须将许多参数传递给函数。我还有一个 SO 答案,其中包含适用于此问题的
notes部分中的信息:stackoverflow.com/a/52047408/3857942
标签: gcc x86-16 inline-assembly disk bios