[029][x86匯編語言]第十三章 習題:修改內核程序和用戶程序,改由用戶程序自行提供棧空間

學習筆記

《x86匯編語言:從實模式到保護模式》
http://www.lxweimin.com/p/d481cb547e9f

答案參考

https://blog.csdn.net/longintchar/article/details/51167487?locationNum=5&fps=1

本章習題

  • 在本章中,用戶程序只給出建議的棧大小,但并不提供棧空間。現在,修改內核程序和用戶程序,改由用戶程序自行提供棧空間。要求:棧段必須定義在用戶程序之后。

習題解答

修改內核程序 c13_core.asm

 ;建立程序堆棧段描述符
         mov ecx,[edi+0x0c]                 ;4KB的倍率 
         mov ebx,0x000fffff
         sub ebx,ecx                        ;得到段界限
         
         mov eax,4096                        
         mul dword [edi+0x0c]  
         mov edx,edi
         add edx,[edi+0x08]
         add eax,edx                        ;得到棧的高端物理地址

         mov ecx,0x00c09600                 ;4KB粒度的堆棧段描述符
         call sys_routine_seg_sel:make_seg_descriptor
         call sys_routine_seg_sel:set_up_gdt_descriptor
         mov [edi+0x08],cx
  • 計算段界限
計算段界限

《x86匯編語言:從實模式到保護模式》 第237頁

修改用戶程序 c13.asm

usr_stack_len equ 1
usr_stack_cap equ usr_stack_len*0x1000 ; 0x1000 = 4096
     
;===============================================================================
SECTION header vstart=0

         program_length   dd program_end          ;程序總長度#0x00
         
         head_len         dd header_end           ;程序頭部的長度#0x04

         stack_seg        dd section.stack.start                ;用于接收堆棧段選擇子#0x08
         stack_len        dd usr_stack_len                      ;程序建議的堆棧大小#0x0c
                                                  ;以4KB為單位
                                                  
         prgentry         dd start                ;程序入口#0x10 
         code_seg         dd section.code.start   ;代碼段位置#0x14
         code_len         dd code_end             ;代碼段長度#0x18

         data_seg         dd section.data.start   ;數據段位置#0x1c
         data_len         dd data_end             ;數據段長度#0x20
             
;-------------------------------------------------------------------------------
         ;符號地址檢索表
         salt_items       dd (header_end-salt)/256 ;#0x24
         
         salt:                                     ;#0x28
         PrintString      db  '@PrintString'
                     times 256-($-PrintString) db 0
                     
         TerminateProgram db  '@TerminateProgram'
                     times 256-($-TerminateProgram) db 0
                     
         ReadDiskData     db  '@ReadDiskData'
                     times 256-($-ReadDiskData) db 0
                 
header_end:
;===============================================================================
SECTION stack vstart=0
stack_start:        
        times usr_stack_cap db 0    ;4KB的棧空間
stack_end:

;===============================================================================
  • 增加兩個常量 用戶程序棧的大小(以4KB為單位)usr_stack_len 以及 用戶程序棧的容量usr_stack_cap
  • 修改標號stack_seg 以及 stack_len 后面的初始值;
  • 增加段SECTION stack,這樣就由用戶程序自己給自己提供棧空間;

Bochs 調試

  • 從加載程序跳轉到內核程序
由加載程序的
行數   匯編地址  機器碼    匯編指令 
136 00000138 FF6F10     jmp far [edi+0x10]  

在 bochs使用
b 0x7d38
c
就可以跳轉到 加載程序 轉移控制權給 內核程序的這一條指令;

0x7d38  等于 0x7c00+0x138
  • 執行內核程序的指令
來到內核程序之后,遇到的第一條指令是:
行數    匯編地址  機器碼      匯編指令
561 00000159 B930000000    mov ecx,core_data_seg_sel     

而這條指令的真實物理地址是 0x410a9

我希望直接跳到,加載完全部描述符的
這條指令:
   503 000000EB 66894F08            mov [edi+0x08],cx

經過換算,可以得出,目標的真實物理地址
應該是 0x4103b

因此,在bochs里面使用
b 0x4103b
c
就可以跳轉到這條指令了。
  • 使用info gdt查看GDT的內容,看到 Expand-down字樣說明加載棧段成功
    Expand-dwon字樣說明這是向下生長的數據段即棧段.png
棧段都是Expand-down.png

Debug

1、調試用戶程序的時候,將某個SECTION的標號當做是從整個程序開頭的偏移量了

標記了vstart=0 說明標號的值是從段開始的偏移量

2、實際測試 push pop

  • 這里一開始忘記給字符串 message_test 最后加上 0 作為結尾,結果每次運行都死機,死機還死在不同的位置(就是顯示的字符串數量完全不一樣)
