2016-08-08 12 views
0

Следующие исходные файлы собираются отдельно (в исходные двоичные файлы) и загружаются соответственно в сектора 1 и 2 виртуальной дискеты. Затем эта дискета служит загрузочным носителем для виртуальной машины qemu-system-i386.Независимый от положения код в 16-разрядном реальном режиме, загрузочная/гибкая запись

«загрузчик» считывает «первую программу» из сектора 2 дискеты, а затем переходит в память, содержащую только что прочитанный код. Следующий код работает по желанию (т. Е. Печатается приветственное сообщение «первая программа»), но мне нужно указать ORG 0x001E в источнике «первой программы» (полученный путем изучения кода загрузчика в шестнадцатеричном редакторе). 0x001E - это смещение буфера temp, в котором содержится код, считываемый с дискеты.

"Загрузчик":

BITS 16 

bootloader_main: 
    mov bx, 0x07C0  ; Set data segment to bootloader's default segment 
    mov ds, bx 


    mov ah, 0x02  ; BIOS int13h "read sector" function 
    mov al, 1   ; Number of sectors to read 
    mov cl, 2   ; Sector to read 
    mov ch, 0   ; Cylinder/track 
    mov dh, 0   ; Head 
    mov dl, 0   ; Disk number (here, the floppy disk) 
    mov bx, 0x07C0  ; Segment containing the destination buffer 
    mov es, bx 
    mov bx, temp  ; Destination buffer offset 
    int 0x13 

    jmp temp 

    ret 
;end bootloader_main 




temp: times 60 db 17 

times 510-($-$$) db 0  ; Pad rest of sector and add bootloader 
dw 0xAA55      signature 

"первая программа":

BITS 16 
ORG 0x001E  ; Assume that this code will be located 0x001E bytes  
        after start of bootloader (in RAM) 

mov bx, string  ; Print a welcome string 
mov ah, 0x0E 
print_loop: 
    mov al, byte [bx] 
    int 0x10 
    inc bx 
    cmp byte [bx], 0 
    jne print_loop 
;end print_loop 


string: db "This is the first program.", 0 

С другой стороны, я мог бы использовать ORG 0x200 и 0x200 для буфера вместо temp (т.е. загрузить программу в оперативную память только после того, как загрузчик), но ни один из этих хаков не кажется устойчивым, когда речь заходит о создании полезных операционных систем. Как избежать такого рода жесткого кодирования адресов?

+1

Пожалуйста Тэг архитектуры процессора при размещении сборки вопросов. – rjp

+0

Я бы предположил, что базовый адрес - это то, что нужно указать с помощью загрузчика. Большая часть моей работы в этой области была на встроенных системах, и я знаю, что BIOS делает много всего для вас. Для меня, когда я использую загрузчик, у него обычно есть документация, сообщающая мне, где ожидается точка входа. – rjp

+0

Итак, если кто-то собирал программу, которая будет загружена на дискету и прочитана загрузчиком, им будет предложено добавить в свой код код ORG 512 (или какой-либо другой определенный адрес)? И загрузчик всегда будет загружать программу в ту же часть памяти? Трудно представить себе, как из этого сложились современные операционные системы, но я думаю, мне следует больше узнать об истории. – Vale132

ответ

1

Вы можете избежать жесткого кодирования адресов с помощью сегментов. Загрузите «первую программу» по адресу, кратное 16, и загрузите DS с соответствующим сегментом (адрес/16), а затем перейдите на segment:0, где segment - это место, где вы загрузили программу. Используйте ORG 0 в загруженной программе.

Например:

BITS 16 

bootloader_main: 
    mov ax, 0x07C0  ; Set data segment to bootloader's default segment 
    mov ds, ax 

    mov ah, 0x02  ; BIOS int13h "read sector" function 
    mov al, 1   ; Number of sectors to read 
    mov cl, 2   ; Sector to read 
    mov ch, 0   ; Cylinder/track 
    mov dh, 0   ; Head 
    mov bx, program_seg ; load program at program_seg:0 
    mov es, bx 
    xor bx, bx 
    int 0x13 

    mov ax, program_seg 
    mov ds, ax 
    mov ss, ax   ; set stack to end of program_seg 
    mov sp, 0 
    jmp program_seg:0 

