Good day! On some resource were found such lines of code:

*(char **)(if_.esp) = (if_.esp + 4); if_.esp -= 4; *(int *)(if_.esp) = argc; if_.esp -= 4; *(int *)(if_.esp) = 0; 

The comments stated that it was "returning an imaginary address from the stack." Previously, program arguments were passed to this same stack. Help to understand (preferably literally explaining each operation) what these lines mean.

    1 answer 1

    To begin understanding, you need to make one replacement - if_.esp -> p . And analyze in rows.

     *(char **)p= (p + 4); p -= 4; *(int *)p = argc; p -= 4; *(int *)p = 0; 

    Now it becomes clearer. at a certain address that is stored in p (it used to be if_.esp ), the same address is recorded, incremented by 4. After that, the pointer is decreased by 4. The next step at this new address ( p-4 ) is written argc. Likewise, 0 is written at p-8 .

    That is, roughly speaking, it's just

     push p+4 push argc push 0 

    the truth is that there is not enough one more line with p -= 4 , but either the optimizer ate it, or you.

    If you look at it from a greater height, then it is just a simulation of an assembler call call (first, the address of the next instruction is written onto the stack, then two arguments). The esp name hints at this.

    • @KoVadim, thanks. And why is this: "at some address that is stored in p is recorded the same address, increased by 4." ? And, you are right, the line p - = 4 was there) - Ice_Fox
    • What for? so that the ret command would work properly. When the procedure ends and it “corrects the stack” (that is, it takes all the parameters and / or increases if_.esp by 8 (two parameters by 4), then you can take the return address from the stack. Why? do you need to remember another procedure call? The return address still needs to be remembered. But in this case (with a stack entry) it is very easy to do recursion. - KoVadim
    • @KoVadim, thanks! - Ice_Fox