![](/img/trans.png)
[英]Why does my compiler use an 8-bit char when I'm running on a 64-bit machine?
[英]Why does 64-bit VC++ compiler add nop instruction after function calls?
我使用Visual Studio C ++ 2008 SP1, x64
C++
編譯器編譯了以下內容:
我很好奇,為什么編譯器會在那些call
之后添加那些nop
指令?
PS1。 我會理解第二和第三個nop
將是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());
}
PS3。 附加信息: 首先,謝謝大家的意見。
以下是其他觀察結果:
我的第一個猜測是增量鏈接可能與它有關。 但是,項目的Visual Studio
的Release
構建設置具有incremental linking
。
這似乎只影響x64
版本。 構建為x86
(或Win32
)的相同代碼沒有那些nop
,即使使用的指令非常相似:
VS 2013
生成的x64
代碼看起來有些不同,它仍會在一些call
之后添加那些nop
: dynamic
與static
鏈接到MFC也沒有區別存在那些nop
。 這個與VS 2013
動態鏈接到MFC dll: nop
S能后出現near
及far
call
S作為很好,他們什么都沒有做比對。 以下是我從IDA
獲得的代碼的一部分,如果我再進一步說明: 如您所見,在far
call
之后插入nop
,恰好“對齊” B
地址上的下一個lea
指令! 如果僅為了對齊而添加這些內容毫無意義。
near
relative
call
(即那些以E8
開頭的call
)比far
call
s(或以FF
開頭的那些,在這種情況下為15
) 更快一些 鏈接器可能首先嘗試near
call
s,並且因為它們比far
call
s短一個字節,如果成功,它可以在末尾用nop
s填充剩余空間。 但是上面的例子(5)有點打敗了這個假設。
所以我仍然沒有明確的答案。
這純粹是猜測,但它可能是某種SEH優化。 我說優化是因為SEH似乎在沒有NOP的情況下工作正常。 NOP可能有助於加速平倉。
在下面的示例中( 使用VC2017進行實時演示 ),在test1
調用basic_string::assign
后插入了NOP
,但在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();
}
部件:
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
請注意,MSVS默認使用/EHsc
標志進行編譯(同步異常處理)。 如果沒有那個標志, NOP
消失,並且使用/EHa
(同步和異步異常處理), throw()
不再/EHa
,因為SEH始終打開。
1由於某些原因,只有throw()
似乎減少了代碼大小,使用noexcept
使生成的代碼更大並且召喚更多的NOP
。 MSVC ...
這是一個特殊的填充程序,讓異常處理程序/展開函數正確檢測它是否是函數的序言/結尾/正文。
這是由於x64中的調用約定要求堆棧在任何調用指令之前對齊16字節。 這不是(我的知識)硬件要求,而是軟件要求。 這提供了一種方法來確保在進入函數時(即,在調用指令之后),堆棧指針的值總是8模16。因此允許從堆棧中的對齊位置進行簡單的數據對齊和存儲/讀取。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.