A sequence of instructions that does the same thing as push

I would like to know if (and if so, how) it is possible to write a sequence of instructions that will have the same effect as push . For example, if the contents of ax is 1200, and I am doing a push ax , what other instructions can I use to do what push ax does?

+4
source share
4 answers

Some other answers use [sp] to address the stack, but this is not possible in 16-bit mode, as well as in 32-bit or 64-bit modes. However, in 32-bit mode you can use [esp] , and in x86-64 you can use [rsp] to address memory, but in 16-bit mode address memory is not used sp . See here for possible memory addressing modes in 16-bit mode.

So what you need to do: save the bp value somewhere, copy sp to bp , then use bp to address the stack and finally restore the original bp value.

If you have bp storage space, this is easy (this is in the YASM / NASM syntax):

 mov [bp_storage], bp sub sp,2 mov bp,sp mov [bp],ax mov bp,[bp_storage] ... bp_storage dw 0 

Using a register instead of a memory address such as bp_storage is also trivial here.

Edit: A version has been added that does not change flags (below), since push also does not change flags.

The code above changes flags, while push ax does not change any flags. This can be solved by storing the first ah in memory, and then loading the flags in ah using lahf , then storing the flags from ah into memory, then changing the stack as described above, and then restoring the flags from memory through ah using sahf and finally , recover ah from memory.

Edit: To simulate push ax without changing flags, ah must be saved to lahf and loaded to mov [bp],ax . Fixed.

 mov [ah_storage],ah lahf mov [flags_storage],ah mov [bp_storage],bp sub sp,2 mov bp,sp mov ah,[ah_storage] mov [bp],ax mov bp,[bp_storage] mov ah,[flags_storage] sahf mov ah,[ah_storage] ... bp_storage dw 0 ah_storage db 0 flags_storage db 0 

sub modifies AF , CF , OF , PF , SF , ZF , and lahf loads and sahf stores only AF , CF , PF , SF , ZF (no OF ). However, sp should never overflow with normal stack usage.

But if you cannot access memory and want to use the stack to store bp , you can do it, but if you don't have free registers, things get more complicated. But if you use a real mode OS, you can block interrupts with cli , exchange bp and sp , use bp to address the stack, exchange bp and sp again and enable interrupts again with sti .

Edit: The sp value must be subtracted by 2 to simulate push ax . Fixed. This version does not change flags (except interrupt flag).

 cli xchg bp,sp lea bp,[bp-2] mov [bp],ax xchg bp,sp sti 
+7
source

At least if memory is used, it is roughly equivalent:

 sub sp, 2 mov [sp], ax 
+2
source

Subtract the value equal to the size of the data record required from sp, and then move / push the objects you want onto the stack. Compilers do this all the time. Look at the -S output for examples. Beware of problems with atoms / threads if you do this ...

+1
source

If I have not forgotten Intel syntax:

 lea sp, [sp-2] mov [sp], ax 

I used lea to not touch FLAGS (neither push , nor mov , or lea not touch them, but sub and dec do).

EDIT: It turns out I forgot a more important thing: there is no addressing mode [sp] . The correct answer is one of @nrz, mine can be applied to esp and eax (there will be lea esp,[esp-4] ) on 80386 and higher.

+1
source

Source: https://habr.com/ru/post/979159/


All Articles