汇编器MASM(64位)不能识别入口点并抛出错误



我正在学习Windows上x86系列处理器体系结构(32位和64位)的汇编程序。这并不是说我是一个初学者,但我可能不知道所有的事情,至少看起来是关于MASM汇编器的语法。

我使用位于Visual Studio文件夹中的MASM汇编程序(用于64位程序):";..Microsoft Visual Studio2019CommunityVCToolsMSVC14.29.30133binHostx64x64ml64.exe";安装了Visual Studio 2019,我从其文件夹中使用MASM汇编器。我自己用的是Windows 7。

我为32位系统编写了程序,它通常由MASM为32位程序组装并工作。然后我将其代码翻译为64位体系结构(代码中需要进行一些更改)。但是,当它与64位程序的MASM组合时,MASM给出了一个错误消息,据称有一些未解决的"StartOfProgram";的象征。下面是控制台上的内容:

C:Assembler>cd "C:Assembler"
C:Assembler>"C:Program Files (x86)Microsoft Visual Studio2019CommunityVCToolsMSVC14.29.30133binHostx64x64ml64.exe" "C:AssemblerMain.asm" /link /subsystem:windows /entry:StartOfProgram
Microsoft (R) Macro Assembler (x64) Version 14.29.30138.0
Copyright (C) Microsoft Corporation.  All rights reserved.
Assembling: C:AssemblerMain.asm
Microsoft (R) Incremental Linker Version 14.29.30138.0
Copyright (C) Microsoft Corporation.  All rights reserved.
/OUT:Main.exe
Main.obj
/subsystem:windows
/entry:StartOfProgram
LINK : error LNK2001: unresolved external symbol StartOfProgram.
Main.exe : fatal error LNK1120: unresolved external symbols: 1

我花了大约两个星期或一个月的时间来寻找解决这个错误的方法,但我没有找到。

通常,它用来给出一个错误消息,声称有一些未解析的符号"WinMainCRTStartup",但最近我意识到它有这样一个入口点,因为我没有在控制台中明确指定入口点(通过命令"/entry:",这是在控制台从上面),但关于"unresolved external symbol";仍然存在,即使我在需要的地方设置了入口点(即在"StartOfProgram")。


这是我64位版本的程序代码,只需要输出"Hello world"在弹出窗口中:

option  casemap:none    ; As far as i understand, functions from Windows API without case sensitivity not works
; **** Importing what needs ****
includelib  "C:Program Files (x86)Windows Kits10Lib10.0.19041.0umx64kernel32.lib"   ; Downloading main static library to use main functions of Windows API
extern      LoadLibraryA:near    ; I load from static libraries functions used in this program
extern      GetProcAddress:near
extern      FreeLibrary:near
extern      ExitProcess:near
; **** Declaring memory segment ****
.data
text                    db  'Hello world', 0            ; Text in "Text Box"'s window
header                  db  'Title of hello world', 0   ; Header of "Text Box"'s window

nameOfDLL               db  'user32.dll', 0
nameOfProcedureOfDLL    db  'MessageBoxA', 0
handlerToModule         dd  0
addressOfProcedureOfDLL dq  0   ; In 64-bit operating system, addresses are 64-bit, so size of memory area that this label points to - is quad word (dq) (that is 64 bits)
.code
; **** Entry point to program ****
StartOfProgram:    ; For some reason, MASM assembler recommends putting "_" sign before label of entry point to program, if it is 32-bit. Therefore in 64-bit I don't.
mov     rcx, offset nameOfDLL
sub     rsp, 40                         ; Pointer shifting for alignment of stack and plus "shadow space" in stack. It needed by x64 calling convention
call    LoadLibraryA                    ; I dynamically connect DLL so that i can then take function from it
add     rsp, 40

mov     qword ptr handlerToModule, rax

mov     rcx, rax                        ; Functions from Windows API use stdcall convention. stdcall is agreement to pass function parameters to stack backwards, so rax is last. Rax still contains Windows' DLL address (Microsoft call it "handler") (after recent call to Loadlibrary function), so it's better to use register, processor works faster with registers
mov     rdx, offset nameOfProcedureOfDLL
sub     rsp, 40
call    GetProcAddress
add     rsp, 40

