学习笔记
《x86汇编语言:从实模式到保护模式》
https://www.jianshu.com/p/d481cb547e9f
习题一
题目要求
1、修改代码清单14-1和13-3,使用户程序能够正常返回到内核,并在显示消息后停机。
习题解答
- 将用户程序最后的
jmp far [fs:TerminateProgram]
改写成call far [fs:TerminateProgram]
即可;因为,jmp
指令不会改变当前特权级。
习题二
题目要求
2、修改代码清单 14-1 和 13-3 ,使得通过调用门请求读取硬盘扇区的服务时,通过栈传递参数。而且,传递的参数分别是逻辑扇区号、数据段选择子和段内偏移。要求使用
arpl
指令。
参考答案
- 检索到两份解答,下载之后编译运行都可以成功,对理解题意以及解答帮助极大!!
https://blog.csdn.net/longintchar/article/details/51585704
http://www.cnblogs.com/Philip-Tell-Truth/p/5281869.html
习题解答
运行结果
对代码清单13-3:用户程序 c13.asm 进行如下2处修改
- 1、依次压入参数 逻辑扇区号、数据段选择子、段内偏移
push 100 ;逻辑扇区号100
push ds
push buffer
call far [fs:ReadDiskData]
- 2、将用户程序最后的
jmp far [fs:TerminateProgram]
改写成call far [fs:TerminateProgram]
call far [fs:TerminateProgram] ;将控制权返回到系统
对代码清单14-1:内核程序 c14_core.asm 进行如下 5 处修改
- 1、修改子程序
read_hard_disk_0
read_hard_disk_0: ;从硬盘读取一个逻辑扇区
pushad
push ds
mov ebp,esp
mov ax,[ebp+10*4] ;提取 调用者的CS
mov bx,[ebp+12*4] ;提取 数据段选择子
arpl bx,ax ;调整 段选择子的 RPL
mov ds,bx
mov eax,[ebp+13*4];提取 逻辑扇区号
mov ebx,[ebp+11*4];提取 段内偏移
;--------------------------------------------
;中间从 push eax 到 loop .readw 保持不变
;--------------------------------------------
pop ds
popad
retf 3*4 ;3个参数
- 2、符号地址检索表,全部增加一个db字段,除了
salt_2
后面db 3
表示3个参数,其余一律填0
,相当于零个参数,这样,其他的调用门相关代码就都不需要修改了
;符号地址检索表
salt:
salt_1 db '@PrintString'
times 256-($-salt_1) db 0
dd put_string
dw sys_routine_seg_sel
db 0
salt_2 db '@ReadDiskData'
times 256-($-salt_2) db 0
dd read_hard_disk_0
dw sys_routine_seg_sel
db 3
salt_3 db '@PrintDwordAsHexString'
times 256-($-salt_3) db 0
dd put_hex_dword
dw sys_routine_seg_sel
db 0
salt_4 db '@TerminateProgram'
times 256-($-salt_4) db 0
dd return_point
dw core_code_seg_sel
db 0
- 3、
start
标号后,安装门描述符的循环.b3
里,增加参数的设置:or cl,[edi+262] ;用栈传递参数,组装参数个数
mov ecx,salt_items ;C-SALT表的条目数量
.b3:
push ecx
mov eax,[edi+256] ;该条目入口点的32位偏移地址
mov bx,[edi+260] ;该条目入口点的段选择子
mov cx,1_11_0_1100_000_00000B ;特权级3的调用门(3以上的特权级才
;允许访问),0个参数(因为用寄存器
;传递参数,而没有用栈)
or cl,[edi+262] ;用栈传递参数,组装参数个数
call sys_routine_seg_sel:make_gate_descriptor
call sys_routine_seg_sel:set_up_gdt_descriptor
mov [edi+260],cx ;将返回的门描述符选择子回填
add edi,salt_item_len ;指向下一个C-SALT条目
pop ecx
loop .b3
- 4、调用子程序
call sys_routine_seg_sel:read_hard_disk_0
,读取用户程序第一个扇区的内容,增加参数的push
语句
push dword [ebp+12*4] ; 逻辑扇区号
push ds ;数据段选择子
push core_buf ;段内偏移
call sys_routine_seg_sel:read_hard_disk_0
- 5、调用子程序
call sys_routine_seg_sel:read_hard_disk_0
,读取全部的用户程序,修改2件事:首先,push
压入参数,然后需要手动增加add ebx,512
.b1:
push eax ; 逻辑扇区号
push ds ; 数据段选择子
push ebx ; 段内偏移
call sys_routine_seg_sel:read_hard_disk_0
add ebx,512 ;每次调用子程序read_hard_disk_0 都会将ebx压栈,返回再弹出还原,因此本质上每次调用子程序只读取一个扇区,需要手动增加ebx
inc eax
loop .b1