【问题标题】:When compiled inb and outb in inline assembly produce "Error: operand type mismatch"在内联汇编中编译 inb 和 outb 时产生“错误:操作数类型不匹配”
【发布时间】:2019-04-01 04:56:00
【问题描述】:

我正在尝试为 64 位 arch 编写最简单的内核,但我遇到了键盘输入问题。

我目前正在实现这两个函数来管理 I/O

unsigned char inportb (unsigned short _port)
{
    unsigned char rv;
    __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
    return rv;
}

void outportb (unsigned short _port, unsigned char _data)
{
    __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}

但是我收到了这个汇编错误:

main.c: Mensajes del ensamblador:
main.c:51: Error: no coincide el tipo de operando para «in»
main.c:61: Error: no coincide el tipo de operando para «out»

或者用英语:

main.c: Assembler messages:
main.c:51: Error: operand type mismatch for `in'
main.c:61: Error: operand type mismatch for `out'

我的猜测是这段代码(我从http://www.osdever.net/bkerndev/Docs/creatingmain.htm 得到的)是为 32 位汇编设计的。

对于如何解决我的问题的任何帮助将不胜感激。

我用这个脚本构建和运行一切

#!/bin/bash

nasm -f bin boot.asm -o boot.bin
nasm -f elf64 loader.asm -o loader.o

#cc -m64  -ffreestanding -fno-builtin -nostdlib -c main.c
cc -m64 -masm=intel -c main.c
ld  -Ttext 0x100000 -o kernel.elf loader.o main.o 
objcopy -R .note -R .comment -S -O binary kernel.elf kernel.bin

dd if=/dev/zero of=image.bin bs=512 count=2880
dd if=boot.bin of=image.bin conv=notrunc
dd if=kernel.bin of=image.bin conv=notrunc bs=512 seek=1

rm ./boot.bin ./kernel.bin ./main.o ./loader.o ./kernel.elf

qemu-system-x86_64  image.bin

【问题讨论】:

  • 你应该能够收到类似LANG=C gcc arguments的英文消息
  • 确实,它确实在我的 x86-64 GCC 上正确编译
  • 如果这是 x86-64 您是否使用 GCC -masm=intel 选项编译它?如果您是,则必须在内联汇编模板中交换 %0%1,因为如果您使用该选项,源和目标操作数将与默认的 AT&T 语法相反。
  • @MichaelPetch 我正在运行 qemu-system-x86_64
  • @MichaelPetch 即时编辑原始帖子添加构建脚本即时使用

标签: gcc x86 x86-64 inline-assembly osdev


【解决方案1】:

默认情况下,当从 C 代码生成汇编代码时,GCC 使用 AT&T 汇编语法。这可以通过使用-masm=intel GCC 编译选项来覆盖。在更新您的问题时,您的 GCC 命令行中有 -masm=intel

cc -m64 -masm=intel -c main.c

您找到的代码是为 AT&T 语法设计的,其中指令的源操作数在前,目标在后。 -masm=intel 选项扭转了这种行为。你有两个选择。反转内联程序集中的操作数,使其成为目标、源(intel 语法),如下所示:

unsigned char inportb (unsigned short _port)
{
    unsigned char rv;
    __asm__ __volatile__ ("inb %0, %1" : "=a" (rv) : "dN" (_port));
    return rv;
}

void outportb (unsigned short _port, unsigned char _data)
{
    __asm__ __volatile__ ("outb %0, %1" : : "dN" (_port), "a" (_data));
}

另一个选项是从 GCC 命令行中删除 -masm=intel 选项并保持代码不变。这可能更可取,因为大量 OS 开发代码使用 AT&T 语法进行内联汇编。


注意:您可能需要考虑使用gcc 而不仅仅是cc

【讨论】:

    猜你喜欢
    • 2019-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-11
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多