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



这个/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:UsersxxxxDocumentsVisual Studio 2017ProjectsAssembliesDebugA_test.exe" /MANIFEST
/NXCOMPAT /PDB:"C:UsersxxxxDocumentsVisual Studio 2017ProjectsAssembliesDebugA_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:UsersxxxxDocumentsVisual Studio 
2017ProjectsAssembliesDebugA_test.pgd" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" 
/ManifestFile:"DebugA_test.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1

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

在 x64 和 ARM 目标上,实际上没有标准呼叫调用约定,因此没有特殊要求,也没有不一致。入口点代码应遵循这些目标的标准 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, CMASM 将按照 x86 cdecl 调用约定,自动在代码中定义的符号main前面加上下划线_。方便的是,这与上述/ENTRY的行为相匹配。 但是,将入口点命名main并不是最好的主意,因为这意味着它应该是同名的 C 函数。由于入口点不会传递参数,但 C 函数main传递,因此将入口点调用main可能会产生误导。 我建议将其命名为start

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

最新更新