Jim
Jim

Reputation: 423

C++ odd assembly output query

Using Windows 10 Pro with Visual Studio 2022, Debug mode, X64 platform, I have the following code...

int main()
{
    int var = 1;
    int* varPtr = &var;

    *varPtr = 10;

    return 0;
}

In the disassembly window we see this...

    int var = 1;
00007FF75F1D1A0D C7 45 04 01 00 00 00 mov         dword ptr [var],1  
    int* varPtr = &var;
00007FF75F1D1A14 48 8D 45 04          lea         rax,[var]  
00007FF75F1D1A18 48 89 45 28          mov         qword ptr [varPtr],rax  

    *varPtr = 10;
00007FF75F1D1A1C 48 8B 45 28          mov         rax,qword ptr [varPtr]  
00007FF75F1D1A20 C7 00 0A 00 00 00    mov         dword ptr [rax],0Ah  

    return 0;

Upon stepping through the above, the RAX register is loaded with the memory address for the stack variable, var, via...

00007FF75F1D1A14 48 8D 45 04          lea         rax,[var]

Since RAX is not changed after this, why is that same var address being loaded into RAX again, 2 instructions later with...

00007FF75F1D1A1C 48 8B 45 28          mov         rax,qword ptr [varPtr] 

The memory view window shows that the &var address is constant throughout. Am I missing something daft?

[Updated] - switching to release mode and optimisation off returns the above in full. Turning on speed/size optimization returns only that "return 0" code. Would be interesting to see if there's a way to force the compiler to compile everything (using fast switch) and force it to not remove what it thought was redundant, for this example. This minimal appears to be too minimal, lol.

Still concerned about that unneeded double load of RAX - primarily, for such a small program, though yes, that's what 'optimisation' is all about. Sill.

Upvotes: 2

Views: 84

Answers (1)

catnip
catnip

Reputation: 25388

When compiling in Debug mode (i.e. with all optimisations disabled), the compiler generates code like this for a reason.

Suppose you are stepping through the code and you stop on the line that reads *varPtr = 10;. At that point, you decide that you loaded the wrong address into varPtr and would like to change it and continue debugging without stopping, rebuilding and restarting your program.

Well, in Debug mode, you can. Just change the address stored in varPtr (in the Watch window, say) and carry on debugging. Without the 'redundant' second load, this wouldn't work. When the compiler emits said load, it does.

So, to summarise, Debug mode is designed to make debugging easier, while Release mode is designed to make your code run as fast (or be as small) as possible, hopefully with the same semantics.

And just be grateful that compiler writers understand the need for these two modes of operation. Without them, our lives as developers would be much, much harder.

Upvotes: 1

Related Questions