调试程序:杨季文 《80X86汇编语言程序设计教程》例程T10-2.asm
平台:win xp操作系统/bochs 2.6.8/DOS 7.1中文版启动盘/winImage 9.00
构建保护模式下的汇编编译及调试环境着实费了一番功夫.
---题记
一、代码
JUMP16 MACRO selector, offsetv
DB 0EAH
DW offsetv
DW selector
ENDM
JUMP32 MACRO selector, offsetv
DB 0EAH
DW offsetv
DW 0
DW selector
ENDM
DESCRIPTOR STRUC
LIMITL DW 0
BASEL DW 0
BASEM DB 0
ATTRIBUTES DW 0
BASEH DB 0
DESCRIPTOR ENDS
PDESC STRUC
LIMIT DW 0
BASE DD 0
PDESC ENDS
ATDR = 90H
ATDW = 92H
ATDWA = 93H
ATCE = 98H
ATCE32 = 4098H
DATALEN = 16
.386P
;-------------------------------------
DSEG SEGMENT USE16
; ASCII_ARRAY DB 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70
GDT LABEL BYTE
DUMMY DESCRIPTOR <>
CODE32_SEL = 08H
CODE32 DESCRIPTOR
CODE16_SEL = 10H
CODE16 DESCRIPTOR <0FFFFH, , , ATCE, >
; CODE_SEL = CODE - GDT
DATAS_SEL = 18h
DATAS DESCRIPTOR
; DATAS_SEL = DATAS - GDT
DATAD_SEL = 20H
DATAD DESCRIPTOR
; DATAD_SEL = DATAD - GDT
STACKS_SEL = 28H
STACKS DESCRIPTOR <0FFFFH, , , ATDWA, >
NORMAL_SEL = 30H
NORMAL DESCRIPTOR <0FFFFH, 0, 0, ATDW, 0>
GDTLEN = $ - GDT
;
VGDTR PDESC
;
VARSS DW ?
; BUFFERLEN = 256
; BUFFER DB BUFFERLEN DUP (0)
DSEG ENDS
;------------------------------------
CSEG1 SEGMENT USE16 'REAL'
ASSUME CS: CSEG1, DS: DSEG
START:
jmpseg equ 40h ;打算修改的段
mov ax,jmpseg
mov ds,ax ;ds=打算修改的段
xor si,si
mov ax,ds:[si] ;修改 ds:0 的位置
push ax ;安全起见,在堆栈保存这个位置的值
mov byte ptr ds:[si],0cbh ;将这个位置设置为 retf
push cs
push offset back ;设置返回位置
db 0eah ;远跳转
dw 0
dw jmpseg
back: ;跳过去后马上回来
pop ax
mov ds:[si],ax ;再恢复下面就是继续执行了
MOV AX, DSEG
MOV DS, AX
;XCHG BX, BX
MOV BX, 16
MUL BX
ADD AX, OFFSET GDT
ADC DX, 0
MOV WORD PTR VGDTR.BASE, AX
MOV WORD PTR VGDTR.BASE + 2, DX
MOV AX, CSEG2
MUL BX
MOV CODE32.BASEL, AX
MOV CODE32.BASEM, DL
MOV CODE32.BASEH, DH
MOV AX, CSEG3
MUL BX
;ADD AX, OFFSET BUFFER
;ADC DX, 0
MOV CODE16.BASEL, AX
MOV CODE16.BASEM, DL
MOV CODE16.BASEH, DH
MOV AX, SS
MUL BX
;ADD AX, OFFSET BUFFER
;ADC DX, 0
MOV STACKS.BASEL, AX
MOV STACKS.BASEM, DL
MOV STACKS.BASEH, DH
MOV VARSS, SS
LGDT FWORD PTR VGDTR
;
CLI
CALL EA20
MOV EAX, CR0
OR EAX, 1
MOV CR0, EAX
; JUMP16
,
JUMP16
,
; TOREAL: MOV AX, DSEG MOV DS, AX MOV SS, VARSS CALL DA20 STI MOV AH, 4CH INT 21H ; JMP $; poor style. EA20 PROC PUSH AX IN AL, 92H OR AL, 2 OUT 92H, AL POP AX RET EA20 ENDP ; DA20 PROC PUSH AX IN AL, 92H AND AL, 0FDH OUT 92H, AL POP AX RET DA20 ENDP ; CSEG1 ENDS CSEG2 SEGMENT USE32 'PM32' ASSUME CS: CSEG2 SPM32: MOV AX, STACKS_SEL MOV SS, AX MOV AX, DATAS_SEL MOV DS, AX MOV AX, DATAD_SEL MOV ES, AX ; XOR ESI, ESI XOR EDI, EDI MOV ECX, DATALEN CLD NEXT: LODSB PUSH AX CALL TOASCII MOV AH, 01000010B SHL EAX, 16 POP AX SHR AL, 4 CALL TOASCII MOV AH, 01000010B STOSD MOV AL, ' ' STOSW LOOP NEXT ; JUMP32 CODE16_SEL,
; TOASCII PROC ; PUSH SI ; AND AL, 00001111B ; MOV SI, AX ; MOV AL, ASCII_ARRAY[SI] ; POP SI AND AL, 0FH ADD AL, 90H DAA ADC AL, 40H DAA RET TOASCII ENDP ; CODE32LEN = $ CODE32SIG: NOP CSEG2 ENDS CSEG3 SEGMENT USE16 'PM16' ASSUME CS: CSEG3 CODE32LEN = OFFSET CODE32SIG OFFSET_SPM32 = OFFSET SPM32 SPM16: XOR SI, SI MOV DI, DATALEN * 3 * 2 MOV AH, 7 MOV CX, DATALEN AGAIN: LODSB STOSW LOOP AGAIN ; MOV AX, NORMAL_SEL MOV DS, AX MOV ES, AX AND EAX, 0FFFFFFFFH MOV CR0, EAX JMP FAR PTR TOREAL CSEG3 ENDS END START
二、说明
1. offset伪指令依赖于编译环境
16位环境下,采用段:偏移的分段方式管理内存,offset返回dw(单字)段内偏移值;而32位下,offset返回内存绝对地址,即dd(双字)。处理方式为将源代码中offset语句从32位段移至16位段(可用NOP标记)。
2. 编译环境的配置
Microsoft Macro Assembler Version 9.00.21022.08
Microsoft Segmented Executable Linker Version 5.60.339
汇编程序严格依赖编译环境,编译环境是程序可重复性的保证。ml.exe从VS2008/VC/bin 中提取,link.exe取自masm 6.0. masm 6.0 之前的版本不支持32位汇编(如不能准确编译lgdt操作码),其后的版本中直到masm 9.0 才对保护模式汇编稳定支持。
参考 博文 《如何编写引导程序 Hello World》
3. 调试环境的配置
参考 博文《用bochs调试保护模式程序》
三、效果截图
□