这个SideKick是个好东东。 _<s[HGA`z
Q#w mS&$f
下面的程序不是我写的。 xucrp::g
/~~aK2{^X~
用汇编编写DOS下的内存驻留程序(1) h_#x@p
%Xc50n2Z
tj$&89
W^#HR
3D32'KO_"
B( r~Nvc
B3|h$aKC
绪言 zGzeu)d
9'nM$a
dO]N&'P7
0.1 内存驻留与中断 5x856RQ'
TgMa!Vz
1W3+ng
内存驻留程序英文叫Terminate and Stay Resident Program,缩写为TSR.这些程序加载进内存,执行完后,就驻留在内存里,当满足条件时,调到前台来执行。 HHVCw7r0
HY-7{irR~
~Cc%!4f'
内存驻留程序的常用形式有: 8T<LNC
[d
30mVM
W%&t[_21
>诸如Borland 的SideKick弹出式实用程序 vP6NIcWC3
KZrg4TEVi
fy9m
S
>日历系统 (K9pr>le
7[z^0?Pygf
yvR3|
>网络服务器 x-27r
GN
S:2M9nC
7QV@lR<C2R
>通讯程序 hWc`4xdl
)45~YDS;t
.)=T1^[hI
>本地的DOS扩展(如CCDOS,UCDOS等中文系统都属于这个范畴) ]nPfIBoS
NZT2ni4
&U*MLf83`
>一些可恶的人利用TSR技术制作很多可恶的病毒程序,几乎所有的病毒程序都是TSR程序. c=d` DJ
#J=^CE
(zbV-4C
就象多任务系统调度一个进程有一个调度程序一样,在PC中从前台程序进入到一个TSR,也要有一个调度者,只是PC操作系统的调度不称为调度程序,而只称为触发机制.触发机制调度TSR执行在PC机上党称为激活一个TSR.触发机制主要有以下几种: WXHvUiFf
)S?. YCv?
7Z%EXDm4/c
>硬件中断:党用的是键盘中断INT 9H,时钟中断INT 8H,通讯中断INT 14H,磁盘中断INT 13H等等. U}f"a!
N{+6 V`\
~5`p/.L)ZD
>软件中断:党用的是键盘中断INT 16H,时钟中断INT 1CH,DOS中断INT 21H,等等. OM,Dy&Y
p G|-<6WY
2L!s'^m-
>以上各种的结合. [0c7fH`8V
|Y|6`9;
QFekj@
从以上的触发机制可以看出,TSR和PC机的中断系统有着密切的关系.每种激活方式实际上都是与中断有关的.常用特殊的击键序列的识别码是通过截获INT 9H和INT 16H来实现.实际上不管TSR程序的哪一个环节,都与中断有着密切的关系.因此在具体进行TSR和程序设计之前,先介绍PC中断系统.在此只作简单说明. QguRU|y
T:FaD V{
-c%#Hd
在PC机内存的最低端(0000H开始)的1K字节中,存放着256个指针即常说的中为向量或中断矢量(Interrupt vertor),每个中断向量都指向一个子程序,该程序称为中断处理程序(Interrup handler).一个中断向量由四个字节组成,有一个字是中断处理程序的偏移量值,后一个字是中断处理程序的段值.256中断向量一起称为中断向量表. (<GBhNj=c
a(.q=W
03N|@Tu
手式计算中断向量的首址,可通过以下的公式来求得: 0\tV@ 6p2=
1. A@5* Q
mq#8[D
X号中断向量的首址=0000H:X*4 D+4oV6}~
hc7"0mVd{
P+ejyl,
当产生一个中断时,处理器都按顺序执行以下步骤: xXb7/.*qE
'`s\_Q)hG_
a|}v?z\
>在堆栈上压入处理器的标志(相当于指令PUSHF). T{WJf-pI
^.3(o{g
/Ne;Kdp
>在堆栈上压入当前CS和IP值(相当于指令PUSH CS和PUSH IP). WAq)1gwN
U$,-F**
N
m{|
>关闭中断(CLI) `-_kOxe3
B:mtl?69g
PmjN!/
>从中断向量加载的CS和IP,执行中断处理程序. OVq(u
lwi+
h]6m+oPW
5>r2&72=
当执行完中断处理程序后,一般用IRET返回,它的作用是: ^*?mb)
e^!>W %.7Z
lZ,w#sqbY
>从堆栈上取出保存的IP和CS(相当于指令POP CS和PUSH CS). #su R[K*S
<Wrn/%tL
J|$UAOEDa
>同时恢复中断前的处理器标志(相当于指令POPF). ,8.Fd|#L
q,;8Ka )
g\.O5H9Od
中断有多种分类,由触发的原因和实现的性质来分,可分为硬件中断和软件中断,从操作系统分层实现来说,可以分成BIOS中断,BOS中断和用户中断. N>V\
MS5X#B
~ eNKu
一方面,BIOS和DOS通过中断系统向用户提供一个操作系统功能界面.也就是说用户(一般来说是前台程序)的功能主要是通过调用DOS和BIOS的中断服务来实现的,具体来说就是通过INT指令来实现的.另一方面,BIOS和DOS由中断系统所构成,BIOS对硬件成为高层的功能,并通过中断的形式向用户提供. @kstG3@
jJ.isr|`
]mzghH:E
如果在当前程序执行的同时,能将一块代码放在内存,把中断向量指向代码中的子程序,那么在当前程序执行中产生中断时,就有可能执行不属于当前程序和操作系统的代码,产生的中断可能是当前程序产生的软件中断,也可能是由硬件产生的硬件中断.这就是单任务的PC操作系统可能执行多于一个进程的简单说明. y@XE! L
~K$dQb])
hl}iw_e
在PC中断系统中有几个中断具有周期性,即INT 8H,INT 1CH和INT 28H.它们或者周期性被执行用于时间计时,或者周期性产生用于等待.它们是在实现TSR时进行轮询触发的基础.键盘中断(INT 9H和INT 16H)当用户击键时发生,利用它们是进行热键处理的基础.串行口通讯也是触发的一个重要机制.此外众多的软件中断也是触发的媒介.
]v2%h X
(V(8E%<c
cnw?3/J
\]Bwib%h
0.2 DOS的可重入性分析 C[ma
!he
8kdJ;%^N
s2=`haYu
一个多任务操作系统之所以能使多个进行并存,是因为操作系统的大部分代码是可以了重的,对于临界资源有相应的PV操作,使得当调度一个新的进程时,能完整地保存前一个里程的现场,当再一次调度被挂起的进程时能象没有被中断一样继续执行. Mi^/`1
2xxw8_~C
>DM^/EAG{
对于PC机来说,代码的重入性比较弱,对临界资源没有PC操作.当我们用中断程序启动用户的TSR时,如果只保存标志和寄存器,以及当前进程一些信息,那么只保存了当前程序的一部分现场,DOS的临界资源不会自动保存.在进行TSR设计时,一定要了解PC操作系统的重入性和临界资源. !l9i)6
W
DhVO}g)2#
^7Z#g0{^w
重入性总是体现在代码上,所谓可重入代码的指这样的代码,即该代码被执行时还没有从中退出,由于某种原因又一次或者多次进入相同的代码,该代码每次的执行结果都是正确的,就说该代码是可重入的.相反,如果结果不正确,那么就就该代码是不可重入的.下面是一个可重入的子程序的例子: :,Zs{\oI3
JnE\z*NB
Jb;@'o6
Add proc near "!S7D>2y#
(e"\%p`
6Pp3*O`/V
cmp DS:word ptr [si],0 _-=yD@;[D
bU4l|i;j
?3#L?Cq
je DonotAddTheValue 5ho!}K
]0o_-
NI
>mAi/TZC
add ax,DS:word ptr [si] ;$.^
E$"`|D
f
m'n<.1;1{j
DonotAddTheValue: N({0" 7
0{^ 0>H0
X_HU?Q_N
ret #i;y[dQ
6N\f>c
f|+aa6hN
Add endp F:~k4uTW\b
+b
sc3
1[]
9EJ
上面的例子不管在其中任何一处再一次执行该子程序,执行结果不变.为了说明,只举多种可能性中的一种. [iXk v\
W?H-Ng3E
#fVk;]u`[3
mov ds,0100h ;ds=0100h =w;~1i%.k
9P1!<6mN\
*-eDUT|O
mov si,0010h ;si=0010h zhZ!!b^6<
T)#e=WcP]
Mni@@W
mov ax,0001h ;ax,=0001h SX)o0v+
.;J6)h
mXwDB)O{)
call Add B;64(Vsa8
[,yYr
<dWms`QcO
cmp 0100h:word ptr [0010h],0 ;Call Add subroutine 2rG
g
-|DBO0q
BMdcW
MYU\
push ds ;Interrupted [gaB}aLn
W0+m A
'ZFbyt Q2
push si )NLjv=ql
pgw_F
STjk<DP(
push ax bZ SaL^^(
/{R>o0oW
Mp`!zw
R
mov ds,0200h ;ds=0200h o}b_`O
%#7
]
1v~1?+a\2
mov si,0200h ;si=0020h mS?W+jy%
Oa-(Xp,n#
{>Yna"p
mov ax,0003h ;ax=0003h !sVW0JS h
\=2<<
iv
Lk lD^AJA
call Add cI\&&<>SlG
0'Uo3jAB
>F5E^DY
cmp 0200h:word ptr [0020h],0 ;0200:0020h=0004h oiRrpS\T.
ruU &.mZ
*{!E`),FX
jne $!goM~pZ
GZ1c~uAu
5~FXy{ZIH
add ax,0200h:word ptr [0020h] ;ax=0007h [R0E4A?M
+.J/7gD
?s5/
ret ;Return q[TGEgG
3f-J%!aH
d
3;Sy`.
pop ax ;ax=0001h i%GNmD
!g[UFw
6f*QUw~
pop si ;si=0010h e_+SBN1`P&
kInU,/R*
jZgCDA8Mr!
pop ds ;ds=0100h Dqg01_O9O
*@eZt*_
X?aj0# Q
iret ;Return to Add subroutine %CV.xDE8
w6
9GgXX9K
jne yJGnN g
P`L, eYc
@
bIZ0tr4
add ax,0100h:word ptr [0100h] ;ax= 0001h 4?33t] "
LV8{c!"
{k uC+~R
;0100h:0010h= 0002h DQ.; 2W
rVM?[_'O
y=&^=Zh[
;---------------------------------------- quL+UFuM
W`F?j-4
@(CJT
-Ak
;ax = 0003h }B`T%(11=
888"X3.T
|>/m{L[
ret MLvd6tIv,
PI&@/+
[_-[S
mov bx,ax +>QD4z#
$O^"OQ_@
19;Pjo8
而下面的子程序是不可重入的: 9P& \2/ {
D[0g0>K
BIxjY
!!"
Add proc near +W+o~BE
MZvxcr{x
y:YJv x6&4
mov Temp,ax `u"
)*Q}
.#{m1mr
z9
$1jC
mov ax,DS:word ptr [si] 3Ct)5J
O ]!/fZ;(
H~;s$!lG
cmp ax,0 si1Szmx,
wBz5_ OFVw
n{"e8vQx
je DonotTheValue 2gJkpf9JN
rm%MQmF
-ZH6*7!
add ax,Temp Y'O3RA5E
ZC97Z sE
,CIsZ1[VS
DonotTheValue: WelB"L
[5-3PuT&9
v[]&yD
ret TFO4jjiC"
H`OJN.
E`b<^l`
Temp: <O3,b:vw
,56objaE
i4\DSQJ
dw 0 AGV+Y6
6&KcO:}-
_F`RwBOjs
Add endp Qe;R3D=T;