Команды для работы со стеком — КиберПедия 

Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого...

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

Команды для работы со стеком

2017-09-01 210
Команды для работы со стеком 0.00 из 5.00 0 оценок
Заказать работу

Предусмотрено две специальные команды для работы со стеком: push (поместить в стек) и pop (извлечь из стека). Синтаксис:

push источник

pop назначение

При описании работы стека мы уже обсуждали принцип работы команд push и pop. Важный нюанс: push и pop работают только с операндами размером 4 или 2 байта. Если вы попробуете скомпилировать что-то вроде

pushb 0x10

GCC вернёт следующее:

[user@host:~]$ gcc test.s

test.s: Assembler messages:

test.s:14: Error: suffix or operands invalid for `push '

[user@host:~]$

Согласно ABI, в Linux стек выровнен по long. Сама архитектура этого не требует, это только соглашение между программами, но не рассчитывайте, что другие библиотеки подпрограмм или операционная система захотят работать с невыровненным стеком. Что всё это значит? Если вы резервируете место в стеке, количество байт должно быть кратно размеру long, то есть 4. Например, вам нужно всего 2 байта в стеке для short, но вам всё равно придётся резервировать 4 байта, чтобы соблюдать выравнивание. А теперь примеры:

.text

pushl $0x10 /* поместить в стек число 0x10 */

pushl $0x20 /* поместить в стек число 0x20 */

popl %eax /* извлечь 0x20 из стека и записать в

%eax */

popl %ebx /* извлечь 0x10 из стека и записать в

%ebx */

 

pushl %eax /* странный способ сделать */

popl %ebx /* movl %eax, %ebx */

 

movl $0x00000010, %eax

pushl %eax /* поместить в стек содержимое %eax */

popw %ax /* извлечь 2 байта из стека и

записать в %ax */

popw %bx /* и ещё 2 байта и записать в %bx */

/* в %ax находится 0x0010, в %bx

находится 0x0000; такой код сложен

для понимания, его следует избегать

*/

 

pushl %eax /* поместить %eax в стек; %esp

уменьшится на 4 */

addl $4, %esp /* увеличить %esp на 4; таким образом,

стек будет приведён в исходное

состояние */

Интересный вопрос: какое значение помещает в стек вот эта команда

pushl %esp

Если ещё раз взглянуть на алгоритм работы команды push, кажется очевидным, что в данном случае она должна поместить уже уменьшенное значение %esp. Однако в документации Intel1 сказано, что в стек помещается такое значение %esp, каким оно было до выполнения команды - и она действительно работает именно так.

Арифметика

Арифметических команд в нашем распоряжении довольно много. Синтаксис:

inc операнд

dec операнд

 

add источник, приёмник

sub источник, приёмник

 

mul множитель_1

Принцип работы:

· inc: увеличивает операнд на 1.

· dec: уменьшает операнд на 1.

· add: приёмник = приёмник + источник (то есть, увеличивает приёмник на источник).

· sub: приёмник = приёмник - источник (то есть, уменьшает приёмник на источник).

Команда mul имеет только один операнд. Второй сомножитель задаётся неявно. Он находится в регистре %eax, и его размер выбирается в зависимости от суффикса команды (b, w или l). Место размещения результата также зависит от суффикса команды. Нужно отметить, что результат умножения двух -разрядных чисел может уместиться только в -разрядном регистре результата. В следующей таблице описано, в какие регистры попадает результат при той или иной разрядности операндов.

Команда Второй сомножитель Результат
mulb %al 16 бит: %ax
mulw %ax 32 бита: младшая часть в %ax, старшая в %dx
mull %eax 64 бита: младшая часть в %eax, старшая в %edx

Примеры:

.text

movl $72, %eax

incl %eax /* в %eax число 73 */

decl %eax /* в %eax число 72 */

 

movl $48, %eax

addl $16, %eax /* в %eax число 64 */

 

movb $5, %al

movb $5, %bl

mulb %bl /* в регистре %ax произведение

%al? %bl = 25 */

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

char x, y;

x = 250;

y = 14;

x = x + y;

printf("%d ", (int) x);

Большинство сразу скажет, что результат (250 + 14 = 264) больше, чем может поместиться в одном байте. И что же напечатает программа? 8. Давайте рассмотрим, что происходит при сложении в двоичной системе.

11111010 250

+ 00001110 + 14

---------- ---

1 00001000 264

| |

| <------ >|

8 бит

Получается, что результат занимает 9 бит, а в переменную может поместиться только 8 бит. Это называется переполнением - перенос из старшего бита результата. В Си переполнение не может быть перехвачено, но в микропроцессоре эта ситуация регистрируется, и её можно обработать. Когда происходит переполнение, устанавливается флаг cf. Команды условного перехода jc и jnc анализируют состояние этого флага. Команды условного перехода будут рассмотрены далее, здесь эта информация приводится для полноты описания команд.

movb $0, %ah /* %ah = 0 */

movb $250, %al /* %al = 250 */

addb $14, %al /* %al = %al + 14

происходит переполнение,

устанавливается флаг cf;

в %al число 8 */

jnc no_carry /* если переполнения не было, перейти

на метку */

movb $1, %ah /* %ah = 1 */

no_carry:

/* %ax = 264 = 0x0108 */

Этот код выдаёт правильную сумму в регистре %ax с учётом переполнения, если оно произошло. Попробуйте поменять числа в строках 2 и 3.

Команда lea для арифметики

Для выполнения некоторых арифметических операций можно использовать команду lea2. Она вычисляет адрес своего операнда-источника и помещает этот адрес в операнд-назначение. Ведь она не производит чтение памяти по этому адресу, верно? А значит, всё равно, что она будет вычислять: адрес или какие-то другие числа.

Вспомним, как формируется адрес операнда:

смещение(база, индекс, множитель)

Вычисленный адрес будет равен база + индекс? множитель + смещение.

Чем это нам удобно? Так мы можем получить команду с двумя операндами-источниками и одним результатом:

movl $10, %eax

movl $7, %ebx

 

leal 5(%eax),%ecx /* %ecx = %eax + 5 = 15 */

leal -3(%eax),%ecx /* %ecx = %eax - 3 = 7 */

leal (%eax,%ebx),%ecx /* %ecx = %eax + %ebx? 1 = 17 */

leal (%eax,%ebx,2),%ecx /* %ecx = %eax + %ebx? 2 = 24 */

leal 1(%eax,%ebx,2),%ecx /* %ecx = %eax + %ebx? 2 + 1 = 25 */

leal (,%eax,8),%ecx /* %ecx = %eax? 8 = 80 */

leal (%eax,%eax,2),%ecx /* %ecx = %eax + %eax? 2 = %eax? 3 = 30 */

leal (%eax,%eax,4),%ecx /* %ecx = %eax + %eax? 4 = %eax? 5 = 50 */

leal (%eax,%eax,8),%ecx /* %ecx = %eax + %eax? 8 = %eax? 9 = 90 */

Вспомните, что при сложении командой add результат записывается на место одного из слагаемых. Теперь, наверно, стало ясно главное преимущество lea в тех случаях, где её можно применить: она не перезаписывает операнды-источники. Как вы это сможете использовать, зависит только от вашей фантазии: прибавить константу к регистру и записать в другой регистр, сложить два регистра и записать в третий… Также lea можно применять для умножения регистра на 3, 5 и 9, как показано выше.

Команда loop

Синтаксис:

loop метка

Принцип работы:

· уменьшить значение регистра %ecx на 1;

· если %ecx = 0, передать управление следующей за loop команде;

· если %ecx , передать управление на метку.

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

.data

printf_format:

.string "%d\n "

 

.text

.globl main

main:

movl $0, %eax /* в %eax будет результат, поэтому в

начале его нужно обнулить */

movl $10, %ecx /* 10 шагов цикла */

 

sum:

addl %ecx, %eax /* %eax = %eax + %ecx */

loop sum

 

/* %eax = 55, %ecx = 0 */

 

/*

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

*/

pushl %eax

pushl $printf_format

call printf

addl $8, %esp

 

movl $0, %eax

ret

На Си это выглядело бы так:

#include <stdio.h >

 

int main()

{

int eax, ecx;

eax = 0;

ecx = 10;

do

{

eax += ecx;

} while(--ecx);

printf("%d\n ", eax);

return 0;

}


Поделиться с друзьями:

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

История развития пистолетов-пулеметов: Предпосылкой для возникновения пистолетов-пулеметов послужила давняя тенденция тяготения винтовок...

Архитектура электронного правительства: Единая архитектура – это методологический подход при создании системы управления государства, который строится...

Состав сооружений: решетки и песколовки: Решетки – это первое устройство в схеме очистных сооружений. Они представляют...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.037 с.