Установка регистров сегмента после инструкции ORG - PullRequest
0 голосов
/ 04 января 2019

В настоящее время я следую учебнику по разработке ОС , который включает обсуждение загрузчиков.

Мой загрузчик в настоящий момент находится в 16-битном реальном режиме, поэтому я могу использовать предоставленные прерывания BIOS (например, VGA-прерывания видео и т. Д.).

BIOS предоставляет видеопрерывание 0x10 (т.е. вывод телетайпа видео). Видеопрерывание имеет функцию 0x0E, которая позволяет мне выводить символ на экран.

Вот этот основной загрузчик:

org     0x7c00              ; Set program start (origin) address location at 0x7c00.
                            ; This program is loaded by the BIOS at 0x7c00.
bits    16                  ; We live in 16-bit Real Mode.

start:  
        jmp loader

bootmsg     db      "Welcome to my Operating System!", 0        ; My data string.

;-------------------------------------------------------
;   Description:    Print a null terminating string
;-------------------------------------------------------
print:
    lodsb                   ; Load string byte at address DS:SI and place in AL.
                            ; Then, increment/decrement SI as defined by the Direction Flag (DF) in FLAGS.
    or      al, al          ; Set the zero flag - is AL zero?
    jz      printdone       ; Check if this is the null byte
    mov     ah, 0eh
    int     10h
    jmp     print
printdone:
    ret

loader:
    ;|---------- Related to my question ----------|
        xor     ax, ax
        mov     ds, ax
        mov     es, ax
    ;|--------------------------------------------|

    mov     si, bootmsg
    call    print

    cli                     ; Clears all interrupts.
    hlt                     ; Halts the system.

times 510 - ($-$$) db 0    ; Make sure our bootloader is 512 bytes large. 

dw      0xAA55              ; Boot signature - Byte 511 is 0xAA and Byte 512 is 0x55, indicated a bootable disk.1

Как показано в приведенном выше коде, я выделил следующие три строки:

xor     ax, ax
mov     ds, ax
mov     es, ax

Согласно первоисточнику, в нем говорится следующее:

Настройте сегменты так, чтобы они равнялись 0. Помните, что у нас ORG 0x7c00. Это означает, что все адреса основаны на 0x7c00: 0. Поскольку сегменты данных находятся в одном и том же сегменте кода, пустое значение.

Я немного растерялся. Насколько я понимаю, инструкция org говорит загрузчику загрузить эту программу по адресу 0x7c00. Почему бы тогда не принять это как наш начальный адрес? Это означает, что наши два перекрывающихся сегмента данных и кода не расположены по базовому адресу нуля. базовый адрес должен быть 0x7c0. Почему автор устанавливает базовый адрес на 0x0?

mov ax, 07c0h
mov dx, ax
mov es, ax

1 Ответ

0 голосов
/ 05 января 2019

Я изучил инструкцию org и другую документацию, и я понимаю, что происходит.

Согласно документации NASM в директиве org, сокращение от или i g in:

Функция директивы ORG состоит в том, чтобы указать исходный адрес, с которого NASM будет считать, что программа начинается при загрузке в память. [...] ORG NASM делает именно то, что говорит директива: происхождение. Его единственная функция - указывать одно смещение, которое добавляется ко всем внутренним адресным ссылкам в разделе.

Следовательно, компилятор NASM предполагает, что программа будет загружена по адресу, указанному в инструкции origin (т.е. org). BIOS делает именно это. Согласно следующего , как только BIOS обнаружит допустимый загрузочный сектор, который содержит действительную загрузочную подпись, загрузчик будет " загружен в память в 0x0000: 0x7c00 (сегмент 0, адрес 0x7c00)".

Из приведенной выше цитаты, когда в документации NASM говорится «ссылки на внутренние адреса», это относится ко всем ссылкам на конкретные области памяти, которые используются в коде (например, ссылка на метку и т. Д.). Например, строка в коде загрузчика выше: mov si, bootmsg разрешит bootmsg до 0x07c00 + offset, где смещение определяется положением первого байта моей строки bootmsg (то есть 'W').

С моим кодом выше, если я разбираю bin-файл с помощью утилиты ndisasm , я вижу следующее:

00000000  EB2C              jmp short 0x2e
00000002  57                
00000003  656C              
00000005  636F6D            
00000008  6520746F          
0000000C  206D79            
0000000F  204F70            
00000012  657261            
00000015  7469              
00000017  6E                
00000018  67205379          
0000001C  7374              
0000001E  656D              
00000020  2100              
00000022  AC                lodsb
00000023  08C0              or al,al
00000025  7406              jz 0x2d
00000027  B40E              mov ah,0xe
00000029  CD10              int 0x10
0000002B  EBF5              jmp short 0x22
0000002D  C3                ret
0000002E  31C0              xor ax,ax
00000030  8ED8              mov ds,ax
00000032  8EC0              mov es,ax
00000034  BE027C            mov si,0x7c02
00000037  E8E8FF            call 0x22
0000003A  FA                cli
0000003B  F4                hlt
00000...  ...               ...

(я удалил сгенерированные инструкции с 0x00000002 до 0x00000020, потому что это моя строка bootmsg, представляющая данные, а не код).

Как видно из выходной сборки, по адресу 0x00000034 мой bootmsg был заменен на 0x7c02 (например, 0x7c00 + смещение = 0x02).

Майкл Петч также дал очень твердое понимание. Распространенным заблуждением считается то, что загрузчик загружен в 0x7c0: 0x0000 (сегмент 0x07c0, смещение 0). Хотя технически это можно использовать, но вместо этого было стандартизировано использование смещения сегмента, равного нулю ( Хорошая практика - применять CS: IP в самом начале загрузочного сектора ). Как уже упоминал Майкл, если вам нужна дополнительная информация, обратитесь к разделу 4 следующего руководства по адресации смещения сегмента .

...