The following code works when i set the 'debug' to 'x86'
.386
.model flat, stdcall
.stack 4096
ExitProcess PROTO, dwExitCode: DWORD
.data
; define your variables here
.code
main PROC
; write your assembly code herer
mov eax ,3
mov ebx ,8
add eax, ebx
INVOKE ExitProcess ,0
main ENDP
END main
But does not work when i change 'x86' to 'x64'
it also fails if i try to use '64bit' register like rax
First, please take a look at my article "How to build a x64/x86-project with a standalone x64/x86 assembly file".
Let's go through the error messages one by one (you can move the cursor to the errorneous line by double-clicking the error message):
A2008 syntax error : . test main.asm 1
The directive .386 is only allowed in 32-bit MASM (ML.EXE). It is not allowed in ML64 (ML64.EXE). ML64 "knows" all instructions which it can know.
A2008 syntax error : . test main.asm 2
The directive .MODEL is only allowed in 32-bit MASM (ML.EXE). It is not allowed in ML64 (ML64.EXE). ML64 uses by default the flat model and the x64 calling convention (not C, BASIC, FORTRAN, PASCAL, SYSCALL or STDCALL).
A2008 syntax error : . test main.asm 3
The directive .STACK is a relic from the MS-DOS era. It's useless if you assemble with ML for Windows (Take a look here). It's not allowed in ML64.
A2008 syntax error : , test main.asm 4
In the directive PROTO, ML64 doesn't like the comma between the PROTO keyword and the first parameter. Remove it.
A2008 syntax error : INVOKE test main.asm 16
The directive INVOKE isn't allowed in ML64 (yet). Replace INVOKE by a CALL and fill in the registers according to the Microsoft x64 calling convention:
mov ecx, 0
call ExitProcess
A2008 syntax error : main test main.asm 18
A2088 END directive required at end of file test main.asm 18
The directive END must not contain an additional entry point for ML64. Remove "main". This also eliminates the second error. Set the entry point in the Visual Studio linker options according to my article.
Related
Having such a simple assembly Win 32 program:
.386
.model flat, stdcall
option casemap :none
EXTERN printf :PROC ; declare printf
.data
HelloWorld db "Hello Wolrd!:-)", 0
.code
start:
sub esp, 4
push offset HelloWorld
call printf
add esp, 4
ret
end start
I can successfully compile it by just:
ml.exe /c HelloWorld.asm
BUT have a problem linking it. When I use:
link HelloWorld.obj libcmt.lib
I'm getting an error:
unresolved external symbol _main called in _mainCRTStartup
What have I change/correct to to successfully link the program to run it?
P.S.
Please don't tell me to use just nasm. I'd like to use ml & link from my MSVC.
With some minor tweaks this now builds correctly.
.386
.model flat, c
option casemap :none
includelib libcmt.lib
includelib legacy_stdio_definitions.lib
EXTERN printf :PROC ; declare printf
.data
HelloWorld db "Hello World!:-)", 0
.code
main PROC
push offset HelloWorld
call printf
add esp, 4
ret
main ENDP
END
The main edits are
.model flat, c sets the calling conventions for procedures to C.
If you decide to keep .model flat, stdcall it'll require these changes.
Replace
EXTERN printf :PROC
main PROC
with
printf PROTO NEAR C,:DWORD
main PROC NEAR C
Included libcmt.lib and legacy_stdio_definitions.lib which statically links the native C-Runtime startup into your code.
Changed entry point from start to main. There's an entry point (_mainCRTStartup) within the C-Runtime library (CRT) libcmt.lib, which does some initialization tasks, and then hands off control to the entry point for your application main. You can change the default entry point, but usually you want the convenience of the initialization the CRT entry point does for you automatically.
Removed the first sub esp,4 so the remaining one push is balanced by the add esp,4, so ESP is pointing at the return address when ret runs.
To build, open a Windows command prompt and run:
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars32.bat"
to set the MSVC Environment initialized for: 'x86'
Next, run these MASM commands
ml.exe /c /coff HelloWorld.asm
link.exe /SUBSYSTEM:console HelloWorld.obj
The program displays
Hello World!:-)
Your error message says that it can't find the exported symbol (i.e. function) "_main". I expect renaming your start function to _main would get it to compile.
Having such a simple assembly Win 32 program:
.386
.model flat, stdcall
option casemap :none
EXTERN printf :PROC ; declare printf
.data
HelloWorld db "Hello Wolrd!:-)", 0
.code
start:
sub esp, 4
push offset HelloWorld
call printf
add esp, 4
ret
end start
I can successfully compile it by just:
ml.exe /c HelloWorld.asm
BUT have a problem linking it. When I use:
link HelloWorld.obj libcmt.lib
I'm getting an error:
unresolved external symbol _main called in _mainCRTStartup
What have I change/correct to to successfully link the program to run it?
P.S.
Please don't tell me to use just nasm. I'd like to use ml & link from my MSVC.
With some minor tweaks this now builds correctly.
.386
.model flat, c
option casemap :none
includelib libcmt.lib
includelib legacy_stdio_definitions.lib
EXTERN printf :PROC ; declare printf
.data
HelloWorld db "Hello World!:-)", 0
.code
main PROC
push offset HelloWorld
call printf
add esp, 4
ret
main ENDP
END
The main edits are
.model flat, c sets the calling conventions for procedures to C.
If you decide to keep .model flat, stdcall it'll require these changes.
Replace
EXTERN printf :PROC
main PROC
with
printf PROTO NEAR C,:DWORD
main PROC NEAR C
Included libcmt.lib and legacy_stdio_definitions.lib which statically links the native C-Runtime startup into your code.
Changed entry point from start to main. There's an entry point (_mainCRTStartup) within the C-Runtime library (CRT) libcmt.lib, which does some initialization tasks, and then hands off control to the entry point for your application main. You can change the default entry point, but usually you want the convenience of the initialization the CRT entry point does for you automatically.
Removed the first sub esp,4 so the remaining one push is balanced by the add esp,4, so ESP is pointing at the return address when ret runs.
To build, open a Windows command prompt and run:
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars32.bat"
to set the MSVC Environment initialized for: 'x86'
Next, run these MASM commands
ml.exe /c /coff HelloWorld.asm
link.exe /SUBSYSTEM:console HelloWorld.obj
The program displays
Hello World!:-)
Your error message says that it can't find the exported symbol (i.e. function) "_main". I expect renaming your start function to _main would get it to compile.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a Visual Studio C/C++ project with a single assembly file main.asm in it. During the process of building the project I get the errors:
1>main.asm(5): error A2008: syntax error : .
1>main.asm(6): error A2008: syntax error : .
1>main.asm(7): error A2008: syntax error : .
1>main.asm(8): error A2008: syntax error : ,
1>main.asm(20): error A2008: syntax error : INVOKE
My code for main.asm is:
; program 3.1
; sample Assembly program - MASM (32-bit)
.386 ; Line 5
.MODEL FLAT, stdcall ; Line 6
.STACK 4096 ; Line 7
ExitProcess PROTO, dwExitCode:DWORD ; Line 8
.data
sum DWORD 0
.code
_main PROC
mov eax, 25
mov ebx, 50
add ebx, ebx
mov sum, eax
INVOKE ExitProcess, 0 ; Line 20
_main ENDP
END
A screenshot of Visual Studio with my code and the errors:
Why am I getting these errors and how can I fix them?
Based on the errors you are showing on the line starting with .MODEL, .STACK, and .386 I can only gather that you are building for a 64-bit target rather than a 32-bit target. You likely also received errors related to the INVOKE directive as well. None of these directives are supported by 64-bit MASM and thus are generating errors. In 64-bit code the model is always assumed to be flat and the calling conventions for CDECL, STDCALL, THISCALL, FASTCALL etc are all the same and follow the Windows 64-bit Calling Convention.
You have two choices:
Build a 32-bit application. In Visual Studio as part of the menu bars there is a pull down box for the platform. The platform can be adjusted in the toolbar by changing x64 to x86:
Modify the code to work with 64-bit code. To build in 64-bit you have to replace INVOKE with CALL and the Windows 64-bit calling convention must be used. You can remove the .STACK, .MODEL, and .386 directives. Modify the definition of the external procedures by declaring them EXTERN with a PROC type. The code could look something like:
; program 3.1
; sample Assembly program - MASM (64-bit)
extern ExitProcess:PROC
public mainCRTStartup
.data
sum DWORD 0
.code
mainCRTStartup PROC ; Use mainCRTStartup if making a CONSOLE app without
; any C/C++ files AND if you haven't overridden the
; ENTRY point in the Visual Studio Project.
sub rsp, 8+32 ; Align stack on 16 byte boundary and allocate 32 bytes
; of shadow space for call to ExitProcess. Shadow space
; is required for 64-bit Windows Calling Convention as
; is ensuring the stack is aligned on a 16 byte boundary
; at the point of making a call to a C library function
; or doing a WinAPI call.
mov eax, 25
mov ebx, 50
add ebx, ebx
mov sum, eax
xor ecx, ecx ; Set Error Code to 0 (RCX is 1st parameter)
call ExitProcess
mainCRTStartup ENDP
END
The entry point may be different for your environment depending on whether you are creating a GUI or CONSOLE application and whether your project has a C/C++ file present.
Function names in the 64-bit calling convention are not required to start with an underscore unlike 32-bit Windows code.
Pretty new to assembly, having fun poking at it. I am wanting to split the functionality of my program across multiple files, specifically by grouping similar functions together for organization. These other files would be called by the main file (and hopefully even other non-main files). I haven't yet managed to do so, and would like help.
I am not using an IDE, preferring to use notepad++, ml.exe, and link.exe (from MASM folder) to write, assemble, and link the program myself. Most online resources I have looked at assume Visual Studio, and give code that doesn't work for me, or maybe is incomplete b/c the IDE does something else. I do not intend to start using an IDE.
I would like to learn the "best" way, meaning, the way that is most useful for future projects. Can I set it up in such a way that I can just copy the file and write a couple lines of code to use it in a different project in the future? Or maybe that's bad practice and I should learn a more standard method instead? I understand this platform is not for opinionated questions, and I'm hoping this question is more factually based than opinion.
All useful info I can think of:
Language: Masm assembly x86
Computer: 64 bit Windows
Code:
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
Driver.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
Utils.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
Terminal output
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 . . .
Now that your question has been updated with a minimal, complete, verifiable example some specific problems can be identified. When you declare a function with PROC there is a language naming and calling convention applied to each function. Not specifying one associates no special processing.
You can specify a default language with the model directive as a second parameter. In both your files you have used:
.model flat
So you haven't associated a default language. You have defined ClearRegs as:
ClearRegs PROC C
[snip]
ClearRegs ENDP
The problem here is that PROC C specifies the C language calling convention and naming convention. With COFF format (32-bit) the C naming convention requires an underscore (_) to be prepended to the beginning of the function name. If you were to generate a MAP file you'd discover that the Function name exported from utils.asm is actually _ClearRegs and not ClearRegs.
There are a number of ways to fix this. You can choose not to add a default language to the .model directive and tell Driver.asm that ClearRegs is defined as a C PROTOtype by changing:
ClearRegs PROTO
to
ClearRegs PROTO C
So now utils.asm is exporting _ClearRegs and Driver.asm is importing _ClearRegs as both sides match and MASM will handle adding the extra underscore. INVOKE ClearRegs will use the naming convention associated with the PROTO statement which says the language is C so it will add the extra _ for you.
This brings up an additional change you can make. An END directive can be used to specify the entry point to your program rather than using /entry:<name> on the linker command line. The entry point has to have a name that starts with an _ to satisfy the linker.
You currently use this in Driver.asm:
PUBLIC _start
_start:
Main PROC
[snip]
Main ENDP
END
And you use /entry:start when linking. You could change this to be:
_Main PROC
[snip]
_Main ENDP
END _Main ; END with a function name tells linker to use _Main as program entry point
When linking you can now remove the /entry option altogether and you don't need the _start label anymore. We can do better though. The entry point called by the MS C Runtime startup assumes the function is following the C language naming and calling convention. What is preferable is to do this:
Main PROC C
[snip]
Main ENDP
END Main ; END with a function name tells linker to use _Main as program entry point
If you intend to make all your functions PROC C then you can avoid specifying C in most places by changing the default language in both Utils.asm and Driver.asm by changing:
.model flat
to:
.model flat, C
This will change the default for PROTO statements, PUBLIC statements specifying a function defined with PROC and PROC statements themselves. Your code in Driver.asm could look like:
.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 could look like:
.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
And you'd link with:
link /debug /subsystem:console /out:Driver.exe Utils.obj Driver.obj \masm32\lib\kernel32.lib
I want to write 16 bit 8086 assembly code in visual studio 2010
but gives me error:
code:
.MODEL small
.STACK 100h
.data
message BYTE "Hello, world!","$"
.code
mov ah,9
mov dx,OFFSET message ; addr of buffer
int 21h
END
output gives me this error:
fm.obj : fatal error LNK1190: invalid fixup found, type 0x0001
I using masm32v11. What should I do?
Where does the Assembler know where the starting address is?
Using Microsoft (R) Segmented Executable Linker Version 5.60.339 Dec 5 1994 (16bit linker)
and added start and end start the code Assembles and links just fine. MASM32 includes a 16bit linker in the bin directory. You must pass different command line parameters to ML to Assemble 16bit code correctly though.
.MODEL small
.STACK 100h
.data
message BYTE "Hello, world!","$"
.code
start:
mov ah,9
mov dx,OFFSET message ; addr of buffer
int 21h
END start
So to recap - your code needs a starting address and an end,
You can use the current ML that comes with MASM32 to Assemble 16 bit and 32 bit code. To link 16 bit code you must use a 16 bit linker, to link 32 bit code, you must use a 32 bit linker.
From one of my 16 bit DOS apps:
ML.EXE /DMASM /DDOS /Zm /c /nologo /I"f:\masm32\Include" "dosdisplay.asm"
link16.exe /NOLOGO "dosdisplay.obj"
Assemble and link with these commands:
ml.exe /omf filename.asm
link16.exe filename.obj
Info:
When you invoke ml.exe without any specific parameters the type of object file that it generates will be in COFF format. COFF format name mangling requires that your code should have a _start and end _start. what you have written will work for Intel's OMF object files.