现在您的问题已经用最小的、完整的、可验证的示例进行了更新,可以识别一些特定的问题。当你声明一个函数时PROC
每个函数都有一个语言命名和调用约定。不指定则表示不进行特殊处理。
您可以使用模型指令作为第二个参数指定默认语言。在您使用的两个文件中:
.model flat
所以您还没有关联默认语言。你已经定义了ClearRegs
as:
ClearRegs PROC C
[snip]
ClearRegs ENDP
这里的问题是PROC C
指定C语言调用约定和命名约定。采用 COFF 格式(32 位)C命名约定需要下划线(_
) 添加到函数名称的开头。如果您要生成 MAP 文件,您会发现从导出的函数名称实用程序.asm实际上是_ClearRegs
并不是ClearRegs
.
有很多方法可以解决这个问题。您可以选择不添加默认语言.model
指示和告诉Driver.asm
that ClearRegs
被定义为C通过更改原型:
ClearRegs PROTO
to
ClearRegs PROTO C
So now 实用程序.asm正在出口_ClearRegs
and 驱动程序.asm正在导入_ClearRegs
当双方匹配时,MASM 将处理添加额外的下划线。INVOKE ClearRegs
将使用与相关的命名约定PROTO
声明说语言是C所以它会添加额外的_
为你。
这会带来您可以进行的额外更改。一个END
指令可用于指定程序的入口点,而不是使用/entry:<name>
在链接器命令行上。入口点的名称必须以_
以满足链接器的要求。
您当前使用此功能驱动程序.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
那么你可以避免指定C
在大多数地方通过更改默认语言实用程序.asm and 驱动程序.asm通过改变:
.model flat
to:
.model flat, C
这将更改默认值PROTO
声明,PUBLIC
指定函数定义的语句PROC
and PROC
陈述本身。你的代码在驱动程序.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
实用程序.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