Stack 100h что это

Структура программы на языке ассемблера


Глава из книги “Ассемблер для процессоров Intel Pentium”


Автор: Ю. Магда
Источник: Ассемблер для процессоров Intel Pentium
Материал предоставил: Издательство «Питер»

Опубликовано: 08.04.2006
Версия текста: 1.0

Stack 100h что это. magdaasm. Stack 100h что это фото. Stack 100h что это-magdaasm. картинка Stack 100h что это. картинка magdaasm

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

4.1. Организация сегментов

Для хорошего понимания, как работает программа на ассемблере, нужно очень четко представлять себе организацию сегментов. Применительно к процессорам Intel Pentium термин “сегмент” имеет два значения:

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

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

Логические сегменты могут содержать три основных компонента программы: программный код, данные и стек. Макроассемблер MASM обеспечивает правильное отображение этих компонентов на физические сегменты памяти, при этом сегментные регистры CS, DS и SS содержат адреса физических сегментов памяти.

4.2. Директивы управления сегментами и моделями памяти макроассемблера MASM

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

Модель памятиАдресация кодаАдресация данныхОперационная системаЧередование кода и данных
TINYNEARNEARMS-DOSДопустимо
SMALLNEARNEARMS-DOS, WindowsНет
MEDIUMFARNEARMS-DOS, WindowsНет
COMPACTNEARFARMS-DOS, WindowsНет
LARGEFARFARMS-DOS, WindowsНет
HUGEFARFARMS-DOS, WindowsНет
FLATNEARNEARWindows NT, Windows 2000, Windows XP, Windows 2003Допустимо
Таблица 4.1. Параметры моделей памяти

Все семь моделей памяти поддерживаются всеми компиляторами MASM, начиная с версии 6.1.

Модель small поддерживает один сегмент кода и один сегмент данных. Данные и код при использовании этой модели адресуются как near (ближние). Модель large поддерживает несколько сегментов кода и несколько сегментов данных. По умолчанию все ссылки на код и данные считаются дальними (far).

Модель medium поддерживает несколько сегментов программного кода и один сегмент данных, при этом все ссылки в сегментах программного кода по умолчанию считаются дальними (far), а ссылки в сегменте данных — ближними (near). Модель compact поддерживает несколько сегментов данных, в которых используется дальняя адресация данных (far), и один сегмент кода с ближней адресацией (near). Модель huge практически эквивалентна модели памяти large.

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

Модель tiny работает только в 16-разрядных приложениях MS-DOS. В этой модели все данные и код располагаются в одном физическом сегменте. Размер программного файла в этом случае не превышает 64 Кбайт. С другой стороны, модель flat предполагает несегментированную конфигурацию программы и используется только в 32-разрядных операционных системах. Эта модель подобна модели tiny в том смысле, что данные и код размещены в одном сегменте, только 32-разрядном. Хочу напомнить, что многие примеры из этой книги разработаны именно для модели flat.

Параметр соглашение_о_вызовах используется для определения способа передачи параметров при вызове процедуры из других языков, в том числе и языков высокого уровня (C++, Pascal). Параметр может принимать следующие значения: C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL. При разработке модулей на ассемблере, которые будут применяться в программах, написанных на языках высокого уровня, обращайте внимание на то, какие соглашения о вызовах поддерживает тот или иной язык. Более подробно соглашения о вызовах мы будем рассматривать при анализе интерфейса программ на ассемблере с программами на языках высокого уровня.

Параметр тип_ОС равен OS_DOS, и на данный момент это единственное поддерживаемое значение этого параметра.

Здесь параметр flat указывает компилятору на то, что будет использоваться 32-разрядная линейная адресация. Второй параметр c указывает, что при вызове ассемблерной процедуры из другой программы (возможно, написанной на другом языке) будет задействован способ передачи параметров, принятый в языке C. Следующий пример:

Здесь используются модель памяти large, соглашение о передаче параметров языка C и отдельный сегмент стека (регистр SS не равен DS).

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

4.3. Структура программ на ассемблере MASM

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

Здесь оператор end main указывает на точку входа main в главную процедуру. Оператор end закрывает последний сегмент и обозначает конец исходного текста программы. В 16-разрядных приложениях MS-DOS можно инициализировать сегментные регистры так, чтобы они указывали на требуемый логический сегмент данных. Листинг 4.1 демонстрирует это.

Затем строка s1, адресуемая через регистры DS:DX, выводится на экран с использованием прерывания 9h функции 21h MS-DOS. Попробуйте закомментировать проанализированные две строки кода и посмотреть на результат работы программы.

Для 32-разрядных приложений шаблон исходного текста выглядит иначе:

Основное отличие от предыдущего примера — другая модель памяти (flat), предполагающая 32-разрядную линейную адресацию с атрибутом near.

