如何修改简单Win32汇编程序的入口点名称
问题原因
你遇到的报错不是链接器忽略了/ENTRY选项,而是你链接时引入了C运行时库libcmt.lib导致的:
MSVC的C运行时库(CRT)自带默认启动入口_mainCRTStartup,该入口会完成CRT初始化、全局变量构造等前置工作后,调用用户实现的main函数。你虽然指定了自定义入口my_start,但libcmt.lib中的CRT启动代码本身包含对_main符号的未解析引用,链接时找不到该符号就会抛出错误。
解决方案
你可以根据自己的需求选择以下两种方案:
方案1:保留CRT启动逻辑,仅替换用户入口名称
如果你不需要修改程序底层启动流程,仅想把用户层入口从main改成my_start,不需要修改/ENTRY参数,只要给链接器增加别名映射即可:
- 链接时添加
/ALTERNATENAME:_main=_my_start参数,告诉链接器找不到_main符号时,用_my_start作为替代。
修改后的链接指令如下:
link /SUBSYSTEM:CONSOLE /ALTERNATENAME:_main=_my_start HelloWorld.obj libcmt.lib legacy_stdio_definitions.lib
该方案不需要修改汇编代码,CRT的初始化、退出逻辑都会正常运行,调用printf等CRT函数也不会出现异常。
方案2:完全自定义程序入口,跳过CRT默认启动流程
如果你需要把my_start作为程序的第一个执行入口,完全接管启动流程,需要做两处修改:
- 调整汇编代码,入口函数结束时主动调用
ExitProcess退出进程,不要直接ret(自定义入口没有上层调用者,直接返回会触发内存访问错误);如果要使用printf等CRT函数,需要先手动完成CRT初始化:
.386 .model flat, c option casemap :none EXTERN printf :PROC EXTERN ExitProcess :PROC EXTERN __acrt_initialize :PROC ; 对应MSVC2019 CRT初始化函数 EXTERN __acrt_uninitialize :PROC ; CRT清理函数 includelib kernel32.lib includelib libcmt.lib includelib legacy_stdio_definitions.lib .data HelloWorld db "Hello j World!:-)", 0 .code my_start PROC ; 初始化CRT call __acrt_initialize ; 调用printf push offset HelloWorld call printf add esp, 4 ; 清理CRT push 0 call __acrt_uninitialize ; 退出进程 push 0 call ExitProcess my_start ENDP END
- 链接时保留
/ENTRY:my_start参数,同时添加/NODEFAULTLIB:libcmt.lib避免CRT强制解析_main符号:
link /ENTRY:my_start /SUBSYSTEM:CONSOLE /NODEFAULTLIB:libcmt.lib HelloWorld.obj libcmt.lib legacy_stdio_definitions.lib kernel32.lib
内容的提问来源于stack exchange,提问作者darek_911
相关产品推荐
相关产品推荐

