从harddrive读取字符串并使用程序集

时间:2018-03-12 19:41:09

标签: assembly x86 operating-system bios mbr

我正在使用#34;使用程序集编写您自己的操作系统只需握住您的手即可#34;项目。我已经从头开始写了一些与MikeOS类似的东西,除了硬盘读写。阅读和写作的重要性是允许操作系统大于 B asic I 输入 O 输出 S < / strong>系统记忆长度为512。

我写了一个测试用例,用于从硬盘读取并在屏幕上打印第一个字符。使用 qemu ,我可以定义哪个文件用作硬盘驱动器,我定义了寄存器的位置,程序在读取函数中断期间可以指向具有0x80选项的硬盘驱动器。

第一个测试代码没有选择硬盘驱动器,因此读取代码将读取自己运行的二进制文件并产生一个&#34; a&#34;假设由于二进制文件在运行文件的开头产生了一个&#34; a&#34;(ascii),加载到 B asic I nput O utput S ystem。

所以我的问题是......

  1. 当我定义硬盘驱动器选择时,为什么它不能读取字符串&#34; Hello&#34;在屏幕上的文件中,就像我没有定义硬盘一样?

  2. 我的代码是否正确并且&#34; a&#34;在屏幕上制作是一个巧合,有一个&#34; a&#34;在模拟器中运行的生成的二进制文件的开头?

  3. 为了大家的缘故,请回复解释和代码。我在Stack Overflow中发现了两个问题,这两个问题都是用英语解释来解释他们的代码有什么问题但没有代码来说明他们在解释中的正确性。解释但不展示你的工作是一个有争议的问题。

    不建议我使用C,C ++或除了汇编之外的任何其他内容,如果你已经完成了你的研究,我已经完成了我的研究并拆分了高级语言,如C,C ++或其他任何你会看到的简单&#34;定义和读取控制台上的字符串&#34;不仅要大得多,而且要在效率方面不小心。这些拆解的C代码与手写汇编示例的比较也将在项目文件中发布。

    我感谢您的时间,当我作为开源教程发布项目时,社会将会感谢您花了多少时间保存与我相同位置的其他人。 (人类知识属于世界--An​​titrust电影,2001年)

    [bits   16]
    [org 0x7c00]
    
    message db "Hello"
    
    mov ah, 0x02    ;point to read sector function
    mov ch, 0x00    ;ch track/cylinder number
    mov dh, 0x00    ;dh head number
    mov cl, 0x00    ;cl sector number
    mov dl, 0x80    ;drive number 80 is drive0, 81 is drive1
    int 0x13
    
    ;read disk into terminal.... might be working, just displays 'a'...
    mov ah, 0x0e
    mov al, [bx]
    int 0x13
    
    ;Purpose, move to the next character read from file
    mov ah, 0x0e
    mov es, bx
    mov al, [bx]
    int 0x13
    
    times 510 - ($-$$) db 0
    dw 0xAA55
    
    
    
    ;==============================================================
    ;               Reference Notes
    ;==============================================================
    ;
    ;;;;;;;;;;;;; Interupt 02 - Read from sector ;;;;;;;;;;;;
    ;AH = 02
    ;AL = number of sectors to read (1-128 dec.)
    ;CH = track/cylinder number  (0-1023 dec., see below)
    ;CL = sector number  (1-17 dec.)
    ;DH = head number  (0-15 dec.)
    ;DL = drive number (0=A:, 1=2nd floppy, 80h=drive 0, 81h=drive 1)
    ;ES:BX = pointer to buffer
    ;
    ;on return:
    ;AH = status  (see INT 13,STATUS)
    
    ;AL = number of sectors read
    ;CF = 0 if successful
    ;   = 1 if error
    
    ;;;;;;;; Inturrupt 13 - Video card functions ;;;;;;;;
    ;AH = 02, means TTY mode, print to console mode
    ;AL = which character to print to console
    

1 个答案:

答案 0 :(得分:2)

通过在代码之前的开头放置message,处理器将尝试将字符串解码为指令并执行它们。这可能会导致意外的行为和崩溃。您可以将数据放在代码之后和引导签名之前。汇编程序( NASM )在引导加载程序的开头生成了一个包含hello的字节序列。 CPU无法区分组成字符串的字节或实际代码。 CPU看到一个字节序列并尝试解码字节并执行它们。

您的代码不会阻止处理器执行超出实际指令的结尾。您可以使用jmp $创建无限循环或关闭中断并使用说明hlt后跟clihlt处理器来解决此问题。

Int 13h/ah=2h磁盘读取需要:

  • 设置要在 AL
  • 中读取的扇区数
  • 需要段:在中断调用之前磁盘读取应在 ES:BX 中的偏移地址
  • 不要硬编码DL(启动驱动器)并使用BIOS在DL中传递给我们的内容
  • 扇区号(与气缸和磁头不同)是基于1的值,而不是基于0的值。这意味着磁盘上的第一个扇区(引导加载程序)位于CHS =(0,0,1),而不是(0,0,0)。使用扇区号0无效。

此引导加载程序将引导加载程序的副本读取到内存中0x0000:0x7E00,来自Cylinder,Head,Sector(CHS)(0,0,1),来自引导磁盘,传递到 DL 中的引导加载程序通过BIOS。此代码遵循我的General Bootloader Tips,设置我们自己的堆栈并将 DS 寄存器明确设置为0。

bits   16
org 0x7c00

    cld             ; Set forward direction for string related functions like LODSB
    xor ax, ax      ; XOR register with itself sets register to 0
    mov ds, ax      ; DS = 0x0000
    mov ss, ax      ; SS:SP =0x0000:0x7C00
    mov sp, 0x7c00  ; Set SS:SP since we will be loading data from disk to memory
                    ;    We want to ensure the data we read is not in the same
                    ;    memory as the stack. Stack will grow down from 0x0000:0x7c00
                    ;    in memory just below the bootloader

    ; Read 1 sector starting at CHS = 0,0,1 (the boot sector)
    ; to 0x0000:0x7E00. This creates a copy of the bootloader
    ; in memory in the memory just after where we are loaded at
    ; 0x0000:0x7c00
    mov es, ax      ; ES:BX memory to read to 0x0000:0x7E00
    mov bx, 0x7e00  ;     0x0000:0x7E00 is in the memory just after our bootloader
                    ;     which ran from 0x7c00 to 0x7dff.
    mov al, 0x01    ; Number of sectors to read
    mov ah, 0x02    ; point to read sector function
    mov ch, 0x00    ; ch track/cylinder number
    mov dh, 0x00    ; dh head number
    mov cl, 0x01    ; cl sector number
                    ; dl is set by the BIOS before transferring control to our bootloader
    int 0x13

    ; Print the message from the copy of the bootloader loaded at 0x7E00
    mov si, message + 0x200
    call print_string
    cli
    hlt

; Function: print_string
;           Display a string to the console on display page 0
;
; Inputs:   SI = Offset of address to print
; Clobbers: AX, BX, SI

print_string:               ; Routine: output string in SI to screen
    mov ah, 0eh             ; BIOS tty Print
    xor bx, bx              ; Set display page to 0 (BL)
    jmp .getch
.repeat:
    int 10h                 ; print character
.getch:
    lodsb                   ; Get character from string
    test al,al              ; Have we reached end of string?
    jnz .repeat             ;     if not process next character
.end:
    ret

message db "Hello", 0

times 510 - ($-$$) db 0
dw 0xAA55

print_string是我写的一个打印NUL终止字符串的函数。 SI 寄存器中提供了字符串的存储器偏移量。