I'm new to assembly. I want to call two or more functions but not lose or push anything into stack. I used jmp but this one is ignoring next lines in code and leaves current function. So is it possible to do this? (Additional information: I have many functions and want to hook them (Create (pre/original/post) function). I don't want to make hook separately (this will take huge space, i want one universal), so i have created naked functions for all of them which will store some information in variables for incoming function and them will jump into universal function (naked too + assembly code), this will loop Pre hooks and calls them, then will call original... But issue is that 'call' is not the case and jmp function is just ignoring next code)
-
Can you include some code for context? That would help a lot. – tadman Sep 18 '18 at 19:33
-
1Can you please post some code (in the question) as a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) for *one* function that shows what you are asking? – Weather Vane Sep 18 '18 at 19:33
-
What is the relevance to the C tag? – Christian Gibbons Sep 18 '18 at 19:34
-
Calling conventions depend upon the API. So without giving your API and/or calling conventions, your question don't make much sense. – Basile Starynkevitch Sep 18 '18 at 19:34
-
I think that would confuse you, but if you still asking here's my "universal" function https://pastebin.com/X03AeeRQ – Sep 18 '18 at 19:35
-
The code you linked does not look like "I'm new to assembly" code. Is it your code? – Weather Vane Sep 18 '18 at 19:39
-
Yes, i have started learning yesterday :/ – Sep 18 '18 at 19:40
-
You do not want to push anything on the stack, but you also want to return to the call site after the function has finished. You have to realize that the return address has to be stored *somewhere* because the function in principle can be called from anywhere. The call instruction saves it on the stack. You can also save it in a register, but you have to be careful not to overwrite the register in the body of the function. If you want to save it in a register, you would have to use a combination of lea and jump. – Ajay Brahmakshatriya Sep 18 '18 at 19:51
-
But my main query is why do you not want to push anything on the stack? What is the constraint? Is the constraint really necessary? This looks like an XY problem to me. – Ajay Brahmakshatriya Sep 18 '18 at 19:52
-
Thanks for reply, but how to use both together (lea esi – Sep 18 '18 at 19:59
-
I think i can solve my problem if i'll get how to replace or pop current return address – Sep 18 '18 at 20:46
1 Answers
You've found both options. The behavior is completely determined by this question:
Do you save a return address?
If the answer is yes, you have behavior like call, and stuff gets pushed onto the stack (at least a return address).
If the answer is no, you don't return to the calling function, so the rest of it gets skipped (like jmp
).
The Law of the Excluded Middle says there are no other options.
A possible way to get around this, is to save the return address (coming back to your trampoline) right on top of the original return address (saving that somewhere else, thread-local storage perhaps). That way you maintain the stack layout needed by the function you are forwarding to. Part of your post-hook then needs to put the original return address back.

- 277,958
- 43
- 419
- 720
-
-
@BeqaGurgenidze: If for some reason you want to avoid pushing a return address onto the stack, you could (in theory if you don't care about performance) load a return address into a register, like a RISC-style link register (like `lea rcx, [rel ret_addr]`, and have the callees return with `jmp rcx` or whatever. But the functions you call have to be written specially to do that instead of using `ret`. So you can avoid `call`/`ret`, using regular indirect branches, but that defeats the return-address predictor stack. (So Ben, you were overzealous in applying the Law of Excluded Middle). – Peter Cordes Sep 18 '18 at 21:33
-
@BeqaGurgenidze: Here's an example of what I was talking about. [mov & jmp to & jmp back vs call & ret](https://stackoverflow.com/q/38542382). My answer there explains why it's a terrible idea and you should just let `call` push a return address. – Peter Cordes Sep 18 '18 at 21:48
-
@PeterCordes - what do you mean by "defeat"? Using a link register should work fine on x86, and the return stack isn't affected if you use neither `call` nor `ret`. Most likely it could be faster in some scenarios where you are OK with a custom calling convention since you are replacing a `call` and `ret` with a reg-reg `mov` (if at all - maybe you can just do that once if you call the function many times) and an indirect jump. So no memory accesses, store forwarding, speculative call limit, etc. – BeeOnRope Sep 18 '18 at 22:55
-
@BeeOnRope: I should have said "doesn't benefit from", potentially giving you branch mispredicts on `jmp r15` where you wouldn't have any with `call` / `ret`. Interesting point that a call-site in a loop could reuse the same link-reg value, if your custom calling convention didn't clobber it. It could actually be good in a loop. – Peter Cordes Sep 18 '18 at 23:15
-
2Yes, you are more likely to get branch mispredicts when stuff is cold (although even the `call/ret` pair may soft-mispredict the `call` in that case), but if you are contemplating such a crazy thing I guess you are calling this a lot so it's somehow hot, and then I guess the indirect predictor would do fine. So I wouldn't dismiss it entirely (of course as you pointed out elsewhere the first step would just be to inline it, but maybe if you have a bazillion call sites it makes sense, or for a small JITed function, etc). – BeeOnRope Sep 18 '18 at 23:17
-
@PeterCordes: Pretty sure he's calling an existing function, so the return address does have to go on the stack. But yes, there are specific cases of "yes, save the return address" that don't use the stack. – Ben Voigt Sep 19 '18 at 02:54