![](/img/trans.png)
[英]C++: For two different functions with do-while loops, why does x+=y give the same result as x=x+y in one function but not the other?
[英]Why assembly function called from C++ give different result in flags if addition made with two variables or one variable and one numeric literal?
如果有人可以,请帮助我!
我写了一个 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 编译的汇编代码 用 Code::Blocks 编写的 C++ 代码,使用 MSVC 2019 编译。程序运行在 Intel x64Arch(酷睿 i7)上。 这些程序(理论上)使用默认的 (x64 ABI) 调用约定。 如果我不在 rflags 查询之前的添加表达式中使用“=”,则在这两种情况下都不起作用。 (我想 MSVC 将加法处理为“NOP”并独立于加法返回最后一个进位......)
有人可以解释这个异常是什么原因吗?
任何关于编译器如何选择根据 asm 实现 C +
运算符的期望都是没有根据的。 一些调整选项可以使它更喜欢lea
而不是不设置标志的add
。 (对于 GCC,这实际上是-mtune=atom
的情况)。
启用优化后,它可能会以不同的顺序执行,而不是在非内联函数调用之前。
或者对于+1
,MSVC 可能选择了不修改 CF 的inc
。 鉴于您的 FLAGS 结果仅在低位不同,这里看起来就是这种情况。 ( CF是最低位)。 对于那一点,您正在阅读inc
之前 CF 中恰好留下的任何值。 其他位由inc
写入。
您可以通过调试器单步执行来检查编译器生成的 asm,或将其放在https://godbolt.org/
并且也没有理由假设在执行到达您的函数调用时 FLAGS 仍然从 asm for +
设置。 即使是内联 asm 也不能可靠地做到这一点。 如果您想从add
中读取 FLAGS,则add
需要在您的 asm 中,而不是编译器生成的。
优化器不将先前 C 语句的 FLAG 结果视为函数调用的输入,或根本不考虑可观察到的副作用(除了编译器生成的代码有意读取 FLAGS 结果,例如jnz
在 add 之后实现if(foo)
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.