Рассылка закрыта
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Низкоуровневое программирование для дZенствующих (FAQ) ЯНВАРЬ 2001
НИЗКОУРОВНЕВОЕ ПРОГРАММИРОВАНИЕ ДЛЯ ДZЕНСТВУЮЩИХ (FAQ) АРХИВ MAIL-КОНФЕРЕНЦИИ RTFM_HELPERS ЗА ЯНВАРЬ 2001 Сайт: http://hi-tech.nsys.by/ Информация о конференции: http://hi-tech.nsys.by/forum/ Модератор aka Beltsy: bejenari@beltsy.md Co-moderator aka Serrgio: serrgio@gorki.unibel.by [В О П Р О С - О Т В Е Т] ======================================================================= ВОПРОС: При компиляции программ отладчик выдает код A2034: must be in segment block как избавиться от этой ошибки? BELTSY: Отладчик программы НЕ КОМПИЛИРУЕТ, этим занимается КОМПИЛЯТОР!!! Следовательно, при компиляции ОТЛАДЧИК не может НИЧЕГО "выдавать". ----------------------------------------------------------------------- ВОПРОС: Из #9 (РАЗБОРКИ С ПРОЦЕДУРАМИ, п.3) цитирую: :0100 XOR AL,AL ;первое окошко рисуем, как и раньше... :0102 MOV BH,10 :0104 MOV CH,05 :0106 MOV CL,10 :0108 MOV DH,10 :010A MOV DL,3E :010C MOV AH,06 :010E INT 10 :0110 CALL 011E ;четыре раза вызываем подпрограмму, ;начинающуюся по адресу 011E. Вот тут у меня вопрос: как мне узнать этот адрес 011E? Ведь когда я пишу программу, я не знаю точного адреса начала будущей подпрограммы. BELTSY: Когда Вы пишете программу, Вы используете метки (label), а ассемблер их уже переводит в эти цифры. Приведенный Вами код - написан на МИКРОассемблере, там АДРЕСА меток нужно просчитывать самому, что совсем не сложно. Зная, что программа начинается со смещения 100h и количество байт которые занимает каждая команда, пишем программу и подщитываем ;). Изврат, конечно, но зато очень хорошее упражнение для мозгов :). ----------------------------------------------------------------------- ВОПРОС: Существует ли какой нибудь декомпилятор Виндовых *.hlp файлов? SERRGIO: Есть такая хорошая среда для разработки разнообразных хелпов - RoboHELP Office. И в ней среди разнообразных тулсов есть и Help-to-Source aka "декомпилятор Виндовых (да и всех прочих) *.hlp файлов". ----------------------------------------------------------------------- ВОПРОС: Каким образом можно записать BOOT-сектор? Может какое прерывание есть под это? BELTSY: BOOT сектор это всего-лишь самый первый сектор на диске, т.е. самые первые 512 байт. Поэтому писать в него можно темже прерыванием, что и в любой другой, т.е. биосовским 13h, функция ah=03. ----------------------------------------------------------------------- ВОПРОС: ...вот такую наипростейшую программу сассемблировать в дебаггере и заставить работать аккуратно не получается: text segment 'code' assume CS:text, DS:text begin: mov AX,text mov DS,AX mov AH,09h mov DX,offset message int 21h mov AH,4Ch mov AL,00h int 21h message db 'Привет!$' text ends end begin Как эта программа выглядит в дебаге при ассемблировании? BELTSY: Не знаю зачем Вы заносите в DS значение text, Вы же assume написали, этого достаточно, DS и так уже какой надо... Но это Ваши проблемы ;) А в дебаге ЭТО вот как "выгледеть" должно: -a 1A2A:0100 mov ah,09 1A2A:0102 mov dx,10D 1A2A:0105 int 21 1A2A:0107 mov ah,4C 1A2A:0109 mov al,00 1A2A:010B int 21 1A2A:010D -e 10D 'Привет!$' -d 100 [дамп памяти опущен] -g Привет! C:\>_ ----------------------------------------------------------------------- ВОПРОС: Я читаю сейчас на 5-й раз 4-й выпуск рассылки и так не могу понять, почему при выводе дампа и подсчете колличества RAM'а, мы меняли значения наоборот, т.е. там было написанно 81 32h, а переводить и складывать мы должны были 32 81h, ведь когда вы присваиваете регистру AX=27f4h Вы же присваеваете AH=27h, а AL=f4h и в регистре эти значения не меняются местами, по-крайней мере у вас там так написанно. YOSHI: В памяти данные хранятся: МЛАДШИЙ БАЙТ ПО МЛАДШЕМУ АДРЕСУ. Например, мы определили в ассемблере слово: ... dw 1234h. Здесь 12h - старший байт, 34h - младший. Следуя принципу "младший байт по младшему адресу", выходит, что в памяти это слово будет храниться как 34 12 (проверь в отладчике!). Если к этому слову обращаться как к "слову", то все буден нормально, а если обращаться побайтно, то вот тут уже придется менять их местами. А с AX все в порядке: AH - старшая часть, AL - младшая. Присваивая AX значение 1234h (mov ax,1234h), AH присваивается 12h, AL присваивается 34h. ----------------------------------------------------------------------- ВОПРОС: Что делает комманда XOR? YOSHI: XOR - побитовая операция логического исключающего ИЛИ над двумя операндами, результатом которой является "истина", если только один из двух операндов имеет значение "истина". И "ложь", если оба операнда имеют значение "ложь" или "истина". (Короче, если биты разные, то результат - 1, а если одинаковые, то результат - 0). Таблица истинности: A B C ======= 0 0 0 0 1 1 1 0 1 1 1 0 С помощью XOR можно инвертировать биты: xor ax,ax ;очистили ax xor al,01h ;инвертировали первый бит, теперь al=0001b xor al,01h ;инвертировали первый бит, теперь al=0000b ZERO-Q Дополним :) 11 07 06 04 02 00 OF SF ZF AF PF CF 0 R R ? R 0 OF, SF, ZF, AF, PF, CF - такие вот мнемоники флагового регистра; 11, 07, 06, 04, 02, 00 - номера битов оного; Значения: 0 - после выполнения команды флаг равен 0 (сбрасывается); R - значение зависит от результата; ? - флаг неопределен. Схемка такая вот: xor приемник,источник Результат операции помещается в приемник (или в первый операнд). ----------------------------------------------------------------------- ВОПРОС: По какому адресу находиться видеопамять в режиме 640x480? S. YAR: Если мне не изменяет память, во всех ГРАФИЧЕСКИХ режимах плат EGA и VGA (и всех более современных плат в совместимых с VGA режимах) видеопамять начинается по адресу 0A000h:0. Только нужно знать организацию этой видеопамяти - она (организация) разная в разных режимах... Очевидно, в вопросе речь идет о режиме VGA, 640x480, 16 цветов... В этом режиме видеопамять разбита на 4 цветовые плоскости, в один момент времени в адресуется только одна (смена производится записью в соответствующий IO-регистр VGA-контроллера). Один единовременно адресуемый байт видеопамяти отвечает за 8 смежных (по горизонтали) точек экрана. Это вкратце... ======================================================================= [О Б С У Ж Д Е Н И Е] ======================================================================= WARORC Чем отличается файл типа .com , от файла типа .txt, имхо, когда я смотрел в NC, то я никакой разницы в коде не заметил, но компьютер-то определяет, что этот надо интерпретировать как код для выполнения, так вот в чем различия, разъясните мне, плз.? ZERO-Q Расширением!! ;-) Не компьютер определяет, а проце$$ор, а ему, чесна говоря, по-барабану какой "хлам" в него летит. Ах. В том то и прелесть низкоуровневого программинга. А еще появились вот какие соображения: Создаем в любом ДОСовском текстовом редакторе файл со следующим содержимым: Alt+049 Alt+0192 Alt+064 Alt+0205 Alt+032. Сохраняем его, например как, 1.txt. Запускаем уже полюбившийся нам дZебургер, даем команды: -n 1.txt -l -g и видим: Нормальное завершение работы проги. Даем команду: -u100 и видим: :0100 xor ax,ax :0102 inc ax :0103 int 20 Даем команду: -d100 и видим: :0100 31 C0 40 CD 20 Открываем файл 1.txt в встроенном редакторе NC видим туже самую последовательность хексовых цифр. Вывод: разница между .com и .txt - в расширении имени. Программы можно писать и таким образом. Мораль: никогда не пишите так программы. WARORC Я пробывал запускать в дебугере текстовик и он работал. НО раз МД или другая операционка, определяет, что делать с файлом, то следовательно она смотрит на расширение, но она же не мы, т.е. она же не думает, ага это тхт мы его не будем давать проццу на выполнение, а раз она их различает, то следовательно различия должны быть в коде, а раз их нет, то как она умудряется их различать? Это не вопрос, мне просто интересно. BELTSY Короче так. По сути между txt и com никаких различий НЕТ. Шо там набор цифр, шо там тоже самое. Более того, был у нас txt, а мы его переименовали в com и стал он com-ом! Попробуй сделать так, ну и запусти его. Потом нажимай сразу на Reset и читай дальше. МС-ДОС не смотрит на код, а только на расширение. Если в командной строке введешь С:\>aaaa.txt и нажмешь, то она ничего не сделает, а как-тока переименовали все пошло ........... на Reset жми. В коде различий НЕТ!!! для ДОСа тока в расширениях. А вот в других операционках, например UNIX, расширений вообще нету. Надеюсь с расширениями разобрались............. YOSHI Не совсем согласен. MS-DOS, все-таки, смотрит на код при определении формата файла. Например, если дос увидит в сигнатуре файла (сигнатура - здесь первые два байта файла) код 5A 4D, то есть "MZ" или "ZM", то этот файл дос определяет как EXE, если что-то другое, то COM. Можете проверить (правда для этого нужно правильно указывать заголовок EXE файла формата MZ). Пример: Файл COMMAND.COM в windows имеет размер 95,192 Кб. Как это COM файл имеет размер более 65,536 Кб??? Да просто это самый настоящий EXE, который переименован в COM. А вот теперь, надеюсь, разобрались. BELTSY Согласен, но не со всем. возьми переименуй ехе-ный файл в тотже txt. Ну введи его в командной строке. запустит??? а фиг запустит!!! Так что в первую очередь дос смотрит на расширение, а уж потом на все остальное!!! ----------------------------------------------------------------------- ZERO-Q В девятом выпуске, всем нам известной рассылки "Низкоуровневое программирование для ДZенствующих", в пункте четвертом [4] есть пример программы, где мы с Вами рисуем окошки на дисплее. Я не стал лениться и нарисовал тринадцать таких окошечек при помощи следующей последовательности нуликов и единичек: :0100 mov ax,0600 ;65 байт :0103 mov bh,70 :0105 mov cx,0000 :0108 mov dx,184f :010B int 10 :010D call 0133 :0110 call 0133 :0113 call 0133 :0116 call 0133 :0119 call 0133 :011C call 0133 :011F call 0133 :0122 call 0133 :0125 call 0133 :0128 call 0133 :012B call 0133 :012E call 0133 :0131 int 20 :0133 sub bh,10 :0136 add,cx,0101 :013A sub dx,0101 :013E int 10 :0140 ret Захотел я было CALL LOOP-ом закрутить, да вот загвоздка, а точнее КОНКУРЕНЦИЯ, на CX претендуют сразу и INT 10 и LOOP. Но решил я не отчаиваться и закрутить все это еще через СТЕК. Думал я долго и кипели мозги (все как по прогнозу SERRGIO), и придумал. Ура! Кричу я, брызгая слюной на свой дисплей, а тут как кирпичом по голове (наверное это и имеет ввиду SERRGIO); В СТЕК? В СТЕК? Да тут на стек этот тоже своего рода КОНКУРЕНЦИЯ. Когда выполняешь CALL он пихает в стек адрес следующей за ним команды, для последующего возвращения по этому адресу командой RET (будь она неладна). Не это не кирпичом по голове, а прямо как-то веслом по плечу. Вообщем дZенствовал долго и на дZенствовал я следующее: :0100 mov ax,0600 ;42 байта :0103 mov bx,700C :0106 mov cx,0000 :0109 mov dx,184f :010C int 10 :010E push cx :010F jmp 0113 :0111 mov bl,cl :0113 pop cx :0114 add cx,0101 :0118 push cx :0119 sub dx,0101 :011D sub bh,10 :0120 int 10 :0122 xor cx,cx :0124 mov cl,bl :0126 loop 0111 :0128 int 20 Во как закрутил! Вы представляете! И эта штука работает! Да к тому же так как хотелось. Хотя хотелось CALL LOOP-ом завернуть. Через некоторое время получилось следующее: :0100 mov ax,0600 ;38 байт :0103 mov bx,7000 :0106 mov cx,0000 :0109 mov dx,184F :010C int 10 :010E cmp bl,0C :0111 jz 0124 ;кстати я пишу в своем дZебургере je, :0113 add cx,0101 ;а он сам переводит на jz. Кто знает :0117 sub dx,0101 ;подскажите почему? :011B sub bh,10 :011E inc bl :0120 int 10 :0122 jmp 010E :0124 int 20 А CALL LOOP-ом я так не закрутил. Дался он мне и все тут. Может у кого получалось разрешить такую вот заморочку? DINOZAUR Я тоже подзенствовал и родил такое: segment qwe 'code' assume cs:qwe org 100h beg: mov ax,0600h mov bh,70h mov cx,0000h mov dx,184fh int 10h mov ax,12 lpb: push ax call wnd pop ax dec ax jnz lpb int 20h wnd: mov ax,0600h sub bh,10h add cx,0101h sub dx,0101h int 10h ret ends qwe end beg Скрестил бульдога с носорогом... 2K В результате ужасающих по своей ничем необоснованной жестокости генетических эксперементов родился нижеследующий МОНСТР: ;loop+call segment kk assume cs:kk org 100h begin: mov ax,0600h mov bh,70h mov cx,0000h push cx mov dx,184fh int 10h mov cx,12 push cx pop cx N_wind: push cx call wnd pop cx loop N_wind int 20h wnd: pop es pop ds pop cx sub bh,10h add cx,0101h sub dx,0101h int 10h push cx push ds push es ret ends kk end begin Безумное количество инструкций pop и push! надо с этим что-то делать. Но результат налицо -- call работает вместе с loop. WUNICORN И это занимает 48 байт ;) Если поставить себе задачу сделать именно loop+call, то можно вот так (38 байт): CODESG segment assume cs:CODESG org 100h MAIN proc mov ax,0600h mov bh,70h mov dx,0184fh ;mov si,0h xor si,si mov cx,0dh NextWin: xchg si,cx call WINDOW xchg si,cx loop NextWin int 20h MAIN endp WINDOW proc int 10h sub bh,10h add cx,0101h sub dx,0101h ret WINDOW endp CODESG ends end MAIN Но вообще-то для данной задачи ИМХО лучше обойтись вообще без call и еще чуть-чуть поизвращаться, тогда можно загнать все в 33 байта: CODESG segment assume cs:CODESG org 100h MAIN proc mov di,0101h mov ax,0600h mov bh,70h mov dx,0184fh xor si,si mov cx,0dh NextWin: xchg si,cx int 10h sub bh,10h add cx,di sub dx,di xchg si,cx loop NextWin int 20h MAIN endp А еще меньше можно ? :) WUNICORN Утро вечера мудренее оказалось :) Ведь таки можно еще байт выиграть :) 32 байта: CODESG segment assume cs:CODESG org 100h MAIN proc mov di,0101h mov ax,0600h mov bh,70h mov dx,0184fh xor si,si mov cx,0dh NextWin: xchg si,cx int 10h sub bh,10h add cx,di sub dx,di xchg si,cx loop NextWin ;int 20h ret ; Так тоже можно из комушника выйти :) MAIN endp CODESG ends end MAIN ZERO-Q dinozaur Вы писали: d> закрутить call с loop'ом (Zero-Q) d> я тоже подзенствовал и родил такое: что-то я не как не догоню вот этот участок: ..... dec ax jnz 0110 int 20 d> Скрестил бульдога с носорогом... Кста, скрестить бульдога с носорогом! Тоже надо уметь. И объясните "чайнику" плз, в чем разница между MASM and TASM. А то целый час ушел на перекачку 3,9Мб MASM с сайта hi-tech, а Serrgio глаголит, что нужен TASM. DINOZAUR > d> закрутить call с loop'ом (Zero-Q) > d> я тоже подзенствовал и родил такое: > что-то я не как не догоню вот этот участок: > ..... > dec ax > jnz 0110 > int 20 segment qwe 'code' assume cs:qwe org 100h beg: mov ax,0600h mov bh,70h mov cx,0000h mov dx,184fh int 10h mov ax,12 ;число повторов lpb: ;начало цикла push ax ;сохраняем число повторов call wnd ;выводин окно pop ax ;высстанавливаем число повторов dec ax ;уменьщаем на еденицу его jnz lpb ;если не ноль то на начало цикла int 20h ;если ноль в числе повторов, wnd: ;то конец :-) ну а тут все ясно mov ax,0600h sub bh,10h add cx,0101h sub dx,0101h int 10h ret ends qwe end beg > d> Скрестил бульдога с носорогом... > Кста, скрестить бульдога с носорогом! > Тоже надо уметь. Гы :-)) > И объясните "чайнику" плз, в чем разница между MASM and > TASM. А то целый час ушел на перекачку 3,9Мб MASM с сайта > hi-tech, а Serrgio глаголит, что нужен TASM. Если уж выхода > нет, то придется и его качать. Для начала разницы нет... я юзаю тасм от Борланд Си 3.0 2K W> Но вообще-то для данной задачи ИМХО лучше обойтись вообще W> без call и еще чуть-чуть поизвращаться, тогда можно W> загнать все в 33 байта: [..] W> А еще меньше можно ? :) Можно: заменить последний int 20h на ret. некоторое снижение быстродействия, но уже 32 байта. WUNICORN G> Можно: заменить последний int 20h на ret. некоторое G> снижение быстродействия, но уже 32 байта. Ну, это я уже с утра пораньше догадалась и в эху кинула :) А вот если уйти от loop, то получается вообще 29 байт: CODESG segment assume cs:CODESG org 100h MAIN proc mov di,0101h mov ax,0600h mov bh,70h mov dx,0184fh xor cx,cx mov si,0dh NextWin: int 10h sub bh,10h add cx,di sub dx,di dec si jnz NextWin ret MAIN endp CODESG ends end MAIN 2K В таком варианте увеличивается скорость (причем увеличение прямо пропорционально количеству окошек): CODESG segment assume cs:CODESG org 100h MAIN proc mov di,0101h mov ax,0600h mov bx,7010h ;было mov bh,70h mov dx,0184fh xor cx,cx mov si,0dh NextWin: int 10h sub bh,bl ;было sub bh,10h add cx,di sub dx,di dec si jnz NextWin ret MAIN endp CODESG ends end MAIN DINOZAUR > G> Можно: заменить последний int 20h на ret. некоторое > G> снижение быстродействия, но уже 32 байта. Ну, на такое снижение можно начхать... в конце-концов программа завершается только один раз :-) > А вот если уйти от loop, то получается вообще 29 байт: Вообще-то тут используется то, что при вызове int 10 у нас регистры сохраняются... Но это не всегда верно... Если вызывать свою процедуру, то не факт, что она все так и оставит после себя. Правда можно ее заставить(сохранять все в стеке при входе и восстанавливать при выходе). Но это влечет дополнительные расходы (пролог & эпилог в каждой проц писать накладно). Поэтому большинство компиляторов с языков высокого уровня так не делает... ZERO-Q W> А вот если уйти от loop, то получается вообще 29 байт: Кста, сабж письма у Вас, как я понял леди :), проходит как loop+call, а от loop Вы пытаетесь убежать :(, что-то как-то не в тему, ну да ладно. Все варианты хороши. Господа :), хочу Вам сообщить, что я искренне доволен подобными письмами. Я вот еще подписан на один офлайновый форум по железу, так там такие правила: 1)задал тему, в течении четырех дней отвечаем; 2)если ответы помогли и вполне устраивают, то посылается в группу письмо с сабжем "Вопрос закрыт". Что я с удовольствием и делаю (да не разругается модератор), хотя правила в группе вообще не проходили и "награды", я думаю мне не сулит. Коврик для мыши совершил недопустимую операцию и будет свернут :). ======================================================================= (С) HI-TECH group. All rights reserved and reversed. Оригинальная грамматика авторов сохранена.
http://subscribe.ru/
E-mail: ask@subscribe.ru | Отписаться | Рейтингуется SpyLog |
В избранное | ||