3

I don't understand why CALL function in this code doesn't work:

#include<stdio.h>

void main() {

    __asm {

        jmp L1

        L2:
        mov eax, 8
        ret

        L1:
        call L2
    }
}

If i debug the code step by step, the line 'call L1' is not processed, and program directly skips to the end. What is wrong? I'm working on VisualStudio2015 with Intel 32-bit registers.

Johan
  • 74,508
  • 24
  • 191
  • 319
glc78
  • 439
  • 1
  • 8
  • 20
  • 2
    Debuggers frequently don't fully understand inline assembly. Is it possible that the code is being executed properly but the debugger is failing to trace it correctly? You can find out by setting EAX to something other than 8 before the `jmp L1` and then inspecting its value after the `call L2`. Do this in your code, not from the debugger. – zwol Sep 06 '16 at 14:12
  • 1
    Also, if you're going to write code like this, consider using a stand-alone `.asm` file rather than "inline assembly" inserted into a C function. That is much less likely to run foul of the compiler. (Specifically, compilers often get very, very confused if you use `call`, or otherwise move the stack pointer, inside an assembly insert.) – zwol Sep 06 '16 at 14:14
  • 2
    Also look at disassembly of the final binary created by the compiler. Do the branches go where you expect, or did the compiler compile it wrong? – Peter Cordes Sep 06 '16 at 14:14
  • What is the point of `call` here, instead of `jmp`? Call is intended for calling other functions, not jump to labels within the same function. This is just not going to work in inline assembly. – Cody Gray - on strike Sep 06 '16 at 14:15
  • @Cody. Presumably the OP is just trying to see how asm works, and maybe reduced something else to this [mcve]. Still, yes, this is not a good idea, and inline-asm [isn't even a very good way to learn assembly language](http://stackoverflow.com/questions/34520013/using-base-pointer-register-in-c-inline-asm/34522750#34522750). (especially not use of call/ret). The [x86 tag wiki](http://stackoverflow.com/tags/x86/info) even recommends against using inline asm to learn assembly (since I wrote that, too :P) – Peter Cordes Sep 06 '16 at 14:17
  • 3
    Is it possible you just used the debugger wrong and used F10 to stepover rather than F11 to step into the call? I imagine the call to L2 happened but you didn't step into the L2 function to execute it instruction by instruction. – Michael Petch Sep 06 '16 at 14:17
  • @CodyGray I guess it's a way of writing whole asm program inside one C function, with local asm procedures involved, while avoiding defining them as global functions. I think the code should work as is, and should be usable for tiny test projects. – Ped7g Sep 06 '16 at 14:17
  • I cannot see how that is instructive. If you want to learn assembly language, use MASM. [This can be done from within Visual Studio](http://stackoverflow.com/questions/20078021/how-to-enable-assembly-language-support-in-visual-studio-2013). Anyway, I just fired up VS myself and tested this. Works perfectly fine with F11 to single-step. So voting to close as non-reproducible. – Cody Gray - on strike Sep 06 '16 at 14:21
  • 1
    @CodyGray : It is reproducible if you assume they used step over instead of step into. From the OPs perspective it would appear like the call didn't happen (even though it did). I figure that is exactly what the issue is. – Michael Petch Sep 06 '16 at 14:22
  • @Michael Petch - Thanks! You were right, using F11 instead of F10 i see the call step. But i just didn't know what is the difference between F10 and F11. Sometime F10 works correctly also with CALL. – glc78 Sep 06 '16 at 14:25
  • 1
    @caramelleamare : F10 will not step into a call instruction by instruction unless you happened to set a break point in the function - in which case the debugger would execute the function until the break point was hit and stop there. – Michael Petch Sep 06 '16 at 14:25
  • @zwol - I checked and it's like you say: the program works right but i don't see the call step, because of the use of F10 instead of F11, as i answered to Michael Petch. Very helpfull. – glc78 Sep 06 '16 at 14:28

1 Answers1

5

The problem
You've stumbled on the difference between step over F10 and step into F11.

When you use (the default) step over, call appears to be ignored.
You need to step into the code and then the debugger will behave as you'd expect.

Step over
The way this works with step over is that the debugger sets a breakpoint on the next instruction, halts there and moves the breakpoint to the next instruction again.
Step over knows about (conditional) jumps and accounts for that, but disregards (steps over) call statements; it interprets a call as a jump to another subroutine and 'assumes' you want to stay within the current context.
These automatic breakpoints are ephemeral, unlike manual breakpoints which persist until you cancel them.

Step into
Step into does the same, but also sets a breakpoint at every call destination; in effect leading you deep into the woods traversing every subroutine.

Step out
If you've stepped too deep 'into' a subroutine Visual Studio allows you to step out using ShiftF11; this will take you back to the next instruction after the originating call.
Some other debuggers name this feature "run until return".

Debugging high level code
When the debugger is handling higher language source code (e.g. C) it keeps a list of target addresses for every line of source code. It will plan its breakpoints per line of source code.
Other than the fact that every line of high level code translates to zero or more lines of assembly it works the same as stepping through raw assembly code.

Johan
  • 74,508
  • 24
  • 191
  • 319
  • Maybe you could have described the difference between the two a bit more. As the step-over is trying to put breakpoint after the current instruction, without examination of it (instruction = command line in high level language). Step-into will analyse current line first, and if some call is involved, it will put breakpoint into it (either high level call, or in ASM directly `call` is considered). Debuggers often have also "Step-out", which will keep executing current code, till it goes out of current scope ("RET" in ASM), can be handy if you accidentally went too deep with "step-into". – Ped7g Sep 06 '16 at 17:00
  • For assembly language, you may want "step single instruction" instead of either of the above. I can't tell if this is possible with Visual Studio from the documentation, but it [does appear to be possible with WinDbg](https://msdn.microsoft.com/en-us/library/windows/hardware/ff540661%28v=vs.85%29.aspx). – zwol Sep 07 '16 at 15:59