这个SideKick是个好东东。 J_U1eSz<j
$9*Xfb/
下面的程序不是我写的。 6}Y^X
`EU=u_N
用汇编编写DOS下的内存驻留程序(1) V}7I?
G
S! ,.#e (Y
RhbYDsG
UX2`x9
|...T
4:^Y
H*yX
Iq:
Dw;L=4F
|
绪言 GC$Hp!H
>F,~ QHcz
@?*26}qp
0.1 内存驻留与中断 |??uVA)\X
&hd+x5
|/ZpZ7
内存驻留程序英文叫Terminate and Stay Resident Program,缩写为TSR.这些程序加载进内存,执行完后,就驻留在内存里,当满足条件时,调到前台来执行。 2#6yO`?uo
r6 ,5&`&
3j<]
W
内存驻留程序的常用形式有: E[2c`XFd8
7Y@&&
)#Y*]
>诸如Borland 的SideKick弹出式实用程序 v.\1-Q?
5@Ot@o
T
-C2V$1
>日历系统 $}W=O:L+D
]_|qv1K6
5x4JDaG2
>网络服务器 %S.R@C[3
#12PO q
z{``v|K
>通讯程序 +n^$4f
A#2Fd7&
;2)@NH
>本地的DOS扩展(如CCDOS,UCDOS等中文系统都属于这个范畴) "=9L7.E)
3boINmX
A(Ugam~}
>一些可恶的人利用TSR技术制作很多可恶的病毒程序,几乎所有的病毒程序都是TSR程序. OyZgg(iN
|nz,srr~
\|DcWH1
就象多任务系统调度一个进程有一个调度程序一样,在PC中从前台程序进入到一个TSR,也要有一个调度者,只是PC操作系统的调度不称为调度程序,而只称为触发机制.触发机制调度TSR执行在PC机上党称为激活一个TSR.触发机制主要有以下几种: ~2V|]Y;s
D1
9uI&U4
RH6qi{)i!
>硬件中断:党用的是键盘中断INT 9H,时钟中断INT 8H,通讯中断INT 14H,磁盘中断INT 13H等等. 7qgHH p
vlm&)DIt
a,M7Bbx
>软件中断:党用的是键盘中断INT 16H,时钟中断INT 1CH,DOS中断INT 21H,等等. k=w%oqpN
RjSVa.x
O)`R)MQ)
>以上各种的结合. |CY.Y,
6BLw 4m=h
gHvxmIG
从以上的触发机制可以看出,TSR和PC机的中断系统有着密切的关系.每种激活方式实际上都是与中断有关的.常用特殊的击键序列的识别码是通过截获INT 9H和INT 16H来实现.实际上不管TSR程序的哪一个环节,都与中断有着密切的关系.因此在具体进行TSR和程序设计之前,先介绍PC中断系统.在此只作简单说明. lkFv5^%
<d$|~qS_
?$pp%
在PC机内存的最低端(0000H开始)的1K字节中,存放着256个指针即常说的中为向量或中断矢量(Interrupt vertor),每个中断向量都指向一个子程序,该程序称为中断处理程序(Interrup handler).一个中断向量由四个字节组成,有一个字是中断处理程序的偏移量值,后一个字是中断处理程序的段值.256中断向量一起称为中断向量表. %{&yXi:mS
h&[]B*BLr
9dJARSUuF
手式计算中断向量的首址,可通过以下的公式来求得: gAgzM?A1(
z930Wi{@
8WZM}3x$f{
X号中断向量的首址=0000H:X*4 @\z2FJ79w
,V.X-`Y
W84JB3p
当产生一个中断时,处理器都按顺序执行以下步骤: >=6tfLQ
%@kmuz??
y!mjZR,&
>在堆栈上压入处理器的标志(相当于指令PUSHF). e<9IwS!/
PRWS[
2[yk
VoWlBH
>在堆栈上压入当前CS和IP值(相当于指令PUSH CS和PUSH IP). 5R/k -h^`
gI'4g ZH
DP &,jU6
>关闭中断(CLI) e6
QUe.S
vM1f
-I-
9'\18_w
>从中断向量加载的CS和IP,执行中断处理程序. <k6Zx-6X<
-+#\WB{AI
wC`])z}bT
当执行完中断处理程序后,一般用IRET返回,它的作用是: F^3Q0KsT
^yu0Veypy
<i%.bfQ/-
>从堆栈上取出保存的IP和CS(相当于指令POP CS和PUSH CS). >q[ (UV
+VI2i~
mcpM<vY/H
>同时恢复中断前的处理器标志(相当于指令POPF). \;.\g6zX
#l+U(zH:JG
68+9^
中断有多种分类,由触发的原因和实现的性质来分,可分为硬件中断和软件中断,从操作系统分层实现来说,可以分成BIOS中断,BOS中断和用户中断. yWsNG;>
/b@8#px
^6Hfq^ejt
一方面,BIOS和DOS通过中断系统向用户提供一个操作系统功能界面.也就是说用户(一般来说是前台程序)的功能主要是通过调用DOS和BIOS的中断服务来实现的,具体来说就是通过INT指令来实现的.另一方面,BIOS和DOS由中断系统所构成,BIOS对硬件成为高层的功能,并通过中断的形式向用户提供. Qg<_te)\
K82pWpR
UOy`N~\gh+
如果在当前程序执行的同时,能将一块代码放在内存,把中断向量指向代码中的子程序,那么在当前程序执行中产生中断时,就有可能执行不属于当前程序和操作系统的代码,产生的中断可能是当前程序产生的软件中断,也可能是由硬件产生的硬件中断.这就是单任务的PC操作系统可能执行多于一个进程的简单说明. LylB3BM
vt
v|H
#fRhG^QKp
在PC中断系统中有几个中断具有周期性,即INT 8H,INT 1CH和INT 28H.它们或者周期性被执行用于时间计时,或者周期性产生用于等待.它们是在实现TSR时进行轮询触发的基础.键盘中断(INT 9H和INT 16H)当用户击键时发生,利用它们是进行热键处理的基础.串行口通讯也是触发的一个重要机制.此外众多的软件中断也是触发的媒介. a~9U{)@F
+0;6.PK
|94"bDL3~
37 T<LU
0.2 DOS的可重入性分析 Zq}w}v
V&eti2&zO
:0Rd )*k,v
一个多任务操作系统之所以能使多个进行并存,是因为操作系统的大部分代码是可以了重的,对于临界资源有相应的PV操作,使得当调度一个新的进程时,能完整地保存前一个里程的现场,当再一次调度被挂起的进程时能象没有被中断一样继续执行. c'vxT<8fWW
Gvb>M=9
_b&Mrd
对于PC机来说,代码的重入性比较弱,对临界资源没有PC操作.当我们用中断程序启动用户的TSR时,如果只保存标志和寄存器,以及当前进程一些信息,那么只保存了当前程序的一部分现场,DOS的临界资源不会自动保存.在进行TSR设计时,一定要了解PC操作系统的重入性和临界资源. %kxq" =3
9H_2Y%_
0gL]^_+7
重入性总是体现在代码上,所谓可重入代码的指这样的代码,即该代码被执行时还没有从中退出,由于某种原因又一次或者多次进入相同的代码,该代码每次的执行结果都是正确的,就说该代码是可重入的.相反,如果结果不正确,那么就就该代码是不可重入的.下面是一个可重入的子程序的例子: g>1yQ
i"_)91RA
z+@aQ@75
Add proc near mawomna
G{pfyfF
A{bt
Z#k
cmp DS:word ptr [si],0 )~rfx
P|!GXkS
UwvGw5)q
je DonotAddTheValue sbjAZzrX2i
`M6!V
D}>pl8ke~g
add ax,DS:word ptr [si] <IC=x(T
1j`-lD
\j+O |#`|)
DonotAddTheValue: SsIy ;l
lQ<2Vw#Yl
E!8FZv8
ret {Uz@`QO3
=!*e; L
^&03D5@LoY
Add endp C
},;M@xV
C\ZL*,%}
'nz;|6uC
上面的例子不管在其中任何一处再一次执行该子程序,执行结果不变.为了说明,只举多种可能性中的一种. TUw^KSa
0~iC#lHO
osoreo;V^
mov ds,0100h ;ds=0100h }/nbv;)
o+4/L)h
&na#ES$X,
mov si,0010h ;si=0010h me_DONW
%g5TU 6WP
.0:BgM
mov ax,0001h ;ax,=0001h v~H1Il_+
-icOg6%
O#7ONQfBO
call Add *`mPPts}
' Ph
:2pd2 S
cmp 0100h:word ptr [0010h],0 ;Call Add subroutine yM}}mypS
&=Gz[1
L
GbFLu`
I u
push ds ;Interrupted WS/^WxRY
W2D^%;mw
2?u>A3^R
push si +iz5
%Qe<f
o]t6u .L
9
c1g,:8\
push ax Kfa7}f_
0&mo1 k_U
g{.>nE^Sc5
mov ds,0200h ;ds=0200h #=V%S
2~
!
@{rkp
s:'M[xI
mov si,0200h ;si=0020h 6}='/d-[
^VK-[Sz&
Sf);j0G,D
mov ax,0003h ;ax=0003h w,bILv)
nm'sub
F[<EXL
Q
call Add
D>+&= 5{
6vbWe@#U/
kT&-:: ^R
cmp 0200h:word ptr [0020h],0 ;0200:0020h=0004h jV]'/X<
>@KQ )p' `
zlF*F8>m
jne ^1s!OT Is
?&I gD.
]( V+ qj
add ax,0200h:word ptr [0020h] ;ax=0007h K{.s{;#
M#LQz~E
x|d Xa0=N_
ret ;Return e^&QT
1t_$pDF}
+0rMv
pop ax ;ax=0001h l
TY%,s
guz{DBlK
dIQ7u
pop si ;si=0010h l=8)_z;~D
PVP,2Yq!
"u~l+aW0
pop ds ;ds=0100h *:J#[ET,
F1JSf&8
gcqcY
iret ;Return to Add subroutine #4%4iR5%
4:q<<vCJv
]W7(}~m
jne QWH1xId
bj\v0NKN4
Y]/(R"-2G
add ax,0100h:word ptr [0100h] ;ax= 0001h 7?-eR-
WMnR+?q
IMIZ#/
;0100h:0010h= 0002h \HLI
y
t
j&+HC
F' s(
$n
;---------------------------------------- (f#QETiV
SweaERl
/=w9bUj5v
;ax = 0003h ?BT\)@h
fu?5gzT+b
5!$m3j_,]?
ret b Gq0k&
@=,2{JF*6
)X@Obg
mov bx,ax @'C f<wns
{Z 3t0F
X|K"p(N
而下面的子程序是不可重入的: 0,)B~|+
5 WSu
ML'4 2z
Y
Add proc near 8J{I6nPF
e48`cX\E
wUWSW<
mov Temp,ax +(0Fab8g
34-QgE
] as_7
mov ax,DS:word ptr [si] TC[_Ip&
s
`HSTq2
`2c>M\c4U
cmp ax,0 o90SXa&l/
5tT-[mQ*
Zx,R6@l
je DonotTheValue }d
dwL
0L"CM?C
AWHB^}!}
add ax,Temp -fw0bL%0
ZHUAM59bx
<MZ$ baK
DonotTheValue: EF=.L
{
OSk:njyC[
|};]^5s9
ret ;F9<Yv
Ev* b
|7n&I`#
Temp: #mlTN3
i/9QOw~
AN7WMX
dw 0 Ug_5INK
Q];gC{I
$C0NvJf
Add endp FL% GW: