Поскольку данные находятся в той же области памяти, что и программы, программа может изменять свой код во время выполнения. Например, для защиты от взлома может быть использовано шифрование: основной код программы зашифрован, и она сама себя расшифровывает при запуске.
Пример самомодифицирующейся программы:
|
ассемблер |
псевдокод |
|
jmp decode main: data ba6b data ba98 data 27a8 data 4444 decode: mov @main,r0 mov 4,r1 loop: xor bbbb,(r0)+ sub 1, r1 jnz loop jmp main |
переход на блок расшифровки начало основной части в этом и следующем словах будет "mov 123, R0"
здесь будет "system 13" здесь будет "stop" начало блока расшифровки R0:= начало зашифрованного блока R1:= 4 ; нужно расшифровать 4 слова начало цикла расшифровка: xor с маской BBBB16 уменьшить счетчик если счетчик не ноль, перейти на начало цикла перейти на основную программу |
Пользователь может добавить свои
подпрограммы в ПЗУ. Для этого нужно
сначала отладить подпрограмму, а затем
сохранить ее в специальном формате с
помощью кнопки
или пункта меню «Программа – Сохранить
как ПЗУ». Например, напишем подпрограмму,
которая переставляет биты числа в
обратном порядке, используя циклический
сдвиг через бит переноса:
|
ассемблер |
псевдокод |
|
mov 1234, R0 call reverse stop reverse: push R1 push R2 mov 10, R2 xor R1, R1 next-bit: rcl 1, R0 rcr 1, R1 sub 1, R2 jnz next-bit mov R1, R0 pop R2 pop R1 ret |
R0:= 123416 вызов подпрограммы стоп начало подпрограммы сохранить R1 в стеке сохранить R2 в стеке R2:= 16 = 1016 R1:= 0
старший бит R0 попадает в бит переноса бит переноса попадает в старший бит R1 R2:= R2 – 1 если R20, перейти к метке next-bit R0:= R1 восстановить R2 из стека восстановить R1 из стека возврат из подпрограммы |
Отладив эту программу, уберем верхние три строчки, оставив только процедуру, и применяем команду меню «Программа – Сохранить как ПЗУ». Полученный файл (он будет иметь расширение .rom) открываем в любом текстовом редакторе (например, в Блокноте) и добавляем в начало комментарий:
; Перестановка битов R0
; в обратном порядке
;-----------------------
2E10 PUSH R1
2E20 PUSH R2
01D2 MOV 10, R2
0010
0911 XOR R1, R1
9E00 RCL 1, R0
AE01 RCR 1, R1
03D2 SUB 1, R2
0001
4D0D JNZ 000A
FFF4
0110 MOV R1, R0
3E20 POP R2
3E10 POP R1
0D00 RET
Теперь остается добавить (также в текстовом редакторе) этот фрагмент в конец файла lampanel.rom. Новая процедура будет доступна при следующем запуске программы «ЛамПанель».
Регистры:
R0, R1, R2, R3 – регистры общего назначения;
PC – программный счетчик;
SP – указатель стека;
PS – регистр состояния:
бит 0 – знак (бит N, negative),
бит 1 – равенство нулю (бит Z, zero)
бит 2 – бит переноса (бит C, carry).
Обозначения при описании форматов команд:
n – число в шестнадцатеричной системе счисления
Rx – некоторый регистр общего назначения
Px – некоторый порт
Метки:
Метка – это последовательность символов, заканчивающаяся двоеточием. Кроме метки, в строке не должно быть других символов.
Основные команды:
NOP – нет операции
STOP – останов
MOV Ry,Rx – пересылка Rx:=Ry
MOV n,Rx – пересылка Rx:=n
ADD Ry,Rx – сложение Rx:=Rx+Ry
ADD n,Rx – сложение Rx:=Rx+n
SUB Ry,Rx – вычитание Rx:=Rx–Ry
SUB n,Rx – вычитание Rx:=Rx–n
CMP Ry,Rx – сравнение (установка флагов по разности Rx–Ry)
CMP n,Rx – сравнение (установка флагов по разности Rx–n)
MUL Ry,Rx – умножение Rx:=Rx*Ry
MUL n,Rx – умножение Rx:=Rx*n
DIV Ry,Rx – деление Rx:=Rx div Ry
DIV n,Rx – деление Rx:=Rx div n
Логические операции:
NOT Rx – логические «НЕ» (инверсия) Rx:=not Rx
AND Ry,Rx – логическое «И» (конъюнкция) Rx:=Rx and Ry
AND n,Rx – логическое «И» (конъюнкция) Rx:=Rx and n
OR Ry,Rx – логическое «ИЛИ» (дизъюнкция) Rx:=Rx or Ry
OR n,Rx – логическое «ИЛИ» (дизъюнкция) Rx:=Rx or n
XOR Ry,Rx – «исключающее ИЛИ» Rx:=Rx xor Ry
XOR n,Rx – «исключающее ИЛИ» Rx:=Rx xor n
Сдвиги:
SHL n,Rx – логический сдвиг влево Rx:=Rx shl n
SHR n,Rx – логический сдвиг вправо Rx:=Rx shr n
SAR n,Rx – арифметический сдвиг вправо Rx:=Rx sar n
ROL n,Rx – циклический сдвиг влево Rx:=Rx rol n
ROR n,Rx – циклический сдвиг вправо Rx:=Rx ror n
RCL n,Rx – циклический сдвиг влево через перенос Rx:=Rx rcl n
RCR n,Rx – циклический сдвиг вправо через перенос Rx:=Rx rcr n
Байтовые команды:
MOVB Ry,Rx – пересылка младшего байта Rx:=Ry
MOVB n,Rx – пересылка младшего байта Rx:=n
CMPB Ry,Rx – сравнение (установка флагов по разности байтов Rx–Ry)
CMPB n,Rx – сравнение (установка флагов по разности байтов Rx–n)
SHLB n,Rx – логический сдвиг байта влево Rx:=Rx shl n
SHRB n,Rx – логический сдвиг байта вправо Rx:=Rx shr n
SARB n,Rx – арифметический сдвиг байта вправо Rx:=Rx sar n
ROLB n,Rx – циклический сдвиг байта влево Rx:=Rx rol n
RORB n,Rx – циклический сдвиг байта вправо Rx:=Rx ror n
RCLB n,Rx – циклический сдвиг байта влево через перенос Rx:=Rx rcl n
RCRB n,Rx – циклический сдвиг байта вправо через перенос Rx:=Rx rcr n
SWAPB Rx – поменять местами байты в регистре Rx
Переходы:
JMP адрес или метка – безусловный переход
JGE адрес или метка – если больше или равно
JL адрес или метка – если меньше
JNZ адрес или метка – если не нуль
JZ адрес или метка – если нуль
JLE адрес или метка – если меньше или равно
JG адрес или метка – если больше
Процедуры:
CALL адрес или метка – вызов процедуры
SYSTEM номер – вызов процедуры из ПЗУ с заданным номером
RET – возврат из процедуры
Размещение данных:
DATA число – число записывается в память как слово
DATA "строка" – символьная строка записывается в память
Работа со стеком:
PUSH Rx – сохранить в стеке регистр Rx
POP Rx – восстановить из стека регистр Rx
Работа с портами, которые управляют лампочками:
Порты: P0, P1, P2, P3, P4, P5, P6, P7. Все порты доступны на чтение и запись.
IN Py,Rx – ввод из порта Py в регистр Rx
OUT Rx,Py – вывод из регистра Rx в порт Py
Относительная адресация:
MOV @метка,Rx – записать адрес метки в регистр Rx
(Rx) – операнд находится в ячейке, адрес которой записан в регистре Rx
(Rx)+ – то же самое, но после выполнения операции значение Rx увеличивается на 2 для команды, работающей со словом, и на 1 для байтовой команды
|
© К.Ю. Поляков, 2010 |
http://kpolyakov.narod.ru |