从 MASM 文档中的 /ENTRY 页面获得的下面突出显示的句子是否正确?

Ale*_*der 0 x86 assembly masm

这个/ENTRY (MASM) 文件在其备注部分说:

评论

/ENTRY 选项将入口点函数指定为 .exe 文件或 DLL 的起始地址。

该函数必须定义为使用 __stdcall 调用约定。

这似乎并不完全正确,因为下面的代码在 VS2017 中没有问题。

.586
.MODEL flat, C
.stack 4096

.CODE
main PROC
    mov eax, -1
main ENDP

END 
Run Code Online (Sandbox Code Playgroud)

其中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
Run Code Online (Sandbox Code Playgroud)

Ros*_*dge 7

这是部分正确的。这里的实际要求相当复杂,部分矛盾。对于 x86 目标,实际入口点代码使用的调用约定对可执行文件无关紧要,但需要对 DLL 使用 stdcall 调用约定。但是,在 x86 目标上,与该/ENTRY选项一起传递的名称会被自动修饰,就好像它是遵循 cdecl 调用约定的函数一样,无论是生成可执行文件还是 DLL。

在 x64 和 ARM 目标上,实际上没有 stdcall 调用约定,因此没有特殊要求,也没有不一致。入口点代码应该遵循这些目标的标准 cdecl 约定,并且与/ENTRY选项一起传递的名称没有被修饰。

入口点汇编代码要求

在可执行文件的情况下,入口点是不带参数调用的,因此 cdecl 和 stdcall 调用约定是等效的,因此任何一个都可以用于入口点代码。在 DLL 的情况下,入口点使用三个参数调用,相同的参数传递给DllMain,这些参数使用 stdcall 调用约定传递。在 x86 目标上,DLL 的入口点代码应ret 12在返回时使用指令弹出这些参数。

/ENTRY 如何处理它的参数

在 x86 目标(而不是 x64 和 ARM 目标)上,/ENTRY链接器选项会_按照符号名称的 cdecl 约定自动在传递的符号前面加上下划线。@##即使您正在构建 DLL,它也不会添加 stdcall后缀。然后它将这个符号与被链接的代码中的符号进行模糊匹配。如果你使用/ENTRY:foo那么它首先会尝试找到一个名为符号_foo,如果没有找到它,它会寻找一个名为符号foo或一个开始_foo@foo@


对示例代码的评论

请注意,因为您.MODEL flat, C在示例代码中使用 MASM 将按照 x86 cdecl 调用约定自动在代码中main定义的符号_前面加上下划线。方便地,这与上述行为相匹配/ENTRY。但是,命名入口点并不是最好的主意,main因为这意味着它应该是同名的 C 函数。由于您的入口入口点没有传递参数,但 C 函数main确实如此,因此调用您的入口点可能会产生误导main。我建议start改为命名它。

最后,.STACK 指令在构建 32 位或 64 位 PECOFF 程序时没有任何用处。它仅在创建 16 位程序时有用。