Замечу, что директива SEGMENT может применяться с любой моделью памяти, не только flat. При использовании директивы SEGMENT потребуется указать компилятору на то, что все сегментные регистры устанавливаются в соответствии с моделью памяти flat. Это можно сделать при помощи директивы ASSUME:

Регистры FS и GS программами не используются, поэтому для них указывается атрибут ERROR.

Сейчас мы рассмотрим программный код 32-разрядной процедуры на ассемблере (она называется _seg_ex), в которой используются два логических сегмента данных. Процедура выполняет копирование строки src, находящейся в сегменте данных data1, в область памяти dst в сегменте данных data2 и содержит один логический сегмент программного кода (code segment).

Успокою читателей, незнакомых с принципами работы процедур (они рассмотрены далее в книге): в данном случае нас будет интересовать код внутри процедуры _seg_ex (команды, находящиеся между директивами _seg_ex proc и _seg_ex endp). Исходный текст программного кода процедуры _seg_ex представлен в листинге 4.2.

При использовании модели flat доступ к данным осуществляется по 32-разрядному смещению, поэтому смысл показанных ниже команд, загружающих адреса логических сегментов (а заодно и адреса строк src и dst) в регистры ESI и EDI, думаю, понятен:

Группа следующих команд выполняет копирование строки src в dst, при этом регистр CX содержит количество копируемых байтов:

Здесь процедура seg_ex является внешней, поэтому объявлена как extern.

Результатом выполнения программы будет строка на экране дисплея

Источник

Стек (stack) в Ассемблере

Итак, что же такое стек и для чего он нужен?

Стек — это специально отведенная область памяти для хранения промежуточных данных.

Давайте немного договоримся об определениях.

Пусть будет так, что сегмент «растет» сверху вниз:

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

Теперь вам необходимо вооружиться отладчиком. Давайте рассмотрим вышесказанное на примере:

Напечатайте такую программу в редакторе (обязательно!):

Ничего сложного. Запускаем отладчик.

Итак, смотрим на пару регистров SS:SP. SS=CS=DS=ES (это понятно). SP=0FFFEh (т.е. указывает на вершину стека).

Теперь заходим в процедуру. Для CV нажимаем F8, для AFD F1.

Опа! SP изменился. Он уменьшился на 2. Компьютер поместил в стек адрес возврата из процедуры (на инструкцию int 20h) Проще говоря, call перешел на метку Our_proc, поместив в стек адрес возврата из этой подпрограммы.

Нажимаем еще раз F8/F1. Что получилось? SP опять изменился! Но теперь он увеличился на 2 (стал равным 0FFFEh). Т.е. команда ret взяла из стека адрес возврата и перешла по нему. Как раз на int 20h.

В данном случае говорят, что мы выравнили стек. Он был изначально равен 0FFFEh и остался равен перед выходом 0FFFEh.

Вот один из способов использования стека. Но на этом мы не остановимся и рассмотрим несколько операторов ассемблера, которые позволяют работать со стеком.

Поместить в стек число

Достать из стека число

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

Вот как это запишется:

Здесь мы загружаем в AX число 345h, сохраняем его, ждем нажатия клавиши (при этом сама клавиша будет в AX, т.е. AX изменится) и восстанавливаем AX. В итоге AX будет содержать число 345h, что, как говорится, и требовалось доказать.

Однако, стоит заметить такой момент. Допустим, мы помещаем в стек следующие регистры: AX, BX, CX:

Обратите внимание, что восстанавливать со стека нужно в обратном порядке:

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

Но в процедурах ассемблера необходимо очень тщательно следить за стеком. Вот пример :

Следить за стеком (как уже говорилось) позволяет пара регистров SS (сегмент):SP (смещение).

Вот пример, в котором мы изменим регистры SS:SP, не запрещая прерывания:

Отсюда два правила:

1) Прежде чем менять регистры SS:SP, необходимо запретить все прерывания командой cli, а затем разрешить командой sti.

2) SS:SP нужно устанавливать на свободную область памяти. При этом следует убедиться, что код не утратил работоспособности.

Источник

Stack 100h что это

Stack 100h что это. cif plata. Stack 100h что это фото. Stack 100h что это-cif plata. картинка Stack 100h что это. картинка cif plata

9.1 АССЕМБЛЕР. ЭТАПЫ РАЗРАБОТКИ ПРОГРАММЫ.

Язык программирования наиболее полно учитывающий особенности «родного» микропроцессора и содержащий мнемонические обозначения машинных команд называется Ассемблером. Программа, написанная на Ассемблере называется исходной программой. Далее остановимся на версии, называемой Турбо Ассемблер.

Stack 100h что это. assm. Stack 100h что это фото. Stack 100h что это-assm. картинка Stack 100h что это. картинка assm

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

9.2 ФОРМАТ КОМАНД И ИХ КЛАССИФИКАЦИЯ

