【发布时间】:2020-06-23 18:58:59
【问题描述】:
我在 Windows 上使用 i686 gcc。当我使用单独的 asm 语句构建代码时,它起作用了。但是,当我尝试将它组合成一个语句时,它不会生成并给我一个error: unsupported size for integer register。
这是我的代码
u8 lstatus;
u8 lsectors_read;
u8 data_buffer;
void operate(u8 opcode, u8 sector_size, u8 track, u8 sector, u8 head, u8 drive, u8* buffer, u8* status, u8* sectors_read)
{
asm volatile("mov %3, %%ah;\n"
"mov %4, %%al;\n"
"mov %5, %%ch;\n"
"mov %6, %%cl;\n"
"mov %7, %%dh;\n"
"mov %8, %%dl;\n"
"int $0x13;\n"
"mov %%ah, %0;\n"
"mov %%al, %1;\n"
"mov %%es:(%%bx), %2;\n"
: "=r"(lstatus), "=r"(lsectors_read), "=r"(buffer)
: "r"(opcode), "r"(sector_size), "r"(track), "r"(sector), "r"(head), "r"(drive)
:);
status = &lstatus;
sectors_read = &lsectors_read;
buffer = &data_buffer;
}
【问题讨论】:
-
这是 16 位代码。你用什么选项来编译它?也许指针宽度是个问题?如果删除一些操作数,哪一个会导致编译错误?此外,您忘记了
"memory"clobber,在将寄存器中的指针传递到取消引用它们的内联 asm 语句时,这通常是安全所必需的。另外,为什么全局变量作为临时变量?你为什么要在函数结束之前给按值函数 args 赋值?调用者不会看到status=lstatus的任何效果,这不是C 的工作方式。你的意思是*status = lstatus吗? -
如果您打算尝试将 GCC 与 16 位代码一起使用,我可能会建议您考虑使用分叉的 ia16-gcc elf 交叉编译器。这是一项正在进行的工作,但它处理 16 位代码比常规 GCC 编译器要好得多。甚至还有一个 lib86 库,允许您通过函数进行 BIOS 中断调用(尽管它似乎缺乏使用 32 位寄存器的能力,而这是少数 BIOS 服务所必需的)
-
@mike 我在你之前的问题中向你展示了这个任务的正确代码是什么样的。你为什么要回到这个糟糕透顶的实现?
-
@mike 请注意,BIOS 调用只是让
es:bx保持不变。您需要在es:bx中提供缓冲区地址,BIOS 会将数据加载到该地址。当调用返回时地址仍然存在,这就是为什么一些资源记录调用返回缓冲区地址的原因。但是,这通常适用于除ax之外的所有寄存器。 -
@PeterCordes Gcc 要求
ss、es和ds指向同一个内存,因此无需在内联程序集中设置es。
标签: c assembly gcc x86-16 inline-assembly