x86 Сборочный набор различий "push'es" и "pusha"
Мне сказали поместить действительные регистры в стек, чтобы не перезаписывать их позже в "подпрограмме", и мне ясно, что все это знают. Но когда я прочитал код моих товарищей, я нашел следующий код:
puts: ; display character in ax
push ax
push bx
push cx
push dx
mov dx, ax
mov ah, 9h
int 21h
pop dx
pop cx
pop bx
pop ax
ret
Потом я увидел pusha
а также popa
команды. Я полагаю, это можно сделать следующим образом:
puts: ; display character in ax
pusha
mov dx, ax
mov ah, 9h
int 21h
popa
ret
Есть ли разница между pusha
и набор push
эс? Заранее спасибо.
3 ответа
Да, pusha
а также popa
функционально эквивалентны, хотя бы потому, что они выдвигают / выталкивают все регистры. Однако нужно ли это делать для простого вызова прерывания DOS?
Перевод в режим прерывания
...
- Ответственность за восстановление всех используемых регистров лежит на процедуре прерывания.
( http://www.shsu.edu/csc_tjm/spring2001/cs272/interrupt.html)
Как и во всех операциях, делайте столько, сколько нужно, и ничего больше. Вызов прерывания должен сохранять регистры - кроме тех, которые задокументированы для изменения. Обычные статусные звонки возвращают свой результат в AX
и может изменить флаги, и ничего не менять. Если прерывание меняет что-то еще (ds:dx
Например, это должно быть указано в документации.
В вашем коде, используя ah=09 / int 21
единственное изменение
Возвращение: AL = 24 часа
и поэтому все остальные регистры можно смело считать "сохраненными".
Есть причина, по которой прерывание сохраняет как можно больше. Во всем мире прерывание ("настоящие", а не вызываемые пользователем) может произойти в любое время, когда выполняется другой код.
Есть также веская причина не использовать pusha/popa
без разбора. Ваш стек имеет ограниченный размер - конечно, он большой, но так же, как и количество подпрограмм, которые могут быть вложены. И в 32- и 64-битном коде регистры также намного больше.
Каждая подпрограмма должна сохранять только те регистры, которые, как известно, меняются, и, отражая это, вы должны сохранять только те, которые вам понадобятся позже, прежде чем вы вызовете такую подпрограмму. В примере кода их нет, так что вы можете безопасно удалить все нажатия и выталкивания.
pusha
операция толкает больше, чем ax
, bx
, cx
а также dx
регистры:
"Вставляет все регистры общего назначения в стек в следующем порядке: (E)AX, (E)CX, (E)DX, (E)BX, (E)SP, (E)BP, (E)SI, (E)DI. Значение SP - это значение до фактического нажатия SP."
Вы можете сделать в основном то же самое, нажав регистры, используя восемь push
инструкции, но это будет толкать другое значение для sp
, Вы можете просто опустить указатель стека, так как на самом деле нет необходимости нажимать его. Нажатие и извлечение семи регистров заполняет ту же цель, что и pusha
а также popa
даже если это не делает то же самое:
push ax
push bx
push cx
push dx
push bp
push si
push di
...
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
pusha
сохраняет еще несколько регистров, в частности, значение sp
перед выполнением, bp
, si
, а также di
, Помимо этого, поведение в значительной степени идентично.