如何修复汇编代码中的‘error: invalid combination of opcode and operands’错误?
Let's break down the issues with your code and fix them step by step:
1. Resolve the Compilation Error (Line 16)
The error on line 16 (mov si,prompt) is likely due to one of two scenarios:
- Assembler-specific address syntax: If you're using MASM/TASM instead of NASM, you need to explicitly use
offsetto fetch the address of a label:
For NASM, the original line should work, but if you still hit the error, try replacingmov si, offset promptlea si,stringwithmov si,string—since you only need the buffer's starting address,leais unnecessary here. - Unterminated string: While this is a runtime issue, some assemblers throw unexpected errors when parsing strings without a null terminator. We'll fix this next.
2. Critical Runtime Fixes (Even If They Don't Break Compilation)
Your bootloader has a few issues that will fail at runtime, even after fixing the compilation error:
A. Null-Terminate All Strings
Your print_string function stops when it hits a 0 byte, but your prompt string doesn't have one. Add a null terminator to avoid infinite loops:
prompt db "Hello>", 0
B. Replace DOS Interrupt int 21h with BIOS Interrupt
int 21h is a DOS-specific interrupt, which doesn't exist in the raw BIOS environment where bootloaders run. Use the BIOS keyboard interrupt int 16h instead to read keystrokes. Here's a fixed read_string function with backspace support:
read_string: .repeat: mov ah, 00h ; int 16h function 0: read raw keystroke int 16h ; Get key into AX (AL = ASCII char, AH = scan code) cmp al, 0x0D ; Check if it's Enter (carriage return) je .done ; Exit loop if Enter is pressed cmp al, 0x08 ; Check if it's Backspace je .backspace mov [si], al ; Store character in buffer mov ah, 0Eh ; Echo the character to screen int 10h inc si ; Move buffer pointer forward jmp .repeat .backspace: cmp si, string ; Don't backspace past the buffer start je .repeat dec si mov byte [si], 0 ; Clear the deleted character mov ah, 0Eh ; Erase character on screen (backspace + space + backspace) mov al, 0x08 int 10h mov al, ' ' int 10h mov al, 0x08 int 10h jmp .repeat .done: mov byte [si], 0 ; Null-terminate the input string ret
C. Proper Newline Handling
BIOS expects both carriage return (13) and line feed (10) for a proper newline. Update your eol definition:
eol db 13,10,0
Fixed Full Code
Here's the complete corrected bootloader code:
BITS 16 jmp short bootloader_start nop bootloader_start: mov ax, 07C0h ; Set up 4K of stack space above buffer add ax, 544 ; 8k buffer = 512 paragraphs + 32 paragraphs (loader) ;cli ; Disable interrupts while changing stack mov ss, ax mov sp, 4096 ;sti ; Restore interrupts mov ax, 07C0h ; Set data segment to where we're loaded mov ds, ax mov si,prompt call print_string mov si,string call read_string mov si, string call print_string print_string: ; Routine: output string in SI to screen ;pusha mov ah, 0Eh ; int 10h 'print char' function .repeat: lodsb ; Get character from string cmp al, 0 je .main_done ; If char is zero, end of string int 10h ; Otherwise, print it jmp .repeat .main_done: mov si,eol .eol_repeat: lodsb ; Get character from string cmp al, 0 je .done ; If char is zero, end of string int 10h ; Otherwise, print it jmp .eol_repeat .done: ;popa ret read_string: .repeat: mov ah, 00h ; int 16h function 0: read raw keystroke int 16h ; Get key into AX (AL = ASCII char, AH = scan code) cmp al, 0x0D ; Check if it's Enter (carriage return) je .done ; Exit loop if Enter is pressed cmp al, 0x08 ; Check if it's Backspace je .backspace mov [si], al ; Store character in buffer mov ah, 0Eh ; Echo the character to screen int 10h inc si ; Move buffer pointer forward jmp .repeat .backspace: cmp si, string ; Don't backspace past the buffer start je .repeat dec si mov byte [si], 0 ; Clear the deleted character mov ah, 0Eh ; Erase character on screen mov al, 0x08 int 10h mov al, ' ' int 10h mov al, 0x08 int 10h jmp .repeat .done: mov byte [si], 0 ; Null-terminate the input string ; Print newline after input mov si, eol .eol_loop: lodsb cmp al, 0 je .read_done mov ah, 0Eh int 10h jmp .eol_loop .read_done: ret eol db 13,10,0 ; Carriage return + line feed + null terminator prompt db "Hello>", 0 ; Null-terminated prompt string string times 80 db 0 times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s dw 0xAA55 ; The standard PC boot signature
内容的提问来源于stack exchange,提问作者Dorian Niemiec

