How do I install asm on Windows [duplicate] - windows

I wanted to write something basic in assembly under Windows. I'm using NASM, but I can't get anything working.
How do I write and compile a hello world program without the help of C functions on Windows?

This example shows how to go directly to the Windows API and not link in the C Standard Library.
global _main
extern _GetStdHandle#4
extern _WriteFile#20
extern _ExitProcess#4
section .text
_main:
; DWORD bytes;
mov ebp, esp
sub esp, 4
; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle#4
mov ebx, eax
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
lea eax, [ebp-4]
push eax
push (message_end - message)
push message
push ebx
call _WriteFile#20
; ExitProcess(0)
push 0
call _ExitProcess#4
; never here
hlt
message:
db 'Hello, World', 10
message_end:
To compile, you'll need NASM and LINK.EXE (from Visual studio Standard Edition)
nasm -fwin32 hello.asm
link /subsystem:console /nodefaultlib /entry:main hello.obj

NASM examples.
Calling libc stdio printf, implementing int main(){ return printf(message); }
; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits. It needs to be linked with a C library.
; ----------------------------------------------------------------------------
global _main
extern _printf
section .text
_main:
push message
call _printf
add esp, 4
ret
message:
db 'Hello, World', 10, 0
Then run
nasm -fwin32 helloworld.asm
gcc helloworld.obj
a
There's also The Clueless Newbies Guide to Hello World in Nasm without the use of a C library. Then the code would look like this.
16-bit code with MS-DOS system calls: works in DOS emulators or in 32-bit Windows with NTVDM support. Can't be run "directly" (transparently) under any 64-bit Windows, because an x86-64 kernel can't use vm86 mode.
org 100h
mov dx,msg
mov ah,9
int 21h
mov ah,4Ch
int 21h
msg db 'Hello, World!',0Dh,0Ah,'$'
Build this into a .com executable so it will be loaded at cs:100h with all segment registers equal to each other (tiny memory model).
Good luck.

These are Win32 and Win64 examples using Windows API calls. They are for MASM rather than NASM, but have a look at them. You can find more details in this article.
This uses MessageBox instead of printing to stdout.
Win32 MASM
;---ASM Hello World Win32 MessageBox
.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
.data
title db 'Win32', 0
msg db 'Hello World', 0
.code
Main:
push 0 ; uType = MB_OK
push offset title ; LPCSTR lpCaption
push offset msg ; LPCSTR lpText
push 0 ; hWnd = HWND_DESKTOP
call MessageBoxA
push eax ; uExitCode = MessageBox(...)
call ExitProcess
End Main
Win64 MASM
;---ASM Hello World Win64 MessageBox
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
.data
title db 'Win64', 0
msg db 'Hello World!', 0
.code
main proc
sub rsp, 28h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, msg ; LPCSTR lpText
lea r8, title ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
add rsp, 28h
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
main endp
End
To assemble and link these using MASM, use this for 32-bit executable:
ml.exe [filename] /link /subsystem:windows
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main
or this for 64-bit executable:
ml64.exe [filename] /link /subsystem:windows
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
Why does x64 Windows need to reserve 28h bytes of stack space before a call? That's 32 bytes (0x20) of shadow space aka home space, as required by the calling convention. And another 8 bytes to re-align the stack by 16, because the calling convention requires RSP be 16-byte aligned before a call. (Our main's caller (in the CRT startup code) did that. The 8-byte return address means that RSP is 8 bytes away from a 16-byte boundary on entry to a function.)
Shadow space can be used by a function to dump its register args next to where any stack args (if any) would be. A system call requires 30h (48 bytes) to also reserve space for r10 and r11 in addition to the previously mentioned 4 registers. But DLL calls are just function calls, even if they're wrappers around syscall instructions.
Fun fact: non-Windows, i.e. the x86-64 System V calling convention (e.g. on Linux) doesn't use shadow space at all, and uses up to 6 integer/pointer register args, and up to 8 FP args in XMM registers.
Using MASM's invoke directive (which knows the calling convention), you can use one ifdef to make a version of this which can be built as 32-bit or 64-bit.
ifdef rax
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
else
.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
endif
.data
caption db 'WinAPI', 0
text db 'Hello World', 0
.code
main proc
invoke MessageBoxA, 0, offset text, offset caption, 0
invoke ExitProcess, eax
main endp
end
The macro variant is the same for both, but you won't learn assembly this way. You'll learn C-style asm instead. invoke is for stdcall or fastcall while cinvoke is for cdecl or variable argument fastcall. The assembler knows which to use.
You can disassemble the output to see how invoke expanded.

