程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 詳解駐留exe文件

詳解駐留exe文件

編輯:匯編語言

運行重定位exe文件,重定位因子調度覆蓋模塊,鏈接器3制靜態覆蓋塊,析棧初始startup

(1) X86匯編語言的組,段,類

偽指令group/segment,定義組/段,這使:

(1.1) 同組的各段,處於同一64k空間

(1.2) 段可聲明'對齊,組合,類'可選屬性:

(1.2.1) 段首,能對齊到BYTE,WORD,PARA(16字節),PAGE(256字節),缺省對齊到PARA.

(1.2.2) 不同源文的同名同類段,想靠鏈接,形成空間鄰接或重疊的同名組合邏輯

段時,需用PUBLIC,COMMON,指明組合形式:

(1.2.2.1) PUBLIC,指明此段按對齊屬性,鄰在已包含在此組合邏輯段內的最末字面段之後

(1.2.2.2) COMMON,指明此段與同屬此組合邏輯段的其他字面段,從組合邏輯段首鋪展

同屬組合邏輯段的各參與段的最大對齊屬性(例如,WORD比BYTE大),決定組合邏輯段的對齊屬性.

不與其它段組合的段,稱為單邏輯段.

以下,用"邏輯段",統稱組合邏輯段及單邏輯段.

(1.3) 類用'cls'指明,未指明類的各段,屬'匿名'類.同類各段,鄰接排列.

(2) 解釋各邏輯段空間關系的3個源文

a1.asm,聲明1個組,4個段,涉及'匿名','dec_'類

(2.1) grp組,含seg1段

(2.2) seg1段

(2.3) ovlap段,用COMMON參與組合,'dec_'類

(2.4) touch段,用PUBLIC參與組合

(2.5) stk1段,用STACK指明棧段及PARA對齊

grp GROUP seg1
seg1 SEGMENT PAGE
str1 DB "S1$"
seg1 ENDS
ovlap SEGMENT PARA COMMON 'dec_'
str3 DB '11$'
ovlap ENDS
touch SEGMENT PUBLIC
     ASSUME cs:touch,ds:NOTHING
     ORG 11H
@: mov ah,9
     mov bx,grp  ;取grp段值
     mov ds,bx
     mov dx,OFFSET str1 ;取str1相對seg1偏置
     int 21h
     EXTRN str2:far
     mov dx,OFFSET grp:str2 ;取str2相對grp偏置
     int 21h
     ASSUME ds:ovlap
     mov bx,SEG str3  ;取str3段值
     mov ds,bx
     lea dx,str3  ;取str3相對ds偏置
     int 21h
touch ENDS
stk1  SEGMENT PAGE STACK
     DW 16H DUP (4AH) ;初值4AH的16H個字
stk1 ENDS
     END @
   a2.asm,聲明1個組,3個段,涉及'匿名','dec_','_stk'類:

(2.6) ovlap段,用COMMON參與組合,'dec_'類

(2.7) stk2段,用STACK指明棧段及PARA對齊,'_stk'類

(2.8) grp組,含seg3段

(2.9) seg3段,'dec_'類

ovlap SEGMENT COMMON 'dec_'
     DB '2'
ovlap ENDS
stk2 SEGMENT WORD STACK '_stk'
     DW 13H DUP (2BH) ;初值2BH的13H個字
stk2 ENDS
grp GROUP seg3
seg3 SEGMENT 'dec_'
     PUBLIC str3
str3 DB '33$'
seg3 ENDS
     END

a3.asm,聲明1個組,4個段,涉及'匿名','_stk'類:

(2.10) grp組,含seg2段

(2.11) touch段,用PUBLIC參與組合

(2.12) seg2段

(2.13) stk2段,用STACK指明棧段及PARA對齊,'_stk'類

(2.14) seg1段

grp GROUP seg2
touch SEGMENT BYTE PUBLIC
     EXTRN str3:far
     ASSUME cs:touch,ds:NOTHING