Инструкция записывается на отдельной строке и включает до четырех полей, необязательные из которых выделены [ ]:

Операндами могут быть явно или неявно задаваемые двоичные наборы, над которыми производятся операции.Операнды приводятся в одной из четырех систем счисления и должны оканчиваться символом b(B), o(O), d(D), h(H) для 2, 8, 10 или 16-ной СС. К шестнадцатиричному числу добавляется слева ноль, если оно начинается с буквы.

Для МП 1810ВМ86 (8086) команда занимает от одного до шести байтов. Первым байтом команды всегда является код операции, например код команды INT XXh равен CD(HEX).

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

В первом случае операнд(ы) располагаются в регистрах микропроцессора (МП), например по команде MOV AX,CX пересылается содержимое CX в AX.

При непосредственной адресации операнд располагается в памяти непосредственно за КОП, инструкция MOV AL,0f5h записывает число 245(f5) в регистр AL.

В случае прямой адресации за КОП следует не сам операнд, а адрес ячейки памяти или внешнего устройства, например команда IN AL,40h вводит байт данных из внешнего устройства с адресом 40h.

Косвенная адресация отличается от регистровой тем, что в регистре хранится адрес операнда, т.е. по команде MOV AL,[BX] в аккумулятор al будет записано число из ячейки памяти с адресом, хранящимся в регистре BX.

Стековая адресация производится к операндам расположенным в области памяти, называемой стек.

9.3 НЕКОТОРЫЕ ОПЕРАТОРЫ, ПРЕДОПРЕДЕЛЁННЫЕ ИМЕНА, ДИРЕКТИВЫ И КОМАНДЫ АССЕМБЛЕРА 80X86(8088)

9.3.1 ПРЕДОПРЕДЕЛЕННЫЕ ИМЕНА

в сегментном регистре DS теперь адрес сегмента данных.

9.3.2 ОПЕРАТОРЫ

mov si, 01010101b SHR 3; в регистр SI будет загружено число 0Ah (00001010).

mov dl, (10d OR 5d) XOR 7d; (dl) будет равно 8.

mov dl,[es:bx]; поместить в dl байт данных из сегмента es и отстоящий от его начала на (bx) байтов (смещение).

mov bx, OFFSET table

9.3.3 ДИРЕКТИВЫ (ПСЕВДООПЕРАТОРЫ)

videoram = 0B800h; присвоение videoram = 0B000h;

Вызов этого макроса производится командой: Swap m,n

.MODEL tiny;под программу,данные и стек отводится один общий сегмент (64 Kb).

.STACK 200h; выделяет 512 байтов для стека.

9.3.4 КОМАНДЫ ПЕРЕСЫЛКИ

mov al,[table + bx] Регистр BXРегистр ALАдресКод0010XX0800 (table)08xxxx081058

mov al,[table + bx] Регистр BXРегистр ALАдресКод0010580800 (table)08xxxx081058

2. PUSH RP; поместить на вершину стека содержимое пары регистров RP (например push bx).

3. POP RP; снять с вершины стека два байта и поместить в пару RP (например pop ax).

4. XCHG DST, SRC; поменять местами содержимое (DST) и (SRC). Оба операнда не могут быть одновременно содержимым ячеек памяти.

5. XLAT SRC; извлечь из таблицы с начальным адресом SRC байт данных имеющий номер от начала таблицы = (AL), и поместить его в AL. Адрес SRC должен находиться в регистре BX. Другой вариант: XLATB.

6. IN ACCUM, PORT; поместить в аккумулятор AL или AX байт или слово из порта с адресом PORT. Если адрес порта FF, то адрес порта указывается косвенно, через содержимое регистра DX (специальная функция регистра общего назначения).

7. OUT PORT, ACCUM; переслать из аккумулятора AL или AX байт или слово в ВУ с символическим адресом PORT.

8. LEA RP,M; загрузить в регистр RP эффективный адрес (смещение) ячейки памяти с символическим адресом M.

9.3.5 АРИФМЕТИЧЕСКИЕ КОМАНДЫ

1. ADD DST, SRC; сложить содержимое SRC и DST и результат переслать в DST.

add al, [mem_byte]; mem_byte однобайтовая ячейка памяти

add [mem_word], dx; mem_word двухбайтовая ячейка памяти

2. INC DST; увеличить (DST) на 1 (инкремент (DST)).

3. SUB DST, SRC; вычесть (SRC) из (DST) и результат поместить в DST.

4. DEC DST; декремент (DST).

5. CMP DST, SRC; сравнить содержимое DST и SRC. Эта команда выполняет вычитание (SRC) из (DST) но разность не помещает в DST и по результату операции воздействует на флаги.

BX0101 1111 0000 1111 = 5F0FDX0111 0111 0111 0111 = 7777BX (результат)0111 1111 0111 1111 = 7F7F

