Foreversoft.ru

IT Справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Косвенная адресация в ассемблере

Ассемблер. Системные вызовы и режимы адресации

Обновл. 23 Фев 2020 |

Системные вызовы — это программные интерфейсы между пользователем и ядром. Мы уже использовали следующие системные вызовы:

sys_write — для вывода на экран;

sys_exit — для выхода из программы.

Системные вызовы Linux

В своих программах на ассемблере вы можете использовать системные вызовы Linux. Для этого нужно:

поместить номер системного вызова в регистр EAX;

сохранить аргументы системного вызова в регистрах EBX, ECX и т.д.;

вызвать соответствующее прерывание (80h);

результат обычно возвращается в регистр EAX.

Есть шесть регистров, в которых хранятся и используются аргументы необходимого системного вызова:

EBX

ECX

EDX

ESI

EDI

EBP

Эти регистры принимают последовательные аргументы. Если есть более шести аргументов, то ячейка памяти первого аргумента сохраняется в регистре EBX.

В следующем примере мы будем использовать системный вызов sys_exit :

А в следующем — sys_write :

Все системные вызовы перечислены в /usr/include/asm/unistd.h вместе с их номерами (значение, которое помещается в EAX перед вызовом int 80h ).

В следующей таблице приведены некоторые системные вызовы, которые мы будем использовать:

%eax Название %ebx %ecx %edx %esx %edi
1sys_exitint
2sys_forkstruct pt_regs
3sys_readunsigned intchar *size_t
4sys_writeunsigned intconst char *size_t
5sys_openconst char *intint
6sys_closeunsigned int

В следующей программе мы запрашиваем число, а затем выводим его на экран:

Результат выполнения программы выше:

Please enter a number:
1234
You have entered:1234

Режимы адресации

Большинство инструкций на языке ассемблера требуют обработки операндов. Адрес операнда предоставляет место, где хранятся данные, подлежащие обработке. Некоторые инструкции не требуют операнда, в то время как другие могут требовать один, два или три операнда. В тех случаях, кода инструкции требуется два операнда, то первый операнд обычно является местом назначения, содержащий данные в регистре или в ячейке памяти, а второй — исходником. Исходник содержит либо данные для доставки (немедленная адресация), либо адрес (в регистре или в памяти) данных. Как правило, исходные данные остаются неизменными после операции.

Есть три основных режима адресации:

Регистровая адресация

Прямая (или ещё «непосредственная») адресация

Адресация памяти

Регистровая адресация

В режиме регистровой адресации регистр содержит операнд. В зависимости от инструкции регистр может быть первым операндом, вторым или обоими. Например:

Стек и косвенная адресация

В этой статье мы с вами познакомимся с основными понятиями, которые связаны со стеком в Assembler, напишем небольшую программу, изучим несколько новых команд.

Общая информация

Итак, что же такое стек: если коротко, то стек — область памяти на ядре процессора, там хранятся адреса. По своей сути, это абстрактный тип данных. В понимании он довольно прост и следующая иллюстрация отображает принцип работы стека:

Принцип работы можно выразить простыми словами: первым пришел — последним вышел, и наоборот: последним пришел — первым вышел. Это полностью описывает работу стека в Assembler.

Часто этот принцип сравнивают с обоймой в пистолете, когда вы заряжаете обойму, то тот патрон который был первым, выстрелит самым последним.

Стек в Assembler

Для основ, нам необходимо знать 2 новые команды:

  • push — поместить в стек
  • pop — вытащить из стека

Также нам понадобится такая конструкция :
[esp] — это указатель на вершину стека, как раз с ней мы и будем работать.

Приступим к коду, а те, кто не знают где его писать и как скомпилировать — добро пожаловать в предыдущую статью.

Уже знакомые строки, которые необходимо прописывать.
Перейдем к разделу кода:

Сначала в регистры ax и ecx помещаем значения(h означает шестнадцатеричную систему исчисления,и по сути никак не относится к числу). Заметьте, что в регистр ax, содержащий максимум 2 байта, можно поместить только 4 цифры, а в регистр ecx, содержащий 4 байта, только 8.

Затем с помощью команды push, помещаем в стек значения регистров ax и ecx соответственно, то есть сначала мы положили 2 байта, а затем еще 4 байта. Таким образом сейчас на вершине стека лежит то число из 8 знаков.

