My problem is that this: When I try to execute an .exe assembled in NASM and Windows 8 64 bits tells me that this .exe isn't compatible with 64 bits. So, how should I assemble this code (I obtained it from the Web)?
Used code
STD_OUTPUT_HANDLE equ -11
STD_INPUT_HANDLE equ -10
NULL equ 0
global start
extern ExitProcess, GetStdHandle, WriteConsoleA, ReadConsoleInputA
section .data ;message we want to display on console
msg db "Press a key to continue...", 13, 10, 0
msg.len equ $ - msg
consoleInHandle dd 1
section .bss ;buffers declaration
buffer_out resd 2
buffer_in resb 32
section .text
start: ;starting point of our program
push STD_OUTPUT_HANDLE
call GetStdHandle ;call to get a handle to the
push NULL ;specified mode (input, output...)
push buffer_out
push msg.len
push msg
push eax ;contains the GetStdHandle result
call WriteConsoleA ;call to print our msg in console
read:
push STD_INPUT_HANDLE
call GetStdHandle ;new call to get input handle
push NULL
push 1
push buffer_in
push eax
call ReadConsoleInputA ;call to detect user input
;this function will wait til
exit: ;it detects enough keypresses
push NULL ;(in this case, 1)
call ExitProcess
Command used to assemble this:
nasm -fwin32 main.asm -o main.exe
You ran the assembler this way:
nasm -fwin32 main.asm -o main.exe
If you assemble with -fwin32
this will not generate an executable. It actually generates an object file. The issue is that an OBJ
file in this case is not an executable. It would be like taking a TXT
file, renaming it an EXE
and trying to run that. It won't.
So you should have executed nasm this way:
nasm -fwin32 main.asm -o main.obj
This outputs a file main.obj
. You can't run an object file. It must be processed by a linker to produce an exe
. The linker will also be used to resolve the systems calls like WriteConsoleA
, ExitProcess
etc.
There are many linkers out there including Microsoft's linker called link.exe. I do not know if you have a Microsoft compiler installed or not, so I am going to recommend using a free one to help you along. You can download one called GoLink from here. You can read the GoLink manual here. Once downloaded you can extract GoLink.exe to the same directory as your nasm.exe.
The command you will need to use to link main.obj
to produce main.exe
is:
GoLink.exe main.obj kernel32.dll /fo main.exe /console
This will take main.obj
and kernel32.dll
and link them together and produce an executable called main.exe
. kernel32.dll
is the DLL(shared library) that holds the system functions WriteConsoleA
, ExitProcess
, ReadConsoleInputA
and GetStdHandle
. Without it the linker will not be able to create a final executable and will exit with an error saying as such.
You have one major problem in your program that will likely make it crash when inputting characters. I have modified it to look like this:
STD_OUTPUT_HANDLE equ -11
STD_INPUT_HANDLE equ -10
NULL equ 0
global start
extern ExitProcess, GetStdHandle, WriteConsoleA, ReadConsoleInputA
section .data ;message we want to display on console
msg db "Press a key to continue...", 13, 10, 0
msg.len equ $ - msg
section .bss ;buffers declaration
buffer_out resd 1
buffer_in resb 32
events_read resd 1
section .text
start: ;starting point of our program
push STD_OUTPUT_HANDLE
call GetStdHandle ;call to get a handle to the
push NULL ;specified mode (input, output...)
push buffer_out
push msg.len
push msg
push eax ;contains the GetStdHandle result
call WriteConsoleA ;call to print our msg in console
read:
push STD_INPUT_HANDLE
call GetStdHandle ;new call to get input handle
push events_read ;push dword buffer to return # of events read
;This paramater can't be NULL/0
push 1
push buffer_in
push eax
call ReadConsoleInputA ;call to detect user input
;this function will wait til
exit: ;it detects enough keypresses
push NULL ;(in this case, 1)
call ExitProcess
Your code originally had:
push NULL
I changed it to:
push events_read ;push dword buffer to return # of events read
;This paramater can't be NULL/0
I also added the events_read
variable (a single DWORD allocated with resd
to the .bss
section):
events_read resd 1
You can find the Microsoft documentation for ReadConsoleInputA
here to find out more about the parameters. Note that with 32 bit windows applications parameters are pushed onto the stack in reverse order as they appear in the documentation. The documentation says:
BOOL WINAPI ReadConsoleInput(
_In_ HANDLE hConsoleInput,
_Out_ PINPUT_RECORD lpBuffer,
_In_ DWORD nLength,
_Out_ LPDWORD lpNumberOfEventsRead
);
Parameters
hConsoleInput [in] A handle to the console input buffer. The handle
must have the GENERIC_READ access right. For more information, see
Console Buffer Security and Access Rights.
lpBuffer [out] A pointer to
an array of INPUT_RECORD structures that receives the input buffer
data. The storage for this buffer is allocated from a shared heap for
the process that is 64 KB in size. The maximum size of the buffer will
depend on heap usage.
nLength [in] The size of the array pointed to by
the lpBuffer parameter, in array elements.
lpNumberOfEventsRead [out]
A pointer to a variable that receives the number of input records
read.