Reputation: 1621
In result to my post Can I use int21h on windows xp to print things?, I have seen an article about using Windows API's and in this article was a reference to using the _WriteConsole@4 API to print a message to the console. The article is at http://cs.lmu.edu/~ray/notes/x86assembly/.
Here is my code so far:
.386P
.model flat
extern _ExitProcess@4:near
extern _GetStdHandle@4:near
extern _WriteConsoleA@20:near
public _go
.data
msg byte 'if you get this, it worked.', 10
handle dword ?
written dword ?
.code
start:
_go:
push -11
call _GetStdHandle@4
mov handle, eax
push 0
push offset written
push 13
push offset msg
push handle
call _WriteConsoleA@20
push 0
call _ExitProcess@4
end start
I am using this syntax to compile the code: ML:
ml (the file is called test.asm) test.asm /c
Link:
link test.obj C:\masm32\lib\kernel32.lib /SUBSYSTEM:CONSOLE /entry:go
I have gotten it to compile and link, but when I run the .exe that is produced, it does absolutely nothing, not even an error return. The console is just black. Why is this?
Any help would be greatly appreciated. And to the users of this forum, I apologize for bombarding stackoverflow.com every day, it is just that I have very few resources to learn with.
Thanks in advance,
Progrmr
Upvotes: 4
Views: 6407
Reputation: 5884
First off, the link you are getting your sample code is from a NASM user and he probably never used MASM from the way he speaks of it. He also writes his MASM sample like NASM format. The fact that you want to use Assembly means you have to be an advanced computer user. You need to know how to use batch files, how to set system paths and other things. When something goes wrong, you learn by researching. So you got an error saying it can't find masm32rt.inc but you say you are using MASM32. I use batch files and an IDE for Assembly and I have my system paths pointing to various directories in MASM32.
Add the absolute path to your masm32\include directory before masm32rt.inc. While you are at it, open masm32rt.inc in a text editor and see what is in it - error fixed.
You start your source file with:
.586
.option casemap:NONE
.model flat, stdcall
include yourincludeshere and it could be a bunch
includelib yourlibshere same here a bunch
masm32rt.inc contains that already and it contains include and includelib for libs and includes that are widely used. We use it to save a bunch of typing.
Now open any include file in \masm32\include the includes are just setting up the protos for the API calls so you can use invoke for parameter checking, it also aliases the API calls so we don't have to type WriteConsoleA instead we just write WriteConsole hell, you could even do YoConsole equ and in your code you would write YoConsole for WriteConsole.
That being said, we don't use - extern _WriteConsoleA@20:near as NASM would nor do we need to set our entry label to public MASM knows your entry point by this:
.code
yourentrypointname:
end yourentrypointname
we also don't have to specify the libs to the linker since we use includelib in our source.
Also, DO NOT, I repeat DO NOT get into the habit of using hard coded numbers in your parameters. Get out of that habit NOW!! Windows header files use DEFINES for a reason - code readability, We (the folks that help you) don't need to lookup what -11 means for that API call, I used the define and you know what that parameter means. Plus what if you have that WriteConsole call 40 times? If you use an equate, you need to change just the equate instead of search and replace. If you want decent MASM tutorials search for Iczelion they are old and contain a few errors but they will get you started, many of us in the early days have used those tutorials.
Upvotes: 3
Reputation: 5884
This works without problem:
include masm32rt.inc
.data
szMsg db "I am in the console!", 0
MSG_LEN equ $ - szMsg
.data?
BytesWriten dd ?
.code
start:
push STD_OUTPUT_HANDLE
call GetStdHandle
push NULL
push offset BytesWriten
push MSG_LEN
push offset szMsg
push eax
call WriteConsole
push 0
call ExitProcess
end start
your entry label is _go yet you tell the linker is is go - /entry:go so it creates the console but does not execute any code! You don't need to tell the linker the entry point in this case, your entry point is start... How does the linker know? The end start
Upvotes: 2
Reputation: 20693
You could try MASM32, here is a hello world example for console application :
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««« *
.486
.model flat, stdcall
option casemap :none ; case sensitive
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\kernel32.inc
include \masm32\macros\macros.asm
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\kernel32.lib
.code
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
print "Hello world"
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
But if you want to stick with your current assembler, we can look under macros.asm there is a print Macro :
print MACRO arg1:REQ,varname:VARARG ;; display zero terminated string
invoke StdOut,reparg(arg1)
IFNB <varname>
invoke StdOut,chr$(varname)
ENDIF
ENDM
So you want StdOut, in MASM32 it looks like this :
StdOut proc lpszText:DWORD
LOCAL hOutPut :DWORD
LOCAL bWritten :DWORD
LOCAL sl :DWORD
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov hOutPut, eax
invoke StrLen,lpszText
mov sl, eax
invoke WriteFile,hOutPut,lpszText,sl,ADDR bWritten,NULL
mov eax, bWritten
ret
StdOut endp
So at the end of this journey, you have to use WriteFile not WriteConsole :)
Upvotes: 1