Далее, с помощью команды pop, вынимаем значения в регистры ax и ecx соответственно. Только заметьте, так как регистр ax, как мы уже сказали, может содержать 4 цифры(или правильнее сказать 2 байта), то в него запишется только 2 байта. Это означает что, то значение из 8 цифр, которое лежит на вершине, будет разделено пополам, а последняя половинка запишется в регистр ax(по принципу последним пришел — первым вышел). То есть в регистр ax запишется 4433h. И после этого в регистр ecx запишется 4 байта, а именно, то что останется: ecx = 22116655h.
Итак, поменяли значения регистра, а теперь изучим косвенную адресацию:

Косвенная адресация

Для понимания нужна полная сосредоточенность: итак, после выполнения команд pop(которая вытаскивает значения, но не удаляет его), вершина стека сместилась относительно наших значений сначала на 2 байта, а затем еще на 4, в общем на 6 байт. Так вот, с помощью косвенной адресации [esp-2] и [esp-6] мы можем обратится как раз к тем значениям: в итоге мы в ecx поместим значение, которое было в самом начале: 66554433h, в регистр ax: 2211h(просто вернули первоначальные значения).

Читать еще:  Способы адресации в эвм

Для того, чтобы лучше понять этот материал, советую воспользоваться отладчиком, и посмотреть как будут меняться значения регистров и значение, которое хранится на вершине стека(оно находится в правом нижнем окне и подсвечено серым цветом).

На этом мы закончим с изучением темы стек в Assembler, если у вас остались вопросы, то пишите в комментариях.

Ассемблеры. Режимы адресации

Трудно установить различие между ассемблером и компилятором, но можно сказать, что ассемблеры переводят машинно-ориентированные языки, а компиляторы – проблемно-ориентированные языки в машинные коды. Ассемблер образует программу, команды которой отражают внутреннюю структуру машины.

Существует ряд основных функций, таких как трансляция мнемонических кодов операций в их эквиваленты на машинном языке или присваивание машинных адресов символическим меткам, которые должны выполняться любым ассемблером.

Однако за пределом этого базового уровня возможности, предоставляемые ассемблерами, а также схемы их построения сильно зависят от входного языка, а также языка машины.

Ассемблеры – машинно-ориентированные языки (состоят из мнемокодов-команд процессора).

Одним из аспектов машинной зависимости является имеющиеся различия в форматах машинных команд и кодах операций. С другой стороны некоторые средства языка не имеют прямой связи со структурой компьютера. Их выбор является произвольным и определяется разработчиком языка. Многие Ассемблеры представляют гибкие средства обработки исходной программы и соответствующего ей объектного кода.

Одни из этих средств позволяют располагать сгенерированные машинные команды и данные в объектной программе в порядке, отличном от порядка, в котором расположены соответствующие им исходные предложения.

Другие позволяют создавать несколько независимых частей объектной программы. Каждая из этих частей сохраняет свою индивидуальность и обрабатывается загрузчиком отдельно от других частей.

Для перевода исходной программы в ее объектное преставление необходимо:

1) Преобразовать мнемонические коды операций в их эквиваленты на машинном языке.

2) Преобразовать символические операнды в эквивалентные им машинные адреса.

3) Построить машинные команды в соответствующем формате.

4) Преобразовать константы, заданные в исходной программе во внутренние машинные представления.

5) Записать объектную программу и выдать листинг.

Все указанные действия (кроме 2 ) могут быть выполнены простой построчной обработкой исходной программы, но трансляция адресов вызывает определенные трудности т. к. неизвестны адреса, которые будут присвоены меткам поэтому большинство Ассемблеров выполняют 2 просмотра исходной программы.

Основной задачей первого просмотра является поиск символических имен и назначение им адресов.

Фрагменты программы, содержащие ссылки “вперед” запоминаются во время первого просмотра. Дополнительный просмотр таких заполненных определений выполняются по мере продвижения этого процесса ассемблирования, по завершению этого процесса выполняется обычный 2-й просмотр. Фактическая трансляция выполняется во время второго просмотра.

Ассемблер наряду с трансляцией команд исходной программы должен так же выполнять и директивы Ассемблера. Эти директивы не переводятся непосредственно в машинные коды, а управляют работой самого Ассемблера. В заключительной фазе своей работы Ассемблер должен записать полученный объектный код на некоторые устройства вывода.

Если рассматривать объектный код отдельно то в общем случае невозможно определить какие значения представляют адреса, зависящие от местонахождения программы, а какие – не изменяемые объекты. Поскольку Ассемблеру не известен фактический адрес начала загрузки он не может выполнить необходимую настройку адресов, используемых программой. Однако Ассемблер может указать загрузчику те части объектной программы, которые нуждаются в настройке при загрузке. Объектная программа содержит информацию необходимую для выполнения подобной модификации называется перемещаемой программой.