mov     addressOfProcedureOfDLL, rax    ; I save address of procedure that i took from GetProcAddress. In 64-bit operating system, addresses are 64-bit, so needs to transfer rax register and not eax

mov     rcx, 0
mov     rdx, offset text
mov     r8, offset header
mov     r9, 0
sub     rsp, 40
call    addressOfProcedureOfDLL         ; It is better to immediately pass address of function through memory address label and not through register containing this address, because computer will still have to go to this address later and there is no point in wasting time reading from  register of same address
add     rsp, 40        
mov     rcx, offset handlerToModule
sub     rsp, 40
call    FreeLibrary
add     rsp, 40
mov     rcx, 0
sub     rsp, 40
call    ExitProcess
add     rsp, 40
end

这是我的32位版本的程序代码(正常组装和工作):

.386    ; There indicates processor with minimal set of functions (since new Intel processors (in "x86" family of architectures) are compatible (so far) with instructions of old Intel processors of same family of architectures)
option  casemap:none    ; As far as i understand, functions from Windows API without case sensitivity not works
; **** Importing what needs ****
includelib  "C:Program Files (x86)Windows Kits10Lib10.0.19041.0umx86kernel32.lib"   ; Downloading main static library to use main functions of Windows API
;includelib  "C:Program Files (x86)Windows Kits10Lib10.0.19041.0umx86User32.lib"
extern      _LoadLibraryA@4:near    ; I load from static libraries a functions used in this program
extern      _GetProcAddress@8:near
extern      _FreeLibrary@4:near
extern      _ExitProcess@4:near
.model flat
; **** Declaring a memory segment ****
.data
text                    db  'Hello world', 0            ; Text in "Text Box"'s window
header                  db  'Title of hello world', 0   ; Header of "Text Box"'s windowокна
nameOfDLL               db  'user32.dll', 0
nameOfProcedureOfDLL    db  'MessageBoxA', 0
handlerToModule         dd  0
addressOfProcedureOfDLL dd  0
.code
; **** Entry point to program ****
_StartOfProgram:    ; For some reason, MASM assembler recommends putting "_" sign before label of entry point to program, if it is 32-bit
push    offset nameOfDLL
call    _LoadLibraryA@4                 ; I dynamically connect DLL so that i can then take function from it
mov     handlerToModule, eax
push    offset nameOfProcedureOfDLL
push    eax                             ; Functions from Windows API use stdcall convention. stdcall is agreement to pass function parameters to stack backwards, so eax is last. Eax still contains Windows' DLL address (Microsoft call it "handler") (after recent call to Loadlibrary function), so it's better to use register, processor works faster with registers
call    _GetProcAddress@8
mov     addressOfProcedureOfDLL, eax    ; I save address of procedure that i took from GetProcAddress
push    0
push    offset header
push    offset text
push    0
call    addressOfProcedureOfDLL
push    handlerToModule
call    _FreeLibrary@4
push    0
call    _ExitProcess@4
end _StartOfProgram

下面是32位版本程序的结果:32位版本程序的结果

问题已在注释中解决。正如@Peter Cordes和@David Wohlferd所说,我需要根据指令在我的程序中发布我的标签;public";然后写标签的名字,或者重写我的入口点标签使用指令"proc";和";endp";在这些指令的开头加上name of label


我更喜欢通过"public";指令,因为我认为它更接近低级编程。在这种情况下,我必须在程序中使用"public";指令,然后在其末尾写上标签的名称,以便外部程序可以使用。显然,MASM汇编器给出了一个错误,因为它没有看到它可以从外部访问,因此不认为将它指定为入口点是正确的,尽管它可以猜测,如果我指定它为入口点,那么它可以从外部切换到它。显然,MASM的开发者并没有这样做。

下面是一个使用指令"public";在我的程序中(我使用指令"public"):public StartOfProgram

我注意到我可以把它放在代码的任何地方

下面是一个使用指令"proc";和";endp";在我的程序:

StartOfProgram proc     ; - Beginning of this directivical procedure
; ... there may be the code itself inside this directivical procedure
StartOfProgram endp     ; - End of this directivical procedure

问题中我的代码有其他错误,与这个问题的主题分开;我已经改正了。

相关内容