Recently I've simply been trying to learn some Assembly and I figured Nasm would be a good choice since I am more used to its intel_syntax. Anyways, after deliberately trying to find some example programs for 64-bit Windows, I found this SO post and attempted to use the code provided by the 2nd answer. The only thing is that the code was for x86 windows which is not my target platform. So I attempted to write the program for 64-bit Windows (Note the word attempted). I am fairly new to Assembly so my code is most likely not correct and I would appreciate it if anyone would point out such errors.
The problem I have encountered, however, is with linking. For some reason, when I try to link the object file, the gcc linker cannot the resolve the external symbols (i.e. The winapi functions) and I cannot figure out why it is doing that.
Here is my code (I commented every line so that I could try to understand what the program is doing but please feel free to edit this post and change anything if it is wrong).
section .text ;Section of the src file that contains the actual runtime code
global WinMain@16 ;Makes the address WinMain global. @16 signifies 16 bytes of parameters
extern _GetStdHandle@4 ;Assures compiler of an external definition of the declared function 'GetStdHandle()'
extern _WriteFile@36 ;Assures compiler of an external definition of the declared function 'WriteFile()'
extern _ExitProcess@4 ;Assures compiler of an external definition of the declared function 'ExitProcess()'
WinMain@16: ;Label marking the entry-point of the program (Windows expects 'WinMain' unless explicitly specified)
mov rbp, rsp ;Move Stack Pointer value equal to Base Pointer
sub rsp, 4 ;Move Stack Pointer back (i.e. subtract) 4 bytes to store DWORD '-11' (defined by 'STD_OUTPUT_HANDLE')
push -11 ;Push '-11' into stack
call _GetStdHandle@4 ;Calls GetStdHandle(-11) since -11 has been pushed. @4 signifies 4 bytes of parameters
mov rbx, rax ;rax stores return value -> move that value to rbx
push 0 ;Push 0 (NULL) onto the stack (This is the last argument in the function)
lea rax, [rbp - 4] ;Store address of DWORD in rax register (4 byte value, 8 byte pointer)
push rax ;Push address of DWORD as the next parameter
push (msg_end - msg) ;Push number of bytes to write (3rd parameter)
push msg ;Push pointer to constant data bytes (2nd parameter)
push rbx ;Push value stored in 'rbx' (The HANDLE) into the 1st parameter
call _WriteFile@36 ;Calls WriteFile(hStdOut, msg, msg_len, bytes_written, NULL). @36 signifies 36 bytes of parameters
push 0 ;Push 0 onto the stack (parameter)
call _ExitProcess@4 ;Calls ExitProcess(0) and ends the program. @4 signifies 4 bytes of parameters
; ---- << Nothing gets called a beyond this line >> ---- ;
hlt ;I have no clue why you need to halt here
msg: ;Label marking the start of the message
db "Hey world", 10 ;Actual data, (db = define bytes). "Hey world" and 10 (new-line character)
msg_end: ;Label marking the end of the message
To compile, I run the following
nasm -f win64 Main.asm -o Main.bin
and to link I run this and get the following output...
gcc -o Hello.exe Main.o
bin/Main.o:src/Main.asm:(.text+0xa): undefined reference to `_GetStdHandle@4'
bin/Main.o:src/Main.asm:(.text+0x21): undefined reference to `_WriteFile@36'
bin/Main.o:src/Main.asm:(.text+0x28): undefined reference to `_ExitProcess@4'
collect2.exe: error: ld returned 1 exit status
As you can see, it can't link to the external functions, what's interesting is that it works perfectly fine when I try to call 'c' functions such as 'puts'
Anyways, if you could help me out here and point out any errors in my code I would greatly appreciate it.