对 X86 分段感到困惑

Confused about X86 segmentation

我正在写一个引导扇区来加载我的 16 位实模式 DOS 克隆,我卡在了一些可能很明显的东西上,但我花了几个小时试图理解为什么它不会'没用。

基本上,我正在尝试将 DSCSSS 设置为零,但保持 ES 设置直接超过 7C00 以加载系统。

但是当 运行 我的代码通过调试器时,它说没有任何内容被读入内存,即:root、FAT 等 (???)

基本上,我试图将 DS:SI (0000:7C00+FILE) 与 ES:DI (07E0:0000) 进行比较,但无济于事。我听到有人告诉我它实际上用 DS:DI 检查 DS:SI ,所以我试了一下,但也没有用。 07E0:0000 不应该直接在 0000:7C00 之后吗? cmpsb 是否要求 ESDS 相同?

我看过 Intel 的手册,上面说 cmpsb 比较 DS:SIES:DI,但我认为我没有误解太多。 07E0:0000 是 0x7E00,不是吗?

无论如何,感谢您的帮助。我很感激。

编辑:我忘了说,如果我将 ES 归零并将加载地址放入 BX,一切正常。但是当它被翻转时,ES=07E0BX=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]
  1. 汇编程序将对您所要求的内容进行编码,并将 AXword NUMFATS 相乘,这涉及使用垃圾高字节(在本例中为值 224) !
  2. 你同样错误地添加了 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