求大大们讲解一下杨季文老师第10章保护模式T10-5.asm看不懂的几个地方,多谢

feekee 2019-07-17 04:46:48
首先,以下代码用masm5.0或者tasm2.0均可以编译生成t10-5.obj,然后再用tlink.exe /3 t10-5.obj可以正确生成exe文件。

为了便于理解,我把书上对这个例子的说明也贴出来,这样方便大大们快速识别出问题
看不懂的地方都在代码的注释区标出来了



;T10-5.ASM
;演示任务切换和任务内特权级变换
include 386SCD.ASM
.386P
;全局描述符表
GDTSEG SEGMENT PARA USE16
GDT LABEL BYTE
dummy descriptor <>
normal descriptor <0ffffh,0,0,atdw,0>
normal_sel=normal-gdt
effgdt label byte
demotss descriptor <demotsslen-1,demotssseg,,at386tss,>
demotss_sel=demotss-gdt
demoldtab descriptor <demoldtlen-1,demoldtseg,,atldt,>
demoldt_sel=demoldtab-gdt
;临时任务的任务状态段描述符
temptss descriptor <temptsslen-1,temptssseg,,at386tss+dpl2,>
temptss_sel=temptss-gdt
;临时任务代码段
tempcode descriptor <0ffffh,tempcodeseg,,atce,>
tempcode_sel=tempcode-gdt
;子程序代码段描述符
subr descriptor <subrlen-1,subrseg,,atce+d32,>
subr_sel=subr-gdt+rpl3

videobuff descriptor <0ffffh,0,0,0f00h+atdw+dpl3,0>
video_sel=videobuff-gdt
gdnum=($-effgdt)/(size descriptor)
gdtlen=$-gdt
gdtseg ends

;演示任务的任务状态段
DemoTSSSEG segment para use16
dd 0 ;链接字
dd DemoStack0LEN ;0级堆栈指针
dw DemoStack0_SEL,0
dd 0 ;1级堆栈指针
dw ?,0
dd DemoStack2LEN ;2级堆栈指针
DW Demostack2_sel,0
dd 0 ;cr3
dw demobegin,0 ;eip
dd 0 ;eflags
dd 0 ;eax
dd 0 ;ecx
dd 0 ;edx
dd 0 ;ebx
dd DemoStack2LEN ;esp
dd 0 ;ebp
dd 0 ;esi
dd 0B8000H ;edi
dw video_sel,0 ;es
dw DemoCode_sel,0 ;cs
dw DemoStack2_sel,0 ;ss
dw DemoData_sel,0 ;ds
dw ToDLDT_SEL,0 ;fs
dw ToTTSS_SEL,0 ;gs
dw DemoLDT_SEL,0 ;ldtr
dw 0
dw $+2 ;I/O许可位图指针
db 0ffh ;I/O许可位图结束字节
DemoTSSLEN=$
DemoTSSSEG ends

;演示任务的局部描述符表LDT
DemoLDTSEG segment para use16
demoldt label byte
demostack0 descriptor <demostack0len-1,demostack0seg,,atdw+d32,>
demostack0_sel=(demostack0-demoldt)+til
demostack2 descriptor <demostack2len-1,demostack2seg,,atdw+d32+dpl2,>
demostack2_sel=(demostack2-demoldt)+til+rpl2
;演示代码段描述符
democode descriptor <democodelen-1,democodeseg,,atce+d32+dpl2,>
democode_sel=(democode-demoldt)+til+rpl2
;演示数据段描述符
demodata descriptor <demodatalen-1,demodataseg,,atdw+d32+dpl3,>
demodata_sel=(demodata-demoldt)+til
;把LDT作为普通数据段描述的描述符(DPL=2)
todldt descriptor <demoldtlen-1,demoldtseg,,atdw+dpl2,>
todldt_sel=(todldt-demoldt)+til
;把tss作为普通数据段描述的描述符(DPL=2)
TOTTSS descriptor <temptsslen-1,temptssseg,,atdw+dpl2,>
tottss_sel=(tottss-demoldt)+til
demoLDNUM=($-demoldt)/(size descriptor)
;指向子程序subrb的调用门(dpl=3)
tosubr gate <subrb,subr_sel,0,at386cgat+dpl3,0>
tosubr_sel=(tosubr-demoldt)+til+rpl2
;指向临时任务temp的任务门(DPL=3)
totempt gate <0,temptss_sel,0,attaskgat+dpl3,0>
totempt_sel=(totempt-demoldt)+til
demoldtlen=$-demoldt
demoldtseg ends
;演示任务的0级堆栈
DemoStack0SEG segment para use32
demostack0len=1024
db demostack0len dup(0)
demostack0seg ends

