c00*_*0fd 20 c++ 64-bit assembly disassembly visual-studio
我使用Visual Studio C++ 2008 SP1,x64 C++编译器编译了以下内容:
我很好奇,为什么编译器会nop在那些calls 之后添加这些指令?
PS1.我会理解第二和第三个nops将是4字节边距上的代码对齐,但是第一个nop会打破这个假设.
PS2.编译的C++代码中没有循环或特殊的优化内容:
CTestDlg::CTestDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTestDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
//This makes no sense. I used it to set a debugger breakpoint
::GdiFlush();
srand(::GetTickCount());
}
Run Code Online (Sandbox Code Playgroud)
PS3.附加信息: 首先,谢谢大家的意见.
以下是其他观察结果:
我的第一个猜测是增量链接可能与它有关.但是,项目中的Release构建设置Visual Studio已incremental linking关闭.
这似乎x64只影响构建.构建为x86(或Win32)的相同代码没有那些nops,即使使用的指令非常相似:
x64产生的代码VS 2013有些不同,它仍会nop在某些calls 之后添加s:dynamicVS static链接到MFC做这些的存在没有区别nop秒.这个是通过动态链接到MFC dll构建的VS 2013:nops可以出现在s near和far calls 之后,它们与对齐无关.IDA如果我再深入一点,这里是我获得的代码的一部分:如您所见,在恰好"对齐" 地址上的下一条指令nop之后插入!如果仅为了对齐而添加这些内容就毫无意义.far callleaB
near relative callS(即那些以E8)是稍快比far callS(或与启动的人FF,15在这种情况下)链接器可能首先尝试使用near calls,并且因为它们比far calls 短一个字节,如果成功,它可以nop在末尾用s 填充剩余空间.但是上面的例子(5)有点打败了这个假设.
所以我仍然没有明确的答案.
这纯粹是一个猜测,但它可能是某种 SEH 优化。我说优化是因为 SEH 似乎在没有 NOP 的情况下也能正常工作。NOP 可能有助于加速平仓。
在下面的示例(VC2017 的现场演示NOP)中,在调用basic_string::assignintest1但不是 in test2(相同但声明为非抛出1 )后插入了一个。
#include <stdio.h>
#include <string>
int test1() {
std::string s = "a"; // NOP insterted here
s += getchar();
return (int)s.length();
}
int test2() throw() {
std::string s = "a";
s += getchar();
return (int)s.length();
}
int main()
{
return test1() + test2();
}
Run Code Online (Sandbox Code Playgroud)
集会:
test1:
. . .
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign
npad 1 ; nop
call getchar
. . .
test2:
. . .
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign
call getchar
Run Code Online (Sandbox Code Playgroud)
请注意,MSVS 默认情况下使用/EHsc标志(同步异常处理)进行编译。如果没有该标志,NOPs 就会消失,而有了/EHa(同步和异步异常处理),throw()则不再产生影响,因为 SEH 始终处于打开状态。
1由于某种原因throw()似乎只是减少了代码大小,使用noexcept会使生成的代码更大并召唤更多的NOPs。微软VC...
小智 -3
这是由于 x64 中的调用约定导致堆栈在任何调用指令之前必须对齐 16 字节。(据我所知)这不是硬件要求,而是软件要求。这提供了一种方法来确保在进入函数时(即在调用指令之后),堆栈指针的值始终为 8 模 16。从而允许简单的数据对齐以及从堆栈中的对齐位置存储/读取。
| 归档时间: |
|
| 查看次数: |
1079 次 |
| 最近记录: |