
汇编语言-x86从实模式到保护模式8.3.7的加载用户程序(加载器)问题请教各位汇编大神。下面的程序有错吗?
请问各位汇编大神,下面的加载器程序有错吗?为什么加载不到用户程序?我是写进虚拟机硬盘的,用汇编语言-x86从实模式到保护模式推荐的写虚拟硬盘程序写进去的shu_1equ1...
请问各位汇编大神,下面的加载器程序有错吗?为什么加载不到用户程序?
我是写进虚拟机硬盘的,用汇编语言-x86从实模式到保护模式推荐的写虚拟硬盘程序写进去的
shu_1 equ 100 ;声明常数
section mbr align=16 vstart=0x7c00
start:
;设置堆栈段和指针主
mov dx,0
mov ss,dx
mov sp,dx
;---
mov ax,[cs:kaishidizhi] ;计算用于加载用户程序的逻辑段
mov dx,[cs:kaishidizhi+0x02]
mov bx,16
div bx
mov ds,ax ;令DS和ES指向该段以进行操作
mov es,ax
;---以下读取程序的起始部分
xor di,di
xor bx,bx ;加载到DS:0x0000处
mov si,shu_1 ;程序在硬盘上的起始逻辑扇区号
call read_hard_disk_0
;---以下判断整个程序有多大(有多少个扇区)
mov ax,[0]
mov dx,[2]
mov bx,512 ;512字节每扇区
div bx
cmp dx,0
jnz @1 ;未除尽,因此结果比实际扇区数少1
dec ax ;已经读了一个扇区,扇区总数减1
;---
@1:
cmp ax,0 ;考虑实际长度小于等于512个字节的情况
jz rukuoduan
;读取剩余的扇区
push ds ;以下要用到并改变DS寄存器
mov cx,ax ;循环次数(剩余扇区数)
@2:
mov ax,ds
add ax,0x20 ;得到下一个以512字节为边界段地址
mov ds,ax
xor bx,bx ;每次读时,偏移地址始终为0x0000
inc si ;下一个逻辑扇区
call read_hard_disk_0
loop @2 ;循环读,直到读完整个功能程序
pop ds ;恢复数据段基址到用户程序头部段
;----计算入口点代码段基址
rukuoduan:
mov ax,[0x06]
mov dx,[0x08]
call xiugaiduan
mov [0x06],ax ;回填修正后的入口点代码段基址
;---开始处理段重定位表
mov cx,[0x0a] ;需要重定位的项目上数量
mov bx,0x0c ;重定位表首地址
@03:
mov ax,[bx]
mov dx,[bx+0x02] ;32位地址的高16位
call xiugaiduan
mov [bx],ax ;回真段的基址
add bx,4 ;下一个重定位项(每项占4个字节)
loop @03
;---
jmp far [0x04] ;转移到用户程序
;--------------------------------------
read_hard_disk_0: ;从硬盘读取一个逻辑扇区
push ax ;输入:DI:SI=起始逻辑扇区号
push bx ; DS:BX=目标缓冲区地址
push cx
push dx
mov dx,0x1f2
mov al,1
out dx,al ;读取的扇区数
inc dx ;0x1f3
mov ax,si
out dx,al ;LBA地址0~7
inc dx ;0x1f4
mov al,ah
out dx,al ;LBA地址8~15
inc dx ;0x1f5
mov ax,di
out dx,al ;LBA地址16~23
inc dx ;0x1f6
mov al,0xe0 ;LBA28模式,主盘
or al,ah ;LBA地址24~27
out dx,al
inc dx ;0x1f7
mov al,0x20 ;读命令
out dx,al
;----
waits:
in al,dx
and al,0x88
cmp al,0x08
jnz waits ;不忙,且硬盘已准备好数据传输
mov cx,256 ;总共要读取的字数
mov dx,0x1f0
dushuju:
in ax,dx
mov [bx],ax
add bx,2
loop dushuju
pop dx
pop cx
pop bx
pop ax
ret
;---------------------------------
xiugaiduan: ;计算16位段地址
push dx ;输入:DX:AX=32位物理地址
;返回:AX=16位段基地址
add ax,[kaishidizhi]
adc dx,[kaishidizhi+0x02]
shr ax,4
ror dx,4
and dx,0xf000
or ax,dx
pop dx
ret
;--------------------------------
kaishidizhi dd 0x10000 ;用户程序被加载的物理起始地址
times 510-($-$$) db 0
db 0x55,0xaa 展开
我是写进虚拟机硬盘的,用汇编语言-x86从实模式到保护模式推荐的写虚拟硬盘程序写进去的
shu_1 equ 100 ;声明常数
section mbr align=16 vstart=0x7c00
start:
;设置堆栈段和指针主
mov dx,0
mov ss,dx
mov sp,dx
;---
mov ax,[cs:kaishidizhi] ;计算用于加载用户程序的逻辑段
mov dx,[cs:kaishidizhi+0x02]
mov bx,16
div bx
mov ds,ax ;令DS和ES指向该段以进行操作
mov es,ax
;---以下读取程序的起始部分
xor di,di
xor bx,bx ;加载到DS:0x0000处
mov si,shu_1 ;程序在硬盘上的起始逻辑扇区号
call read_hard_disk_0
;---以下判断整个程序有多大(有多少个扇区)
mov ax,[0]
mov dx,[2]
mov bx,512 ;512字节每扇区
div bx
cmp dx,0
jnz @1 ;未除尽,因此结果比实际扇区数少1
dec ax ;已经读了一个扇区,扇区总数减1
;---
@1:
cmp ax,0 ;考虑实际长度小于等于512个字节的情况
jz rukuoduan
;读取剩余的扇区
push ds ;以下要用到并改变DS寄存器
mov cx,ax ;循环次数(剩余扇区数)
@2:
mov ax,ds
add ax,0x20 ;得到下一个以512字节为边界段地址
mov ds,ax
xor bx,bx ;每次读时,偏移地址始终为0x0000
inc si ;下一个逻辑扇区
call read_hard_disk_0
loop @2 ;循环读,直到读完整个功能程序
pop ds ;恢复数据段基址到用户程序头部段
;----计算入口点代码段基址
rukuoduan:
mov ax,[0x06]
mov dx,[0x08]
call xiugaiduan
mov [0x06],ax ;回填修正后的入口点代码段基址
;---开始处理段重定位表
mov cx,[0x0a] ;需要重定位的项目上数量
mov bx,0x0c ;重定位表首地址
@03:
mov ax,[bx]
mov dx,[bx+0x02] ;32位地址的高16位
call xiugaiduan
mov [bx],ax ;回真段的基址
add bx,4 ;下一个重定位项(每项占4个字节)
loop @03
;---
jmp far [0x04] ;转移到用户程序
;--------------------------------------
read_hard_disk_0: ;从硬盘读取一个逻辑扇区
push ax ;输入:DI:SI=起始逻辑扇区号
push bx ; DS:BX=目标缓冲区地址
push cx
push dx
mov dx,0x1f2
mov al,1
out dx,al ;读取的扇区数
inc dx ;0x1f3
mov ax,si
out dx,al ;LBA地址0~7
inc dx ;0x1f4
mov al,ah
out dx,al ;LBA地址8~15
inc dx ;0x1f5
mov ax,di
out dx,al ;LBA地址16~23
inc dx ;0x1f6
mov al,0xe0 ;LBA28模式,主盘
or al,ah ;LBA地址24~27
out dx,al
inc dx ;0x1f7
mov al,0x20 ;读命令
out dx,al
;----
waits:
in al,dx
and al,0x88
cmp al,0x08
jnz waits ;不忙,且硬盘已准备好数据传输
mov cx,256 ;总共要读取的字数
mov dx,0x1f0
dushuju:
in ax,dx
mov [bx],ax
add bx,2
loop dushuju
pop dx
pop cx
pop bx
pop ax
ret
;---------------------------------
xiugaiduan: ;计算16位段地址
push dx ;输入:DX:AX=32位物理地址
;返回:AX=16位段基地址
add ax,[kaishidizhi]
adc dx,[kaishidizhi+0x02]
shr ax,4
ror dx,4
and dx,0xf000
or ax,dx
pop dx
ret
;--------------------------------
kaishidizhi dd 0x10000 ;用户程序被加载的物理起始地址
times 510-($-$$) db 0
db 0x55,0xaa 展开
展开全部
你对硬盘的io操作不知道你的虚拟机是否支持?
你改成用int 13h试试?
你改成用int 13h试试?
更多追问追答
追问
支持啊,我用x86从实模式到保护模式的源码试了一下都可以的啊,我还对了十次源代码看了都没有问题,还用x86从实模式到保护模式的源码的加载器试了我的用户程序都可以就是,就是我写的加载器不行,真想不明白。
追答
你的意思是这段程序要写到硬盘的主引导扇区中,系统启动的时候自动运行这段程序,然后读取几个扇区的内容到你的地址中,然后跳转到你加载的程序中?
要成功需要几个条件:1.代码正确,这个你已经核对多次了,应该没问题。
2.你这段代码确实写到你的硬盘主引导扇区中了。读出来检查一下,方法自己想。
3.你需要加载的程序已经存在于你想读的扇区中了。读出来检查一下。
4.读取过程没错,读出来的程序能正常运行。可以改成用int13h读试试。
另外,你用的什么虚拟机?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询
广告 您可能关注的内容 |