добавление ассемблерного кода стереть отображаемые строки

avatar
Joker
8 апреля 2018 в 09:19
142
1
0

Я пытаюсь написать свою мини ОС. Я учусь на других проектах, поэтому я действительно понятия не имею, подходит ли мой код для загрузчика и ядра. Я использую сборку 16 бит, NASM и загружаю загрузчик и ядро ​​в виде файлов .bin на образ дискеты. Я запускаю ОС с qemu. Я дошел до того, что добавление дополнительных строк кода стирает отображаемые строки, которые появляются при запуске ОС. Например, если я запускаю ОС и появляется сообщение «Добро пожаловать в мою ОС!», после добавления некоторых строк кода это будет выглядеть так: «Добро пожаловать в m» (конец исчезает).

вот мой код:

bootloader.asm

[bits 16]
[org 0x7c00]

                                ; Use the boot drive number passed to us by BIOS in register DL
start:
    xor ax,ax                   ; We want a segment of 0 for DS
    mov ds,ax                   ;     Set AX to appropriate segment value
    mov es,ax                   ; In this case we'll default to ES=DS
    mov bx,0x8000               ; Stack segment can be any usable memory

    mov ss,bx                   ; This places it with the top of the stack @ 0x80000.
    mov sp,ax                   ; Set SP=0 so the bottom of stack will be @ 0x8FFFF


    cld                         ; Set the direction flag to be positive direction

    mov si, welcome_msg
    call print_string

    mov si, kernel_load
    call print_string

    pushf
    stc

    mov ah,00h                  ; Reset Disk Drive
    int 13h

    read_sector:
        mov ax, 0x0
        mov es, ax              ; ES = 0
        mov bx, 0x1000          ; BX = 0x1000. ES:BX=0x0:0x1000 
                                ; ES:BX = starting address to read sector(s) into
        mov ah, 02              ; Int 13h/AH=2 = Read Sectors From Drive
        mov al, 01              ; Sectors to read = 1
        mov ch, 00              ; CH=Cylinder. Second sector of disk
                                ; is at Cylinder 0 not 1
        mov cl, 02              ; Sector to read = 2
        mov dh, 00              ; Head to read = 0
                                ; DL hasn't been destroyed by our bootloader code and still
                                ;     contains boot drive # passed to our bootloader by the BIOS
        int 13h                 ; Read Sectors From Drive

        jc error_kernel_load    ; error loading kernel
        popf
        jmp 0x0:0x1000          ; jmp to kernel offset
        cli                     ; Disable interrupts to circumvent bug on early 8088 CPUs
        hlt                     ; halts the central processing unit (CPU) until the next external interrupt

error_kernel_load:
        mov si, error_msg
        call print_string
        mov si, restart_msg
        call print_string
        mov ah,00               ; wait for key press
        int 16h
        xor ax,ax               
        int 19h                 ; reboot the computer

print_string:                   ; Routine: output string in SI to screen
        lodsb                   ; Get character from string
        or al,al
        jz exit
        mov ah,0x0e
        int 10h                 ; int 10h 'print char' function
        jmp print_string
exit:
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Messages to print
    welcome_msg db 'Welcome to Bootloader!!!',0x0D,0x0A,0
    kernel_load db 'Loading kernel....',0x0D,0x0A,0
    error_msg db 'Kernel.bin not found!',0x0D,0x0A,0
    restart_msg db 'Press any key to restart..',0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


times 510-($-$$) db 0       ; Create padding to fill out to 510 bytes
dw      0xaa55              ; Magic number in the trailer of a boot secto

kernel.asm

[bits 16]
[org 0x1000]

section .data:
    cursor_col:     db     0                ; cursor column
    cursor_row:     db     0                ; cursor row
    line_col:       dw     0                ; line column
    line_row:       dw     0                ; line row

    color:          db     3Fh              ; background and forground color (at start set random the formal way > number+letter)

    mode:           db     0


start:
    mov ax, 07C0h                           ; Set up 4K stack space after this bootloader
    add ax, 288                             ; (4096 + 512) / 16 bytes per paragraph
    mov ss, ax
    mov sp, 4096