@1: mov cx,SEG grp  ;取grp段值
     mov ds,cx
     mov dx,OFFSET grp:str3 ;取str3相對grp偏置
     int 21h
     mov cx,seg1   ;取seg1段值
     mov ds,cx
     mov dx,OFFSET seg1:str4 ;取str4相對seg1偏置
     int 21h
     mov ah,4ch   ;程序終止
     int 21h
touch ENDS
seg2 SEGMENT BYTE
     PUBLIC str2
str2 DB "S2$"
seg2 ENDS
stk2 SEGMENT WORD STACK '_stk'
     DW 31H DUP (0B2H) ;初值B2H的31H個字
stk2 ENDS
seg1 SEGMENT BYTE
str4 DB "%$"
seg1 ENDS
     END @1
   用masm5.exe(版5.10B,囿95 DDK),生成同名obj及lst文件.例如,匯編a1,命令行是:

masm5 a1,,a1;

用含覆蓋管理器的link4.exe(版5.01.17,同囿DDK),依序鏈接obj,生成a.exe程序文件,a.map映像文件,命令行是:link4 a1+a2+a3,a,a,,,

a.exe,顯'S1S22133%'

a.map含:

Start Stop  Length Name          Class
00000H 00002H 00003H SEG1        
00010H 00055H 00046H TOUCH        
00060H 0008BH 0002CH STK1        
0008CH 0008EH 00003H SEG2        
0008FH 00090H 00002H SEG1        
000A0H 000A2H 00003H OVLAP         DEC_
000B0H 000B2H 00003H SEG3          DEC_
000C0H 00147H 00088H STK2          _STK
Origin  Group
0000:0  GRP
entry point at 0001:0011

(3) 邏輯段排列准則:按鏈接次序,按字面段的源文次序,按類名大寫ASCII次序

因此,a.exe含8個邏輯段(段名被大寫):

(3.1) '匿名'類的a1的單邏輯段SEG1

(3.2) '匿名'類的a1與a3的組合邏輯段TOUCH,參與的a1及a3中touch字面段,代碼相接.

(3.3) '匿名'類的a1的單邏輯段STK1

(3.4) '匿名'類的a3的單邏輯段SEG2

(3.5) '匿名'類的a3的單邏輯段SEG1

(3.6) 'DEC_'類的a1與a2的組合邏輯段OVLAP,參與的a2及a3中ovlap字面段,使str3變為'21$'

(3.7) 'DEC_'類的a2的單邏輯段SEG3

(3.8) '_STK'類的a2與a3的組合邏輯段STK2,參與的a2及a3中stk2字面段,按PUBLIC,兩空間鄰接
   (4) 鏈接時,程序cs:ip及ss:sp設定

用'END expression'形式指明的各偽指令,最先者,expression所在段,及expression相對所在段的偏置,是程序的cs:ip.無此偽指令,cs,ip是0.

例如,a1的'END @'先於a3的'END @1',因此,程序a.exe入口,cs=1,是@所在段相對exe文件裝入模塊首的節數,ip=11,是@相對所在段的偏置.

用組合屬性STACK指明的各邏輯段,map文件最末者,是棧段;無此邏輯段,map文件最先邏輯段,是棧段.

例如,指明STACK的組合邏輯段STK2,後於單邏輯段STK1,因此,程序a.exe棧區,ss=STK2相對exe文件裝入模塊首的節數0ch,sp=88h,是STK2尺寸.

(5) 匯編時的機器碼暫定

能/不能被鏈接解決的作為操作數的段值/段偏置,其指令後面,帶後綴R被暫定;能被鏈接解決的外部定義,其指令後面,帶後綴E被暫定.因此,

a1.lst含:

