Не секрет что каждый из нас хоть раз открывал com или exe файлы блокнотом, видел письмена подобные этим:

В целях приподнятия завесы тайны странного наречия и написана эта статья.
Сразу стоит отметить, что символы, приведенные выше, по большей части, не несут смысловой нагрузки в своем начертании. Они являются визуальной формой числового представления. В свою очередь, числовое представление является операционным кодом машинного языка, и хранителем сакрального смысла этих тайных знаков.
Перейдем к более детальному изучению. Для этого нам понадобится книга написанная в недрах корпорации intel (intel 80386 Programmer's Reference Manual). Где детально рассказывается о формате инструкций процессора.
Обычно первой программой на любом языке программирования является вывод сообщения «Hello World!». Чтож… Не будем отступать от классики и приступим.
На первом этапе, нам придется опустится как можно ближе к опкодам и написать программу на языке Ассемблера
Теперь, имея на руках готовую программу, можно перейти к этапу трансляции.
Это просто смещение и код для него не генерируется. Будем использовать 100h для будущего расчета адресов.
Переведем в машинные коды. Открываем второй том интеловской книги на странице с инструкцией mov. И видим…
Как же выбрать из всего этого множества необходимую команду? Регистр ah является байтным регистром. Плюс нам необходимо занести в регистр число 9. Поэтому выбираем опкод для MOV reg8, imm8, это B0+rb, где rb номер регистра, который можно взять из следующей таблицы.
Номер регистра ah равен 4. Отсюда B0+4=B4. Число, которое будет занесено в регистр, пишется следом за опкодом инструкции. Таким образом, mov ah, 9h превращается в B4, 9 (запятая поставлена лишь для визуального отделения чисел).
Следующая инструкция
Теперь транслируем
Запишем полученную программу:
Вернемся к нашей заглушке потому, как нам все еще необходимо рассчитать адрес нашей строки для вывода. Теперь это сделать достаточно просто. Посчитаем все пары цифр по порядку. Их девять (число 100h не входит в один байт. Поэтому требуется два). Таким образом, адрес строки будет равен 100h+9h=109h. Заменяем 100h на 109h. Число 109h, по понятным причинам, не может быть помещено в один байт, поэтому понадобиться двухбайтовое значение 09,01 таким образом, получаем следующую программу:
Для простоты кодирования приведем числа к десятичной системе счисления (для оправдания заголовка, на калькуляторе)
Вооружаемся блокнотом и вставляем нужные ASCII символы.
Не забываем ввести в конце

Все что осталось это сохранить наш файл с расширением com и запустить.

В целях приподнятия завесы тайны странного наречия и написана эта статья.
Сразу стоит отметить, что символы, приведенные выше, по большей части, не несут смысловой нагрузки в своем начертании. Они являются визуальной формой числового представления. В свою очередь, числовое представление является операционным кодом машинного языка, и хранителем сакрального смысла этих тайных знаков.
Практика
Перейдем к более детальному изучению. Для этого нам понадобится книга написанная в недрах корпорации intel (intel 80386 Programmer's Reference Manual). Где детально рассказывается о формате инструкций процессора.
Обычно первой программой на любом языке программирования является вывод сообщения «Hello World!». Чтож… Не будем отступать от классики и приступим.
На первом этапе, нам придется опустится как можно ближе к опкодам и написать программу на языке Ассемблера
Язык ассемблера, или просто ассемблер — низкоуровневый язык программирования, использующий мнемоники, инструкции и операнды для представления машинного кода
Википедия
org 100h
mov ah,9h
mov dx,message
int 21h
int 20h
message db 'Hello World$'
Теперь, имея на руках готовую программу, можно перейти к этапу трансляции.
Трансляция
org 100h
Это просто смещение и код для него не генерируется. Будем использовать 100h для будущего расчета адресов.
mov ah,9h
— заносим в регистр ah число 9h.Переведем в машинные коды. Открываем второй том интеловской книги на странице с инструкцией mov. И видим…
Opcode | Instruction | Clocks | Description |
88 /r | MOV r/m8,r8 | 2/2 | Move byte register to r/m byte |
89 /r | MOV r/m16,r16 | 2/2 | Move word register to r/m word |
89 /r | MOV r/m32,r32 | 2/2 | Move dword register to r/m dword |
8A /r | MOV r8,r/m8 | 2/4 | Move r/m byte to byte register |
8B /r | MOV r16,r/m16 | 2/4 | Move r/m word to word register |
8B /r | MOV r32,r/m32 | 2/4 | Move r/m dword to dword register |
8C /r | MOV r/m16,Sreg | 2/2 | Move segment register to r/m word |
8D /r | MOV Sreg,r/m16 | 2/5,pm=18/19 | Move r/m word to segment register |
A0 | MOV AL,moffs8 | 4 | Move byte at (seg:offset) to AL |
A1 | MOV AX,moffs16 | 4 | Move word at (seg:offset) to AX |
A1 | MOV EAX,moffs32 | 4 | Move dword at (seg:offset) to EAX |
A2 | MOV moffs8,AL | 2 | Move AL to (seg:offset) |
A3 | MOV moffs16,AX | 2 | Move AX to (seg:offset) |
A3 | MOV moffs32,EAX | 2 | Move EAX to (seg:offset) |
B0 + rb | MOV reg8,imm8 | 2 | Move immediate byte to register |
B8 + rw | MOV reg16,imm16 | 2 | Move immediate word to register |
B8 + rd | MOV reg32,imm32 | 2 | Move immediate dword to register |
C6 | MOV r/m8,imm8 | 2/2 | Move immediate byte to r/m byte |
C7 | MOV r/m16,imm16 | 2/2 | Move immediate word to r/m word |
C7 | MOV r/m32,imm32 | 2/2 | Move immediate dword to r/m dword |
Как же выбрать из всего этого множества необходимую команду? Регистр ah является байтным регистром. Плюс нам необходимо занести в регистр число 9. Поэтому выбираем опкод для MOV reg8, imm8, это B0+rb, где rb номер регистра, который можно взять из следующей таблицы.
rb | rb | rd | |
0 | AL | AX | EAX |
1 | CL | CX | ECX |
2 | DL | DX | EDX |
3 | BL | BX | EBX |
4 | AH | SP | ESP |
5 | CH | BP | EBP |
6 | DH | SI | ESI |
7 | BH | DI | EDI |
Номер регистра ah равен 4. Отсюда B0+4=B4. Число, которое будет занесено в регистр, пишется следом за опкодом инструкции. Таким образом, mov ah, 9h превращается в B4, 9 (запятая поставлена лишь для визуального отделения чисел).
Следующая инструкция
mov dx, message
. В регистр dx заносим адрес строки message. Пока рассчитать его мы не можем, поэтому поставим временную заглушку. Пользуясь двумя приведенными выше таблицами, получаем опкод для mov dx — BA,100, где 100 является временной мерой.Теперь транслируем
int 21h
и int 20h
, из приведенной ниже таблицы можно получить нужные опкоды — это CD,21 и CD,20.Opcode | Instruction | Clocks | Description |
CD ib | INT imm8 | 37 | Interrupt numbered by immediatebyte |
CD ib | INT imm8 | pm=59 | Interrupt--Protected Mode, same privilege |
CD ib | INT imm8 | pm=99 | Interrupt--Protected Mode, moreprivilege |
CD ib | INT imm8 | pm=119 | Interrupt--from V86 mode to PL 0 |
CD ib | INT imm8 | ts | Interrupt--Protected Mode, via task |
Запишем полученную программу:
B4, 09, BA, 100, CD, 21, CD, 20
.Вернемся к нашей заглушке потому, как нам все еще необходимо рассчитать адрес нашей строки для вывода. Теперь это сделать достаточно просто. Посчитаем все пары цифр по порядку. Их девять (число 100h не входит в один байт. Поэтому требуется два). Таким образом, адрес строки будет равен 100h+9h=109h. Заменяем 100h на 109h. Число 109h, по понятным причинам, не может быть помещено в один байт, поэтому понадобиться двухбайтовое значение 09,01 таким образом, получаем следующую программу:
B4, 09, BA, 09, 01, CD, 21, CD, 20.
Кодинг
Для простоты кодирования приведем числа к десятичной системе счисления (для оправдания заголовка, на калькуляторе)
180, 9, 186, 9, 1, 205, 33, 205, 32
.Вооружаемся блокнотом и вставляем нужные ASCII символы.
Не забываем ввести в конце
Hello World!$
.
Все что осталось это сохранить наш файл с расширением com и запустить.