Не обязательно внутри объектной программы сгенерированные машинные коды и данные должны располагаться в том же порядке, в котором они были в исходном тексте. Многие Ассемблеры предоставляют средства, позволяющие создавать несколько независимых частей объектной программы. Часть программы, которая сохраняет после Ассемблирования свою индивидуальность и может загружаться и перемещаться независимо от других, называется управляющей секцией (УС)

Имена управляющей в одной УС не может непосредственно используются в другой секции, но поскольку управляющие секции образуют связные части программы, то необходимо предоставить средства для связывания их друг с другом. Команда одной управляющей секции должны иметь возможность ссылаться на команды или области данных, расположенные в другой секции. Такие ссылки нельзя обрабатывать обычным образом, поскольку управляющие секции загружаются и перемещаются независимо друг от друга а Ассемблеру ничего не известно о том где будут расположены другие управляющие секции во время выполнения программы такие ссылки между управляющими. Называются внешними ссылками для каждой внешней ссылки Ассемблер генерирует информацию, которая дает возможность загрузчику выполнить требуемые связывание программы. Ассемблер должен запоминать в какой управляющей секции было определено то или иное имя. Любая попытка использовать имя из другой управляющей секции должен отмечаться как ошибка, если это имя не объявлено в качестве внешнего. Ассемблер должен решать использовать одинаковые имена в разных управляющих секциях. Для занесения внешних имен Ассемблер оставляет место в объектном коде. Кроме того он должен включить в объектную программу информацию, позволяющую загрузчику занести необходимые данные куда требуется.

Для этого надо определить 2 типа записей:

— Запись-определение (содержит информацию о внешних именах, определенных в данной управляющей секции)

— Запись–ссылка (содержит список имен, используемых в качестве внешних ссылок)

Большинство Ассемблеров наряду с одиночными терминами разрешается использовать выражения. Выражения классифицируются как абсолютные или относительные, в зависимости к какому типу относятся их значения.

Читать еще:  Какой правильный адрес электронной почты

Наличие нескольких управляющих секций, каждая из которых может перемещаться независимо от других, создает дополнительные трудности при обработке выражений.

Когда в выражении используются внешние ссылки, Ассемблер, в общем случае, не может определить, корректно оно или нет.

Группировка относительных терминов для проверки корректности не может быть сделана, если неизвестно какие термины принадлежат одной из секций. А во время Ассемблирования эта информация отсутствует. В этом случае Ассемблер вычисляет известные ему термины и комбинирует их так, чтобы получить начальное значение выражения. Кроме того, он генерирует записи-модификаторы, позволяющие загрузчику закончить вычисления.

Команды центрального процессора рассматриваются как операционные ресурсы нижнего уровня доступные программисту.

Использование операционных ресурсов планируются в виде последовательности машинных команд процессора, которые в языке ассемблера отличаются названием операций и форматами операндов, что синтаксически определяется режимами адресации.

Главной особенностью языка ассемблера является использование одного названия операций для всех семантически идентичных действий независимо от форматов и размеров данных.

Форматы данных определяются типом именованных областей памяти или явными указателями.

Режимы адресаций можно разделить на 7 групп:

1) регистровая адресация (mov AX,BX) при которой микропроцессор извлекает операнд из регистра и помещает результат в регистр.

2) непосредственная адресация, которая позволяет указывать значение константы в качестве операнда источника mov cx,25h

3) Прямая, при которой исполнительный адрес является составной частью команды. Микропроцессор добавляет этот адрес к содержимому регистра DS и получает 20-битовый физический адрес операнда (mov AX, DAN) DAN – символическое имя, определяемое в сегменте данных.

4) косвенно регистровая, при которой исполнительный адрес содержится в базовом регистре BX, указателе базы BP или индексном регистре SI или DI (mov DI, offset DAN mov AL, [BX]). Косвенные регистровые операнды заключаются в квадратные скобки.

5) адресация по базе (mov AL, [BX]+4) Ассемблер вычисляет исполнительный адрес с помощью сложения содержимого регистров BX или BP, в которые загружается базовый адрес со значением сдвига.

6) прямая адресация с индексированием

mov AL, TABL[DI]) загрузили 6й элемент массива

Исполнительный адрес вычисляется как сумма значений сдвига и содержимого индексного регистра SI или DI.