;===============================================================================
SECTION data vstart=0    
                         
         buffer times 1024 db  0         ;緩沖區

         message_1         db  0x0d,0x0a,0x0d,0x0a
                           db  '**********User program is runing**********'
                           db  0x0d,0x0a,0
         message_2         db  '  Disk data:',0x0d,0x0a,0

         message_test      db 0x0d,0x0a,0x0d,0x0a
                           db '>>>>>> test stack pass <<<<<<',0x0d,0x0a,0
data_end:

;===============================================================================

        ;>>>>>>>>>>>> TEST STACK <<<<<<<<<<<<<<<<<<<<<<
                push ecx
                
                mov ecx,1000
            testpush:
                push ebx
                loop testpush
            
                mov ecx,1000
            testpop:
                pop ebx
                loop testpop
                
                pop ecx
        
                
            mov ebx,message_test
            call far [fs:PrintString]

        ;>>>>>>>>>>>> TEST STACK <<<<<<<<<<<<<<<<<<<<<<

實際測試用戶程序的棧 測試結果
  • 心得:以后如果要寫有關測試的輸出語句,就應該在代碼可以正常運行的時候,先保證這條輸出語句也可以正常運行,再去功能化新的代碼,不然根本分不清是新代碼的功能有缺陷還是輸出語句本身錯了,誰會想到一條簡單的輸出函數調用都會錯,而且錯是錯在輸出用的字符串這里,沒錯,這就是匯編。

完整源碼

用戶程序 c13.asm (第十三章 習題答案)

           ;代碼清單13-3
         ;文件名:c13.asm
         ;文件說明:用戶程序 
         ;創建日期:21:58 2018/6/4
     
usr_stack_len equ 1
usr_stack_cap equ usr_stack_len*0x1000 ; 0x1000 = 4096
     
;===============================================================================
SECTION header vstart=0

         program_length   dd program_end          ;程序總長度#0x00
         
         head_len         dd header_end           ;程序頭部的長度#0x04

         stack_seg        dd section.stack.start                ;用于接收堆棧段選擇子#0x08
         stack_len        dd usr_stack_len                      ;程序建議的堆棧大小#0x0c
                                                  ;以4KB為單位
                                                  
         prgentry         dd start                ;程序入口#0x10 
         code_seg         dd section.code.start   ;代碼段位置#0x14
         code_len         dd code_end             ;代碼段長度#0x18

         data_seg         dd section.data.start   ;數據段位置#0x1c
         data_len         dd data_end             ;數據段長度#0x20
             
;-------------------------------------------------------------------------------
         ;符號地址檢索表
         salt_items       dd (header_end-salt)/256 ;#0x24
         
         salt:                                     ;#0x28
         PrintString      db  '@PrintString'
                     times 256-($-PrintString) db 0
                     
         TerminateProgram db  '@TerminateProgram'
                     times 256-($-TerminateProgram) db 0
                     
         ReadDiskData     db  '@ReadDiskData'
                     times 256-($-ReadDiskData) db 0
                 
header_end:
;===============================================================================
SECTION stack vstart=0
stack_start:        
        times usr_stack_cap db 0    ;4KB的棧空間
stack_end:

;===============================================================================
SECTION data vstart=0    
                         
         buffer times 1024 db  0         ;緩沖區

         message_1         db  0x0d,0x0a,0x0d,0x0a
                           db  '**********User program is runing**********'
                           db  0x0d,0x0a,0
         message_2         db  '  Disk data:',0x0d,0x0a,0

         message_test      db 0x0d,0x0a,0x0d,0x0a
                           db '>>>>>> test stack pass <<<<<<',0x0d,0x0a,0
data_end:

;===============================================================================
      [bits 32]
;===============================================================================
SECTION code vstart=0
start:
         mov eax,ds
         mov fs,eax
     
         mov eax,[stack_seg]
         mov ss,eax
         mov esp,0
     
         mov eax,[data_seg]
         mov ds,eax
     
         mov ebx,message_1
         call far [fs:PrintString]
     
         mov eax,100                         ;邏輯扇區號100
         mov ebx,buffer                      ;緩沖區偏移地址
         call far [fs:ReadDiskData]          ;段間調用
     
         mov ebx,message_2
         call far [fs:PrintString]
     
         mov ebx,buffer 
         call far [fs:PrintString]           ;too.
     
        
        ;>>>>>>>>>>>> TEST STACK <<<<<<<<<<<<<<<<<<<<<<
                push ecx
                
                mov ecx,1000
            testpush:
                push ebx
                loop testpush
            
                mov ecx,1000
            testpop:
                pop ebx
                loop testpop
                
                pop ecx
        
                
            mov ebx,message_test
            call far [fs:PrintString]

        ;>>>>>>>>>>>> TEST STACK <<<<<<<<<<<<<<<<<<<<<<


        jmp far [fs:TerminateProgram]       ;將控制權返回到系統 
         
         

      
code_end:

;===============================================================================
SECTION trail
;-------------------------------------------------------------------------------
program_end:
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容