DemoStack2SEG segment para use32
demostack2len=512
db demostack2len dup(0)
demostack2seg ends

;演示任务的数据段
DemoDataSEG segment para use32
message db 'Value=',0
demodatalen=$
demodataseg ends

subrseg segment para use32
assume cs:subrseg
subrb proc far
push ebp
mov ebp,esp
pushad
mov eax,[ebp+12]
mov esi,eax
mov ah,7
jmp short subr2
subr1: stosw
subr2: lodsb
or al,al
jnz subr1
mov edx,[ebp+16]
mov ecx,8
subr3: rol edx,4
mov al,dl
call htoasc
stosw
loop subr3
popad
pop ebp
ret 8
subrb endp

htoasc proc
and al,0fh
add al,90h
daa
adc al,40h
daa
ret
htoasc endp
subrlen=$
subrseg ends

DemoCodeSEG segment para use32
assume cs:DemoCodeSEG
DemoBegin:
mov fs:tosubr.dcount,2 ;?看不懂的地方2,这里的段寄存器为啥是fs
push dword ptr gs:temptask.treip ;?看不懂的地方3,这里的段寄存器为啥是gs
push offset Message
call32 tosubr_sel,0 ;这个子函数看得懂
assume ds:temptssseg
push gs
pop ds ;看不懂的地方4,为啥要push gs然后pop ds
mov ax,normal_sel
mov temptask.trds,ax
mov temptask.tres,ax
mov temptask.trfs,ax
mov temptask.trgs,ax
mov temptask.trss,ax
jump32 totempt_sel,0 ;看不懂的地方5,这里的totempt_sel选择子对应的是段temptssseg,而段temptssseg是个没赋初值的结构
;体,怎么跳转过去呢?
DemoCodeLEN=$
DemoCodeSEG ends

temptssseg segment para use16
temptask taskss <>
db 0ffh
temptsslen=$
temptssseg ends

tempcodeseg segment para use16
assume cs:tempcodeseg
Virtual:
mov BX,tempTSS_SEL
LTR BX
jump16 demotss_sel,0 ;这里进行了切换到任务DemoTSSSEG,因为EIP是demobegin,这里跳转到demobegin
toreal:
clts
mov eax,cr0
and eax,0fffffffeh
mov cr0,eax
jump16 <seg real>,<offset real>
tempcodelen=$
tempcodeseg ends

RDataSEG segment para use16
VGDTR PDESC <GDTLEN-1,>
SPVAR DW ?
SSVAR DW ?
RDataSEG ends

RCodeSEG segment para use16
assume cs:rcodeseg,ds:rdataseg,es:rdataseg ;看不懂的地方1,以前没见到过一个段同时和两个段寄存器对应的代码
start:
mov ax,Rdataseg
mov ds,ax
cld
call init_gdt

mov ax,DemoLDTSEG
mov fs,ax
mov cx,DemoLDNUM
mov SI,OFFSET DemoLDT
call init_ldt

mov ssvar,ss
mov spvar,sp

lgdt qword ptr vgdtr
cli
mov eax,cr0
or eax,1
mov cr0,eax
jump16 <tempCode_sel>,<offset virtual>
Real:
mov ax,RDataSEG
mov ds,ax
lss sp,dword ptr spvar
sti
mov ax,4c00h
int 21h

init_gdt proc near
push ds
mov ax,gdtseg
mov ds,ax
mov cx,gdnum
mov si,offset effgdt
initg: mov ax,[si].basel
movzx eax,ax
shl eax,4
shld edx,eax,16
mov [si].basel,ax
mov [si].basem,dl
mov [si].baseh,dh
add si,size descriptor
loop initg
pop ds

mov bx,16
mov ax,gdtseg
mul bx
mov word ptr vgdtr.base,ax
mov word ptr vgdtr.base+2,dx
ret
init_gdt endp