bootloader_end: 
program_seg equ (bootloader_end - bootloader_main + 0x7c00 + 15)/16 

times 510-($-$$) db 0  ; Pad rest of sector and add bootloader 
dw 0xAA55     ; signature 
BITS 16 
ORG 0 

mov bx, string  ; Print a welcome string 
mov ah, 0x0E 
print_loop: 
    mov al, byte [bx] 
    int 0x10 
    inc bx 
    cmp byte [bx], 0 
    jne print_loop 
;end print_loop 


string: db "This is the first program.", 0 

я удалил mov dl, 0 инструкцию, потому что вы не должны жесткий код этого значения. BIOS передаст номер диска загрузочного устройства в DL, поэтому вам не нужно его менять.

+0

Другим распространенным трюком является копирование кода загрузчика в другом месте (вы копируете, чтобы вы знали, где) и загрузите второй сектор поверх исходного загрузочного сектора, снова предоставив вам известное местоположение. Много подходов. –

+0

@DavidHoelzer Вопрос о том, как загрузить программу на некорректном «известном» адресе, представлял собой вопрос. Помимо того, как выбран сегмент нагрузки, этот пример по сути является тем, как MS-DOS обрабатывает файлы .COM. –

0

В этом примере вы можете ввести любой код между jmp Load_Buffer & Load_Buffer, если он не переполняет последние 4 байта загрузочного сектора.

загрузчиком

BOOTSEG  equ 0x7c0 
    LOW_MEM  equ 18 
    DISKIO  equ 19 

Определить, сколько 4k страниц имеющиеся и преобразовать это в сегменте адреса. В моем случае это 0x8FC0.

xor  cx, cx 
mov  cl, 64 
int  LOW_MEM    ; Get # of 4k segments to top of memory 
sub  ax, cx 
shl  ax, 6      ; 

Всегда отключать прерывание при модификации указателя стека.Это ставит стек в довольно безопасном месте в верхней части памяти меньше 64k

cli 
mov  ss, ax 
xor  sp, sp 
sti 

На данный момент CS может быть 0 или это может быть 0x7c0 в зависимости от биоса поставщика, но это действительно не имеет значения, потому что только ES: BX важно в этот момент

mov  ax, Load_Buffer 
shr  ax, 4 
add  ax, BOOTSEG 
mov  es, ax 
mov  ax, 0x201     ; Read one sector 
mov  cx, 2      ; Starting @ cylinder 0, sector 2 
xor  dh, dh     ; Head 0 and BIOS has already passed device. 

альтернативой здесь была бы загрузить ES с 0x7c0 и BX с Load_Buffer, как в вашем примере, однако в нашем случае ES = BOOTSEG + Load_Buffer/16.

xor  bx, bx 
int  DISKIO     ; Read sector 2 
jmp  Load_Buffer 

Выравнивание на границе страницы гарантирует, что загрузчик всегда будет работать независимо от того, сколько добавлено выше Load_Buffer, если только не произойдет переполнение последних 4 байтов загрузочного сектора. Для выравнивания требуется только граница страницы, поэтому 16 будет работать так же хорошо.

align 32 
Load_Buffer: 

Это, вероятно, хорошая идея, чтобы заполнить сектор с кодом упаковывают NOP в убегает, не будет вина сегмента.

times 508 - ($-$$) db 144  ; NOP's 0x90 
int  25      ; Incase codes runs away we'll reboot 
dw  0xAA55     ; Boot sig (no required by some emulators) 

Первая программа

Going использовать LODSB, не то, что более правильно, чем ваш путь, но только использует меньше кода.

mov  si, string 
push es 
pop  ds      ; DS:SI now points to string 
mov  ah, 14     ; TTY output 

Loop: 
lodsb       ; Read from DS:SI 
test al, 255    ; Test if these any of these bits are on. 
jz  .Done 
int  16 
jmp  Loop 

Период перед тем ярлыком только NASM функциональность для объявления локальных меток

.Done: 
hlt 
jmp  $ 

string db 'This is the first program', 0 

 Смежные вопросы

  • Нет связанных вопросов^_^