winapi - 如何在 MASM 中为一个项目编写和组合多个源文件?
问题描述
组装很新,玩得很开心。我想将我的程序的功能拆分到多个文件中,特别是通过将类似的功能组合在一起进行组织。这些其他文件将由主文件调用(希望甚至是其他非主文件)。我还没有做到这一点,希望得到帮助。
我没有使用 IDE,我更喜欢使用 notepad++、ml.exe 和 link.exe(来自 MASM 文件夹)来自己编写、组装和链接程序。我看过的大多数在线资源都假设 Visual Studio,并提供对我不起作用的代码,或者可能是不完整的 b/c IDE 执行其他操作。我不打算开始使用 IDE。
我想学习“最好的”方式,意思是对未来项目最有用的方式。我可以这样设置它,以便我可以复制文件并编写几行代码以便将来在不同的项目中使用它吗?或者也许这是不好的做法,我应该学习一种更标准的方法?我知道这个平台不是针对固执的问题,我希望这个问题比意见更基于事实。
我能想到的所有有用信息:
语言:Masm assembly x86
计算机:64 位 Windows
代码:
RUN.bat
@echo off
ml /c /coff /Zi /Fl Driver.asm
ml /c /coff /Zi /Fl Utils.asm
link /debug /subsystem:console /entry:start /out:Driver.exe Utils.obj Driver.obj \masm32\lib\kernel32.lib
Driver.exe
pause
驱动程序.asm
.386
.model flat
.stack 100h
ExitProcess PROTO Near32 STDCALL, dwExitCode:DWORD
ClearRegs PROTO
.DATA
.CODE
PUBLIC _start
_start:
Main PROC
MOV EAX, 0
INVOKE ClearRegs
INVOKE ExitProcess, 0
Main ENDP
END
实用程序.asm
.386
.model flat
.stack 100h
OPTION PROC:PRIVATE ; Set procedures to private by default
PUBLIC ClearRegs
.DATA
.CODE
ClearRegs PROC C
XOR EAX, EAX
XOR EBX, EBX
XOR ECX, ECX
XOR EDX, EDX
XOR ESI, ESI
XOR EDI, EDI
RET
ClearRegs ENDP
END
终端输出
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
Assembling: Driver.asm
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
Assembling: Utils.asm
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
Driver.obj : error LNK2001: unresolved external symbol ClearRegs
Driver.exe : fatal error LNK1120: 1 unresolved externals
'Driver.exe' is not recognized as an internal or external command,
operable program or batch file.
Press any key to continue . . .
解决方案
现在您的问题已经更新为一个最小的、完整的、可验证的示例,可以识别一些特定的问题。当你声明一个函数时PROC
,每个函数都有一个语言命名和调用约定。未指定一关联者无特殊处理。
您可以使用模型指令作为第二个参数指定默认语言。在您使用的两个文件中:
.model flat
所以你没有关联默认语言。您已定义ClearRegs
为:
ClearRegs PROC C
[snip]
ClearRegs ENDP
这里的问题是PROC C
指定了C语言的调用约定和命名约定。对于 COFF 格式(32 位),C命名约定要求_
在函数名称的开头添加下划线 ( )。如果您要生成一个 MAP 文件,您会发现从utils.asm导出的函数名称实际上是_ClearRegs
而不是ClearRegs
.
有很多方法可以解决这个问题。您可以选择不向.model
指令添加默认语言,并通过更改将Driver.asm
其ClearRegs
定义为C PROTOtype:
ClearRegs PROTO
到
ClearRegs PROTO C
所以现在utils.asm正在导出_ClearRegs
,Driver.asm正在导入_ClearRegs
,因为双方都匹配,MASM 将处理添加额外的下划线。将使用与该语言为C的语句INVOKE ClearRegs
关联的命名约定,因此它将为您添加额外的内容。PROTO
_
这带来了您可以进行的额外更改。指令可END
用于指定程序的入口点,而不是/entry:<name>
在链接器命令行上使用。入口点必须有一个以 an 开头的名称_
才能满足链接器的要求。
您当前在Driver.asm中使用它:
PUBLIC _start
_start:
Main PROC
[snip]
Main ENDP
END
并且您/entry:start
在链接时使用。您可以将其更改为:
_Main PROC
[snip]
_Main ENDP
END _Main ; END with a function name tells linker to use _Main as program entry point
链接时,您现在/entry
可以完全删除该选项,并且不再需要_start
标签。不过我们可以做得更好。MS C运行时启动调用的入口点假定函数遵循C语言命名和调用约定。最好这样做:
Main PROC C
[snip]
Main ENDP
END Main ; END with a function name tells linker to use _Main as program entry point
如果您打算创建所有功能PROC C
,则可以通过更改Utils.asm和Driver.asmC
中的默认语言来避免在大多数地方指定:
.model flat
到:
.model flat, C
这将更改PROTO
语句的默认值、PUBLIC
指定用定义的函数的语句PROC
和PROC
语句本身。您在Driver.asm中的代码可能如下所示:
.386
.model flat, C
.stack 100h
ExitProcess PROTO Near32 STDCALL, dwExitCode:DWORD
ClearRegs PROTO
.DATA
.CODE
Main PROC
MOV EAX, 0
INVOKE ClearRegs
INVOKE ExitProcess, 0
Main ENDP
END Main
Utils.asm可能看起来像:
.386
.model flat, C
.stack 100h
OPTION PROC:PRIVATE ; Set procedures to private by default
PUBLIC ClearRegs
.DATA
.CODE
ClearRegs PROC
XOR EAX, EAX
XOR EBX, EBX
XOR ECX, ECX
XOR EDX, EDX
XOR ESI, ESI
XOR EDI, EDI
RET
ClearRegs ENDP
END
你会链接到:
link /debug /subsystem:console /out:Driver.exe Utils.obj Driver.obj \masm32\lib\kernel32.lib
推荐阅读
- reactjs - 覆盖材质 UI MuiInput
- php - 使用 ON DUPLICATE KEY UPDATE 正确处理 PHP 表单数组?
- amazon-web-services - 如何从 AWS Lambda 的 DynamoDB 列表中删除元素?
- python - 将 cython cdef 扩展数组设置为零
- excel - 如果行隐藏在另一个工作表上,则创建循环以隐藏行
- c# - 如何在 MVC EF 中执行 if 语句
- javascript - JavaScript 随机化函数在 HTML 上下文中不起作用但在外部起作用
- java - 试图创建一个数组,“错误:'.class'预期”
- php - laravel中唯一的两列
- database - 是否可以在 CakePHP 3 的会话表中保存附加数据?