1

I'm using MSVC 2015.

I was trying to follow an answer provided here and adapted the program to the following:

#include <iostream>
#include <limits>

inline unsigned long long query_intel_x86_eflags(const unsigned long long query_bit_mask)
{
    return __readeflags() & query_bit_mask;
}

int main(int argc,char **argv)
{
    int x = std::numeric_limits<int>::max();
    int y = std::numeric_limits<int>::max();
    int z = x * y;
    //auto g{__readeflags() & 0x801}; // sees overflow and carry flags
    auto g{query_intel_x86_eflags(0x801)}; // doesn't see overflow and carry flags
    std::cout << std::hex << g << '\n';
}

The problem is that the eflags register is reset during the call to query_intel_x86_eflags() prior to the read of the EFL register.

The following assembly is emitted and it contains a sub instruction that resets the EFL register.

inline unsigned long long query_intel_x86_eflags(const unsigned long long query_bit_mask)
{
00007FF6396D1BF0 48 89 4C 24 08       mov         qword ptr [rsp+8],rcx  
00007FF6396D1BF5 55                   push        rbp  
00007FF6396D1BF6 57                   push        rdi  
00007FF6396D1BF7 48 81 EC C8 00 00 00 sub         rsp,0C8h // changes the flags 
00007FF6396D1BFE 48 8B EC             mov         rbp,rsp  
00007FF6396D1C01 48 8B FC             mov         rdi,rsp  
00007FF6396D1C04 B9 32 00 00 00       mov         ecx,32h  
00007FF6396D1C09 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00007FF6396D1C0E F3 AB                rep stos    dword ptr [rdi]  
00007FF6396D1C10 48 8B 8C 24 E8 00 00 00 mov         rcx,qword ptr [rsp+0E8h]  
    return __readeflags() & query_bit_mask;
00007FF6396D1C18 48 9C                pushfq  
00007FF6396D1C1A 58                   pop         rax  
00007FF6396D1C1B 48 23 85 E0 00 00 00 and         rax,qword ptr [query_bit_mask]  
}

Why does the compiler generate the additional instructions that end up resetting the register?

Community
  • 1
  • 1
wally
  • 10,717
  • 5
  • 39
  • 72
  • 1
    The prologue code appears to be setting up the canary on the stack. Are you looking at a debug build, by any chance? Anyway, for a function this low-level, you probably want `__declspec(naked)` – Igor Tandetnik May 29 '16 at 18:06
  • @IgorTandetnik Aha. Yes it was a debug build. How could I use `__declspec(naked)` in this situation? – wally May 29 '16 at 18:09
  • 1
    You use it in the way described in the documentation, of course. – Igor Tandetnik May 29 '16 at 18:13
  • @IgorTandetnik I'm not sure it is appropriate in this case. I get the following error: `C2485: 'naked': unrecognized extended attribute`. I looked at [this](https://msdn.microsoft.com/en-us/library/h5w10wxs.aspx) and tried `__declspec(naked) inline unsigned long long query_intel_x86_eflags(const unsigned long long query_bit_mask)`. I'm using 64 bit. – wally May 29 '16 at 18:18
  • Never mind. `__declspec(naked)` is only really meaningful when the function body is written mostly in inline assembly (which basically excludes 64-bit build). Such a function can't even have `return` statement. I suspect your best bet is a macro. – Igor Tandetnik May 29 '16 at 18:35
  • @RaymondChen I tried `__forceinline` but it didn't prevent the `sub` instruction from getting generated. – wally May 29 '16 at 20:25
  • Oh well, I figured it was worth a shot. Trying to read eflags is a risky proposition anyway because you have no absolute control over what the compiler does between the thing that sets eflags and your attempt to read it. – Raymond Chen May 29 '16 at 20:29
  • @RaymondChen I'm learning that too now... :) Thanks for the try. – wally May 29 '16 at 21:00

0 Answers0