mov byte [color], 3Fh
    call clear_screen                       ; clear the screen and color it

                                            ; VVV print "Minerald welcome" message VVV
    mov byte [cursor_col], 08               
    mov byte [cursor_row], 28
    call set_cursor                         ; print at the requested position of the screen
    mov si, welcome_string                  ; Put string position into SI
    call print_string                       ; Call our string-printing routine


                                            ; VVV print "Press Space" message VVV
    mov byte [cursor_col], 14
    mov byte [cursor_row], 26
    call set_cursor                         ; print at the requested position of the screen
    mov si, press_key_string                ; Put string position into SI
    call print_string                       ; Call our string-printing routine


    mov ah, 0h                              ; wait for key press
    int 16h                                                 

    mov byte [color], 1Fh
    call clear_screen                       ; clear the screen and color it


    mov byte [cursor_col], 2
    mov byte [cursor_row], 0
    call set_cursor                         ; print at the requested position of the screen
    mov si, basic_background                ; Put string position into SI
    call print_string   

    mov byte [cursor_col], 22
    mov byte [cursor_row], 0
    call set_cursor                         ; print at the requested position of the screen
    mov si, basic_background                ; Put string position into SI
    call print_string                       ; Call our string-printing routine


    mov ah, 0                               ; set display mode function.
    mov al, 13h                             ; mode 13h = 320x200 pixels, 256 colors.
    int 10h                                 ; set it!

    ;=================================      ; rectangles
    mov byte [line_col], 80
    mov byte [line_row], 165

    call print_rectangle                    ; print rectangle

    mov byte [line_col], 80
    mov byte [line_row], 135

    call print_rectangle                    ; print rectangle
    ;==================================


end:
    jmp $                                   ; Jump here - infinite loop!
    ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;
clear_screen:
    mov ah, 06h                             ; Scroll up function
    xor al, al                              ; Clear entire screen
    xor cx, cx                              ; Upper left corner CH=row, CL=column
    mov dx, 184Fh                           ; lower right corner DH=row, DL=column 
    mov bh, byte [color]                    ; set background and foreground color
    int 10h
    ret
;;;;;;;;;;

;;;;;;;;;;
print_string:                               ; Routine: output string in SI to screen
    lodsb                                   ; Get character from string
    or al,al
    jz exit
    mov ah,0x0e                             ; int 10h 'print char' function
    int 10h
    jmp print_string
exit:
    ret

;;;;;;;;;;

;;;;;;;;;;
set_cursor:
    mov dh, byte [cursor_col]               ; cursor col 
    mov dl, byte [cursor_row]               ; cursor row
    mov ah, 02h                             ; move cursor to the right place
    xor bh, bh                              ; video page 0
    int 10h                                 ; call bios service
    ret
;;;;;;;;;;

;;;;;;;;;;
print_rectangle:
    %INCLUDE "print_rectangle.asm"
;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Messages to print
    welcome_string       db 'Welcome to  my OS!', 0
    press_key_string     db 'Press any key to continue...', 0
    enter_message_string db 'Enter your message below',0
    APM_ERROR_string     db 'APM Error...'
    basic_background     db '--------------------------------------------------------------------------------'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;END OF KERNEL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

это команды загрузки:

nasm -f bin -o kernel.bin kernel.asm
nasm -f bin -o bootloader.bin bootloader.asm

dd if=bootloader.bin of=floppy.flp bs=512 seek=0 conv=notrunc 
dd if=kernel.bin of=floppy.flp bs=512 seek=1 conv=notrunc

qemu-system-i386 -fda floppy.flp

изменить:

из списка файлов nasm до усечения сообщений:

   300                                  ; Messages to print
   301 00000191 57656C636F6D652074-         welcome_string       db 'Welcome to my OS!', 0
   302 0000019A 6F204D696E6572616C-
   303 000001A3 644F532100         
   304 000001A8 507265737320616E79-         press_key_string     db 'Press any key to continue...', 0
   305 000001B1 206B657920746F2063-
   306 000001BA 6F6E74696E75652E2E-
   307 000001C3 2E00               
   308 000001C5 456E74657220796F75-         enter_message_string db 'Enter your message below',0
   309 000001CE 72206D657373616765-
   310 000001D7 2062656C6F7700     
   311 000001DE 41504D204572726F72-         APM_ERROR_string     db 'APM Error...'
   312 000001E7 2E2E2E             
   313 000001EA 2D2D2D2D2D2D2D2D2D-         basic_background     db '--------------------------------------------------------------------------------'

из списка файлов nasm после усечения сообщений:

   332                                  ; Messages to print
   333 000001E8 57656C636F6D652074-         welcome_string       db 'Welcome to MineraldOS!', 0
   334 000001F1 6F204D696E6572616C-
   335 000001FA 644F532100         
   336 000001FF 507265737320616E79-         press_key_string     db 'Press any key to continue...', 0
   337 00000208 206B657920746F2063-
   338 00000211 6F6E74696E75652E2E-
   339 0000021A 2E00               
   340 0000021C 456E74657220796F75-         enter_message_string db 'Enter your message below',0
   341 00000225 72206D657373616765-
   342 0000022E 2062656C6F7700     
   343 00000235 41504D204572726F72-         APM_ERROR_string     db 'APM Error...'
   344 0000023E 2E2E2E             
   345 00000241 2D2D2D2D2D2D2D2D2D-         basic_background     db '--------------------------------------------------------------------------------'
   346 0000024A 2D2D2D2D2D2D2D2D2D-
