在内联汇编中编译inb和outb时,产生“错误:操作数类型不匹配”

时间:2018-10-27 19:24:52

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

我正在尝试为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

1 个答案:

答案 0 :(得分:4)

默认情况下,当从 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