To get an .exe with NASM as the assembler and Visual Studio's linker this code works fine:
default rel ; Use RIP-relative addressing like [rel msg] by default
global WinMain
extern ExitProcess ; external functions in system libraries
extern MessageBoxA
section .data
title: db 'Win64', 0
msg: db 'Hello world!', 0
section .text
WinMain:
sub rsp, 28h ; reserve shadow space and make RSP%16 == 0
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx,[msg] ; LPCSTR lpText
lea r8,[title] ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
mov ecx,eax ; exit status = return value of MessageBoxA
call ExitProcess
add rsp, 28h ; if you were going to ret, restore RSP
hlt ; privileged instruction that crashes if ever reached.
If this code is saved as test64.asm, then to assemble:
nasm -f win64 test64.asm
Produces test64.obj
Then to link from command prompt:
path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no
where path_to_link could be C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin or wherever is your link.exe program in your machine,
path_to_libs could be C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64 or wherever are your libraries (in this case both kernel32.lib and user32.lib are on the same place, otherwise use one option for each path you need) and the /largeaddressaware:no option is necessary to avoid linker's complain about addresses to long (for user32.lib in this case).
Also, as it is done here, if Visual's linker is invoked from command prompt, it is necessary to setup the environment previously (run once vcvarsall.bat and/or see MS C++ 2010 and mspdb100.dll).
(Using default rel makes the lea instructions work from anywhere, including outside the low 2GiB of virtual address space. But the call MessageBoxA is still a direct call rel32 that can only reach instructions +-2GiB away from itself.)

Flat Assembler does not need an extra linker. This makes assembler programming quite easy. It is also available for Linux.
This is hello.asm from the Fasm examples:
include 'win32ax.inc'
.code
start:
invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
invoke ExitProcess,0
.end start
Fasm creates an executable:
>fasm hello.asm
flat assembler version 1.70.03 (1048575 kilobytes memory)
4 passes, 1536 bytes.
And this is the program in IDA:
You can see the three calls: GetCommandLine, MessageBox and ExitProcess.

If you want to use NASM and Visual Studio's linker (link.exe) with anderstornvig's Hello World example you will have to manually link with the C Runtime Libary that contains the printf() function.
nasm -fwin32 helloworld.asm
link.exe helloworld.obj libcmt.lib
Hope this helps someone.