init_ldt proc
ildt: mov ax,fs:[si].basel
movzx eax,ax
SHL eax,4
shld edx,eax,16
mov fs:[si].basel,ax
mov fs:[si].basem,dl
mov fs:[si].baseh,dh
add si,size descriptor
loop ildt
ret
init_ldt endp
RCodeSEG ends
end start
...全文
653 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
feekee_majia 2020-01-16
  • 打赏
  • 举报
回复
上面的内容是抄书上的,继续作一下笔记。。 totempt_sel这个选择子,是被采用段间转移指令JMP,通过任务门TOTEMPT切换到临时任务temptssseg;而临时任务在切换到DemoCodeSEG这段之前,挂起的点是ToReal点,所以第5个地方切换以后得以继续执行。。
feekee 2020-01-16
  • 打赏
  • 举报
回复
原来第5个问题书上有讲,只怪自己当时一边干别的事,一边看书,浮躁没看下去。。 totempt_sel这个选择子,是采用段间转移指令JMP,通过任务门TOTEMPT切换到临时任务。临时任务的现场从临时任务的TSS恢复,临时任务的挂起点是临时任务代码段内的ToReal点,所以就从该点下去继续执行
feekee 2019-09-18
  • 打赏
  • 举报
回复
关于这个example, 第一个“没见到过一个段同时和两个段寄存器对应的代码”,感谢早打大打核战争老师解释; 剩下几个,确实看不懂为啥这样写,能否请老师们具体解释一下,多谢。 另外,语法什么的明白,就是看不懂二、三的用法和四的安排,以及五的原理。多谢
feekee 2019-07-23
  • 打赏
  • 举报
回复
感谢楼上两位,最近领导布置任务比较多,等过一段再细看这个exa,多谢
tielian 2019-07-21
  • 打赏
  • 举报
回复
DemoCodeSEG 这个段的执行环境已经在DemoTSSSEG中设置好了。

jump16 demotss_sel,0 ;

这里通过TSS切换到DemoCodeSEG,将DemoTSSSEG中设置的值全部加载到对应的寄存器中。你的问题全部在DemoTSSSEG这个TSS段中,要仔细看。

ASSUME 是伪指令, 配合SEGMENT伪指令使用的,其作用是告诉编译器寻址某一特定段时要使用哪一个段寄存器。
  • 打赏
  • 举报
回复
assume cs:rcodeseg,ds:rdataseg,es:rdataseg ;看不懂的地方1,以前没见到过一个段同时和两个段寄存器对应的代码
=========================================
这个确实没啥用,但是也可以这么写,可能有用的地方是串扫描、串复制,这里没有


mov fs:tosubr.dcount,2 ;?看不懂的地方2,这里的段寄存器为啥是fs
=========================================
他初始化的代码有:
mov ax,DemoLDTSEG
mov fs,ax

剩下的你慢慢看吧

feekee 2019-07-17
  • 打赏
  • 举报
回复
把386scd.asm也贴上去吧,发现还是用代码格式贴清晰一些,多谢各位
;符号常量等的定义
;存储段描述符/系统段描述符结构类型的定义
descriptor	struc
limitl		dw	0
basel		dw	0
basem		db	0
attributes	dw	0
baseh		db	0
descriptor	ends
;门描述符结构类型的定义
gate	struc
offsetl		dw	0
selector	dw	0
dcount		db	0
gtype		db	0
offseth		dw	0
gate	ends
;伪描述符结构类型的定义
pdesc	struc
limit	dw	0
base	dd	0
pdesc	ends
;TSS结构类型的定义
taskss	struc
	trlink	dw	?,0
	tresp0	dd	?
	trss0	dw	?,0
	tresp1	dd	?
	trss1	dw	?,0
	tresp2	dd	?
	trss2	dw	?,0
	trcr3	dd	?
	treip	dd	?
	treflag	dw	?,?
	treax	dd	?
	trecx	dd	?
	tredx	dd	?
	trebx	dd	?
	tresp	dd	?
	trebp	dd	?
	tresi	dd	?
	tredi	dd	?
	tres	dw	?,0
	trcs	dw	?,0
	trss	dw	?,0
	trds	dw	?,0
	trfs	dw	?,0
	trgs	dw	?,0
	trldt	dw	?,0
	trflag	dw	0
	triomap	dw	$+2
