問題已經找到,創建虛擬機的時候硬碟應該設定為PATA模式
如題,寫了兩個小程式,其中一個是用戶程式,用來顯示一句話;另一個是加載程式,位于主引導扇區中,用來把用戶程式加載到記憶體中并執行。
現在出現這個問題,在VirtualBox里面只能看到游標閃動,卻不見字串;用bochs除錯最終可以看到這個字串。下面是程式分別在VirtualBox里運行,在bochs里除錯時的截圖。


///////////////////////////////////////////////____用戶程式__________________________/////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;用戶程式說明:
;頭部包含了程式長度program_length、入口點code_entry、重定位表項數和重定位表
;===========================================================
SECTION header align=16 vstart=0
program_length dd program_end ;程式長度
code_entry dw start ;入口點偏移地址
dd section.code.start ;入口點段地址
realloc_tbl_len dw (header_end-code_segment)/4 ;重定位表項
code_segment dd section.code.start ;重定位表,分別是代碼段、資料段、堆疊段的段地址
data_segment dd section.data.start
stack_segment dd section.stack.start
header_end: ;頭部的結尾
;===========================================================
SECTION data align=16 vstart=0
msg dd 'Welcome to GoalPower workroom!' ;在螢屏上顯示的字串
dd 0
;===========================================================
SECTION code align=16 vstart=0
start:
mov ax, [stack_segment] ;初始化堆疊段暫存器
mov ss, ax
mov sp, stack_end ;初始化堆疊指標暫存器
mov ax, [data_segment] ;初始化資料段暫存器(這里沒有初始化ES,因為在加載程式里面已經設定完了)
mov ds, ax
mov bx, msg ;將要顯示的字串的偏移地址賦給BX
call put_string ;呼叫顯示字串的程序
jmp $ ;無限回圈
;----------------------------------------------------------------------------------------------------
;顯示字串的程序,將字符逐個放到顯存里
;輸入:BX=字串的首地址
put_string:
push ax
push cx
push dx
push bx
push si
push ds
push es
mov ax, 0xB800
mov es, ax
mov ch, 0x04
xor si, si
.put_char:
mov cl, [bx]
or cl, cl
jz .exit
mov word [ES:si], cx
add si, 2
inc bx
jmp .put_char
.exit:
pop es
pop ds
pop si
pop bx
pop dx
pop cx
pop ax
ret
;===========================================================
SECTION stack align=16 vstart=0 ;堆疊段
resb 0x100
stack_end: ;堆疊段的結尾
;===========================================================
SECTION trail align=16
program_end: ;程式的結尾
///////////////////////////////////////////////____加載程式__________________________/////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
app_lba_start equ 100 ;用戶程式所在的邏輯扇區號
SECTION mbr align=16 vstart=0x7c00
;設定堆疊段和堆疊指標
mov ax,0
mov ss,ax
mov sp,ax
mov ax,[cs:phy_base] ;計算用于加載用戶程式的邏輯段地址
mov dx,[cs:phy_base+0x02]
mov bx,16
div bx
mov ds,ax ;設定DS和ES指向該段以進行操作
mov es,ax
;以下讀取程式的起始部分
xor di,di
mov si,app_lba_start ;程式在硬碟上的起始邏輯扇區號
xor bx,bx ;加載到DS:0x0000處
call read_hard_disk_0
;以下判斷整個程式有多大
mov dx,[2]
mov ax,[0]
mov bx,512 ;512位元組/扇區
div bx
cmp dx,0
jnz @1 ;未除盡,因此結果比實際扇區數少1
dec ax ;已經讀了一個扇區,扇區總數減1
@1:
cmp ax,0 ;考慮實際長度小于等于512個位元組的情況
jz direct
;讀取剩余的扇區
push ds ;以下要用到并改變DS暫存器
mov cx,ax ;回圈次數(剩余扇區數)
@2:
mov ax,ds
add ax,0x20 ;得到下一個以512位元組為邊界的段地址
mov ds,ax
xor bx,bx ;每次讀時,偏移地址始終為0x0000
inc si ;下一個邏輯扇區
call read_hard_disk_0
loop @2 ;回圈讀,直到讀完整個功能程式
pop ds ;恢復資料段基址到用戶程式頭部段
;計算入口點代碼段基址
direct:
mov dx,[0x08]
mov ax,[0x06]
call calc_segment_base
mov [0x06],ax ;回填修正后的入口點代碼段基址
;開始處理段重定位表
mov cx,[0x0a] ;需要重定位的專案數量
mov bx,0x0c ;重定位表首地址
realloc:
mov dx,[bx+0x02] ;32位地址的高16位
mov ax,[bx]
call calc_segment_base
mov [bx],ax ;回填段的基址(用戶程式中此位置在編譯時放置的是匯編地址,在這里要計算出邏輯段的段地址)
add bx,4 ;下一個重定位項(每項占4個位元組)
loop realloc
jmp far [0x04] ;轉移到用戶程式
;-------------------------------------------------------------------------------
read_hard_disk_0: ;從硬碟讀取一個邏輯扇區
;輸入:DI:SI=起始邏輯扇區號
; DS:BX=目標緩沖區地址
push ax
push bx
push cx
push dx
mov dx,0x1f2
mov al,1
out dx,al ;讀取的扇區數
inc dx ;0x1f3
mov ax,si
out dx,al ;LBA地址7~0
inc dx ;0x1f4
mov al,ah
out dx,al ;LBA地址15~8
inc dx ;0x1f5
mov ax,di
out dx,al ;LBA地址23~16
inc dx ;0x1f6
mov al,0xe0 ;LBA28模式,主盤
or al,ah ;LBA地址27~24
out dx,al
inc dx ;0x1f7
mov al,0x20 ;讀命令
out dx,al
.waits: ;等待硬碟回應
in al,dx
and al,0x88
cmp al,0x08
jnz .waits
mov cx,256 ;總共要讀取的字數
mov dx,0x1f0
.readw:
in ax,dx
mov [bx],ax
add bx,2
loop .readw
pop dx
pop cx
pop bx
pop ax
ret
;-------------------------------------------------------------------------------
calc_segment_base: ;計算16位段地址
;輸入:DX:AX=32位物理地址
;回傳:AX=16位段基地址
push dx
add ax,[cs:phy_base]
adc dx,[cs:phy_base+0x02]
shr ax,4
ror dx,4
and dx,0xf000
or ax,dx
pop dx
ret
;-------------------------------------------------------------------------------
phy_base dd 0x10000 ;用戶程式被加載的物理起始地址
times 510-($-$$) db 0
db 0x55,0xaa
uj5u.com熱心網友回復:
代碼沒有問題,問題出在設定硬碟鏡像時沒有選擇PATA模式,現在一切都正常了。uj5u.com熱心網友回復:
我是bochs不能顯示,但在VirtualBox里是正常的uj5u.com熱心網友回復:
我將 virtualbox 控制器的型號改為 PIIX4 就可以顯示了。轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/246288.html
標籤:匯編語言
