Комментарии 55
Было интересно, спасибо. Понастольгировал по ассемблеру и 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, через который можно делать разные операции: вывод на экран, чтение с клавиатуры, работу с файлами, управление памятью, завершение программы с кодом возврата.
Можно было бы сэкономить один байт, сказав
mov ax, .... А можно было бы иint 20hсказать, без mov-ов...
Ну можно было тогда вообще ограничиться вульгарным RETN. Для СОМ-файла на вершину стека при запуске помещается ноль, JMP short CS:0 отправит на начало PSP, где как раз лежит то самое INT 20h.
А копирование CS в DS так и вовсе лишнее, потому как на старте СОМ-файла все сегментные регистры получают одно и то же значение. А если на это не закладываться (мало ли в каком DOSe будем запускать, вдруг он неаккуратный) - всё равно можно было упростить себе жизнь использованием пары команд PUSH CS; POP DS;.
Но цель-то статьи, скорее всего - разъяснение, как построить точный опкод конкретной команды.
А если надо вывести строку со знаком доллара?
.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 startint 29 display char, недокументированная
Челлендж для тех, кто ассемблера боится. Это в начале 90х, помню, все знакомые (причём больше физики, чем программисты) гонялись за книжками по ассемблеру, прерываниям DOS/BIOS и т.п. - типа без этого ты вообще в компьютерах не разбираешься. Сейчас большинство программистов мыслят в терминах своих ЯП/фреймворков, что там снизу - тёмный лес...
тем более изучение i286 ассемблера не имеет никакого практического смысла
Статья точно не про практический смысл. Тут так, показать немножко низкого уровня для тех кто никогда с этим не сталкивался, детали всё равно уловят только те, кто и так всё это знает )
Удобоваримые книжки стали появляться тогда, когда актуальность уже пропала.
У меня бумажная книжка (Джордейн) появилась заметно раньше всяких документов в электронном виде (Ralph Brown's interrupt list и иже с ними).
Вот я знаю пару десятов ЯП - в каких категориях прикажете мне мыслить?
Это нетипичный случай. Я про вариант, когда человек знает только Javascript и хорошо ещё, если может обобщить знания по Vue и React.
Ну так давайте ничего не делать. Не будем пытаться даже в научно-популярном смысле заинтересовывать горе javascript «программистов», мешать им копаться в своей песочнице.
Ну я среагировал на эту выдержку:
конкретно в такой подаче материала нет практического смысла, никто ни с чем не познакомится и далее не с чем будет сравнивать.
В остальном, не буду спорить, ибо не имею цели ссориться.
спор != ссора )
Сразу- да, согласен! 😜😂 ☝️Но это тот случай, где я выражаюсь в стилистику по смыслу, а не в академическую художественность, скорей с оттенками правоприменения🤣🤣🤣
Ой, а чего я это так разошелся… Совсем уже обалдел посреди дня 😇😀👋
Поехали дальше по тексту…
знакомство с ассемблером имеет практический смысл, так как для вас будут узнаваемы другие материалы
Не считая того, что как раз эта статья, как минимум интересная мне и другим трем с половиной бездельников (шутка! тока закончил раб день, уже дома, поел, обалдел — вот тел в руках нарисовался, наконец) в познавательном смысле.
Поэтому я и прицелился к Вам. Мол чего это Вы нам кайфы ломаете. 🤣😜😀
Далее, да. Согласен с Вами и понял, что статья не тянет на обучалку. И прочее. В этом плане согласен. Нас три с половиной души и вас человек двадцать тридцать, кому есть что поучаствовать в беседе. Тема. Я тут даже подумал, что может автор просто и хотел в паблике обсудить это, просто как пустяк из жизни, как пример для молодых. …. Не знаю. Ну ладно. Не важно. 😇😉
Потом вы меня поразили той простой, как объяснили мне некоторые фундаментальные вещи о машинном коде, которые я не догонял раньше— это бесценно. Вы мастер.
Блин я с вами вместе, и ИИ — скоро программировать начну, практиковать…
😊
Браво! 👏
Но это не имеет ни практического ни развлекательного смысла.
Насчет развлекательного не согласен, а практического почти наверняка нет. Ну, только если вы не продвинутый хакер в наилучшем смысле слова, кто просто листая дамп сходу цепляется глазом за подозрительные значения даже без дизассемблирования.
Там странная статья, очень странная - много неточностей и начинается со фразы: " Регистры бывают разных типов: 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