Unless you call some function this is not at all trivial. (And, seriously, there's no real difference in complexity between calling printf and calling a win32 api function.)
Even DOS int 21h is really just a function call, even if its a different API.
If you want to do it without help you need to talk to your video hardware directly, likely writing bitmaps of the letters of "Hello world" into a framebuffer. Even then the video card is doing the work of translating those memory values into DisplayPort/HDMI/DVI/VGA signals.
Note that, really, none of this stuff all the way down to the hardware is any more interesting in ASM than in C. A "hello world" program boils down to a function call. One nice thing about ASM is that you can use any ABI you want fairly easily; you just need to know what that ABI is.

The best examples are those with fasm, because fasm doesn't use a linker, which hides the complexity of windows programming by another opaque layer of complexity.
If you're content with a program that writes into a gui window, then there is an example for that in fasm's example directory.
If you want a console program, that allows redirection of standard in and standard out that is also possible.
There is a (helas highly non-trivial) example program available that doesn't use a gui, and works strictly with the console, that is fasm itself. This can be thinned out to the essentials. (I've written a forth compiler which is another non-gui example, but it is also non-trivial).
Such a program has the following command to generate a proper header for 32-bit executable, normally done by a linker.
FORMAT PE CONSOLE
A section called '.idata' contains a table that helps windows during startup to couple names of functions to the runtimes addresses. It also contains a reference to KERNEL.DLL which is the Windows Operating System.
section '.idata' import data readable writeable
dd 0,0,0,rva kernel_name,rva kernel_table
dd 0,0,0,0,0
kernel_table:
_ExitProcess#4 DD rva _ExitProcess
CreateFile DD rva _CreateFileA
...
...
_GetStdHandle#4 DD rva _GetStdHandle
DD 0
The table format is imposed by windows and contains names that are looked up in system files, when the program is started. FASM hides some of the
complexity behind the rva keyword. So _ExitProcess#4 is a fasm label and _exitProcess is a string that is looked up by Windows.
Your program is in section '.text'. If you declare that section readable writeable and executable, it is the only section you need to add.
section '.text' code executable readable writable
You can call all the facilities you declared in the .idata section. For a console program you need _GetStdHandle to find he filedescriptors for standard in and standardout (using symbolic names like STD_INPUT_HANDLE which fasm finds in the include file win32a.inc).
Once you have the file descriptors you can do WriteFile and ReadFile.
All functions are described in the kernel32 documentation. You are probably aware of that or you wouldn't try assembler programming.
In summary: There is a table with asci names that couple to the windows OS.
During startup this is transformed into a table of callable addresses, which you use in your program.

For ARM Windows:
AREA data, DATA
Text DCB "Hello world(text)", 0x0
Caption DCB "Hello world(caption)", 0x0
EXPORT WinMainCRTStartup
IMPORT __imp_MessageBoxA
IMPORT __imp_ExitProcess
AREA text, CODE
WinMainCRTStartup PROC
movs r3,#0
ldr r2,Caption_ptr
ldr r1,Text_ptr
movs r0,#0
ldr r4,MessageBoxA_ptr # nearby, reachable with PC-relative
ldr r4,[r4]
blx r4
movs r0,#0
ldr r4,ExitProcess_ptr
ldr r4,[r4]
blx r4
MessageBoxA_ptr DCD __imp_MessageBoxA # literal pool (constants near code)
ExitProcess_ptr DCD __imp_ExitProcess
Text_ptr DCD Text
Caption_ptr DCD Caption
ENDP
END

Related

Assembler MASM (64-bit) does not recognize the entry point and throws an error