taskss	ends
;存储段描述符类型值说明
ATDR=90h
ATDW=92H
ATDWA=93H
ATCE=98H
ATCER=9AH
ATCCO=9CH	;存在的只执行一致代码段类型值
ATCCOR=9EH
;系统描述符和门描述符类型值说明
ATLDT=82h	;局部描述符表段值类型
ATTASKGAT=85H
AT386TSS=89H	;?386TSS类型值
AT386CGAT=8CH	;386调用门
AT386IGAT=8EH
AT386TGAT=8FH
;DPL和RPL值说明
DPL1=20H
DPL2=40H
DPL3=60H
RPL1=01H
RPL2=02H
RPL3=03H
IOPL1=1000H
IOPL2=2000H
IOPL3=3000H
;其他常量值说明
D32=4000H	;在描述可执行段的描述符中,表示32位代码段
TIL=04H	;描述符表标志
VFML=0002H
IFL=0200H
;32位偏移的段间转移宏指令
JUMP32	MACRO	selector,offsetv
	DB	0eaH
	DW	offsetv	;32位偏移
	DW	0
	DW	selector
	ENDM
CALL32	MACRO	selector,offsetv
	db	09ah
	dw	offsetv
	dw	0
	dw	selector
	endm
JUMP16	MACRO	selector,offsetv
	db	0eah
	dw	offsetv
	dw	selector
	endm
call16	MACRO	selector,offsetv
	db	9ah
	dw	offsetv
	dw	selector
	endm
feekee 2019-07-17
  • 打赏
  • 举报
回复
把386scd.asm也贴上去吧,点回复没出来专门的回复页面,就不以专门的代码格式发了
;符号常量等的定义
;存储段描述符/系统段描述符结构类型的定义
descriptor struc
limitl dw 0
basel dw 0
basem db 0
attributes dw 0
baseh db 0
descriptor ends
;门描述符结构类型的定义
gate struc
offsetl dw 0
selector dw 0
dcount db 0
gtype db 0
offseth dw 0
gate ends
;伪描述符结构类型的定义
pdesc struc
limit dw 0
base dd 0
pdesc ends
;TSS结构类型的定义
taskss struc
trlink dw ?,0
tresp0 dd ?
trss0 dw ?,0
tresp1 dd ?
trss1 dw ?,0
tresp2 dd ?
trss2 dw ?,0
trcr3 dd ?
treip dd ?
treflag dw ?,?
treax dd ?
trecx dd ?
tredx dd ?
trebx dd ?
tresp dd ?
trebp dd ?
tresi dd ?
tredi dd ?
tres dw ?,0
trcs dw ?,0
trss dw ?,0
trds dw ?,0
trfs dw ?,0
trgs dw ?,0
trldt dw ?,0
trflag dw 0
triomap dw $+2
taskss ends
;存储段描述符类型值说明
ATDR=90h
ATDW=92H
ATDWA=93H
ATCE=98H
ATCER=9AH
ATCCO=9CH ;存在的只执行一致代码段类型值
ATCCOR=9EH
;系统描述符和门描述符类型值说明
ATLDT=82h ;局部描述符表段值类型
ATTASKGAT=85H
AT386TSS=89H ;?386TSS类型值
AT386CGAT=8CH ;386调用门
AT386IGAT=8EH
AT386TGAT=8FH
;DPL和RPL值说明
DPL1=20H
DPL2=40H
DPL3=60H
RPL1=01H
RPL2=02H
RPL3=03H
IOPL1=1000H
IOPL2=2000H
IOPL3=3000H
;其他常量值说明
D32=4000H ;在描述可执行段的描述符中,表示32位代码段
TIL=04H ;描述符表标志
VFML=0002H
IFL=0200H
;32位偏移的段间转移宏指令
JUMP32 MACRO selector,offsetv
DB 0eaH
DW offsetv ;32位偏移
DW 0
DW selector
ENDM
CALL32 MACRO selector,offsetv
db 09ah
dw offsetv
dw 0
dw selector
endm
JUMP16 MACRO selector,offsetv
db 0eah
dw offsetv
dw selector
endm
call16 MACRO selector,offsetv
db 9ah
dw offsetv
dw selector
endm

21,458

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