7) адресация по базе с индексированием — адрес высчитывается как сумма значений базового регистра, индексного регистра и сдвига (mov AX,AL[BX][DX]

|следующая лекция ==>
IFS-менеджер и FSD-драйверы|Структура машинной команды. Префикс замены сегмента в памяти

Дата добавления: 2014-01-07 ; Просмотров: 3184 ; Нарушение авторских прав?

Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

Режимы адресации и форматы машинных команд

Микропроцессор Intel предоставляет множество способов доступа к операндам. Операнды могут содержаться в регистрах, самих командах, в памяти или в портах ввода-вывод. Режимы адресации разделяются на семь групп:

1. Регистровая адресация.

2. Непосредственная адресация.

3. Прямая адресация.

4. Косвенная регистровая адресация.

5. Адресация по базе.

6. Прямая адресация с индексированием.

7. Адресация по базе с индексированием.

Микропроцессор выбирает режим адресации по значению поля режима команды. Ассемблер присваивает то или иное значение полю режима в зависимости от того, какой вид имеют операнды в исходной программе. Например, если есть команда

То ассемблер закодирует оба операнда (AX, BX) для регистровой адресации. Если же поместить регистр BX в квадратные скобки:

То Ассемблер закодирует операнд-источник для косвенной регистровой адресации.

В табл. 1 приведены форматы операндов языка ассемблер и указан какой из регистров сегмента используется для вычисления физического адреса.

Режим адресацииФормат операндаРегистр сегмента
РегистровыйРегистрНе используется
НепосредственныйДанноеНе используется
ПрямойМетка СдвигDS DS
Косвенный регистровый[BX] [BP] [DI] [SI]DS SS DS DS
По базе[BX]+сдвиг [BP]+сдвигDS CS
Прямой с индексированием[DI]+сдвиг [SI]+сдвигDS DS
По базе с индексированием[BX][SI]+сдвиг [BX][DI]+сдвиг [BP][SI]+сдвиг [BP][DI]+сдвигDS DS SS SS

В зависимости от формата операнда и режима адресации формируется объектный код или машинная команда. Форматы машинных команд достаточно разнообразны. Приведем лишь основные форматы команд с двумя операндами.

1) Формат «регистр-регистр» (2байта):

КОП d w 11 reg1 reg2

7 . 2 1 0 7 6 5 4 3 2 1 0

Команды этого формата описывают обычно действие reg1:=reg1‑reg2 или reg2:=reg2‑reg1. Поле КОП первого байта указывает на операцию (‑), которую надо выполнить. Бит w определяет размер операндов, а бит d указывает, в какой из регистров записывается результат:

w = 1 — слова d = 1 — reg1:=reg1‑reg2

= 0 — байты = 0 — reg2:=reg2‑reg1

Во втором байте два левых бита фиксированы (для данного формата), а трехбитовые поля reg1 и reg2 указывают на регистры, участвующие в операции, согласно следующей таблице:

regW=1W=0RegW=1W=0
AXALSPAH
CXCLBPCH
DXDLSIDH
BXBLDIBH

2) Формат «регистр-память» (2-4 байта):

КОП |d|w| |mod|reg|mem| |адрес (0-2 байта)

Эти команды описывают операции reg:=reg‑mem или mem:=mem‑reg. Бит w первого байта определяет размер операндов (см. выше), а бит d указывает, куда записывается результат: в регистр (d=1) или в ячейку памяти (d=0). Трехбитовое поле reg второго байта указывает операнд-регистр (см. выше), двухбитовое поле mod определяет, сколько байтов в команде занимает операнд-адрес (00 — 0 байтов, 01 — 1 байт, 10 — 2 байта), а трехбитовое поле mem указывает способ модификации этого адреса. В следующей таблице указаны правила вычисления исполнительного адреса в зависимости от значений полей mod и mem (a8 — адрес размером в байт, a16 — адрес размером в слово):

Читать еще:  Что называют адресным пространством

mem mod 00 01 10

000 [BX]+[SI] [BX]+[SI]+a8 [BX]+[SI]+a16

001 [BX]+[DI] [BX]+[DI]+a8 [BX]+[DI]+a16

010 [BP]+[SI] [BP]+[SI]+a8 [BP]+[SI]+a16

011 [BP]+[DI] [BP]+[DI]+a8 [BP]+[DI]+a16

100 [SI] [SI]+a8 [SI]+a16

101 [DI] [DI]+a8 [DI]+a16

110 a16 [BP]+a8 [BP]+a16

111 [BX] [BX]+a8 [BX]+a16

Замечания. Если в команде не задан адрес, то он считается нулевым.

Если адрес задан в виде байта (a8), то он автоматически расширяется со знаком до слова (a16). Случай mod=00 и mem=110 указывает на отсутствие регистров-модификаторов, при этом адрес должет иметь размер слова (адресное выражение [BP] ассемблер транслирует в mod=01 и mem=110 при a8=0). Случай mod=11 соответствует формату «регистр-регистр».

3) Формат «регистр-непосредственный операнд» (3-4 байта):