I am studying assembler for the x86 family of processor architectures (32-bit and 64-bit) on Windows. It is not to say that I'm quite a beginner, but I probably don't know everything, at least about the syntax of the MASM assembler, as it seems.
I use the MASM assembler (for 64-bit programs) located in folders belonging to Visual Studio:
"..\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\ml64.exe"
Visual Studio 2019 is installed, and I use the MASM assembler from its folder. I have Windows 7 myself.
I made my program for a 32-bit system, and it was normally assembled by MASM for 32-bit programs and worked. Then I translated its code for a 64-bit architecture (and there are a few changes needed in the code there). But, when assembling it with MASM for 64-bit programs, MASM gave an error message that there was allegedly some unresolved "StartOfProgram" symbol. Here's what's in the console:
C:\Assembler>cd "C:\Assembler"
C:\Assembler>"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\ml64.exe" "C:\Assembler\Main.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:\Assembler\Main.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
I spent about two weeks or month searching for solution to this error, but I didn't find it.
In general, it used to give an error message that allegedly there is some unresolved symbol "WinMainCRTStartup", but recently I kind of realized that it made such an entry point, because I did not explicitly specify entry point in the console (via the command "/entry:", which is in the console from above), but the problem about "unresolved external symbol" remained, even though I set the entry point where I needed it (that is, on "StartOfProgram").
Here is the code of my 64-bit version of the program that just has to output "Hello world" in a pop-up window:
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 Kits\10\Lib\10.0.19041.0\um\x64\kernel32.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
Here is the code of my 32-bit version of this program (which was normally assembled and worked):
.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 Kits\10\Lib\10.0.19041.0\um\x86\kernel32.lib" ; Downloading main static library to use main functions of Windows API
;includelib "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x86\User32.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
And here is result of 32-bit version of program:
Result of 32-bit version of program
The problem was been solved in comments. As said by #Peter Cordes and #David Wohlferd, I needed to publish my label in my program by directive "public" and then writing the name of the label, or rewrite my entry-point-label with using directive "proc" and "endp" with name of label at beginning of this directives.
I prefer a solution through the "public" directive, because I think it is closer to low-level programming. In this case, I had to make my label public in my program using the "public" directive, and then write the name of the label at the end of it, to become available to external programs. The MASM assembler, apparently, gave an error due to fact that it did not see it accessible from the outside and therefore did not consider it correct to assign it as the entry point, although it could guess that if I specify it as entry point, then it is available for switching to it from the outside. Apparently, the developers of MASM didn't do this.
Here is an example of using directive "public" in my program (I used directive "public"):
public StartOfProgram
And I noticed that I can put it anywhere in my code.
Here is an example of using directive "proc" and "endp" in my program:
StartOfProgram proc ; - Beginning of this directivical procedure
; ... there may be the code itself inside this directivical procedure
StartOfProgram endp ; - End of this directivical procedure
My code in the question had other errors, separate from the theme of this question; I've corrected it there.

Interruption service in assembler (int 21h) and it's behavior (w/OllyDbg) [duplicate]

