1

I'm working on a senior design project and have return into a small snag. Is there any situation where in assembly, can you have a situation where you push parameters, then make a jump to a different location, then call the function?

It doesn't seem like you can from the files I have available to me, but they are not all-inclusive. Any help would be appreciated, thanks!

user29451
  • 25
  • 5
  • 2
    Sure, why not? Maybe you call the function with different parameters depending on a condition for example. – Jester Oct 15 '19 at 18:20
  • 1
    You can jump anywhere you want, as long as you maintain the correct state. As an assembly programmer, this is entirely up to you. There's no code being automatically generated/inserted by a compiler like there could be in C (or certainly in C++), so jumps aren't "dangerous". – Cody Gray - on strike Oct 15 '19 at 18:36

2 Answers2

2

All that matters is what's on the stack when execution reaches the top of the function you want to call. It doesn't matter how or in what order it got there, just that ESP points at a return address, ESP+4 points at the first stack arg, and so on.

A function also doesn't know or care whether you reached it with call, or with a jmp tailcall, or even with a jae conditional tailcall.

You don't even have to use push at all, you could sub esp, 24 at the top of a function and just use mov to store your args. (Like gcc -m32 -maccumulate-outgoing-args does, which used to be good on old CPUs without a stack engine where push wasn't as efficient.) Why does gcc use movl instead of push to pass function args?

(Of course more efficient calling conventions pass args in registers, only using the stack if there are more than 2 or 3 integer/pointer args. But same difference, the calling convention specifies required state on entry to a function, not how you make that happen.)


Since you even had to ask this question, remember that the CPU is basically a state machine. Every instruction has its documented effect on the architectural state (register and memory contents, including special regs like EFLAGS and the instruction pointer). Other than that, there is no context. It doesn't matter how you reached a state, only that you're in it.


Context matters for performance for things like partial-register stalls, store-forwarding stalls, branch prediction, and in general for overlapping execution of multiple instructions. But not for correctness.

(I'm ignoring Spectre / Meltdown exploits which create known microarchitectural state and then read that into architectural state.)

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
1

An example of what you are talking about might look like this;

    cmp     al, 32

    push    48
    push    ecx
    push    esi
    jae     test

    call    func01
    jmp     done

test:
    call    func02

done:

Both functions require the same three arguments but depending whether AL >= 32 determines which function is called.

Shift_Left
  • 1,208
  • 8
  • 17
  • 1
    I'd suggest doing `cmp al,32` after the push, so it can macro-fuse with `jae`. Separating flag-set from flag-read is no longer a good idea when you're using `cmp` or `test`. If you wanted to destroy `eax` with a `mov` or `lea` after the `cmp` but before the `jcc`, that would make sense though. – Peter Cordes Oct 15 '19 at 18:48