Hi all,
I have obtained the following code from this forum :
include \masm32\include\masm32rt.inc
.data
HelloWorld db "Hello World!",13,10,0
.code
start:
invoke StdOut, addr HelloWorld
inkey "Press a key to continue ..."
invoke ExitProcess, 0
end start
When I BuildAll with qeditor I get the following link error message :
LINK : fatal error LNK1104: cannot open file "stdOut.exe"
Is this due to a MASM32 installation problem ?
See if the libraries built correctly. If something in you OS settings or AV scanner interferes, you may not have a valid library that contains StdOut. Go to the m32lib directory and run MAKE.BAT and watch if there are any errors, there should be none. If you are getting build errors, then something in your OS or AV settings is stopping the build from working.
More details , please :
Where's stdOut.asm located? How do you open it ?.. maybe by drag'n'drop?
Try Console build
Quote from: AssemblyBeginner on March 10, 2015, 07:09:37 AM
LINK : fatal error LNK1104: cannot open file "stdOut.exe"
it appears that you have an instance of the EXE already running
windows prevents alteration of exe files during program execution
use the task manager to make sure all previous instances of the program have been terminated
then, try assembling it again
Thanks everyone ?
StdOut is the name I gave to the asm file ... I gues, I should have given it a different name to avoid confusion
As kindly, suggested by Vertogra, 'Console build' soved the problem :)
Again, thank you for your help
As a side note , what is the role of 13, 10 in the following code line ?
HelloWorld db "Hello World!",13,10,0
I thought a byte string declaration in asm was only followed by a Null (0) character
t places a CRLF after the string so that the console cursor finished on the next line.
Quote from: hutch-- on March 10, 2015, 10:20:10 AM
t places a CRLF after the string so that the console cursor finished on the next line.
Thank you hutch
In the previous code , I used : 'invoke StdOut, addr HelloWorld' instead of using offset as in the following working snippet .. however the two versions (ie: addr and offset) seem to work in the same way.
include \masm32\include\masm32rt.inc
.data
HelloWorld db "Hello World!",13,10,0
.code
start:
invoke StdOut, offset HelloWorld
inkey "Press a key to continue ..."
invoke ExitProcess, 0
end start
I am curious to know he difference between the two if any
Regards.
for global data (data or data? section), i would use OFFSET
ADDR was intended for use with INVOKE on local variables
if you use ADDR and the assembler needs OFFSET, it will substitute
using the intended specifier makes code a little easier to read, though
Its a very useful distinction to understand, an OFFSET is an absolute address from the start of an executable and this is generally why its used in both initialised data (data with content) and uninitialised data (allocated space). The ADDR notation is a bit more generalised in that it means an ADDRESS which can be either in the data sections OR a stack address, the stack address being dynamic where the data sections are static.
As Dave mentioned you use ADDR with the INVOKE notation as it makes your code easier for you to read. If you are loading a data section address into a register for example you would use the following.
mov eax, OFFSET mydata
Where "mydata" is the address of the data you want from either of the data sections. If you have a look at a disassembly of the code you will find that the mov eax you wrote has a direct offset as the source which is the location of the data in the respective data section.
neither Hutch nor i gave really good explanations of what goes on with ADDR
consider the following example:
INCLUDE \masm32\include\masm32rt.inc
;###########################################################################
SomeFunc PROTO :HWND,:DWORD
;###########################################################################
.DATA
;initialized data goes here
;***************************************************************************
.DATA?
;uninitialized data goes here
;###########################################################################
.CODE
;***************************************************************************
main PROC
INVOKE SomeFunc,0,1
inkey
exit
main ENDP
;***************************************************************************
SomeFunc PROC USES EBX ESI EDI hWnd:HWND,dwArg2:DWORD
;---------------------------
LOCAL dwLocal1 :DWORD
LOCAL rcLocal2 :RECT
LOCAL abLocal3[24] :BYTE
;---------------------------
;some code here
INVOKE GetClientRect,hWnd,addr rcLocal2
;some more code here
lea edx,abLocal3
;some more code here
mov eax,dwArg2
imul eax,5
mov dwLocal1,eax
;some more code here
ret
SomeFunc ENDP
;###########################################################################
END main
this is a disection of the code that is actually generated by the assembler....
;this is the code that is generated for the "INVOKE SomeFunc,0,1" line
00401000: push 1 ;second argument passed in INVOKE
00401002: push 0 ;first argument passed in INVOKE
00401004: call 00401029 ;address of SomeFunc
;some code here generated for the "inkey" macro expansion (not shown for simplicity)
;this is the code generated for the "exit" macro expansion
:00401022 push 0 ;exit code
:00401024 call kernel32.ExitProcess ;ExitProcess API function
=========
;this is the code generated for the "SomeFunc" PROC
;-----------------------------------------------------------------------------
;stack frame initialization
;this is called the PROC "prologue" code, automatically generated by the assembler
;the PROC line has "USES EBX ESI EDI", as well as 2 DWORD arguments
;then, we allocate 44 bytes for local variables
;SomeFunc PROC USES EBX ESI EDI hWnd:HWND,dwArg2:DWORD
; LOCAL dwLocal1 :DWORD
; LOCAL rcLocal2 :RECT
; LOCAL abLocal3[24] :BYTE
00401029: push ebp ;preserve EBP contents
0040102A: mov ebp,esp ;EBP = stack frame base pointer
0040102C: add esp,-44 ;make room for our local variables (44 bytes total)
0040102F: push ebx ;preserve EBX contents
00401030: push esi ;preserve ESI contents
00401031: push edi ;preserve EDI contents
;so, our stack frame looks like this
;[EBP+12] dwArg2
;[EBP+8] hWnd
;[EBP+4] RETurn address
;[EBP] saved EBP contents
;[EBP-4] dwLocal1, a DWORD
;[EBP-20] rcLocal2, RECT structure (4 DWORD's)
;[EBP-44] abLocal3, 24 byte array
;when you PUSH or POP during the course of your function code, the ESP register changes to point to the current "top of stack"
;however, the EBP register does not change - it always points to the same address on the stack
;-----------------------------------------------------------------------------
;this is the code generated for the "INVOKE GetClientRect,hWnd,addr rcLocal2" line of code
;notice that ADDR causes the assembler to generate an LEA instruction
00401032: lea eax,[ebp-20] ;EAX = ADDR rcLocal2
00401035: push eax
00401036: push dword ptr [ebp+8] ;hWnd argument
00401039: call user32.GetClientRect ;GetClientRect API function
;-----------------------------------------------------------------------------
;this is the code generated for the "lea edx,abLocal3" line of code
0040103E: lea edx,[ebp-44] ;EDX = ADDR abLocal3
;-----------------------------------------------------------------------------
;some example code to familiarize you with local variables
00401041: mov eax,[ebp+12] ;"mov eax,dwArg2"
00401044: imul eax,5 ;"imul eax,5"
00401047: mov [ebp-4],eax ;"mov dwLocal1,eax"
;-----------------------------------------------------------------------------
;this is called the PROC "epilogue" code, automatically generated by the assembler whenever RET occurs
0040104A: pop edi ;restore EDI contents
0040104B: pop esi ;restore ESI contents
0040104C: pop ebx ;restore EBX contents
0040104D: leave ;same as, "MOV ESP,EBP", followed by, "POP EBP"
0040104E: ret 8 ;RETurn, and discard 2 DWORD arguments from the stack
Thanks for the answers provided regarding addr vs offset .. dedndave's answer is a bit difficult for me to disgest at this stage as I am an absolute beginner with asm but I'll study it nonetheless ... and I am sure it will come in handy at some point in my learning process
Here is another minimalistic example:
include \masm32\include\masm32rt.inc
.code
MyTest proc title$
LOCAL msg$[100]:BYTE ; a local buffer
int 3
invoke lstrcpy, addr msg$, chr$("Hello")
MsgBox 0, addr msg$, title$, MB_OK
ret
MyTest endp
start: invoke MyTest, chr$("My title")
exit
end start
Under the hood:
00401000 Ú$ 55 push ebp ; NewWin32.00401000(guessed Arg1)
00401001 ³. 8BEC mov ebp, esp
00401003 ³. 83EC 64 sub esp, 64
00401006 ³. CC int3
00401007 ³. 68 00204000 push offset 00402000 ; ÚSrc = "Hello"
0040100C ³. 8D45 9C lea eax, [ebp-64] ; ³
0040100F ³. 50 push eax ; ³Dest
00401010 ³. E8 2D000000 call <jmp.&kernel32.lstrcpyA> ; ÀKERNEL32.lstrcpy
00401015 ³. 6A 00 push 0 ; ÚType = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
00401017 ³. FF75 08 push dword ptr [ebp+8] ; ³Caption
0040101A ³. 8D45 9C lea eax, [ebp-64] ; ³
0040101D ³. 50 push eax ; ³Text
0040101E ³. 6A 00 push 0 ; ³hOwner = NULL
00401020 ³. E8 17000000 call <jmp.&user32.MessageBoxA> ; ÀUSER32.MessageBoxA
00401025 ³. 8BE5 mov esp, ebp
00401027 ³. 5D pop ebp
00401028 À. C2 0400 retn 4