I wanted to write something basic in assembly under Windows. I'm using NASM, but I can't get anything working.
How do I write and compile a hello world program without the help of C functions on Windows?
This example shows how to go directly to the Windows API and not link in the C Standard Library.
global _main
extern _GetStdHandle#4
extern _WriteFile#20
extern _ExitProcess#4
section .text
_main:
; DWORD bytes;
mov ebp, esp
sub esp, 4
; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle#4
mov ebx, eax
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
lea eax, [ebp-4]
push eax
push (message_end - message)
push message
push ebx
call _WriteFile#20
; ExitProcess(0)
push 0
call _ExitProcess#4
; never here
hlt
message:
db 'Hello, World', 10
message_end:
To compile, you'll need NASM and LINK.EXE (from Visual studio Standard Edition)
nasm -fwin32 hello.asm
link /subsystem:console /nodefaultlib /entry:main hello.obj
NASM examples.
Calling libc stdio printf, implementing int main(){ return printf(message); }
; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits. It needs to be linked with a C library.
; ----------------------------------------------------------------------------
global _main
extern _printf
section .text
_main:
push message
call _printf
add esp, 4
ret
message:
db 'Hello, World', 10, 0
Then run
nasm -fwin32 helloworld.asm
gcc helloworld.obj
a
There's also The Clueless Newbies Guide to Hello World in Nasm without the use of a C library. Then the code would look like this.
16-bit code with MS-DOS system calls: works in DOS emulators or in 32-bit Windows with NTVDM support. Can't be run "directly" (transparently) under any 64-bit Windows, because an x86-64 kernel can't use vm86 mode.
org 100h
mov dx,msg
mov ah,9
int 21h
mov ah,4Ch
int 21h
msg db 'Hello, World!',0Dh,0Ah,'$'
Build this into a .com executable so it will be loaded at cs:100h with all segment registers equal to each other (tiny memory model).
Good luck.
These are Win32 and Win64 examples using Windows API calls. They are for MASM rather than NASM, but have a look at them. You can find more details in this article.
This uses MessageBox instead of printing to stdout.
Win32 MASM
;---ASM Hello World Win32 MessageBox
.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
.data
title db 'Win32', 0
msg db 'Hello World', 0
.code
Main:
push 0 ; uType = MB_OK
push offset title ; LPCSTR lpCaption
push offset msg ; LPCSTR lpText
push 0 ; hWnd = HWND_DESKTOP
call MessageBoxA
push eax ; uExitCode = MessageBox(...)
call ExitProcess
End Main
Win64 MASM
;---ASM Hello World Win64 MessageBox
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
.data
title db 'Win64', 0
msg db 'Hello World!', 0
.code
main proc
sub rsp, 28h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, msg ; LPCSTR lpText
lea r8, title ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
add rsp, 28h
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
main endp
End
To assemble and link these using MASM, use this for 32-bit executable:
ml.exe [filename] /link /subsystem:windows
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Main
or this for 64-bit executable:
ml64.exe [filename] /link /subsystem:windows
/defaultlib:kernel32.lib /defaultlib:user32.lib /entry:main
Why does x64 Windows need to reserve 28h bytes of stack space before a call? That's 32 bytes (0x20) of shadow space aka home space, as required by the calling convention. And another 8 bytes to re-align the stack by 16, because the calling convention requires RSP be 16-byte aligned before a call. (Our main's caller (in the CRT startup code) did that. The 8-byte return address means that RSP is 8 bytes away from a 16-byte boundary on entry to a function.)
Shadow space can be used by a function to dump its register args next to where any stack args (if any) would be. A system call requires 30h (48 bytes) to also reserve space for r10 and r11 in addition to the previously mentioned 4 registers. But DLL calls are just function calls, even if they're wrappers around syscall instructions.
Fun fact: non-Windows, i.e. the x86-64 System V calling convention (e.g. on Linux) doesn't use shadow space at all, and uses up to 6 integer/pointer register args, and up to 8 FP args in XMM registers.
Using MASM's invoke directive (which knows the calling convention), you can use one ifdef to make a version of this which can be built as 32-bit or 64-bit.
ifdef rax
extrn MessageBoxA: PROC
extrn ExitProcess: PROC
else
.386
.model flat, stdcall
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib
endif
.data
caption db 'WinAPI', 0
text db 'Hello World', 0
.code
main proc
invoke MessageBoxA, 0, offset text, offset caption, 0
invoke ExitProcess, eax
main endp
end
The macro variant is the same for both, but you won't learn assembly this way. You'll learn C-style asm instead. invoke is for stdcall or fastcall while cinvoke is for cdecl or variable argument fastcall. The assembler knows which to use.
You can disassemble the output to see how invoke expanded.
To get an .exe with NASM as the assembler and Visual Studio's linker this code works fine:
default rel ; Use RIP-relative addressing like [rel msg] by default
global WinMain
extern ExitProcess ; external functions in system libraries
extern MessageBoxA
section .data
title: db 'Win64', 0
msg: db 'Hello world!', 0
section .text
WinMain:
sub rsp, 28h ; reserve shadow space and make RSP%16 == 0
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx,[msg] ; LPCSTR lpText
lea r8,[title] ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA
mov ecx,eax ; exit status = return value of MessageBoxA
call ExitProcess
add rsp, 28h ; if you were going to ret, restore RSP
hlt ; privileged instruction that crashes if ever reached.
If this code is saved as test64.asm, then to assemble:
nasm -f win64 test64.asm
Produces test64.obj
Then to link from command prompt:
path_to_link\link.exe test64.obj /subsystem:windows /entry:WinMain /libpath:path_to_libs /nodefaultlib kernel32.lib user32.lib /largeaddressaware:no
where path_to_link could be C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin or wherever is your link.exe program in your machine,
path_to_libs could be C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64 or wherever are your libraries (in this case both kernel32.lib and user32.lib are on the same place, otherwise use one option for each path you need) and the /largeaddressaware:no option is necessary to avoid linker's complain about addresses to long (for user32.lib in this case).
Also, as it is done here, if Visual's linker is invoked from command prompt, it is necessary to setup the environment previously (run once vcvarsall.bat and/or see MS C++ 2010 and mspdb100.dll).
(Using default rel makes the lea instructions work from anywhere, including outside the low 2GiB of virtual address space. But the call MessageBoxA is still a direct call rel32 that can only reach instructions +-2GiB away from itself.)
Flat Assembler does not need an extra linker. This makes assembler programming quite easy. It is also available for Linux.
This is hello.asm from the Fasm examples:
include 'win32ax.inc'
.code
start:
invoke MessageBox,HWND_DESKTOP,"Hi! I'm the example program!",invoke GetCommandLine,MB_OK
invoke ExitProcess,0
.end start
Fasm creates an executable:
>fasm hello.asm
flat assembler version 1.70.03 (1048575 kilobytes memory)
4 passes, 1536 bytes.
And this is the program in IDA:
You can see the three calls: GetCommandLine, MessageBox and ExitProcess.
If you want to use NASM and Visual Studio's linker (link.exe) with anderstornvig's Hello World example you will have to manually link with the C Runtime Libary that contains the printf() function.
nasm -fwin32 helloworld.asm
link.exe helloworld.obj libcmt.lib
Hope this helps someone.
Unless you call some function this is not at all trivial. (And, seriously, there's no real difference in complexity between calling printf and calling a win32 api function.)
Even DOS int 21h is really just a function call, even if its a different API.
If you want to do it without help you need to talk to your video hardware directly, likely writing bitmaps of the letters of "Hello world" into a framebuffer. Even then the video card is doing the work of translating those memory values into DisplayPort/HDMI/DVI/VGA signals.
Note that, really, none of this stuff all the way down to the hardware is any more interesting in ASM than in C. A "hello world" program boils down to a function call. One nice thing about ASM is that you can use any ABI you want fairly easily; you just need to know what that ABI is.
The best examples are those with fasm, because fasm doesn't use a linker, which hides the complexity of windows programming by another opaque layer of complexity.
If you're content with a program that writes into a gui window, then there is an example for that in fasm's example directory.
If you want a console program, that allows redirection of standard in and standard out that is also possible.
There is a (helas highly non-trivial) example program available that doesn't use a gui, and works strictly with the console, that is fasm itself. This can be thinned out to the essentials. (I've written a forth compiler which is another non-gui example, but it is also non-trivial).
Such a program has the following command to generate a proper header for 32-bit executable, normally done by a linker.
FORMAT PE CONSOLE
A section called '.idata' contains a table that helps windows during startup to couple names of functions to the runtimes addresses. It also contains a reference to KERNEL.DLL which is the Windows Operating System.
section '.idata' import data readable writeable
dd 0,0,0,rva kernel_name,rva kernel_table
dd 0,0,0,0,0
kernel_table:
_ExitProcess#4 DD rva _ExitProcess
CreateFile DD rva _CreateFileA
...
...
_GetStdHandle#4 DD rva _GetStdHandle
DD 0
The table format is imposed by windows and contains names that are looked up in system files, when the program is started. FASM hides some of the
complexity behind the rva keyword. So _ExitProcess#4 is a fasm label and _exitProcess is a string that is looked up by Windows.
Your program is in section '.text'. If you declare that section readable writeable and executable, it is the only section you need to add.
section '.text' code executable readable writable
You can call all the facilities you declared in the .idata section. For a console program you need _GetStdHandle to find he filedescriptors for standard in and standardout (using symbolic names like STD_INPUT_HANDLE which fasm finds in the include file win32a.inc).
Once you have the file descriptors you can do WriteFile and ReadFile.
All functions are described in the kernel32 documentation. You are probably aware of that or you wouldn't try assembler programming.
In summary: There is a table with asci names that couple to the windows OS.
During startup this is transformed into a table of callable addresses, which you use in your program.
For ARM Windows:
AREA data, DATA
Text DCB "Hello world(text)", 0x0
Caption DCB "Hello world(caption)", 0x0
EXPORT WinMainCRTStartup
IMPORT __imp_MessageBoxA
IMPORT __imp_ExitProcess
AREA text, CODE
WinMainCRTStartup PROC
movs r3,#0
ldr r2,Caption_ptr
ldr r1,Text_ptr
movs r0,#0
ldr r4,MessageBoxA_ptr # nearby, reachable with PC-relative
ldr r4,[r4]
blx r4
movs r0,#0
ldr r4,ExitProcess_ptr
ldr r4,[r4]
blx r4
MessageBoxA_ptr DCD __imp_MessageBoxA # literal pool (constants near code)
ExitProcess_ptr DCD __imp_ExitProcess
Text_ptr DCD Text
Caption_ptr DCD Caption
ENDP
END

How to write text to console with 64-bit assembler with modern Windows 10 updates?

I've found a number of 64-bit assembler "Hello World" tutorials online for Windows, but none of them appear to work on my machine with the latest Windows 10 updates. In particular, ExitProcess continues to work, but WriteFile and WriteConsoleA silently fail.
Can someone describe the new ABI for this system call, or provide a fully qualified nasm/yasm example for _write, write, fprintf, printf, or similar functions with a more stable interface? (I am not interested in MessageBoxA or other graphical functions at the moment.) Please note any DLL's required aside from kernel32.dll, msvcrt.dll that declare these external functions.
In the given example you should use 64-bit space for variables stdout and bytesWritten:
stdout dq 0
bytesWritten dq 0
or else saved data in stdout will be overwritten by WriteFile function.
Also you should restore stack after calling WriteFile function:
add rsp,8
or it'll stay corrupt.
Evidently the online 64-bit Windows assembler tutorials do work, however, critical linker flags /entry and /[subsystem:]console were being mangled by Git Bash. So I've adopted the protection of wrapping the linker call in a PowerShell call, to ensure that the linker (either golink or link.exe) uses the correct mode, console, no matter which shell environment is running the linker command.
vsexec.bat:
:: Execute the specified command within a Visual Studio context,
:: where the necessary environment variables are sufficiently configured.
::
:: Usage: vsexec.bat <command>
::
:: Requires a Command Prompt or PowerShell context to operate.
call "C:\\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 %*
hello.asm:
extern GetStdHandle
extern WriteFile
extern ExitProcess
section .rodata
msg db "Hello World!", 0x0d, 0x0a
msg_len equ $-msg
stdout_query equ -11
status equ 0
section .data
stdout dw 0
bytesWritten dw 0
section .text
global start
start:
mov rcx, stdout_query
call GetStdHandle
mov [rel stdout], rax
mov rcx, [rel stdout]
mov rdx, msg
mov r8, msg_len
mov r9, bytesWritten
push qword 0
call WriteFile
mov rcx, status
call ExitProcess
Build steps:
$ nasm -f win64 hello.asm
$ powershell -Command "~\\vsexec.bat link /entry:start /subsystem:console hello.obj kernel32.lib"
Trace:
$ hello.exe
Hello World!
Final notes: I'm not sure what the exact proper stack and return policy is. The Windows documentation suggests that the stack be A) aligned to 16 bytes, B) provide 32 bytes per Windows API call, C) perform a ret at the end of each subroutine. However, when I try to do this, then I get segfaults. Not sure if nasm/link.exe are automatically performing some of the stack management work on my behalf or what, I guess I could check objdump -xDz hello.exe output to examine this further.

There is an assembly code written for Windows API, how to compile it on Linux and run with Wine

There is an example code in this introduction, like below:
; Sample x64 Assembly Program
; Chris Lomont 2009 www.lomont.org
extrn ExitProcess: PROC ; external functions in system libraries
extrn MessageBoxA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
sub rsp,28h ; shadow space, aligns stack
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, message ; LPCSTR lpText
lea r8, caption ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA ; call MessageBox API function
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
Start ENDP
End
The above code is inside hello.asm and on Windows, it can be compiled with:
ml64 hello.asm /link /subsystem:windows /defaultlib:kernel32.lib /defaultlib:user32.lib /entry:Start
I don't have access to Windows and MASM, since I'm on Linux and work with NASM. I think if I compile the code on Linux, I would be able to run it with Wine. But yet, I couldn't figure out how to compile it with NASM on Linux and also I couln't figure out what are the NASM options which are equivalent to the MASM ones. Can anybody help me?
You should have been able to find a nasm syntax hello world. Anyway, here is a quick transcription:
extern ExitProcess
extern MessageBoxA
section .data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
section .text
sub rsp,28h ; shadow space, aligns stack
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, [message] ; LPCSTR lpText
lea r8, [caption] ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
call MessageBoxA ; call MessageBox API function
mov ecx, eax ; uExitCode = MessageBox(...)
call ExitProcess
Assemble using nasm -f win64 hello.asm. You will also need a linker, I used the mingw port as ld hello.obj -lkernel32 -luser32 (let me emphasize this is not the native ld)
Although package names vary from Linux distro to distro, you can do what you are suggesting by installing (or building from source) a mingw-w64 tool chain and the program JWASM. JWASM is a an assembler that is mostly compatible with MASM.
On Debian based distros (including Ubuntu) you should be able to install the prerequisites with:
apt-get install mingw-w64-x86-64-dev binutils-mingw-w64-x86-64 jwasm
With Ubuntu based systems you'll need to prepend the command above with sudo.
You should then be able to assemble and link using something like:
jwasm -win64 hello.asm
x86_64-w64-mingw32-ld hello.o -lkernel32 -luser32 -o hello.exe
The executable should be runnable using wine64

Hello world using nasm in windows assembly

I'm using nasm to compile the following assembly. However the code crashes in the console under Windows.
C:\>nasm -f win32 test.asm -o test.o
C:\>ld test.o -o test.exe
section .data
msg db 'Hello world!', 0AH
len equ $-msg
section .text
global _WinMain#16
_WinMain#16:
mov edx, len
mov ecx, msg
mov ebx, 1
mov eax, 4
int 80h
mov ebx, 0
mov eax, 1
int 80h
According to this post. The main function is not available under Windows and must be replaced by WinMain.
So if your entry point is _start or main, it should be changed to _WinMain#16 and change the ret at the end of the procedure to ret 16:
My working example:
section .text
global _WinMain#16
_WinMain#16:
mov eax, 0
ret 16
The biggest problem is that you are trying to use Linux interupts on windows!
int 80 will NOT work on windows.
We are using Assembly, so your entry point can be ANY label you want. The standard entry point that ld looks for is _start, if you want to use another label, you need to tell ld with the -e option
So if you want your start label to be main, then you need
global main
ld -e main test.o -o test.exe
If you are going to use NASM on Windows, I will recommend using GoLink as your linker.
Here is a simple windows console app:
STD_OUTPUT_HANDLE equ -11
NULL equ 0
global GobleyGook
extern ExitProcess, GetStdHandle, WriteConsoleA
section .data
msg db "Hello World!", 13, 10, 0
msg.len equ $ - msg
section .bss
dummy resd 1
section .text
GobleyGook:
push STD_OUTPUT_HANDLE
call GetStdHandle
push NULL
push dummy
push msg.len
push msg
push eax
call WriteConsoleA
push NULL
call ExitProcess
makefile:
hello: hello.obj
GoLink.exe /console /entry GobleyGook hello.obj kernel32.dll
hello.obj: hello.asm
nasm -f win32 hello.asm -o hello.obj
Although, this same program probably will run in WINE on Linux like a charm. :)
WINE doesn't prevent using Linux system calls from inside Windows PE binaries; the machine instructions run natively and WINE only provides DLL functions.

Resources