NASM汇编语言与计算机系统15-加载器与用户程序的约定(加载器rorjmp far)

本文新用的汇编指令
ror

;假设一个值a="二三抱",那么我让a循环右移1位,那么a="抱二三"
;ror与shr指令使用方式相同
;使用场景:将2个字组合成1个字,例如8086下将0xAB00右移8位,并与0x00CD合并
mov ax,0xAB00
shr ax,8		;走完此行ax=0xAB
mov bx,0x00CD
ror bx,8		;走完此行bx=0xCD00
or  bx,ax		;走完此行bx=0xCDAB,到此场景演示完毕

jmp far

jmp far [0x04]  ;以ds为段寄存器,偏移量04,05的位置是ip
	 			;偏移量06,07的位置是cs

加载器用来将硬盘上的用户程序放到内存,并且回填逻辑段地址,只有这样,用户才能根据逻辑段地址,顺利的运行程序,假设编译好的用户程序在硬盘的LBA号为100的扇区上,下面的代码将读取硬盘100扇区的内容,加载到内存,然后回填段地址,最后将CPU控制权转到用户程序上执行

;从硬盘的第几扇区开始读数据
hard_index   equ 100
;将读取的数据放到memory_index所指定的物理内存处
;==============开始从硬盘读512个字节的数据=====
mov al,1			;操作1个扇区		
mov dx,0x1f2
out dx,al

mov al,hard_index	;从第几个扇区开始操作
mov dx,0x1f3
out dx,al			;此处巨坑,这个端口特殊,
					;必须al,其他8位端口ax也可以

xor al,al			;1f4端口直接写死赋值0,反正读
mov dx,0x1f4		;100逻辑扇区,1f4也用不上
out dx,al

mov dx,0x1f5		;此处同1f4端口,也赋值0
out dx,al

mov dx,0x01F6		;1f6低4位是0,表示操作的扇区号
mov al,0xE0			;1f6高4位表示操作主硬盘,以LBA方式
out dx,al

mov dx,0x1F7		;往1f7写20表示读数据
mov al,0x20 
out dx,al

mov dx,0x1F7
					;无限轮询等待可以读取数据
waits:
	in al,dx
	and al,0x88		;取位7和位3的值
	cmp al,0x08		;如果位7=0,位3=1,说明
	jnz waits		;硬盘控制器准备就绪

mov ax,0x7c0
mov ds,ax			;设置ds,为了获取内存加载地址
mov ax,[memory_index]
mov bx,[memory_index+2]
shr ax,4			
ror bx,4
and bx,0xF000
or  ax,bx			;一顿操作下来,or之后ax=0x1000
mov ds,ax			;此时ds=0x1000

xor si,si 			;一般首选bx,而不是si,毕竟都用ds和bx

mov cx,512			;假设用户程序不超过512个字节
mov dx,0x1F0		;注意1f0是16位端口而不是8位
reads:				;开始读取
	in   ax,dx
	mov  [si],ax		;16位端口用ax
	add  si,2
	loop reads
;==============512字节读读取完毕=============
;假设用户程序不超过512,因为超过512还得
;写一堆代码,可读性太差了
;==============开始段的重定位,此时dx已经等于0x1000
mov  si,0x06		;开始回填main_segment,注意
mov  ax,[si]		;该段必须是16字节对齐【断点7c57】
mov  bx,[si+2]
shr  ax,4			
ror  bx,4
and  bx,0xF000
or   ax,bx
push ds				;将ds的值通过栈操作给bx
pop  bx		
add  ax,bx
mov  [si],ax  

mov ax,[0x0A]		;开始回填table_start至table_end
mov cx,ax			;注意回填的段必须16字节对齐
mov si,0x0C 							
replace_sec:		;循环回填
	mov  ax,[si]	
	mov  bx,[si+2]
	shr  ax,4			
	ror  bx,4
	and  bx,0xF000
	or   ax,bx
	push ds			;将ds的值通过栈操作给bx
	pop  bx		
	add  ax,bx
	mov  [si],ax 
	add  si,4
	loop replace_sec
;============重定位完毕,将cs/ip指向用户程序入口处
jmp far [0x04]		;16位直接远转移【断点7c96】

foreach:
	hlt
	jmp foreach

memory_index:		;范围是10000-9FFFF
	dd  0x10000		;最低位必须是0,因为必须要16字节对齐
times 510-($-$$) db 0
dw 0xAA55
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值