Несколько вопросов начинающего

Тема в разделе "WASM.BEGINNERS", создана пользователем s3dworld, 6 окт 2010.

  1. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Нет. DI подразумевает сегментный регистр ES (SI - DS, BX - DS, BP - SS), поэтому надо писать mov al, [ds:di]
     
  2. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    KIV
    Ты выводишь не черед ту функцию. Через которую ты выводишь, нельзя задать цвета.

    Я решил чуть-чуть упростить задачу (на текущий момент времени). Пока не использую переборы по всей строке, лишь пытаюсь вывести один символ, но указанный по индексу.

    Вот делают так:

    Код (Text):
    1. use16                           ; Используем 16-битный код
    2.  
    3. org 0x7C00                      ; Смещение
    4.  
    5. ; --------------------------------------------------------------------------
    6. ; Начало 16-битного кода
    7. ; --------------------------------------------------------------------------
    8. code16:
    9.     mov AX,[data16]
    10.     mov DS,AX
    11.     mov ES,AX
    12.     mov FS,AX
    13.     mov GS,AX
    14.     mov SS,AX
    15.    
    16.     sti
    17.    
    18.     call InitScreen             ; Инициализация экрана
    19.     call ClearScreen            ; Очищаем весь экран
    20.    
    21.     mov DL,4
    22.     mov DH,4
    23.     call SetCursorPos
    24.    
    25.     mov DS,word [text1]
    26.     mov BL,00000100b
    27.     call DrawText
    28.    
    29.     call LoopProcessor          ; Подвешиваем процессор
    30.  
    31. ; --------------------------------------------------------------------------
    32. ; Подвешивание процессора
    33. LoopProcessor:
    34.     jmp LoopProcessor           ; Переходим на эту же инструкцию
    35. ret
    36. ; --------------------------------------------------------------------------
    37.  
    38. include "BIOS.asm"
    39.  
    40. ; --------------------------------------------------------------------------
    41. ; Начало 16-битных данных
    42. ; --------------------------------------------------------------------------
    43. data16:
    44.     text1 db "Hello my friend!",0x00
    А вот теперь функция вывода строки:

    Код (Text):
    1. ; --------------------------------------------------------------------------
    2. ; Вывод текста
    3. ; BL - атрибуты текста
    4. ; --------------------------------------------------------------------------
    5. DrawText:
    6.     mov AH,0x09                 ; Код функции
    7.     mov BH,0x00                 ; Номер страницы
    8.     mov CX,1                    ; Количество повторений
    9.    
    10.     mov SI,0
    11.  
    12.     mov AL,[DS:SI]
    13.     int 0x10                    ; Вызываем прерывание BIOS
    14. ret
    У меня выводится почему-то символ S. Хотя его нет в начале. А при изменении SI в 1, вообще не выводится символ, только чёрный фон на месте символа.

    Что я не так делаю-то?
     
  3. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    это определённо не та инструкция. надо бы так:
    Код (Text):
    1. mov si, text1
    кстати, вместо mov al, [ds:si] лучше бы написать lodsb. она делает тоже самое но занимает один байт. Поскольку у тебя и оперативки не много, да и загрузочный сектор мал оптимизация по размеру имеет смысл.
    А вот вариант моей функции с использованием вызова BIOS с заданием цвета:
    Код (Text):
    1. write_str:
    2.     mov ah, 0x09 ; Номер вызова
    3.     xor bh, bh ; Номер видео-страницы
    4.     mov cx, 1 ; КОличество вывода каждого символа
    5. @@:
    6.     lodsb ; Загрузим очередной символ
    7.     test al, al ; Проверим не ноль ли это
    8.     jz @f ; Если ноль, то выходим
    9.     int 0x10 ; Выводим символ. При этом BIOS не изменит регистры с параметрами - проверенно
    10.     jmp @b ; Переходим к выводу следующего символа
    11. @@:
    12.     ret ; Возврат из процедуры
    Код (Text):
    1. mov SI,0
    Твои данные начинаются с адреса 0x7C00,а в первом килобайте (0 - 0x3FF) располагается таблица прерываний, а ни как не твоя строка.
    UPD:
    Я понял, что вы хотели сделать командой mov ds, [text1]. Эта команда работает не правильно по трём причинам:
    1) Значение сег. регистра умножается на 16, а потом к нему прибавляется смещение. Так что надо: mov ds, text1 / 16
    2) Вам нужен адрес строки - text1, а не значение двух первых байт строки - [text1].
    3) Ваша строка может и не быть выровнена на 16 байт, поэтому адрес после деления будет неверным.
     
  4. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    SII
    Это не ошибка. При необходимости можно биос настроить так, чтобы он переключался в режим 80*25, но если на компе установлена не текстовая ос, а графическая, то это сделали для подавления лишних мерцаний при переключении режимов.
    все конечно прекрасно и замечательно, но так вы загрузочный сектор никогда не напишите. вам попросту не хватит места. mov dl,4;2 bytes/mov dh, 4;2 bytes вместо mov dx, 0x0404;3 bytes
    Да и в загрузочном секторе мало кто работает с экраном. Если вы в нем включите текстовый режим, очистите экран и т.д. то это лишь приведет к тем самым лишним переключениям экрана, от которых пытается избавиться биос.
    P.S. Несколько советов
    1) если будете писать загрузочный сектор то самое оптимальное делать так (offset'ы внутри команд где возможно станут однобайтными)
    Код (Text):
    1. org 0
    2. ...
    3. cli
    4. xor bx, bx
    5. mov ss, bx
    6. mov sp, 0x7C00
    7. mov bp, sp
    8. далее для адресации внетри 512 байт можно использовать регистр bp с сегментом ss
    9. add bp, 256;а благодаря такой фишке область в которой смещения будут генерироваться однообайтными увеличится вдвое, если не используете переменные в стеке
    10. jmp 0x07C0:@f;после этой настройки можно использовать имена переменных, они будут рассчитаны компилятьром правильно
    11. @@:
    12. push cs
    13. pop ds; теперь можно использовать bx для адресации в сегменте данных
    2) для каких либо переменных необходимых при рассчетах удобно использовать стековую память. тем самым вы исключите большую часть ненужных прикидок, где бы расположить ту или иную переменную и уменьшите размеры команд обращения к ним
    3) не стоит создавать много процедут. их оформление занимает много места. если код выделенный в процедуру используется в программе 1 раз, то его проще заинлайнить. это сэкономит как минимум 4 байта
     
  5. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    KIV
    Ошибаетесь. DI подразумевает использование ES только при строковых операциях. Во всех остальных случаях используется сегмент данных. Кстати говоря, в строковых операциях префикс замены сегмента может подменить сегмент DS на любой другой, но сегмент ES он изменить не может.
     
  6. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Проверил - вы правы. Просто я где-то читал, что DI - ES. То ли автор ошибся, то ли я не так понял. Правда я на такие грабли бы не наступил всё равно - у меня почти всегда DS = ES.
     
  7. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    KIV
    Ну, в ИА-32 полно всяких загибонов, и все их упомнить проблематично... Мне просто во время оно довольно много пришлось писать на асме для 8086, потому и запомнилось...
     
  8. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Спасибо всем! Много для меня полезного написали, однако у меня пока не получается.

    А чем вообще пользоваться удобнее: VMware, VirtualBox, VirtualPC, Bochs или QEMU?
     
  9. SII

    SII Воин против дзена

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    1.483
    Адрес:
    Подмосковье
    Только два последних, насколько знаю, поддерживают отладку, первая троица предназначена не для создания новых ОС и прочих низкоуровневых программ, а для эксплуатации существующих.
     
  10. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Так, с текстом разобрался! Вот теперь решил параметры передавать через стек. Но что-то не получается. Пишу так:

    Код (Text):
    1. use16
    2.  
    3. org 0x7C00
    4.  
    5. code16:
    6.     mov AX,CS
    7.     mov DS,AX
    8.     mov ES,AX
    9.     mov FS,AX
    10.     mov GS,AX
    11.     mov AX,steck16
    12.     mov SS,AX
    13.     mov SP,steckMiddle
    14.    
    15.     sti
    16.    
    17.     call InitScreen
    18.     call ClearScreen
    19.    
    20.     push 0x0101
    21.     call SetCursorPos
    22.    
    23.     mov SI,text1
    24.     mov BL,00000100b
    25.     call DrawText
    26.    
    27.     call LoopProcessor
    28.  
    29. LoopProcessor:
    30.     jmp LoopProcessor
    31. ret
    32.  
    33. include "BIOS.asm"
    34.  
    35. data16:
    36.     text1 db "Hello my friend!",0x00
    37.  
    38. steck16:
    39.     steckEnd    db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    40.                 db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    41.                 db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    42.                 db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    43.     steckMiddle db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    44.                 db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    45.                 db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    46.     steckStart  db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    И потом вот так:

    Код (Text):
    1. SetCursorPos:
    2.     mov AH,0x02                 ; Код функции
    3.     mov BH,0x00                 ; Номер страницы
    4.    
    5.     pop DX
    6.    
    7.     int 0x10                    ; Вызываем прерывание BIOS
    8. ret
    Эмулятор зацикливается, текст (всего один символ) не выводит. Понимаю что не так что-то со стеком сделал. Как правильно?

    Я просто внизу программы зарезервировал 64 байта для стека.
     
  11. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Потому что в стеке данные располагаются так:
    параметры
    адрес возврата
    то есть pop dx извлекает адрес возврата, а не параметр. Надо писать так:
    Код (Text):
    1. push bp
    2. mov bp, sp
    3. mov dx, [bp + 4]
    4. ...
    5. pop bp
    Однако это требует генерации кучи дополнительного кода. В начальном загрузчике лучше ограничится регистрами - сэкономите не один десяток байт. И вообще передача параметров через регистры оптимальнее, но требует думать о том, чтобы не затирать регистр до последнего использования параметра из него или запихивать его в стек, когда это неизбежно и восстанавливать позднее. Но в итоге программа получается намного меньше и быстрее.
    В качестве эмулятора рекомендую Bochs - в нём есть очень хороший отладчик. Чтобы получить представление о его возможностях взгляните хотя бы это:
    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]
     
  12. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    KIV
    Впечатляет. Что-то я для Windows такое не нашёл. Одно только консольное окно с информацией.
     
  13. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Это я для Linux такое долго искал (пришлось собирать из исходников с особенными параметрами). В Windows достаточно написать в bxrc строчку:
    Код (Text):
    1. display_library: win32, options="gui_debug"
    И открывать файл bxrc с помощью bochsdbg.exe, а не просто bochs.exe (пункт в контекстном меню файла в проводнике "Debugger", если бокс поставил ассоциацию файлов, иначе - C:\Program Files\Bochs-2.4.5\bochsdbg.exe). Ещё могу посоветовать опцию magic_break: enabled=1. Заставляет отладчик останавливаться на инструкциях xchg bx, bx - удобно, когда не знаешь адрес где надо встать. Только файлы с этими двумя опциями обычный bochs не dbg не откроет - напишет неизвестная опция. И наконец эта фича появилась начиная с 2.4.2 - в предыдущих её нет.
     
  14. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Всё, сделал. Вот код файла main.asm:

    Код (Text):
    1. use16
    2.  
    3. org 0x7C00
    4.  
    5. code16:
    6.     mov AX,CS
    7.     mov DS,AX
    8.     mov ES,AX
    9.     mov FS,AX
    10.     mov GS,AX
    11.     mov SS,AX
    12.    
    13.     sti
    14.    
    15.     call InitScreen
    16.     call ClearScreen
    17.    
    18.     mov SI,text1
    19.     mov BL,00000100b
    20.     mov DH,1
    21.     mov DL,1
    22.     call DrawText
    23.    
    24.     mov SI,text2
    25.     mov BL,00011010b
    26.     mov DH,3
    27.     mov DL,1
    28.     call DrawText
    29.    
    30.     call LoopProcessor
    31.  
    32. LoopProcessor:
    33.     jmp LoopProcessor
    34. ret
    35.  
    36. include "BIOS.asm"
    37.  
    38. data16:
    39.     text1 db "Hello my friend!",0x00
    40.     text2 db "You in R-Mode.",0x00
    А вот код файла BIOS.asm:

    Код (Text):
    1. ; Инициализация экрана
    2. InitScreen:
    3.     mov AH,0x00                 ; Код функции
    4.     mov AL,0x03                 ; Код режима (80x25x16)
    5.    
    6.     int 0x10                    ; Вызываем прерывание BIOS
    7. ret
    8.  
    9. ; Очистка экрана
    10. ClearScreen:
    11.     mov AH,0x09                 ; Код функции
    12.     mov AL,' '                  ; Выводимый символ
    13.     mov BH,0x00                 ; Номер страницы
    14.     mov BL,00010000b            ; Атрибуты
    15.     mov CX,2000                 ; Количество повторений
    16.    
    17.     int 0x10                    ; Вызываем прерывание BIOS
    18. ret
    19.  
    20. ; Установка положения курсора
    21. ; DH - номер строки
    22. ; DL - номер столбца
    23. SetCursorPos:
    24.     mov AH,0x02                 ; Код функции
    25.     mov BH,0x00                 ; Номер страницы
    26.    
    27.     int 0x10                    ; Вызываем прерывание BIOS
    28. ret
    29.  
    30. ; Вывод текста
    31. ; BL - атрибуты текста
    32. ; DH - номер строки
    33. ; DL - номер столбца
    34. DrawText:
    35.     mov CX,1                    ; Количество повторений
    36.  
    37.     DrawTextLoop:
    38.         call SetCursorPos
    39.         mov AH,0x09                 ; Код функции
    40.         mov BH,0x00                 ; Номер страницы
    41.         mov AL,byte [SI]
    42.         cmp AL,0x00
    43.         jz DrawTextExit
    44.         int 0x10                    ; Вызываем прерывание BIOS
    45.         inc SI
    46.         inc DL
    47.     jmp DrawTextLoop
    48.    
    49.     DrawTextExit:
    50. ret
    А вот результат работы:

    [​IMG]

    Большое всем спасибо! Буду признателен любым советам и комментариям. Я всё таки хочу написать свой мини-ассемблер на C++, который включал бы только то, что мне нужно, с понятным для меня (своим) синтаксисом. Как считаете, стоит ли это делать (не для глобального использования везде и всеми, а только для себя, для успокоения своей души)?
     
  15. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Не советую изобретать велосипед. Всё что только можно (очень мощный макроязык, поддержка практически всех инструкций процессора - даже самых новых) сделано в FASM. Тем кому не нравится немного отличающийся от Intel синтаксиса FASM могут пользоваться TASM, MASM, YASM, NSAM или для любителей AT&T синтаксиса - gas. Ничего нового вы не придумаете всё равно, а получиться лишь урезанный fasm или masm.
    Код (Text):
    1. mov FS,AX
    2. mov GS,AX
    Вы не используете эти регистры. Зачем их инициализировать? Этим вы теряете совместимость с 8086, хотя найти подобный комп сегодня сложновато...
    Код (Text):
    1. mov SS,AX
    А вот это делать совсем не надо, если не устанавливаете свой SP. Ведь при переходе на загрузчик стек был настроен, а вы вполне можете его испортить.
    Советы насчёт оптимизации:
    не mov al, [si]; inc si, а lodsb
    не cmp al, 0, а test al, al
    не mov bh, 0, а xor bh, bh. и так во всех подобных случаях (обнуление регистра)
    больше замечаний нет.

    Так вы планируете переключаться в PM/long mode?
     
  16. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    KIV
    А можно ли для него поставить какой бы он bxrc-файл сам по умолчанию при запуске грузил?
     
  17. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    нет. только править исходники. но если встала ассоциация, то очень даже удобно дважды кликнуть по файлу bxrc. Даже в Linux я так сделал.
     
  18. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    KIV
    Вот я заменил строку:

    Код (Text):
    1. mov AL,byte [SI]
    На:

    Код (Text):
    1. lodsb
    И у меня текст стал выводится перепрыгивая через буквы (возможно через одну, я просто не разглядывал).
     
  19. KIV

    KIV Member

    Публикаций:
    0
    Регистрация:
    16 июл 2009
    Сообщения:
    231
    Убери inc si в конце цикла - lodsb уже делает эту работу.
     
  20. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    KIV
    Спасибо, сейчас сделаю. Да, у меня получилось, я правой кнопкой нажимаю и там есть Debugger. А если просто два раза нажать на файл, то открывается окно и там только завершение.

    [​IMG]