0013 BB ---- R     mov bx,grp
0018 BA 0000 R     mov dx,OFFSET str1
001D BA 0000 E     mov dx,OFFSET grp:str2
0022 BB ---- R     mov bx,SEG str3
0027 8D 16 0000 R     lea dx,str3
a3.lst含:
0000 B9 ---- R @1: mov cx,SEG grp
0005 BA 0000 E  mov dx,OFFSET grp:str3
000A B9 ---- R  mov cx,seg1
000F BA 0000 R  mov dx,OFFSET seg1:str4

(6) 鏈接時的機器碼暫定,及運行重定位exe文件

作為操作數的段值,相對裝入模塊首,被暫定.外殼command.com啟動命令行上的程序時,先開辟被節號x,節長1的存儲控制塊(MCB)標識的空閒內存,此MCB前3個域值為:字節值5A(內存塊鏈尾),字0(無效進程PSP),字y(x+1+y=A000段,即640K內存尾),然後在x+1段首,先建10節程序段前綴(PSP),後鋪展程序的裝入模塊.

這時,exe裝入頭的cs/ss值,與x+11h(叫"裝入段值")相加,形成運行cs/ss值,此為"運行重定位exe".裝入模塊中,鏈接時的各機器碼暫定,與外殼指定的"重定位因子"相加,形成運行邏輯段值.

一般地,重定位因子=裝入段值.也可用功能4b03的裝入段值/重定位因子兩參數,分別指定,如(8)所述.

因此,改a1.exe為a,做debug a,用U 321,反出代碼區:

0321 B409     MOV AH,09              
0323 BB0000    MOV BX,0000 ;取grp段值             
0326 8EDB     MOV DS,BX              
0328 BA0000    MOV DX,0000 ;取str1相對seg1偏置
032B CD21     INT 21               
032D BA8C00    MOV DX,008C ;取str2相對grp偏置
0330 CD21     INT 21               
0332 BB0A00    MOV BX,000A ;取str3段值
0335 8EDB     MOV DS,BX              
0337 8D160000   LEA DX,[0000] ;ASSUME ds:ovlap時,取str3相對ds偏置            
033B CD21     INT 21               
033D B90000    MOV CX,0000 ;取grp段值             
0340 8ED9     MOV DS,CX              
0342 BAB000    MOV DX,00B0 ;取str3相對grp偏置             
0345 CD21     INT 21               
0347 B90800    MOV CX,0008 ;取seg1段值             
034A 8ED9     MOV DS,CX              
034C BA0F00    MOV DX,000F ;取str4相對seg1偏置             
034F CD21     INT 21               
0351 B44C     MOV AH,4C              
0353 CD21     INT 21
   (7) MS-DOS的exe文件兩部構成:

前部,含裝入頭(1ch字節長)及重定位表;後部,是裝入模塊.

鏈接時的各機器碼暫定,相對裝入模塊首的偏置:節,用2個字w_o,w_p,存於重定位表.

(7.1) 裝入頭的字節偏置:

0,1 : 4d(M),5a(Z)標識

2,3 : exe文件淨長度,除以512後的余數

4,5 : exe文件淨長度,被512量的值

6,7 : 重定位表的項數

8,9 : 前部占用節數

a,b : 裝入模塊之後,所需最小節數

c,d : 裝入模塊之後,所需最大節數

e,f : ss相對裝入模塊首的節數

10,11 : sp

12,13 : exe文件的字檢查和

14,15 : ip

16,17 : cs相對裝入模塊首的節數

18,19 : 重定位表相對exe文件的字節偏置

1a,1b : 覆蓋號

a,長840字節(348h),做debug a,用D 100 L2e,顯出exe文件頭的前2Eh個字節:

0100 4D 5A 48 01 02 00 04 00-20 00 00 00 FF FF 0C 00
0110 88 00 D3 A2 11 00 01 00-1E 00 00 00 01 00 14 00
0120 01 00 23 00 01 00 2E 00-01 00 38 00 01 00

(7.2) 解釋裝入頭:

(7.2.1) a的長度,除以512後,余148H,放2,3字節

