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

x86实模式下函数调用不执行,call/jmp偏移计算错误问题咨询

问题解答

偏移计算相关说明

你的判断有误,call指令的偏移计算是正确的:
你用objdump反汇编纯二进制文件时,默认会把文件起始位置作为0地址计算所有偏移,反汇编结果里的0x200是该函数在文件内的偏移量,不是实际运行的内存地址。
你代码开头指定了[org 0x7c00],nasm编译时会自动给所有地址加上0x7c00的基址,比如反汇编里的mov si,0x7e14,实际对应mystring的文件偏移是0x214,0x7c00+0x214=0x7e14,符合编译结果。而且x86实模式下近call是相对寻址,只要代码加载的地址和org声明的一致,跳转就不会出错。

代码运行异常的真实原因

你代码里有三个核心错误:

  1. 打印函数用错中断
    print_char里写的int 0x16是键盘输入中断,不会打印字符,显示字符的BIOS中断是int 0x10。
  2. 字符串打印没有加循环
    你当前的print_string逻辑只会打印第一个字符就返回,没有循环读取后续字符,需要在字符打印、si自增后跳回读取下一个字符的位置。
  3. 函数和字符串被放到了引导扇区外
    你把引导扇区填充代码times 510 - ($ - $$) db 0和魔数dw 0xAA55放在了函数、字符串定义的前面,这会导致print_string、print_char、mystring全部被写到512字节的引导扇区之外。BIOS只会主动加载磁盘的第一个扇区(前512字节)到内存0x7c00位置,后面的内容根本不会被加载,运行时访问这些地址读到的都是未知的垃圾数据。

引导扇区大小规则

标准主引导记录(MBR)的引导扇区必须是刚好512字节,且最后两个字节为魔数0xAA55,超过512字节的部分BIOS不会主动加载,如果你需要使用后面的内容,必须自己编写代码从磁盘读取对应的扇区到内存中。

修复后的代码示例

[org 0x7c00]

mov ah, 0x0e

mov al, 'h'
int 0x10
mov al, 'e'
int 0x10
mov al, 'l'
int 0x10
mov al, 'l'
int 0x10
mov al, 'o'
int 0x10

mov al, '!'
call print_char

mov si, mystring
call print_string

jmp $

; 字符串地址存储在si中
print_string:
    pusha
print_string_loop:
    mov al, [si]
    cmp al, 0x00
    jz print_string_end
    call print_char
    inc si
    jmp print_string_loop ; 加循环读取后续字符
print_string_end:
    popa
    ret

; 打印单个字符,待打印字符存储在al中
print_char:
    pusha
    mov ah, 0x0e
    int 0x10 ; 修正为正确的显示中断
    popa
    ret

mystring:
db "loading operating system",0x00

; 填充和魔数移到文件最后,保证所有代码都在512字节内
times 510 - ($ - $$) db 0
dw 0xAA55

内容的提问来源于stack exchange,提问作者user2138149

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 13:48:04