Есть ли способ использовать popa/pusha без SP? (для процедур с АД)

например:

      var1 dw 8
var2 dw 1
res dw ?


CODESEG
proc plus
pusha
mov bp,sp


    mov ax, [bp+6];var1
    mov bx, [bp+4];var2
    add ax, bx
    mov [res], ax
    

popa
ret 4
endp plus


start :
    mov ax, @data
    mov ds, ax
    
    push [var1]
    push [var2]
    call plus
    
    mov dl, [byte ptr res]
    add dl,30h
    mov ah,2h
    int 21h

эта процедура тоже не будет работать, и я понял, что это как-то связано с нажатием и выталкиванием SP в команде pusha/popa, а затем это портит команду-

      mov bp,sp

и мой вопрос, есть ли способ использовать pusha/popa без SP? или я должен придерживаться нажатия и выталкивания без этих команд?

1 ответ

неизбежно изменяет SP на 8x 2 (или 8x 4 в 32-битном режиме) и сохраняет в стек. Если вам это не нравится, не используйте это; в любом случае это неэффективно, хорошо только для размера кода. (Особенно, если вам не нужно сохранять все 8 регистров, включая SP). например, вы могли бы использоватьpush bx после обычной настройки БП, а такжеpush axесли вы хотите сохранить/восстановить его по какой-то причине, даже если вашему вызывающему абоненту нужно сразу же перезаписать части AX.

Было бы неэффективно экономить BP дважды, но вы могли бы push bp/mov bp, sp/ если вы действительно хотите, чтобы BP указывал на нормальное положение относительно адреса возврата и аргументов стека. Если вы хотите медленно, но упрощенно, это очевидный способ сделать это.

Или, как говорит Шутка, просто учитывайте разное смещение при расчете расстояния, например[bp+14 + 4]. Или послеpusha/mov bp,sp, вы могли быadd bp, 14.
(Если бы вы могли предположить 386 функций,lea bp, [esp+14]может заменить mov+add. Я все еще предполагаю 16-битный режим, поэтому вы будете использовать только 16-битный BP, а не EBP. Если SP правильно расширен нулями в ESP (что является хорошей идеей), вы можете полностью опустить указатель кадра,mov ax, [esp+14 + 4].)

[bp+14]- это слот стека прямо под адресом возврата, так что +4 и +6 - это первые два слова в стеке над адресом возврата, те же смещения, которые вы использовали бы относительно указателя кадра, указывающего на традиционное место.

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


Конечно, для вашей крошечной функции вам нужен только BP и один временный регистр дляmov ax, [bp + ...]/add ax, [bp + ...], и обычно вы оставляете некоторые регистры с затертыми вызовами, которые вы можете использовать без сохранения/восстановления, чтобы вы могли писать небольшие функции без неэффективности pusha/popa. Сохранение и восстановление всего в каждой функции происходит медленно.

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

Другие вопросы по тегам