You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自制操作系统开发中遭遇GCC内联汇编约束无效错误

自制OS编译错误:内联汇编约束无效

编译错误信息

执行make编译时抛出以下错误:

gcc -m32 -nostdlib -nodefaultlibs -Wall -Wextra -ffreestanding -O2 -Iinclude -c src/io.c -o src/io.o
src/io.c:8:44: error: invalid input constraint 'a' in asm
    __asm__ __volatile__("outb %0, %1" : : "a"(value), "Nd"(port));
                                           ^
src/io.c:13:41: error: invalid output constraint '=a' in asm
    __asm__ __volatile__("inb %1, %0" : "=a"(ret) : "Nd"(port));
                                        ^
2 errors generated.
make: *** [src/io.o] Error 1

涉事代码(src/io.c)

#include "io.h"
#include <stdarg.h>

// Function declaration
void itoa(char* buf, int value, int base);

void outb(unsigned short port, unsigned char value) {
    __asm__ __volatile__("outb %0, %1" : : "a"(value), "Nd"(port));
}

unsigned char inb(unsigned short port) {
    unsigned char ret;
    __asm__ __volatile__("inb %1, %0" : "=a"(ret) : "Nd"(port));
    return ret;
}

void printf(const char* format, ...) {
    char** arg = (char**)&format;
    int c;
    char buf[20];

    arg++;

    while ((c = *format++) != 0) {
        if (c != '%') {
            outb(0xE9, c);
        } else {
            char* p;

            c = *format++;
            switch (c) {
            case 'd':
            case 'u':
            case 'x':
                itoa(buf, *((int*)arg++), c == 'd' ? 10 : (c == 'x' ? 16 : 10));
                p = buf;
                goto string;
                break;

            case 's':
                p = *arg++;
                if (!p) {
                    p = "(null)";
                }

string:
                while (*p) {
                    outb(0xE9, *p++);
                }
                break;

            default:
                outb(0xE9, '%');
                outb(0xE9, c);
                break;
            }
        }
    }
}

void gets(char* buffer) {
    char* buf_ptr = buffer;
    while (1) {
        char c = inb(0x60);  // Read keyboard input
        if (c == '\n') {
            *buf_ptr = '\0';
            return;
        } else {
            *buf_ptr++ = c;
            outb(0xE9, c); // Echo character
        }
    }
}

// Definition of itoa
void itoa(char* buf, int value, int base) {
    char* ptr = buf;
    char* ptr1 = buf;
    char tmp_char;
    int tmp_value;

    if (base < 2 || base > 36) {
        *buf = '\0';
        return;
    }

    do {
        tmp_value = value;
        value /= base;
        *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"
                 [35 + (tmp_value - value * base)];
    } while (value);

    if (tmp_value < 0 && base == 10) *ptr++ = '-';

    *ptr-- = '\0';
    while (ptr1 < ptr) {
        tmp_char = *ptr;
        *ptr-- = *ptr1;
        *ptr1++ = tmp_char;
    }
}

使用的Makefile

C_SOURCES = $(wildcard src/*.c)
OBJS = ${C_SOURCES:.c=.o}

CC = gcc
CFLAGS = -m32 -nostdlib -nodefaultlibs -Wall -Wextra -ffreestanding -O2 -Iinclude

all: kernel.bin

kernel.bin: $(OBJS)
    ld -m elf_i386 -T linker.ld -o kernel.bin $(OBJS)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    rm -f src/*.o kernel.bin

问题原因与解决方案

错误根源

outb/inb是8位IO指令,要求操作数对应8位寄存器(AL),但原代码仅用"a"约束(对应AX/EAX寄存器),在-ffreestanding编译模式下,GCC无法自动匹配正确的寄存器位宽,导致约束无效错误。

修复代码

修改outb和inb函数的内联汇编,明确指定操作数位宽:

void outb(unsigned short port, unsigned char value) {
    // %b0 取value的8位部分(对应AL寄存器),%w1表示port的16位部分(DX寄存器或8位立即数)
    __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
}

unsigned char inb(unsigned short port) {
    unsigned char ret;
    // %w1表示port的16位部分,%b0将读取结果存入8位寄存器AL,最终赋值给ret
    __asm__ __volatile__("inb %w1, %b0" : "=a"(ret) : "Nd"(port));
    return ret;
}

额外检查

若使用64位系统编译32位目标,需确保安装了32位编译依赖(如Debian/Ubuntu下执行sudo apt install gcc-multilib),否则-m32参数可能无法正常工作。


内容的提问来源于stack exchange,提问作者Tenefüs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 13:10:56