Assembly 下面突出显示的句子是从MASM文档中的/条目页面获得的,对吗?

Assembly 下面突出显示的句子是从MASM文档中的/条目页面获得的,对吗?,assembly,x86,masm,Assembly,X86,Masm,本(MASM)文件在其备注部分中指出: 评论 /ENTRY选项指定入口点函数作为起始点 .exe文件或DLL的地址 必须定义函数才能使用stdcall调用约定。 这似乎并不完全正确,因为下面的代码在VS2017中可以正常工作 .586 .MODEL flat, C .stack 4096 .CODE main PROC mov eax, -1 main ENDP END 其中,main被定义为链接器选项/条目中的代码入口点。请注意,main不使用stdcall调用约定 这是突出

本(MASM)文件在其备注部分中指出:

评论

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

必须定义函数才能使用stdcall调用约定。

这似乎并不完全正确,因为下面的代码在VS2017中可以正常工作

.586
.MODEL flat, C
.stack 4096

.CODE
main PROC
    mov eax, -1
main ENDP

END 
其中,
main
被定义为链接器选项/条目中的代码入口点。请注意,
main
不使用
stdcall
调用约定

<强>这是突出显示的句子仅指用C或C++编写的代码吗?< /强> < /P> 仅作为文档,我在下面提供了用于运行代码的链接器命令行:

/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

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


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

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

/ENTRY如何处理其参数 在x86目标(而不是x64和ARM目标)上,
/ENTRY
链接器选项会根据符号名称的cdecl约定,自动在传递的符号前面加上下划线
\uu
。它不会添加stdcall
@##
后缀,即使您正在构建DLL。然后,它会将此符号与链接代码中的符号进行模糊匹配。如果使用
/ENTRY:foo
,它将首先尝试查找名为
\u foo
的符号,如果未找到,它将查找名为
foo
的符号或以
\u foo@
foo@
开头的符号


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


最后,在构建32位或64位PECOFF程序时,会出现错误。它仅在创建16位程序时有用。

Ahm-链接器选项中有一个
/ENTRY:“main
。默认调用约定定义为
cdecl
.MODEL flat,C
)。我想,这可能意味着如果该函数是STDCALL函数,则必须定义该函数。对于其他模型,可以定义该函数。但在任何情况下,都需要一个入口点,该入口点也可以是标签(例如,
开始:
。我能说什么呢?答案非常有力,帮助我真正理解了/ENTRY和/SUBSYSTEM链接器选项的复杂性。我想祝贺你给出了这个近乎完美的答案,因为我想向你澄清一点:在你的第二段中,你说:(待续)在x64和ARM目标上,实际上没有stdcall调用约定,因此没有特殊要求,也没有不一致性。入口点代码应该遵循这些目标的标准cdecl约定,并且与/entry选项一起传递的名称没有修饰。”(待续)我想说的是,入口点代码应该没有调用约定,因为我相信至少在x64中名称不会被损坏。这是正确的吗?@Alexander入口点代码应该遵循x64或ARM标准cdecl调用约定,特别是当它返回时。在64位x64启动代码的情况下,这意味着要执行诸如重新调整与任何其他x64函数一样,堆栈和保留某些寄存器。我更新了答案,以便更清楚地说明,即使在32位x86可执行文件中,也应该遵循cdecl或stdcall调用约定,当函数不带参数时,它们恰好是等价的。