КОП |s|w| |11|КОП»|reg| |непосред.операнд (1-2 б)

Команды этого формата описывают операции reg:=reg‑immed (immed — непосредственный операнд). Бит w указывает на размер операндов, а поле reg — на регистр-операнд (см. выше). Поле КОП в первом байте определяет лишь класс операции (например, класс сложения), уточняет же операцию поле КОП» из второго байта. Непосредственный операнд может занимать 1 или 2 байта — в зависимости от значения бита w, при этом операнд-слово записывается в команде в «перевернутом» виде. Ради экономии памяти в ПК предусмотрен случай, когда в операции над словами непосредственный операнд может быть задан байтом (на этот случай указывает 1 в бите s при w=1), и тогда перед выполнением операции байт автоматически расширяется (со знаком) до слова.

4) Формат «память-непосредственный операнд» (3-6 байтов):

КОП |s|w| |mod|КОП»|mem| |адрес (0-2б)| |непоср.оп (1-2б)|

Команды этого формата описывают операции типа mem:=mem‑immed. Смысл всех полей — тот же, что и в предыдущих форматах.

Помимо рассмотренных в ПК используются и другие форматы команды с двумя операндами; так, предусмотрен специальный формат для команд, один из операндов которых фиксирован (обычно это регистр AX). Имеют свои форматы и команды с другим числом операндов.

Из сказанного ясно, что одна и та же операция в зависимости от типов операндов записывается в виде различных машинных команд: например, в ПК имеется 28 команд пересылки байтов и слов. В то же время в ассемблере все эти «родственные» команды записываются единообразно: например, все команды пересылки имеют одну и ту же символьную форму записи:

MOV op1,op2 (op1:=op2)

Анализируя типы операндов, ассемблер сам выбирает подходящую машинную команду.

Регистры указываются своими именами, например:

MOV AX,SI ;оба операнда — регистры

Непосредственные операнды задаются константными выражениями (их значениями являются константы-числа), например:

MOV BH,5 ;5 — непосредственный операнд

MOV DI,SIZE_X ;SIZE_X (число байтов, занимаемых переменной X) — непосредственный операнд

Адреса описываются адресными выражениями (например, именами переменных), которые могут быть модифицированы по одному или двум регистрам; например, в следующих командах первые операнды задают адреса:

При записи команд в символьной форме необходимо внимательно следить за правильным указанием типа (размера) операндов, чтобы не было ошибок. Тип обычно определяется по внешнему виду одного из них, например:

MOV AH,5 ;пересылка байта, т.к. AH — байтовый регистр

MOV AX,5 ;пересылка слова, т.к. AX — 16-битовый регистр;(операнд 5 может быть байтом и словом, по нему ;нельзя определить размер пересылаемой величины)

MOV [BX],300 ;пересылка слова, т.к. число 300 не может быть байтом.

Если по внешнему виду можно однозначно определить тип обоих операндов, тогда эти типы должны совпадать, иначе ассемблер зафиксирует ошибку. Примеры:

MOV DS,AX ;оба операнда имеют размер слова

MOV CX,BH ;ошибка: регистры CX и BH имеют разные размеры

MOV DL,300 ;ошибка: DL — байтовый регистр, а число 300 не

;может быть байтом

Возможны ситуации, когда по внешнему виду операндов нельзя определить тип ни одного из них, как, например, в команде

Здесь число 5 может быть и байтом, и словом, а адрес из регистра BX может указывать и на байт памяти, и на слово. В подобных ситуациях ассемблер фиксирует ошибку. Чтобы избежать ее, надо уточнить тип одного из операндов с помощью оператора с названием PTR:

MOV BYTE PTR [BX],5 ;пересылка байта

MOV WORD PTR [BX],5 ;пересылка слова

(Операторы — это разновидность выражений языка ассемблер, аналогичные функциям.)

Оператор PTR необходим и в том случае, когда надо изменить тип, предписанный имени при его описании. Если, например, X описано как имя переменной размером в слово:

и если надо записать в байтовый регистр AH значение только первого байта этого слова, тогда воспользоваться командой

нельзя, т.к. ее операнды имеют разный размер. Эту команду следует записать несколько иначе:

MOV AH,BYTE PTR X

Здесь конструкция BYTE PTR X означает адрес X, но уже рассматриваемый не как адрес слова, а как адрес байта. (Напомним, что с одного и того же адреса может начинаться байт, слово и двойное слово; оператор PTR уточняет, ячейку какого размера мы имеем в виду.)

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Студент — человек, постоянно откладывающий неизбежность. 11311 — | 7592 — или читать все.

Ссылка на основную публикацию
Adblock
detector