如果用两个变量或一个变量和一个数字文字加成,那么为什么C++调用的汇编函数在标志中给出不同的结果?

如果用两个变量或一个变量和一个数字文字加成,那么为什么C++调用的汇编函数在标志中给出不同的结果?,c++,c,assembly,flags,C++,C,Assembly,Flags,如果有人可以,请帮助我 我编写了一个3行汇编代码来获取RFLAGS的值: PUBLIC x64rflags .code ; Caller C++ function prototype: unsigned long long int x64rflags(); x64rflags PROC pushfq ; RFLAGS into stack pop rax ; RAX = RFLAGS ret x64rflags ENDP

如果有人可以,请帮助我

我编写了一个3行汇编代码来获取RFLAGS的值:

PUBLIC x64rflags
.code
; Caller C++ function prototype: unsigned long long int x64rflags();
x64rflags PROC     
    pushfq          ; RFLAGS into stack
    pop rax         ; RAX = RFLAGS
    ret    
x64rflags ENDP
End
<>我在C++库中使用C++程序检查标志:

//The RFLAGS query function. Result in unsigned long long int value.
extern "C"
{
    unsigned long long int x64rflags();
}

//The FLAGS bits decimal values
enum
{
    FLAGS_CF = 1, //Carry
    FLAGS_PF = 4, //Parity
    FLAGS_AF = 16, //Adjust (Auxiliary carry)
    FLAGS_ZF = 64, //Zero
    FLAGS_SF = 128, //Sign
    FLAGS_TF = 256, //Trap
    FLAGS_IF = 512, //Interrupt enable
    FLAGS_DF = 1024, //Direction
    FLAGS_OF = 2048, //Overflow
    FLAGS_IOPL_LOW = 4096, //I/O privilege level low bit
    FLAGS_IOPL_HIGH = 8192, //I/O privilege level high bit
    FLAGS_NT = 16384, //Nested task
    FLAGS_RF = 65536, //Resume
    FLAGS_VM = 131072, //Virtual 8086 mode
    FLAGS_AC = 262144, //Alignment Check
    FLAGS_VIF = 524288, //Virtual interrupt
    FLAGS_VIP = 1048576, //Virtual interrupt Pending
    FLAGS_ID = 2097152, //CPUID available
};

//The compare function of RFLAGS and inpected values
bool flagschk(unsigned long long int flags, unsigned long long int flagsToChk)
{
    if (flagsToChk == (flagsToChk & flags))
    {
        return true;
    }
    else
    {
        return false;
    }
}

这里是我的C++测试程序:

#define _UNICODE
#define UNICODE

#include <iostream>
#include <windows.h>
#include <string>
#include <x64rflags.h>

using namespace std;
typedef unsigned long long int ulli;

int main()
{
    SetConsoleOutputCP(1250); //ANSI Central European; Central European (Windows)

    ulli ullia, ullib, ullir, actrflags;
    std::string stro1, stro2;

    ullia = 0xffffffffffffffff;
    ullib = 1;
    ullir = ullia + ullib; //CF
    actrflags = x64rflags(); //CALL THE RFLAGS RETURNER ASM FUNCTION
    printf("1 Result: %llu\n", ullir);
    stro1 = "1 The value of actrflags: ";
    stro2 = std::to_string(unsigned long long int(actrflags));
    stro1.append(stro2);
    stro1.append("\n");
    printf(stro1.c_str());


    if(flagschk(actrflags, FLAGS_CF))
    {
        printf("1 condparam = TRUE\n\n");
    }
    else
    {
        printf("1 condparam = FALSE\n\n");
    }
//*/
    ullia = 0xffffffffffffffff;
    ullir = ullia + 1; //CF
    actrflags = x64rflags(); //CALL THE RFLAGS RETURNER ASM FUNCTION
    printf("2 Result: %llu\n", ullir);
    stro1 = "2 The value of actrflags: ";
    stro2 = std::to_string(unsigned long long int(actrflags));
    stro1.append(stro2);
    stro1.append("\n");
    printf(stro1.c_str());


    if(flagschk(actrflags, FLAGS_CF))
    {
        printf("2 condparam = TRUE\n\n");
    }
    else
    {
        printf("2 condparam = FALSE\n\n");
    }

    return 0;
}

我的问题是它在两个探针上给出了不同的结果。 第一个使用变量的方法按预期工作:提高进位并返回TRUE

使用一个变量和一个数字文字的第二个变量不增加进位

其他信息: ml64使用选项/c编译的汇编代码 C++代码编写代码::块,用MSVC 2019编译。 运行在Intel x64Arch core i7上的程序。 理论上,程序使用默认的x64 ABI调用约定。 如果我没有在rflags查询之前的添加表达式中使用=,则在这两种情况下都不起作用。我猜MSVC会将加法作为NOP处理,并独立于加法返回最后一个进位


有人能解释这种异常现象的原因吗?

任何关于编译器如何根据asm选择实现C+运算符的期望都是没有根据的。一些调优选项可能使它更喜欢lea而不是不设置标志的add。对于GCC,事实上-mtune=atom就是这种情况

启用优化后,它可能会以不同的顺序执行,而不是在非内联函数调用之前

或者特别是对于+1,MSVC可能选择了不修改CF的选项。鉴于您的标志结果仅在低位不同,这里的情况与此类似。对于该位,您正在读取在inc之前CF中恰好留下的任何值。其他位由inc写入

您可以使用调试器单步检查编译器生成的asm,也可以将其打开

而且也没有理由假设在执行到达函数调用时,asm仍会为+设置标志。即使内联asm也不能可靠地做到这一点。如果要从add读取标志,则add需要在asm中,而不是编译器生成的


优化器不认为先前C语句的标志结果是函数调用的输入,或者是一个可观察到的副作用,除了编译器生成的代码有意读取标志结果,例如在加法之后的JNZ实现与问题无关的IFFOO

,而不是条件返回真;否则返回false;你可以有返回条件;你看过汇编代码了吗?