对 X86 分段感到困惑
Confused about X86 segmentation
我正在写一个引导扇区来加载我的 16 位实模式 DOS 克隆,我卡在了一些可能很明显的东西上,但我花了几个小时试图理解为什么它不会'没用。
基本上,我正在尝试将 DS
、CS
、SS
设置为零,但保持 ES
设置直接超过 7C00 以加载系统。
但是当 运行 我的代码通过调试器时,它说没有任何内容被读入内存,即:root、FAT 等 (???)
基本上,我试图将 DS:SI
(0000:7C00+FILE) 与 ES:DI
(07E0:0000) 进行比较,但无济于事。我听到有人告诉我它实际上用 DS:DI
检查 DS:SI
,所以我试了一下,但也没有用。
07E0:0000 不应该直接在 0000:7C00 之后吗? cmpsb
是否要求 ES
和 DS
相同?
我看过 Intel 的手册,上面说 cmpsb
比较 DS:SI
和 ES:DI
,但我认为我没有误解太多。 07E0:0000 是 0x7E00,不是吗?
无论如何,感谢您的帮助。我很感激。
编辑:我忘了说,如果我将 ES
归零并将加载地址放入 BX
,一切正常。但是当它被翻转时,ES=07E0
、BX=0
没有任何作用,甚至没有被读取。不知道为什么,因为 ES:BX
应该是一样的,不管你走哪条路。
我的代码:
ORG 7C00H
USE16
BPBBEG:
JMP SHORT BPBPEND
NOP
DB "PEDOS1.0"
BYTSPERSEC: DW 512 ; total bytes per sector on this volume
SECPERCLUS: DB 1 ; total sectors per cluster on this volume
RSVDSECCNT: DW 1 ; unused
NUMFATS: DB 2 ; total FATs on this volume
ROOTENTCNT: DW 224 ; total entries in the Root Directory
DW 80 * 36
DB 240
FATSZ16: DW 9 ; total sectors per FAT on this volume
SECPERTRK: DW 18 ; total sectors per track on this idks
NUMHEADS: DW 2 ; total heads per cyliner on this idks
DD 0
DD 0
DB 0
DB 0
DB 41
DD 0
DB " "
DB "FAT12 "
;
; PEDOS MEMORY MAP
;
; - -- ROM / VIDEO -- A000:0
; - -----------------
; - -- BIOS DATA -- 8000:0
; - -----------------
; - -- FREE -- ????:?
; - -----------------
; - -- BOOT / FREE -- 0000:7C00
; - -----------------
; - -- FREE -- ????:?
; - -----------------
; - -- DRIVERS -- ????:?
; - -----------------
; - -- SYSTEM -- 0050:0
; - -----------------
; - -- BIOS BATA -- 0000:400
; - -----------------
; - -- IVT -- 0000:0
;
;
; INITIALIZE SEGMENT REGISTERS
;
BPBPEND:
XOR AX, AX
MOV DS, AX
CLI
PUSH DS
POP SS
MOV SP, 7C00H
PUSH DS
PUSH CHKDSK
STI
RETF ; SET CS TO KNOWN VALUE
;
; LOAD ROOT DIRECTORY AND CHECK FOR
; SYSTEM FILE
;
CHKDSK:
MOV AX, WORD BUFFER
SHR AX, 4
MOV ES, AX ; ES = 07E0
XOR AX, AX
MOV AX, WORD [FATSZ16]
MUL WORD [NUMFATS]
ADD AL, BYTE [RSVDSECCNT]
;mov bx, 0x7e00
MOV DI, 1
CALL READSEC
; mov ah, 14
; mov al, '/'
; int 16
; jmp $
LEA SI, [FILE] ; ADDRESS OF FILENAME
MOV DI, 0
MOV CX, 11 ; 11 BYTES PER FAT FILENAME
CLD
REPZ CMPSB
JZ LOADFILE
JMP ERROR
; DOSBIOS.SYS CONFIRMED: LOAD THE
; FILE INTO MEMORY.
LOADFILE:
mov ah, 14
mov al, '.'
int 16
jmp $
MOV AX, 32
MOV BX, WORD [ROOTENTCNT] ; TOTAL FATS ON DISK
MUL BX
MOV BX, WORD [BYTSPERSEC] ; FAT SIZE IN SECTORS
DIV BX
;
; AX = SIZE OF ROOT DIRECTORY
; IN SECTORS
;
ADD AX, BP ; SIZE + LOCATION = DATA REGION
POP BX
PUSH BX
MOV DI, 1 ; DOS SIZE IS HARD CODED FOR NOW - MAY
CALL READSEC ; CHANGE IN THE FUTURE
RUNDOS:
POP BX
PUSH 0
PUSH BX
RETF
;
; READ THE SPECIFIED SECTORS INTO MEMORY
; AT LOGICAL ES:BX
;
; IN: DX:AX = HEAD, TRACK, SECTOR NUMBER
; DI = SECTOR COUNT
;
READSEC:
PUSHA
DIV WORD [SECPERTRK]
;
; AX = LBA / SECPERTRACK
; DX = LBA % SECPERTRACK
;
MOV CX, DX
INC CX ; CX = LBA 1
XOR DX, DX
DIV WORD [NUMHEADS]
;
; AX = (LBA / SECPERTRACK) / CYLHEADCNT = CYLINDER
; DX = (LBA / SECPERTRACK) % CYLHEADCNT = HEAD
;
MOV CH, AL
SHL AH, 6
OR CL, AH
MOV DH, DL
MOV DL, 0
;
; DH = HEAD HUMBER
; DL = DRIVE
;
MOV AH, 2
MOV AL, 1
INT 19
JNC NEXTSEC ; IN CASE OF ERRORS, FOLLOW
ERROR:
LEA SI, [ERRMSG] ; SOMETHING WENT WRONG, SO THROW AN ERROR
;
; WRITE SPECIFIED STRING TO VIDEO
; MEMORY
;
; DS:SI = ADDRESS OF STRING
;
PRINT:
LODSB
OR AL, 0
JZ HALT
MOV AH, 14
MOV BX, 7
INT 16
JMP PRINT
HALT:
MOV AX, 0
INT 22
INT 25
;
; CONTINUE 'READSEC'
;
NEXTSEC:
POPA
DEC DI
JZ RETURN ; SKIP PRINT SUBROUTINE
ADD BX, WORD [BYTSPERSEC]
ADD AX, 1
ADC DX, 0
JMP READSEC
RETURN:
RET
;
; KEEP DATA BELOW CODE, UNTIL SECTOR
; MARKER
;
ERRMSG: DB 10, "Disk Error or DOSBIOS.SYS is missing.", 13
DB 10, "Press any key to restart.", 13, 10, 10, 0
FILE: DB "DOSBIOS SYS"
TIMES (512 - 2) - ($ - $$) DB 0
MARKER: DW 0AA55H
BUFFER:
;
; THE SYSTEM IS LOADED DIRECTLY AFTER
; BOOTSTRAP
;
检查您的尺码!
一方面你定义:
RSVDSECCNT: DW 1 ; unused
NUMFATS: DB 2 ; total FATs on this volume
ROOTENTCNT: DW 224 ; total entries in the Root Directory
另一方面你计算:
MOV AX, WORD [FATSZ16]
MUL WORD [NUMFATS]
ADD AL, BYTE [RSVDSECCNT]
- 汇编程序将对您所要求的内容进行编码,并将
AX
与 word NUMFATS 相乘,这涉及使用垃圾高字节(在本例中为值 224) !
- 你同样错误地添加了 RSVDSECCNT,因为涉及的数字太小了 - 至少如果第一个问题得到纠正!但是既然那个被定义为单词你真的应该写
add ax, [RSVDSECCNT]
.
解决方案:
MOVZX AX, BYTE [NUMFATS]
MUL AX, WORD [FATSZ16]
ADD AX, WORD [RSVDSECCNT]
指针进入ES:BX
CHKDSK:
MOV AX, WORD BUFFER
SHR AX, 4
MOV ES, AX ; ES = 07E0
XOR AX, AX
将 XOR AX, AX
更改为 XOR BX, BX
我正在写一个引导扇区来加载我的 16 位实模式 DOS 克隆,我卡在了一些可能很明显的东西上,但我花了几个小时试图理解为什么它不会'没用。
基本上,我正在尝试将 DS
、CS
、SS
设置为零,但保持 ES
设置直接超过 7C00 以加载系统。
但是当 运行 我的代码通过调试器时,它说没有任何内容被读入内存,即:root、FAT 等 (???)
基本上,我试图将 DS:SI
(0000:7C00+FILE) 与 ES:DI
(07E0:0000) 进行比较,但无济于事。我听到有人告诉我它实际上用 DS:DI
检查 DS:SI
,所以我试了一下,但也没有用。
07E0:0000 不应该直接在 0000:7C00 之后吗? cmpsb
是否要求 ES
和 DS
相同?
我看过 Intel 的手册,上面说 cmpsb
比较 DS:SI
和 ES:DI
,但我认为我没有误解太多。 07E0:0000 是 0x7E00,不是吗?
无论如何,感谢您的帮助。我很感激。
编辑:我忘了说,如果我将 ES
归零并将加载地址放入 BX
,一切正常。但是当它被翻转时,ES=07E0
、BX=0
没有任何作用,甚至没有被读取。不知道为什么,因为 ES:BX
应该是一样的,不管你走哪条路。
我的代码:
ORG 7C00H
USE16
BPBBEG:
JMP SHORT BPBPEND
NOP
DB "PEDOS1.0"
BYTSPERSEC: DW 512 ; total bytes per sector on this volume
SECPERCLUS: DB 1 ; total sectors per cluster on this volume
RSVDSECCNT: DW 1 ; unused
NUMFATS: DB 2 ; total FATs on this volume
ROOTENTCNT: DW 224 ; total entries in the Root Directory
DW 80 * 36
DB 240
FATSZ16: DW 9 ; total sectors per FAT on this volume
SECPERTRK: DW 18 ; total sectors per track on this idks
NUMHEADS: DW 2 ; total heads per cyliner on this idks
DD 0
DD 0
DB 0
DB 0
DB 41
DD 0
DB " "
DB "FAT12 "
;
; PEDOS MEMORY MAP
;
; - -- ROM / VIDEO -- A000:0
; - -----------------
; - -- BIOS DATA -- 8000:0
; - -----------------
; - -- FREE -- ????:?
; - -----------------
; - -- BOOT / FREE -- 0000:7C00
; - -----------------
; - -- FREE -- ????:?
; - -----------------
; - -- DRIVERS -- ????:?
; - -----------------
; - -- SYSTEM -- 0050:0
; - -----------------
; - -- BIOS BATA -- 0000:400
; - -----------------
; - -- IVT -- 0000:0
;
;
; INITIALIZE SEGMENT REGISTERS
;
BPBPEND:
XOR AX, AX
MOV DS, AX
CLI
PUSH DS
POP SS
MOV SP, 7C00H
PUSH DS
PUSH CHKDSK
STI
RETF ; SET CS TO KNOWN VALUE
;
; LOAD ROOT DIRECTORY AND CHECK FOR
; SYSTEM FILE
;
CHKDSK:
MOV AX, WORD BUFFER
SHR AX, 4
MOV ES, AX ; ES = 07E0
XOR AX, AX
MOV AX, WORD [FATSZ16]
MUL WORD [NUMFATS]
ADD AL, BYTE [RSVDSECCNT]
;mov bx, 0x7e00
MOV DI, 1
CALL READSEC
; mov ah, 14
; mov al, '/'
; int 16
; jmp $
LEA SI, [FILE] ; ADDRESS OF FILENAME
MOV DI, 0
MOV CX, 11 ; 11 BYTES PER FAT FILENAME
CLD
REPZ CMPSB
JZ LOADFILE
JMP ERROR
; DOSBIOS.SYS CONFIRMED: LOAD THE
; FILE INTO MEMORY.
LOADFILE:
mov ah, 14
mov al, '.'
int 16
jmp $
MOV AX, 32
MOV BX, WORD [ROOTENTCNT] ; TOTAL FATS ON DISK
MUL BX
MOV BX, WORD [BYTSPERSEC] ; FAT SIZE IN SECTORS
DIV BX
;
; AX = SIZE OF ROOT DIRECTORY
; IN SECTORS
;
ADD AX, BP ; SIZE + LOCATION = DATA REGION
POP BX
PUSH BX
MOV DI, 1 ; DOS SIZE IS HARD CODED FOR NOW - MAY
CALL READSEC ; CHANGE IN THE FUTURE
RUNDOS:
POP BX
PUSH 0
PUSH BX
RETF
;
; READ THE SPECIFIED SECTORS INTO MEMORY
; AT LOGICAL ES:BX
;
; IN: DX:AX = HEAD, TRACK, SECTOR NUMBER
; DI = SECTOR COUNT
;
READSEC:
PUSHA
DIV WORD [SECPERTRK]
;
; AX = LBA / SECPERTRACK
; DX = LBA % SECPERTRACK
;
MOV CX, DX
INC CX ; CX = LBA 1
XOR DX, DX
DIV WORD [NUMHEADS]
;
; AX = (LBA / SECPERTRACK) / CYLHEADCNT = CYLINDER
; DX = (LBA / SECPERTRACK) % CYLHEADCNT = HEAD
;
MOV CH, AL
SHL AH, 6
OR CL, AH
MOV DH, DL
MOV DL, 0
;
; DH = HEAD HUMBER
; DL = DRIVE
;
MOV AH, 2
MOV AL, 1
INT 19
JNC NEXTSEC ; IN CASE OF ERRORS, FOLLOW
ERROR:
LEA SI, [ERRMSG] ; SOMETHING WENT WRONG, SO THROW AN ERROR
;
; WRITE SPECIFIED STRING TO VIDEO
; MEMORY
;
; DS:SI = ADDRESS OF STRING
;
PRINT:
LODSB
OR AL, 0
JZ HALT
MOV AH, 14
MOV BX, 7
INT 16
JMP PRINT
HALT:
MOV AX, 0
INT 22
INT 25
;
; CONTINUE 'READSEC'
;
NEXTSEC:
POPA
DEC DI
JZ RETURN ; SKIP PRINT SUBROUTINE
ADD BX, WORD [BYTSPERSEC]
ADD AX, 1
ADC DX, 0
JMP READSEC
RETURN:
RET
;
; KEEP DATA BELOW CODE, UNTIL SECTOR
; MARKER
;
ERRMSG: DB 10, "Disk Error or DOSBIOS.SYS is missing.", 13
DB 10, "Press any key to restart.", 13, 10, 10, 0
FILE: DB "DOSBIOS SYS"
TIMES (512 - 2) - ($ - $$) DB 0
MARKER: DW 0AA55H
BUFFER:
;
; THE SYSTEM IS LOADED DIRECTLY AFTER
; BOOTSTRAP
;
检查您的尺码!
一方面你定义:
RSVDSECCNT: DW 1 ; unused NUMFATS: DB 2 ; total FATs on this volume ROOTENTCNT: DW 224 ; total entries in the Root Directory
另一方面你计算:
MOV AX, WORD [FATSZ16] MUL WORD [NUMFATS] ADD AL, BYTE [RSVDSECCNT]
- 汇编程序将对您所要求的内容进行编码,并将
AX
与 word NUMFATS 相乘,这涉及使用垃圾高字节(在本例中为值 224) ! - 你同样错误地添加了 RSVDSECCNT,因为涉及的数字太小了 - 至少如果第一个问题得到纠正!但是既然那个被定义为单词你真的应该写
add ax, [RSVDSECCNT]
.
解决方案:
MOVZX AX, BYTE [NUMFATS]
MUL AX, WORD [FATSZ16]
ADD AX, WORD [RSVDSECCNT]
指针进入ES:BX
CHKDSK: MOV AX, WORD BUFFER SHR AX, 4 MOV ES, AX ; ES = 07E0 XOR AX, AX
将 XOR AX, AX
更改为 XOR BX, BX