GCC error message in outb macro

时间:2016-02-16 18:59:47

标签: c gcc assembly gas osdev

I'm developing an operating system. So far, I've added an HDD driver to my operating system that uses PIO. Here is the code in hdd.h:

    #ifndef HDD_H_INCLUDED
    #define HDD_H_INCLUDED

    #include "includes.h"

    typedef uint64_t lba48_addr_t;

    typedef uint16_t ide_ctr_t;
    typedef uint16_t ide_disk_t;
    #define MASTER 0x1F0
    #define SLAVE 0x170

    void read_hdd_sector(ide_ctr_t ctr, ide_disk_t disk, lba48_addr_t addr, void* dst);
    void write_hdd_sector(ide_ctr_t ctr, ide_disk_t disk, lba48_addr_t addr, void* src);

    #endif // HDD_H_INCLUDED

Here is the file hdd.c:

    #include "includes.h"

    void read_hdd_sector(ide_ctr_t ctr, lba48_addr_t addr, void* dst) {
        outb(ctr + 6, disk == MASTER ? 0x40 : 0x50);
        outb(ctr + 2, 0x00);
        outb(ctr + 3, (addr >> 24) & 0xFF);
        outb(ctr + 4, (addr >> 32) & 0xFF);
        outb(ctr + 5, (addr >> 40) & 0xFF);
        outb(ctr + 2, 0x01);
        outb(ctr + 3, addr & 0xFF);
        outb(ctr + 4, (addr >> 8) & 0xFF);
        outb(ctr + 5, (addr >> 16) & 0xFF);
        outb(ctr + 7, 0x24);
        uint8_t sig = 0;
        while(!(sig & 0x08)) {
            inb(0x1F7, sig);
        }
        for(int ix = 0; ix < 256; ix++) {
            uint16_t word;
            inw(0x1F0, word);
            *((uint16_t*)(dst + idx * 2)) = word;
        }
    }

    void write_hdd_sector(ide_ctr_t ctr, lba48_addr_t addr, void* src) {
        outb(ctr + 6, disk == MASTER ? 0x40 : 0x50);
        outb(ctr + 2, 0x00);
        outb(ctr + 3, (addr >> 24) & 0xFF);
        outb(ctr + 4, (addr >> 32) & 0xFF);
        outb(ctr + 5, (addr >> 40) & 0xFF);
        outb(ctr + 2, 0x01);
        outb(ctr + 3, addr & 0xFF);
        outb(ctr + 4, (addr >> 8) & 0xFF);
        outb(ctr + 5, (addr >> 16) & 0xFF);
        outb(ctr + 7, 0x34);
        uint8_t sig = 0;
        while(!(sig & 0x08)) {
            inb(0x1F7, sig);
        }
        for(int ix = 0; ix < 256; ix++) {
            outw(0x1F0, *((uint16_t*)(src + idx * 2)));
        }
    }

    #define outb(port, value) __asm("outb %b0, %w1" : : "a" (value), "d" (port))

However, I can't build it. For all of lines that look like this:

    outb(ctr + x, y & 0xFF)

I get an error like this:

Inconsistent operand constraints in an 'asm'.

I've read similar questions where the problem is the -fPIC compiler flag that doesn't allow using EBX but I use neither -fPIC nor EBX registers. Here's the full build log:

    $ make
    /home/alexander/opt/cross/bin/i686-elf-gcc -ffreestanding -Wall -Wextra -Werror -std=c11 -Iinclude -g -c hdd.c -o hdd.c.o
    In file included from include/includes.h:10:0,
                     from hdd.c:1:
    hdd.c: In function 'read_hdd_sector':
    include/system.h:7:27: error: inconsistent operand constraints in an 'asm'
     #define outb(port, value) __asm("outb %b0, %w1" : : "a" (value), "d" (port))
                               ^
    hdd.c:6:5: note: in expansion of macro 'outb'
         outb(ctr + 3, (addr >> 24) & 0xFF);
         ^
    include/system.h:7:27: error: inconsistent operand constraints in an 'asm'
     #define outb(port, value) __asm("outb %b0, %w1" : : "a" (value), "d" (port))
                               ^
    hdd.c:7:5: note: in expansion of macro 'outb'
         outb(ctr + 4, (addr >> 32) & 0xFF);
         ^
    include/system.h:7:27: error: inconsistent operand constraints in an 'asm'
     #define outb(port, value) __asm("outb %b0, %w1" : : "a" (value), "d" (port))
                               ^
    hdd.c:8:5: note: in expansion of macro 'outb'
         outb(ctr + 5, (addr >> 40) & 0xFF);
         ^
    include/system.h:7:27: error: inconsistent operand constraints in an 'asm'
     #define outb(port, value) __asm("outb %b0, %w1" : : "a" (value), "d" (port))
                               ^
    hdd.c:10:5: note: in expansion of macro 'outb'
         outb(ctr + 3, addr & 0xFF);
         ^
    include/system.h:7:27: error: inconsistent operand constraints in an 'asm'
     #define outb(port, value) __asm("outb %b0, %w1" : : "a" (value), "d" (port))
                               ^
    hdd.c:11:5: note: in expansion of macro 'outb'
         outb(ctr + 4, (addr >> 8) & 0xFF);
         ^
    include/system.h:7:27: error: inconsistent operand constraints in an 'asm'
     #define outb(port, value) __asm("outb %b0, %w1" : : "a" (value), "d" (port))
                               ^
    hdd.c:12:5: note: in expansion of macro 'outb'
         outb(ctr + 5, (addr >> 16) & 0xFF);
         ^
    make: *** [hdd.c.o] Error 1

What's strange is that for the same code in write_hdd_sector, no error is shown. I've got no idea what the problem could be. How do I fix this error? Any suggestions?

1 个答案:

答案 0 :(得分:2)

该问题与寄存器的使用无关,而与操作数的大小有关。请参阅typedef uint64_t lba48_addr_t;,并且您的outb内联汇编指令要求两个参数都适合32位。通过编写表格代码......

outb(ctr + x, something_that_uses_the_addr_variable & 0xFF);

该条件无法满足,因为addr的类型为lba48_addr_t,a.k.a uint64_t。为了避免将来出现此类问题,您应该将outb定义为这样的内联函数...

inline void outb(uint16_t port, uint8_t value)
{
    __asm("outb %b0, %w1"
        :: "a"(value), "d"(port));
}