自制操作系统开发中遭遇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
相关产品推荐
相关产品推荐

