Является ли предложение, выделенное ниже, полученное со страницы / ENTRY в документах MASM, правильным? - PullRequest
0 голосов
/ 09 января 2020

Этот / ENTRY (MASM) документ говорит в своем разделе «Замечания»:

Примечания

Параметр / ENTRY определяет функцию точки входа в качестве начальной адрес для файла .exe или DLL.

Функция должна быть определена для использования соглашения о вызовах __stdcall.

Это не совсем верно , поскольку приведенный ниже код работает без проблем в VS2017.

.586
.MODEL flat, C
.stack 4096

.CODE
main PROC
    mov eax, -1
main ENDP

END 

, где main определяется как точка ввода кода в опции компоновщика / ENTRY. Обратите внимание, что main не использует stdcall соглашение о вызовах.

В этом случае выделенное предложение относится только к кодам, написанным в C или C ++?

Только для документации, я предоставляю ниже командную строку компоновщика, используемую для запуска кода:

/OUT:"C:\Users\xxxx\Documents\Visual Studio 2017\Projects\Assemblies\Debug\A_test.exe" /MANIFEST
/NXCOMPAT /PDB:"C:\Users\xxxx\Documents\Visual Studio 2017\Projects\Assemblies\Debug\A_test.pdb" 
/DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" 
"shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG:FASTLINK 
/MACHINE:X86 /ENTRY:"main" /INCREMENTAL /PGD:"C:\Users\xxxx\Documents\Visual Studio 
2017\Projects\Assemblies\Debug\A_test.pgd" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" 
/ManifestFile:"Debug\A_test.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1

1 Ответ

7 голосов
/ 09 января 2020

Это отчасти правильно. Фактические требования здесь более сложны и частично противоречивы. Для целей x86 соглашение о вызовах, используемое фактическим кодом точки входа, не имеет значения для исполняемых файлов, но должно использовать соглашение о вызовах stdcall для DLL. Однако для целей x86 имя, переданное с параметром /ENTRY, автоматически оформляется так, как если бы оно было функцией в соответствии с соглашением о вызовах cdecl, независимо от того, создается ли исполняемый файл или DLL.

На x64 и ARM На самом деле не существует соглашения о вызовах stdcall, поэтому нет особых требований и несоответствий. Код точки входа должен соответствовать стандартному соглашению cdecl для этих целей, а имя, переданное с параметром /ENTRY, не оформлено.

Требования кода сборки точки входа

В случае В исполняемом файле точка входа вызывается без аргументов, поэтому соглашение о вызовах cdecl и stdcall эквивалентно, и поэтому любой из них может использоваться для кода точки входа. В случае DLL точка входа вызывается с тремя аргументами, те же аргументы передаются DllMain , и эти аргументы передаются с использованием соглашения о вызовах stdcall. На целях x86 код точки входа DLL должен выдавать эти аргументы при помощи инструкции ret 12 при возврате.

Как / ENTRY обрабатывает свой аргумент

Для целей x86 (а не для целей x64 и ARM) ) опция компоновщика /ENTRY автоматически ставит перед символом переданный символ подчеркивания _, следуя соглашению cdecl для имен символов. Он не добавляет суффикс stdcall @##, даже если вы создаете DLL. Затем он будет нечётко сопоставлять этот символ с символами в связанном коде. Если вы используете /ENTRY:foo, то сначала он попытается найти символ с именем _foo, а если он его не найдет, он будет искать символ с именем foo или символ, начинающийся с _foo@ или foo@ .


Комментарии к коду вашего примера

Обратите внимание, потому что вы используете .MODEL flat, C в вашем примере кода MASM автоматически префиксом символа main, определенного в вашем коде, с подчеркивание _ в соответствии с соглашением о вызовах x86 cdecl. Удобно, что это соответствует поведению /ENTRY, как описано выше. Тем не менее, это не лучшая идея назвать вашу точку входа main, поскольку это будет означать, что это должна быть функция C с тем же именем. Поскольку ваша точка входа не получает переданные аргументы, но функция C main может ввести в заблуждение вызов вашей точки входа main. Вместо этого я бы предложил назвать его start.

Наконец, директива .STACK ничего не делает при сборке 32-битных или 64-битных программ PECOFF. Это полезно только при создании 16-битных программ.

...