Я скомпилировал следующее, используя компилятор Visual Studio С++ 2008 SP1, x64 C++:
Мне любопытно, почему компилятор добавил эти nop инструкции после этих call s?
PS1. Я бы понял, что 2-й и 3-й nop будут выровнять код по 4-байтовому полю, но 1-й nop нарушит это предположение.
PS2. Код С++, который был скомпилирован, не содержал в нем циклов или специальных элементов оптимизации:
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. Дополнительная информация: Прежде всего, спасибо всем за ваш вклад.
Здесь дополнительные наблюдения:
-
Мое первое предположение заключалось в том, что инкрементная привязка могла иметь какое-то отношение к ней. Но настройки сборки
ReleaseвVisual Studioдля проекта имеютincremental linkingoff. -
Это, по-видимому, влияет только на сборки
x64. Тот же код, построенный какx86(илиWin32), не имеет этихnops, хотя используемые команды очень похожи:
- Я попытался создать его с помощью нового компоновщика, и хотя код
x64, созданныйVS 2013, выглядит несколько иначе, он по-прежнему добавляет теnopпосле некоторыхcalls:
- Также
dynamicvsstatic, связанная с MFC, не имело никакого отношения к присутствию этихnops. Это построено с динамическим связыванием с dll MFC с помощьюVS 2013:
- Также обратите внимание, что те
nopмогут появляться послеnearиfarcall, и они не имеют никакого отношения к выравниванию. Вот часть кода, который я получил отIDA, если я немного пошагую дальше:
Как вы видите, nop вставлен после far call, который происходит, чтобы "выровнять" следующую инструкцию lea по адресу B! Это не имеет смысла, если они были добавлены только для выравнивания.
- Я изначально был склонен полагать, что поскольку
nearrelativecall(т.е. те, которые начинаются сE8), несколько быстрее чемfarcall(или те, которые начинаются сFF,15в этом случае)
компоновщик может сначала попытаться перейти с near call, и поскольку они являются одним байтом, короче far call s, если он преуспеет, он может заполнить оставшееся пространство с помощью nop на конец. Но тогда пример (5) выше своего рода побеждает эту гипотезу.
Таким образом, у меня до сих пор нет четкого ответа на этот вопрос.