Источник
Ped7g
8 апреля 2018 в 09:42
0

Можете ли вы добавить строки с сообщениями из файла листинга NASM? (опция -l kernel.lst и скопируйте всего несколько строк вокруг welcome_string) - чтобы увидеть, как он компилируется и по какому смещению они размещаются.

Joker
8 апреля 2018 в 10:02
0

@ Ped7g Я отредактировал вопрос.

Ped7g
8 апреля 2018 в 10:58
0

Это из версии, которая показывает уже усеченные строки, или из версии, которая работает? Я немного боялся, что вы пересекаете границу сектора 512 байт, но в листинге этого не указано, последнее смещение 0x1EA все еще находится в пределах 512 байт, так что, вероятно, это что-то в коде (которого я еще не читал).

Ped7g
8 апреля 2018 в 11:03
0

В коде, возможно, это не связано с вашей ошибкой, но ваше использование службы int 10,0E неверно, вы не установили BH на текущую страницу, и мне кажется, что все еще может быть какое-то значение из чтения сектора, вероятно, 0x10, что, вероятно, заставляет его работать случайно, но я не хочу глубоко копаться в коде, который написан небрежно и, вероятно, «проверен» просто путем его выполнения и проверки вывода. Прекратите это делать, запустите его в отладчике, пошагово выполняя каждую инструкцию, и проверьте все предположения/эффекты инструкций, не полагайтесь на вывод.

Ped7g
8 апреля 2018 в 11:06
0

На самом деле еще одна важная вещь... проверьте список kernel.lst в начале, я не думаю, что директива section актуальна, поскольку вы используете формат bin для вывода, поэтому ваше ядро, скорее всего, начинается с 0000:1000 с байтами данных, а не с инструкциями, что, вероятно, является еще одной чистой удачей, что вы получаете даже несколько значимый вывод после выполнения данных. Смешивание section и org не имеет смысла, либо вы используете section и более сложный формат исполняемого файла, где компоновщик будет сортировать расположение памяти в соответствии с предоставленным сценарием компоновщика, либо вы используете двоичный файл, где вам нужно разместить себя .

Joker
8 апреля 2018 в 11:53
0

@Ped7g Спасибо за ваши комментарии. Я новичок в этом, и я все еще учусь. Я отредактировал сообщение с файлом листинга после добавления строк кода, предыдущее было до того, как сообщения были усечены. Если я действительно пересечу 512B, что мне делать? загрузить другой сектор? и еще один момент, я тоже новичок в linux, и я не мог понять, как отлаживать сборку с помощью gdb, у вас есть какие-либо предложения?

Joker
8 апреля 2018 в 11:59
0

И я не совсем понял часть "раздел" и "орг". Не могли бы вы объяснить, что такое раздел и что мне делать? Просто стереть метку раздела .data?

Ped7g
8 апреля 2018 в 12:04
0

Если вы пересекаете границу сектора 512B, тогда да, вам нужно загрузить более 1 сектора (вы должны загрузить (size_of_kernel/512) округленное количество секторов). Вы запускаете свой код загрузчика внутри виртуальной машины QEMU, поэтому вам нужен отладчик, способный отлаживать код виртуальной машины, это не так тривиально, как отладка обычного кода приложения, работающего под вашей хост-ОС (и это не тривиально), поэтому я хмурюсь, когда вижу, что люди, которые плохо знакомы с ассемблером, начинают изучать загрузчик и программирование ядра вместо того, чтобы сначала изучать основы ассемблера, потому что это похоже на утроение размера проблем при запуске.

Ped7g
8 апреля 2018 в 12:08
0

И я не занимаюсь разработкой ОС, поэтому я не знаю, как отлаживать код, работающий внутри QEMU, из других вопросов по разработке ОС здесь похоже, что запуск загрузчиков с симулятором BOCHS немного более удобен для отладки, хотя я сам не смог настроить его за 5 минут я выделил на пробу. ...о разделе...взгляните на это с другой точки зрения, вы загружаете байтовые данные "машинный код" с диска в память, затем выполняете его (без какой-либо постобработки загруженных данных), поэтому все инструкции и адреса уже определены в двоичных данных. Директива org регулирует внутренние смещения во время сборки.

Ped7g
8 апреля 2018 в 12:11
0

С другими исполняемыми форматами, такими как ELF (32 или 64 бит), процесс сборки создаст первые объектные файлы, которые имеют только относительные локальные смещения в объектном файле, а не окончательные адреса, org вообще не используется. Затем объектные файлы собираются компоновщиком, и из них собирается окончательный исполняемый файл, соединяя различные символы между разными объектными файлами, а также помещая данные и код в [отдельные иногда] области, где они принадлежат в соответствии со сценарием компоновщика, используемым для связывания. или часть кода определила целевой раздел директивой section, которая предназначена для компоновщика.

