混乱不统一的ds布置方法,是程序内存读写的万恶之源!

debug bootloader,最方便简单直观的办法就是print into console。所以在hacking kernel歇业一个月后,重拾老代码,准备重新改造一番,今天就从增加printf函数开始吧:

;function:在是模式下,打印一串字符串
;@1 input: 要打印的字符串的物理地址, 低位:ax, 高位 dx
;@2 input: 打印的字符长度: cx
;output: null 
printf:
	push ax
	push bx
	push cx
	push dx
	push es
	push ds
	
	;1. first of all, trans the phy addres into logic address
	mov bx, 16
	div bx

        ;做完除法后,ax保存了段地址, dx保存了段内偏移
	mov ds, ax
	mov ax, 0xb800
	mov es, ax
	;cx为字符串的长度,循环次数是字符串的1/2倍
	mov ax, cx
	mov bl, 2
	div bl
	cmp ah, 0x00 ;比较是否存在余数,如果存在则需要将商(al)+1
	je no ;如果不存在余数
	;如果存在余数
	inc al
no:
	xor cx, cx
	mov cl, al
	mov bx, dx
	;当前的id从CUR_INDEX中获取
	mov di, [CUR_INDEX]
lp:	
	;一次性取出2个字节,提高读取效率
	mov ax, [bx] ;直接用dx来寻址把内存赋值到ax还不行~~ 得用bx,神囧啊
	mov byte [es:di], al
	inc di
	mov byte [es:di], 10000100B
	inc di

	mov byte [es:di], ah
	inc di
	mov byte [es:di], 10000100B
	inc di

	add bx, 0x02
	loop lp
	;loop完成后,要把当前的di写回到CUR_INDEX中去,下次重新调用的时候,不会覆盖之前打印的信息
	inc di
	mov [CUR_INDEX], di

	pop ds
	pop es
	pop dx
	pop cx
	pop bx
	pop ax

	ret


这是一个优化版本,增加了多行显示功能,而不是每次从头开始显示,把之前的print值覆盖掉。但是就是因为增加了一个功能,出现了一个郁闷的bug,无法出现预期的多行显示功能。


仔细一看,起始这里出现了一个很隐蔽、而且很严重的问题:混乱的ds布置。

看看数据段的定义:

SECTION data ;align=16
msg1:  		db "loading app at 0x07c00 under raw mode..."					;40bytes 0x7cf0
msg2:		db "now, entering the protect mode! @devxxxx"					;40bytes 0x7d18
msg3:		db "prepare to jump into protected mode....."
;6bytes用于ldgt
gdt_size: 	dw 0										;2bytes  
gdt_baseaddr: 	dd 0x08000									;4bytes  

;用于填充gdt内的段描述符数据   段基址 			 段界限		段属性
NULL_DES: 	descriptor  0x00000000, 		0x00000000, 	0x0000			;8bytes	 
CS_DES: 	descriptor  0x07c00,    		code_length, 	0x4000+0x98		;8bytes	 
;DS_DES: 	descriptor  0x7c00+section.data.start, 	data_end, 	0x92			;8bytes  
DS_DES: 	descriptor  0, 				data_end, 	0x92			;8bytes  0x7d56
 
;保存当前显存区间,当前的index
CUR_INDEX: db 0x00
            
times 510-($-$$)-code_length		db "Q"
                 	     		db 0x55,0xaa

;数据段的长度
data_end equ $ - $$
;END SECTION data


很明显,数据段的msg1,msg2,msg3,都是基于ds=0x0000的。

但是printf函数中,多了如下的一个ds的转换:

	;1. first of all, trans the phy addres into logic address
	mov bx, 16
	div bx

        ;做完除法后,ax保存了段地址, dx保存了段内偏移
	mov ds, ax


这个就不好玩了,从这里看,并无什么大碍,但是到后面涉及到内存寻址,内存读写的时候,问题就来了,见下:

no:
	xor cx, cx
	mov cl, al
	mov bx, dx
	;当前的id从CUR_INDEX中获取
	mov di, [CUR_INDEX]

	;loop完成后,要把当前的di写回到CUR_INDEX中去,下次重新调用的时候,不会覆盖之前打印的信息
	inc di
	mov [CUR_INDEX], di

这2个代码片段分别涉及到了内才能的读操作和写操作。但是呢,[CURRENT]-->真长来说就是基于ds=0x0000,然后+offset current计算的。但是呢,由于print函数之前插一脚的ds重定位操作,导致ds!=0x0000,而是一个具体的段地址值。这样子,mov id, [CUR_INDEX]以及 mov [CUR_INDEX], di都存在重复计算的问题了!

问题现在看上去虽然很初级,也很低级。但是确的确存在,需要引起注意!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值