(7.2.2) a的長度,被512量,占2,放4,5字節

(7.2.3) 重定位表,含4項

(7.2.4) exe文件前部,占20H節

(7.2.5) 重定位表相對a,字節偏置是1eh

(7.3) 相對a,字節偏置是1eh的重定位表解釋:

第1項,w_o=14h,w_p=1,指出此機器碼暫定,相對裝入模塊首,是1節14h偏置,即1*10h+14h=24h(字節).

debug從100h裝a,向高20h節(200h字節),是裝入模塊首,(100h+200h)加上24h的324h處,恰為MOV BX,0000中的段值位置.

第2項,w_o=23,w_p=1,相對裝入模塊首,是1節23h偏置,即1*10h+23h=33h(字節).300h加上33h的333h處,恰為MOV BX,000A中的段值位置.

同理,第3,4項,是MOV CX,0000及MOV CX,0008中的段值位置.

(8) 重定位因子調度覆蓋模塊

功能4b03,鋪展exe裝入模塊.前部略去PSP的裝入模塊,稱覆蓋模塊.

調用覆蓋模塊cs:ip入口的常駐者(如ovlayer.exe),要做:

(8.1) 將覆蓋模塊所在exe裝入頭中的程序cs:ip,讀到entry

(8.2) 調用功能4a,釋放其尾後內存

(8.3) 填寫4b03的裝入段值/重定位因子兩參數

(8.4) 調用功能4b03,它在空閒內存MCB之高1節,鋪展覆蓋模塊

(8.5) 用call entry語句,調用覆蓋模塊cs:ip入口

覆蓋模塊(如ovlayee.exe)工作完時,用retf,返回控制到常駐者.

覆蓋模塊被功能403鋪展時,與(6)同樣處理,作為mov ax,work操作數的段值work,與重

定位因子相加,這使ovlayee.exe,被ovlayer.exe調度,顯示某區/某串值,例如,先顯

o1區串s1值'os1',再顯o2區串s2值'os2'.

(8.6) ovlayee文

要點: 只含1個邏輯段work,故work的機器碼暫定,相對裝入模塊首,必為0,與重

定位因子的相加結果,恰=重定位因子.

要點: 不需寫"END @"偽指令,讓cs/ip為0,而ss/sp,借用ovlayer.exe棧區.

work segment
assume cs:work
push ds
mov ax,work
mov ds,ax
mov ah,9 ;顯串
int 21h ;dx被ovlayer指定
pop ds
retf  ;遠返回
work ends
END

(8.7) ovlayer文

要點: 引入PARA對齊的tail空段,使長度可變的ovlayer.exe,從PSP首到tail,作為新占用內存,tail之上,是空閒內存MCB.

要點: mov bx,tail語句之後,勿寫標號,否則masm5報錯.

o1 segment
s1 db 'os1$'
o1 ends
o2 segment
s2 db 'os2$'
o2 ends
arg segment
loadseg dw   2    ;裝入段值
factor dw   2    ;重定位因子
entry  dd   4
filenam db 'ovlayee.exe',0
header db   1ch   dup(1)
arg ends
stk   segment STACK
     dw   16   dup(9)
stk   ends
root  segment
     assume cs:root,ds:NOTHING
@: mov ax,arg
mov ds,ax
mov ax,3d00h ;讀打開
     mov   dx,offset arg:filenam
int 21h
     jnc   @F     ;@F,@B,向前/後找最近的@@標號
     mov   ah,4ch
     int   21h
@@:   mov   bx,ax      ;句柄送bx
     mov ah,3fh ;讀裝入頭到header
     mov cx,1ch
     mov   dx,offset arg:header
     int 21h
mov ah,3eh ;關閉
int 21h
mov   bx,tail    ;tail指向映像尾節
mov di,es
     sub   bx,di      ;bx是此程序新占用內存的節數
     mov ah,4ah ;新占用內存,始於es所指PSP節,長bx節
     int 21h