4. NOT DST; инверсия всех битов приемника.

5. TEST DST, SRC; выполняет операцию AND над операндами, но воздействует только на флаги и не изменяет самих операндов.

6. SHR DST, CNT; логический сдвиг вправо, освобождающиеся слева биты заполняются нулем, крайний правый бит выталкивается во флаг CF. Операнд DST может быть ячейкой памяти.

до сдвига10110010(CF)=X
после сдвига0—>01011001——>(CF)=0

7. SHL DST, CNT; логический сдвиг влево.

8. RLC DST, CNT; циклический сдвиг влево через перенос

9. RRC DST, CNT;циклический сдвиг вправо через перенос

10. ROR DST, CNT;циклический сдвиг влево

11. ROL DST, CNT;циклический сдвиг вправо

9.3.7 КОМАНДЫ ПЕРЕДАЧИ УПРАВЛЕНИЯ

1. CALL SUBR; вызов подпрограммы с адресом SUBR;

3. JMP NAME; безусловный переход к команде с символическим адресом NAME.

4. JA NAME или JNBE NAME; условный переход, если, например, в результате сравнения CMP DST, SRC приемник по абсолютной величине больше источника, то перейти к метке name.

5. JB NAME или JNAE NAME; условный переход, если, например, в результате сравнения CMP DST, SRC приемник по абсолютной величине меньше источника, то перейти к метке name (команды п4 и п5 выполняются по результатам выполнения операций над беззнаковыми числами).

7. JNZ NAME или JNE NAME; переход по «не нулю». (команды п6 и п7 выполняются по результатам выполнения операций над числами cо знаком ).

9.3.8 КОМАНДЫ УПРАВЛЕНИЯ ЦИКЛАМИ

1. LOOP NAME; эта команда неявно уменьшает (CX) на 1 и осуществляет переход к ближней метке, если (CX) не равно 0.

2. LOOPZ NAME или LOOPE NAME кроме того осуществляет проверку ZF флага. Поэтому цикл заканчивается по условию, когда (CX) = 0 или (ZF) = 0 или и то и другое вместе. Т.о. эта команда служит для обнаружения первого ненулевого результата.

9.3.9 КОМАНДЫ ОБРАБОТКИ СТРОК (ЦЕПОЧЕК БАЙТОВ)

1. LODSB; команда lodsb загружает байт адресованный регистром SI из сегмента данных, и увеличивает SI на 1, если перед этим была введена команда CLD (очистить флаг направления DF) и уменьшает SI на 1, если была использована команда STD (установить флаг направления).

2. MOVSB; эта команда перемещает один байт из ячейки памяти с адресом в регистре SI в ячейку памяти с адресом в регистре DI и увеличивает (SI) и (DI) на 1. Значение SI может находиться, как в сегменте данных DS, так и в дополнительном сегменте ES. Значение DI может находиться только в дополнительном сегменте ES.

3. REP ;префикс повторения команды. Например окончание предыдущей программы может быть записано в виде:

5. REPZ или REPE; префикс повторения. Выполнение команды завершается, когда (CX) = 0 или (ZF) = 0.

В конце этого примера номер первого несовпадающего байта (CX) = 5.

9.3.10 КОМАНДЫ УПРАВЛЕНИЯ МИКРОПРОЦЕССОРОМ

1. CLC; сбросить флаг переноса (CF) = 0.

2. STC; установить флаг переноса (CF) = 1.

3. CMC; инвертировать флаг пнреноса.

4. CLD; очистить флаг направления (DF) = 0, в этом случае операции над строками (цепочками байтов) будут производиться от младшего адреса к старшему.

5. STD; установить флаг направления (DF) = 1,обработка цепочек байтов производится от старшего адреса к младшему.

6. STI; установить флаг прерываний (IF) = 1, разрешить прерывания от внешних устройств.

7.CLI; очистить флаг прерываний.

8. NOP; холостая операция.

9.3.11 КОМАНДЫ ПРЕРЫВАНИЙ

1. INT INUM; эта команда вызывает программное прерывание, то есть переход к ячейке памяти с адресом хранящимся в четырех байтах, начиная с адреса INUM * 4, где INUM = (0. 255). Это 4-х байтовое число является указателем подпрограммы обработчика данного прерывания, и иначе называется вектором прерывания.Таким образом первый килобайт памяти 256 * 4 отводится под векторы прерываний.

Операции инициируемые программными прываниями определяются кодом в регистре AH, например:

9.3.12 ВЛИЯНИЕ КОМАНД НА ФЛАГИ

В таблицу включены только те инструкции, которые влияют на флаги.

Stack 100h что это. flags. Stack 100h что это фото. Stack 100h что это-flags. картинка Stack 100h что это. картинка flags

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *