0

Using Visual Studio 2019 C++ inline ASM...

The following CALL instructions all results in invalid operand.

CALL 0x45CDC8
CALL OFFSET 0x45CDC8
CALL [0x45CDC8] // ?

But this works:

DWORD dword_45CDC8 = 0x45CDC8;
...
CALL dword_45CDC8

My question is WHY does this work and is there a way to just CALL the address instead of declaring it as a variable first?

majidarif
  • 18,694
  • 16
  • 88
  • 133
  • Presumably microsoft in their infinite wisdom decided you never want to call an absolute literal address. Maybe you can trick it with stuff like `$+0x45CDC8-$`? – Jester Apr 26 '21 at 21:47
  • 1
    Does this answer your question? [How to write an absolute target for a near direct relative call/jmp in MASM](https://stackoverflow.com/questions/50058523/how-to-write-an-absolute-target-for-a-near-direct-relative-call-jmp-in-masm) – Nate Eldredge Apr 26 '21 at 21:48
  • @Jester unfortunately `'-' non-constant expression in first operand` – majidarif Apr 26 '21 at 21:53
  • @NateEldredge thanks, it does answer my question partially. still wondering what other solutions are available. – majidarif Apr 26 '21 at 21:54
  • 2
    Frankly, if Peter Cordes doesn't know any solutions, I would believe there aren't any. – Nate Eldredge Apr 26 '21 at 21:58
  • 2
    But you understand the underlying issue? The direct near call instructions on x86 are relative, so the linker would have to calculate the displacement between the address of the instruction following your `CALL` and the desired address `0x45CDC8`, and it lacks the capability to do that. By contrast, your second example is an indirect call with a memory operand, and those are absolute calls, so the previous calculation is not necessary. – Nate Eldredge Apr 26 '21 at 22:00
  • 1
    You can alternatively do something like `MOV EAX, 0x45CDC8` and `CALL EAX` which might save a couple of bytes but needs a scratch register. Or, god forbid, `PUSH 0x45CDC8` and `RET` which will thoroughly confuse the indirect branch predictor. – Nate Eldredge Apr 26 '21 at 22:02
  • @NateEldredge yes I was considering MOV since I thought declaring the variable essentially did this and it worked. but, didn't want to waste/use a register for this. I believe I will just stick with my current solution if there really is none better. thank you. – majidarif Apr 26 '21 at 22:05
  • @NateEldredge: I don't know Windows toolchains or object-file formats very well at all, but unless something's changed, the NASM error message I quoted in my answer there seems to rule out the necessary linker support that would be needed for this to work. Still, I wouldn't rule out it being possible with some amount of trickery, like maybe some kind of equivalent of a linker script to define a symbol at some absolute address when linking. But seems like a duplicate. – Peter Cordes Apr 27 '21 at 03:32
  • @NateEldredge: nitpick: `push`/`ret` will confuse the *return-address* predictor (http://blog.stuffedcow.net/2018/04/ras-microbenchmarks/), which is separate from the indirect branch predictor. (Unless this happens to run right after returning from the kernel, when the return-predictor stack is empty, and it's on a CPU that falls back to the normal indirect-branch predictor in that case.) If it did just use the normal indirect-branch predictor like `call reg` does, it would be fine. – Peter Cordes Apr 27 '21 at 03:33

0 Answers0