add bx,di
     inc bx
     mov   ds:loadseg,bx ;裝入段值=MCB之高1節
mov ax,seg s1 ;重定位因子=s1所在段
     mov   ds:factor,ax
     mov ax,word ptr ds:[header+14h] ;取覆蓋模塊ip
     mov   word ptr ds:[entry],ax
     add bx,word ptr ds:[header+16h] ;覆蓋模塊的cs,加上MCB之高1節
     mov   word ptr ds:[entry+2],bx
mov ax,ds
mov es,ax
     mov ax,4b03h
     mov   bx,offset arg:loadseg   ;es:bx指參數塊
     mov   dx,offset arg:filenam   ;ds:dx指程序名
     int 21h
     mov   dx,offset o1:s1  ;dx是s1相對o1的偏置
     call  ds:entry
mov ax,seg s2
     mov   ds:factor,ax    ;重定位因子=s2所在段
     mov ax,4b03h
     mov   bx,offset arg:loadseg   ;es:bx指參數塊
     mov   dx,offset arg:filenam   ;ds:dx指程序名
     int 21h
     mov   dx,offset o2:s2  ;dx是s2相對o2的偏置
     call  ds:entry
     mov   ah,4ch
     int   21h
root ends
tail  segment  ;空段
tail ends
     END @


   (9) 鏈接器3制靜態覆蓋塊

link4的obj參數,囿於括號時,生成OVERLAY_DATA,OVERLAY_AREA,OVERLAY_END塊,使DOS的exe長達16M.

用4個源文闡述:

(9.1) root文

要點: 入口@需處於裝入模塊首

要點: extrn的near/far,聲明近/遠標號

c_root  segment
     assume cs:c_root
     extrn  ov_near:near,ov_far:far,ov_far1:far
@:   call  ov_near     ;近調用
     call  ov_far     ;遠調用  
     jmp   ov_far1     ;遠轉移
c_root  ends
stk  segment  STACK
     dw   16   dup(1)
stk  ends
     END   @
 

(9.2) ov_near文

要點: ret是近返回

c_near  segment
     assume cs:c_near
     public ov_near
ov_near:mov   ah,2
     mov   dl,'N'
     int   21h
     ret  ;近返回
c_near  ends
     END

(9.3) ov_far文

要點: retf是遠返回

c_far  segment
     assume cs:c_far
     public ov_far
ov_far: mov   ah,2
     mov   dl,'F'
     int   21h
     retf  ;遠返回
c_far  ends
     END
(9.4) ov_far1文:
c_far1 segment
     assume cs:c_far1
     public ov_far1
ov_far1:mov   ah,2
     mov   dl,'f'
     int   21h
       mov  ah,4ch
      int  21h
c_far1 ends
     END
   用masm5,生成擴展名為obj的root,ov_near,ov_far,ov_far1

用link4 root (ov_near ov_far) (ov_far1),root3,3,,,

生成root3.exe,3.map

exe文件,未囿於括號的obj的各邏輯段,及不屬於'CODE'類的代碼,是常駐部分,計為0號覆蓋塊.括號組,生成1號,2號覆蓋塊.

root3.exe,顯'NFf'

改root3.exe為root3,做debug root3,用U 300,反出代碼區:

0300 E82D00    CALL  0330              
0303 9A40000000  CALL  0000:0040            
0308 EA50000000  JMP  0000:0050
            

3.map含:

Start Stop  Length Name          Class
Resident
00000H 0000CH 0000DH C_ROOT       
00010H 0002FH 00020H STK         
00030H 00036H 00007H C_NEAR       
00040H 00046H 00007H C_FAR        
00050H 00059H 0000AH C_FAR1       
00060H 00082H 00023H OVERLAY_DATA      DATA
00090H 00090H 00000H OVERLAY_AREA      CODE
00090H 00090H 00000H OVERLAY_END      CODE
Overlay 1H
Overlay 2H
Origin  Group
0006:0  DGROUP

