Как работает регистр указателя стека
Ну как работает стек? Например инструкция:
push ax
равно:
sub sp, 4
mov sp, ax
где sp - указатель стека. Это правильно?
Мой вопрос - какой смысл вычитать 4 из регистра sp, если через мгновение я изменяю его на совершенно другое значение?
4 ответа
Я думаю, что это должно прочитать
mov [sp], ax
То есть поместите значение ax в память, на которую указывает sp.
Это не так push ax
работает. Ваш пример кода того, чему он равен, должен быть:
sub sp, 4
mov [ss:sp], ax
Вы не перезаписываете значение SP с помощью AX. Вместо этого вы копируете AX в адрес памяти, на который указывает SS:SP (используя сегмент стека, а не сегмент данных)... Но на самом деле это даже не точно. Что вам действительно нужно, это что-то вроде этого:
mov [tmp], sp
pushf ;push flags
sub [tmp], 4
popf
mov sp, [tmp]
mov [ss:sp], ax
Но на самом деле, даже это не совсем точно. mov sp, [tmp]
приведет к неявному cli
должно быть выполнено (в ожидании mov ss, foobar
), что может быть нежелательным
В принципе, push
делает что-то довольно простое, но подробности вокруг этой простой вещи делают ее очень полезной.
Разница в том, что sub esp, 4
установит флаги, но push не установит флаги. Кроме того, это должно быть mov [esp],eax
, 16-разрядные версии, которые вы показываете, указывают на то, что вы используете очень старую книгу. Никто больше не программирует на 16-битной машине (кроме встроенных микроконтроллеров, возможно).
На x86 флаги OF, SF, ZF, ZF, PF и CF будут установлены вычитанием, но никакие флаги не будут затронуты PUSH
,
Вы двигаете ценность ax
в следующий доступный кадр стека. Указатель стека строится вниз (так что если у вас слишком много значений, он теряет значение ниже нуля и выдает ошибку, а не переполняется чем-то важным), поэтому следующее доступное расположение кадра стека - это одно слово (4 байта) перед текущим местоположением.