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.
Related
Having such a simple Win32 assembly program
.386
.model flat, c
option casemap :none
;includelib C:\Users\Darek\Dev\VC\lib\libcmt.lib
;includelib C:\Users\Darek\Dev\VC\lib\legacy_stdio_definitions.lib
EXTERN printf :PROC ; declare printf
.data
HelloWorld db "Hello j World!:-)", 0
.code
main PROC
push offset HelloWorld
call printf
add esp, 4
ret
main ENDP
END
I'd like to change the entry point name from the standard main to say my_start, so I've changed the name of the main function to my_start
...
my_start PROC
...
my_start ENDP
...
and then linked like below
link /ENTRY:my_start /SUBSYSTEM:CONSOLE HelloWorld.obj libcmt.lib
but getting the linker error:
undefined external symbol _main called in _mainCRTStartup
Why does the linker ingres the ENTRY option?
What I'm doing wrong and what to do to get it working?
P.S.
I'm using the ml and link provided with my MSVC 2019
C requires your main program to be called main. That's a restriction imposed by C, not the hardware itself. I've only ever used UASM and x86-16, so I'm not familiar with Win32 syntax, but you might be able to try this:
my_start equ main
(Assuming Win32 has an equ directive that is.)
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.
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.
.386
.model flat, c
.stack 100h
printf PROTO arg1:Ptr Byte
.data
msg1 byte "Hello World!", 0Ah, 0
.code
main proc
INVOKE printf, ADDR msg1
ret
main endp
end main
Hi, I am getting the below errors:
I searched around and found someone said that it can be fixed by linking the microsoft runtime library
Can anyone teach me how can I exactly fix it?
Thanks
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol _printf referenced in function _main testing C:\Users\Kin\Desktop\assembly\testing\testing\Source.obj 1
Error LNK1120 1 unresolved externals testing C:\Users\Kin\Desktop\assembly\testing\Debug\testing.exe 1
I don't have VS 2017 installed to try this. Important: Make sure you create a Console Application and not a Windows Application. Once you create this project make sure MASM is added to the build customizations. Add an .ASM file to your project.
Take your code and insert the following lines at the top:
includelib libcmt.lib
includelib libvcruntime.lib
includelib libucrt.lib
includelib legacy_stdio_definitions.lib
An explanation as to why these lines are needed in Visual Studio later than 2013 can be found in this Stackoverflow Answer.
You want the C runtime to be the entry point to your console application (which in turn will call your main). Because of this you MUST remove main from the last line that says end main. When you do end main it bypasses the C runtime startup startup. Failure to properly initialize the C runtime will likely lead to the program crashing when you make calls like printf. It should simply be end and not end main.
The final code you should test is:
includelib libcmt.lib
includelib libvcruntime.lib
includelib libucrt.lib
includelib legacy_stdio_definitions.lib
.386
.model flat, c
.stack 100h
printf PROTO arg1:Ptr Byte
.data
msg1 byte "Hello World!", 0Ah, 0
.code
main proc
INVOKE printf, ADDR msg1
ret
main endp
end
Since Visual Studio 2015, printf is now "inlined" into C code. The assembly code to get around this would be complicated. I ended up including a small C source file in the project with a unused call to printf to get around this problem. I don't recall if the generated printf code is parameter count dependent. I just use the same or more parameters in the dummy C source code call to printf than what I use in the assembly code.
I was trying writing a simple command line program in assembly using the Win32 API. I wrote the following, got it to compile and link with zero errors or warnings, and started it from a command line, but nothing appeared at the command prompt. Can anyone see what's wrong or what would make it say "Hello World!" at the command line? The program:
; Block 1
.386
.model flat,stdcall
option casemap:none
; Block 2
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
; Block 3
.data
szMsg db "Hello World!",0
nNumToWrite dd 12
; Block 4
.data?
numwritten dd ?
CommandLine LPSTR ?
; Block 5
.code
start:
invoke GetCommandLine
mov CommandLine,eax
invoke WriteConsole,CommandLine,addr szMsg,nNumToWrite,numwritten,NULL
xor eax,eax
invoke ExitProcess,eax
end start
Are you linking it as a console program or as a GUI program? That's a property of an executable in Win32.