改root3.exe為root3,做debug root3,用D 100 L2A,顯出exe文件頭的前2Ah個字節:

0100 4D 5A 83 00 02 00 03 00-20 00 01 00 FF FF 01 00
0110 20 00 79 52 00 00 00 00-1E 00 00 00 01 00 04 00
0120 06 00 06 00 00 00 0B 00-00 00
   root3的重定位表,含3項:

第1項,w_o=4,w_p=6,指出OVERLAY_DATA塊的字節偏置4,5

第2項,w_o=6,w_p=0,指出CALL 0000:0040中的段值位置.

第3項,w_o=b,w_p=0,指出JMP 0000:0050中的段值位置.

用D 360 L23,顯出OVERLAY_DATA塊:

0360 01 00 03 00 00 00 00 00-00 00 00 00 00 00 00 00
0370 00 00 00 52 4F 4F 54 33-2E 45 58 45 00 00 00 00
0380 00 00 3F

筆者探出,對OVERLAY_DATA塊,字節偏置2,3,是覆蓋塊數3,偏置4,5,是cs相對裝入模塊首的節數.

(10) 析棧初始

ML611,匯編map含
00000H , 00000H _TEXT         CODE
00000H , 00019H _DATA         DATA
00020H , 00020H STACK         STACK
00040H , 00033H TAIL        
Origin  Group
0000:0  DGROUP
entry point at 0004:0000
的t.asm
.model small  ;僅數據段,代碼段
.data  ;隨psp
assume cs:@data
cry   dw  '$!'
i72:  push ax
      push dx
      push ds
      mov ah,9
     mov dx,cs
      mov ds,dx
     lea dx,cry
     int 21h
      pop ds
      pop dx
      pop ax
     iret
i27  dw  0,@data
.stack  32
tail  segment
.startup
     mov ax,2572h
      lea dx,i72
     int 21h
      mov dx,256+i27  ;計psp的駐容
      mov byte ptr es:[1],27h  ;es矢psp
      sub i27[2],16  ;矢psp
      call dword ptr i27  ;轉psp:0
tail  ends
     end
lst含
0015 0000 ---- R   i27  dw  0,@data
0000      tail  segment
     .startup
0017  mov ax,2572h
002F  call dword ptr i27

exe文件頭

0100 4D 5A 73 00 02 00 02 00-20 00 00 00 FF FF 02 00
0110 20 00 00 00 00 00 04 00-1E 00 00 00 01 00 17 00
0120 00 00 01 00 04 00

重定位表,第1項,矢i27的@data,第2項,矢17字節長的.startup第1字節

00 BA0000    MOV  DX,0000  ;運行時,字節1,2,加mcb所占節號及11h,制DS
03 8EDA     MOV  DS,DX
05 8CD3     MOV  BX,SS  ;外殼,已加好mcb所占節號及13h到SS
07 2BDA     SUB  BX,DX  ;13h-11h,差值2節,合20h字節
09 D1E3     SHL  BX,1
0B D1E3     SHL  BX,1              
0D D1E3     SHL  BX,1              
0F D1E3     SHL  BX,1              
11 FA      CLI   ;防來中斷                12 8ED2     MOV  SS,DX  ;              
14 03E3     ADD  SP,BX  ;本模式,移棧段環境到數據段高端
16 FB      STI
                  

(10.1) DEBUG t.exe實例

棧初始前,DS矢psp,SS已加好,SP=exe頭偏移10,11字節值20h:

AX=0000 BX=0000 CX=0073 DX=0000 SP=0020 BP=0000 SI=0000 DI=0000
DS=188B ES=188B SS=189D CS=189F IP=0000

初始後,DS,SS矢@data,SP多加棧容20h字節:

AX=0000 BX=0020 CX=0073 DX=189B SP=0040 BP=0000 SI=0000 DI=0000
DS=189B ES=188B SS=189B CS=189F IP=0017

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved