Comments 54
Было интересно, спасибо. Понастольгировал по ассемблеру и com файлах.
PS скриншоты такого качества, что ничего не видно.
Ага, олдскулы сводит, когда читаешь, как кто-то открывает для себя то, с чего ты начинал много лет назад
Да, поддерживаю. Спасибо автору за перевод!
За снимками экрана в нормальном качестве пришлось идти в источник. @Sivchenko_translate, поправьте, пожалуйста.
b: b4 4c mov ah,0x4c
d: b0 2a mov al,0x2a
Хм. Можно было бы сэкономить один байт, сказав mov ax, ...
. А можно было бы и int 20h
сказать, без mov-ов...
mov ax, 4C2Ah ; AH = 4Ch, AL = 2Ah — то же самое, что два mov
int 21h
Тогда почему часто делают два mov?
читаемость и семантика;
гибкость при изменении кода возврата;
оптимизация компилятора не всегда выбирает mov ax, imm16;
психология и традиция
Пример гибкости кода возврата:
mov ah, 4Ch ; функция exit — фиксирована
mov al, [result] ; код возврата — переменный
int 21h
Пример кода на C:
exit(42);
Вы же можете изменить код возврата, как пример - согласно условиям?!
int 20 - завершение программы (Terminate). Работает только для .COM-файлов - не подходит для .EXE Требует, чтобы CS указывал на начало программы, если вы изменили CS, то он не сработает. Не позволяет передать код возврата.
int 21 - главный системный вызов DOS, через который можно делать разные операции: вывод на экран, чтение с клавиатуры, работу с файлами, управление памятью, завершение программы с кодом возврата.
А если надо вывести строку со знаком доллара?
.model tiny
.code
org 100h
start:
mov dx, offset msg ; адрес строки
mov si, dx ; SI = указатель на строку
print_loop:
lodsb ; загружаем байт в AL и увеличиваем SI
cmp al, '$' ; это наш особый символ?
je print_dollar ; если да — обрабатываем отдельно
cmp al, 0 ; конец строки?
je done
mov dl, al ; DL = символ
mov ah, 02h ; функция: вывод символа
int 21h
jmp print_loop
print_dollar:
mov dl, '$' ; выводим символ '$'
mov ah, 02h
int 21h
jmp print_loop
done:
mov ah, 4Ch ; завершение программы
int 21h
msg db 'Price: $25.00', 0Dh, 0Ah, 0
end start
Она простая
Это тебе нейронка насобачила? Нет никакого смысла делать отдельную ветку для $
Я не пользуюсь нейронками, от слова совсем. Если можно так сказать - я из "старой школы", когда еще код записывали в тетради, а доступа к компам не было. Уже в этом веке давно все тетради оцифровал, все записи перевел в "читабельный" вид и сделал себе программу по записям
А теперь ответ на Ваш вопрос: $ - специальный управляющий символ, терминатор строки
А зачем тогда эта избыточность? Вот что могло пойти не так если $ печатать как и все остальные символы?)))
Давайте попроще постараюсь объяснить...
Вы не можете "просто напечатать $", потому что вы не знаете, где он "настоящий", а где - конец строки.
Что сделает DOS:
Начинает выводить: P, r, i, c, e, :, ...
Видит $ и считает, что строка закончилась;
Останавливается;
На экране: "Price:"
Упс.. - строка обрезана, 25.00 и перевод строки - не выводятся. Потому что ah=09h не умеет отличать символ "$" от "конца строки".
$ - специальный управляющий символ
Тем не менее выводите вы его той же самой второй функцией 21го прерывания )
Это не избыточность, а разделение ответственности:
ah=09h — для строк с терминатором,
ah=02h — для контролируемого вывода символов.
Поэтому я постарался сделать пример попроще...
Раз уж выводите все символы через ah=02h, смысл в отдельной обработке доллара вроде как пропадает.
Для соего примера, я ставил целью не эффективность, а обучение. Пример с веткой, как обучающий приём, чтобы подчеркнуть особую роль символа $ в DOS.
"Улучшенная" версия кода (для "матёрых"):
.model tiny
.code
org 100h
start:
mov si, offset msg
print_loop:
lodsb ; AL = символ
cmp al, 0 ; конец строки?
je done
mov dl, al ; DL = символ
mov ah, 02h ; вывод символа
int 21h
jmp print_loop
done:
mov ah, 4Ch
int 21h
msg db 'Price: $25.00', 0Dh, 0Ah, 0
end start
int 29 display char, недокументированная
не совсем понял смысла челенжа, мнемокод и номер команды неразрывно связаны, пишете сначала на ассемблере, потом конвертируете в HEX, создаёте в HEX редакторе - вуаля. Но это не имеет ни практического ни развлекательного смысла.
Челлендж для тех, кто ассемблера боится. Это в начале 90х, помню, все знакомые (причём больше физики, чем программисты) гонялись за книжками по ассемблеру, прерываниям DOS/BIOS и т.п. - типа без этого ты вообще в компьютерах не разбираешься. Сейчас большинство программистов мыслят в терминах своих ЯП/фреймворков, что там снизу - тёмный лес...
я вас не понял, в чем проявляется боязнь ассемблера, но при этом нет боязни писать в HEX? логику не прослеживаю.
тем более изучение i286 ассемблера не имеет никакого практического смысла если вы не собрались писать какой-то проект в DOS. А применение ASM вставок в современном коде например для повышения производительности - это совсем не про MOV AH и INT 21h.
для чего было гоняться за книжками по ассемблеру если был Norton Guides и куча текстовиков с описанием? Удобоваримые книжки стали появляться тогда, когда актуальность уже пропала. Бывший СССР схавал в начале 90-х всё что на западе кушали 15 лет, так что в одном кабинете у вас могли стоять и i286 и Pentium на винде.
Не особо понимаю в чем заключается мышление в терминах ЯП. Человек мыслит категориями представления данных, а не командами ЯП. Вот я знаю пару десятов ЯП - в каких категориях прикажете мне мыслить? Мышление на питоне сильно отличается от C++ при всей когда-то похожести синтаксиса. Поэтому задача всегда решается категориями представления данных, вполне вероятно когда вы осмыслите в каких данных выражена ваша задача, то и выбор ЯП вы будете производить исходя из этого, разве нет?
тем более изучение i286 ассемблера не имеет никакого практического смысла
Статья точно не про практический смысл. Тут так, показать немножко низкого уровня для тех кто никогда с этим не сталкивался, детали всё равно уловят только те, кто и так всё это знает )
Удобоваримые книжки стали появляться тогда, когда актуальность уже пропала.
У меня бумажная книжка (Джордейн) появилась заметно раньше всяких документов в электронном виде (Ralph Brown's interrupt list и иже с ними).
Вот я знаю пару десятов ЯП - в каких категориях прикажете мне мыслить?
Это нетипичный случай. Я про вариант, когда человек знает только Javascript и хорошо ещё, если может обобщить знания по Vue и React.
человек знающий только джава скрипт не сильно тянет на программиста и на того кому нужно что-то читать про хекс, повторю еще раз - конкретно в такой подаче материала нет практического смысла, никто ни с чем не познакомится и далее не с чем будет сравнивать. Обычный ассемблер, коды команд - и этого вполне достаточно для понимания.
Ну так давайте ничего не делать. Не будем пытаться даже в научно-популярном смысле заинтересовывать горе javascript «программистов», мешать им копаться в своей песочнице.
А давайте вы перестанете читать по диагонали и попытаетесь понять смысл мною сказанного, это сильно полезнее чем упомянутая статья.
Ну я среагировал на эту выдержку:
конкретно в такой подаче материала нет практического смысла, никто ни с чем не познакомится и далее не с чем будет сравнивать.
В остальном, не буду спорить, ибо не имею цели ссориться.
спор != ссора ) ну и мы не спорим, а обсуждаем тему.
могу объяснить свой тезис - знакомство с ассемблером имеет практический смысл, так как для вас будут узнаваемы другие материалы, вы прочитаете о том что происходит в реальности. Статья же это некая форма челенжа и скорее интересна тем кто уже знаком с темой и хочет может быть развлечься. Изучать машинный код в таком формате глупость, так как в таком виде никто не программирует, вы не встретите литературу или код в таком же формате, то есть это не нужно никому никогда и нигде. Поэтому если вы хотите гипотетическому явасприптеру показать что такое машинный код и как с этим работать, воспользуйтесь ассемблером, это ничуть не сложнее яваскрипта (как для меня так даже легче, так как нет никаких заумных синтаксисов, просто мнемокод и параметры, из сложного наверное только то, что нет возможности создавать кучу переменных и тем более массивы как таковые, у вас для манипуляции всегда только регистры ЦПУ, а все действия выполняются либо с ними же либо с памятью, собственно всё программирование это перемещение ячеек памяти туда-сюда и арифметические операции над числами, то есть уровень 4-го класса алгебры и первого года информатики).
спор != ссора )
Сразу- да, согласен! 😜😂 ☝️Но это тот случай, где я выражаюсь в стилистику по смыслу, а не в академическую художественность, скорей с оттенками правоприменения🤣🤣🤣
Ой, а чего я это так разошелся… Совсем уже обалдел посреди дня 😇😀👋
Поехали дальше по тексту…
знакомство с ассемблером имеет практический смысл, так как для вас будут узнаваемы другие материалы
Не считая того, что как раз эта статья, как минимум интересная мне и другим трем с половиной бездельников (шутка! тока закончил раб день, уже дома, поел, обалдел — вот тел в руках нарисовался, наконец) в познавательном смысле.
Поэтому я и прицелился к Вам. Мол чего это Вы нам кайфы ломаете. 🤣😜😀
Далее, да. Согласен с Вами и понял, что статья не тянет на обучалку. И прочее. В этом плане согласен. Нас три с половиной души и вас человек двадцать тридцать, кому есть что поучаствовать в беседе. Тема. Я тут даже подумал, что может автор просто и хотел в паблике обсудить это, просто как пустяк из жизни, как пример для молодых. …. Не знаю. Ну ладно. Не важно. 😇😉
Потом вы меня поразили той простой, как объяснили мне некоторые фундаментальные вещи о машинном коде, которые я не догонял раньше— это бесценно. Вы мастер.
Блин я с вами вместе, и ИИ — скоро программировать начну, практиковать…
😊
Браво! 👏
Но это не имеет ни практического ни развлекательного смысла.
Насчет развлекательного не согласен, а практического почти наверняка нет. Ну, только если вы не продвинутый хакер в наилучшем смысле слова, кто просто листая дамп сходу цепляется глазом за подозрительные значения даже без дизассемблирования.
Там странная статья, очень странная - много неточностей и начинается со фразы: " Регистры бывают разных типов: AH, AL, AX, EAX, RAX - это все 1 регистр.". Новичкам крышу снесёт, а эксперты её уже "разнесли" - минус 15
Если и ссылаться, то надо ссылаться на документы такого уровня: "Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1, Section 3.4 "Registers""
"Мне понравилась такая идея, и я решил повторить такой опыт, но немного в иной форме – а именно, под 16-разрядной DOS в реальном режиме."
Можно и в нереальном.
Однако, напомнило, как когда-то писал всякую мелочь прямо в hex-редакторе... Как минимум, такое точно писал. Без objdump и т.п., ибо на той дискетке кроме volkov commander ничего из средств разработки не было.
Потом таки купил диск и дальше уже turbo assembler и т.п....
Интересно, спасибо!
Было бы интересно прочитать статью о том, как сделать такую же программу, работающую вовсе без ОС (например, вместо загрузчика). Ведь там не будет каких-то прерываний dos, ведь и dos нет. Только функции BIOS.
Кто то вообще понял как программировать на асме по этой статье ... 🤔 ?
Это статья не для обучения, а для развлечения тех, кто четверть века назад игрался с ассемблером.
Чтобы погрузится в ассемблер, нужно идти вот сюда. Там рассматривается программирование на ассемблере от Z80, 6502, 68000, 8086, ARM, ARM Thumb, 65816 до 6809, PDP-11, Risc-V, MIPS, TMS9900, SuperH, IBM370, PowerPC. ;)
Так же есть ютуб канал, где эти уроки представлены в формате видеотуториалов.
Далее скопируем CS в DS
Какое-то мучительное получилось копирование. Иногда такое делают без промежуточного регистра
push cs
pop ds
B4 4C B0 2A CD 21 ; exit
Из .com файла можно выйти просто инструкцией ret. Вот объяснение как это работает https://devblogs.microsoft.com/oldnewthing/20200309-00/?p=103547
Вспомнил. 90-е, школьные годы. Накодил какую-то штуку минимальную весёлую на ассемблере. А удобно было сразу COM-файлы прямо в Hiew писать (грубо говоря, это такой просмотрщик файлов для ~нортон коммандера) - там сразу переключаешься между байткодом и ассемблером. Так вот, накодил масенькое что-то, позвонил другу однокласснику и по телефону проводному продиктовал байты, он это так же у себя вбил и запустил. Сидите, гогочете :)
Слабенький туториал.
Если под Dos, покажите расчет условных прыжков, либо для loop, чтобы в машкоде их писать.
Если под Win, что-то такое https://wasm.in/blogs/win32-appy-by-hand.330
для x64 https://wasm.in/blogs/hello-world-v-mashinnyx-kodax.683
А вообще сегодня на Хабр зашел за "android app in bare opcodes", но видимо не судьба. На это бы взглянул с удовольствием.
Эх, молодость, ностальгия. Помню как руками по книжке в машинные коды вссемблерные инструкции переводил. Потом это всё загонялось в программу на Basic, которая эти коды записывала в память и передавала туда управление. Я так даже игры какие-то совсем мелкие писал. Забыл как этот комп назывался и не знаю, аналог чего он был. Он умел на кассеты код записывать и читать с них. "Поиск" что ли он назывался.
Ah, Al это же восьмибитные части AX! Он же сам по себе 16-битный, и, вместе с BX входит в 32-битный EAX. Разве нет?
Ah, Al это же восьмибитные части AX! Он же сам по себе 16-битный
Да.
вместе с BX входит в 32-битный EAX. Разве нет?
Нет. Когда процессоры Intel перешли на 32 бита, регистры общего назначения расширили до 32 бит. AX -> EAX, BX -> EBX и т.д.
BX не объединяли с AX для получения EAX.
Когда переходили на 64 бита, провернули приблизительно такой же трюк. EAX расширили до RAX, EBX до RBX и т.д.
Программа «Hello World» на машинном коде под DOS