Ped7g
8 апреля 2018 в 12:14
0

Когда вы создаете двоичный файл, то, что вы видите в листинге: line_number address(offset) machine_code_bytes буквально то, что у вас есть в файле .bin (ну, только часть машинного кода, номера строк и смещения - это просто информация для вас, откуда машина код был скомпилирован, и куда он приземлится) ... у вас наш kernel.bin начинается с нескольких нулей, созданных db 0, и вы будете в загрузчике jmp 0:0x1000 в этих байтах данных и выполните их как инструкции. (поскольку для процессора байт памяти - это байт памяти, он не может сказать, что такое код, а что данные, нет никакой разницы).

Ped7g
8 апреля 2018 в 12:17
0

А в реальном режиме 16b машинный код 00 00 является кодом операции инструкции add [bx+si],al ... и т. д., так что это то, что вы выполняете. ("db" - это не инструкция, это директива для генерации значений байтов ассемблером, поэтому, когда вам нужен какой-то байт в машинном коде со значением 13, вам не нужно вспоминать, какая инструкция имеет код операции, начинающийся с 13, но вы можете написать db 13... и наоборот, мнемоника инструкций поможет вам не вспоминать, что ret это db 195 (хотя это сработает, для большинства людей будет слишком много запоминать кодировки всех инструкций и запишите их цифрами).

Joker
8 апреля 2018 в 12:33
1

Спасибо за уделенное время. Я все еще учусь в старшей школе, и раньше я программировал на ассемблере [для Windows], но, по-видимому, я все еще не на 100% владею всеми основами. Последний комментарий о том, что вы можете использовать «db 195» вместо «ret», для меня нов и довольно интересен. Очень помогло, большое спасибо :)

Ped7g
8 апреля 2018 в 12:39
0

Хм, почитайте что-нибудь о принципах/архитектуре компьютеров, о том, что такое "машинный код" и как кодируются инструкции по сборке... и еще раз взгляните на файл листинга и сравните его, просматривая содержимое kernel.bin (в linux install "hd " = hexdump? В Ubuntu вы можете найти его в пакете "bsdmainutils"), чтобы увидеть, как этот машинный код в листинге является единственным содержимым, которое заканчивается в файле "bin", и это то, что процессор видит + выполняет (но в " двоичный», так как ЦП работает только с битами — т. е. уровнями электрического тока в ячейках, которые обрабатываются как логические значения 0 или 1).

Ped7g
8 апреля 2018 в 12:44
0

Может показаться, что все немного сложно и странно, но постарайтесь подумать об этом больше с точки зрения проектировщика HW, как вы все время работаете с электрическими токами 0/1, и как все спроектировано так, чтобы быть на самом деле глупо-простым. , то есть содержимое памяти не имеет каких-либо флагов, если оно хранит инструкции, целые числа или числа с плавающей запятой, это было бы слишком много возни с транзисторами и т. д. Вскоре вся машина и сборка представляют собой на самом деле очень простой переросший детерминированный калькулятор, меняющий свое состояние каждый такт.

Ped7g
8 апреля 2018 в 12:47
0

Тогда многое из этого «странного ассемблера» будет иметь гораздо больше смысла, поскольку ассемблер - это не столько язык программирования (логический, ориентированный на человека), сколько языки высокого уровня, поскольку он больше отражает аппаратную конструкцию ЦП, так что это логично с точки зрения размещения миллионов транзисторов на небольшом чипе, «логика программирования» является вторичной в этом процессе, позволяя создавать приложения с помощью ЦП, но не беспокоясь о том, что какая-то конкретная инструкция ведет себя «причудливо» с точки зрения человеческой логики. вид, если дизайн HW таким образом является более элегантным и производительным.

Joker
8 апреля 2018 в 12:54
0

Все, что вы сказали, имеет большой смысл, я почитаю больше об архитектуре :)

Ответы (1)

avatar
Ped7g
8 апреля 2018 в 12:29
1

Ответ на исходный вопрос:

Это потому, что ваше ядро ​​становится длиннее, и в сумме оно занимает больше одного сектора диска, но вы продолжаете загружать в память только один сектор (512 байт), так что остальная часть строки остается только на диске, никогда не входит в память.

Есть также несколько других проблем (некоторые упомянутые в моих комментариях), но они на самом деле не имеют отношения к усечению строки, и я не в настроении+времени просматривать весь ваш загрузчик +kernel и исправьте все ошибки, которые у вас там есть, поэтому я остановлюсь здесь (с точки зрения ответа).