When I call a PROC this way:
INVOKE FormatNum,PtrMyString
the program freezes, like a general fault page
What's wrong in this program? As it is it works, but if I call FormatNum
it freaks out.
;---------------------------------------------------------------------------------
; MACRO ustrv$
;---------------------------------------------------------------------------------
; A new macro that converts an unsigned integer to a string
; using a call to function crt__ultoa.
; This is a modifies version of ustr$ macro of MASM32 package.
; The difference is that the string to fill is defined in the
; Main program and the content of it can be used for later
; needs.
;---------------------------------------------------------------------------------
include \masm32\include\masm32rt.inc
FormatNum PROTO :DWORD
ustrv$ MACRO DDvalue1, DDvalue2 ;; unsigned integer to string
invoke crt__ultoa,DDvalue1,DDvalue2,10
EXITM <offset DDvalue2>
ENDM
;---------------------------------------------------------------------------------
.data
MyString DB 20 dup (0),0
PtrMyString DD MyString
NumToFormat DD 3123456789
;---------------------------------------------------------------------------------
Sep DB ",",0 ; used for decimal numbers separator - choose yours
lpSep DD Sep ; When calling GetNumberFormat
Tsep DD ".",0 ; used for thousand numbers separator - choose yours
lpTsep DD Tsep ; When calling GetNumberFormat
;---------------------------------------------------------------------------------
.data?
Buffer DB 255 dup(?) ; used by GetNumberFormat
NumFmt NUMBERFMT <> ; to format with thousand separator integer numbers
;---------------------------------------------------------------------------------
; Structure for number formatting
;---------------------------------------------------------------------------------
; NUMBERFMTA STRUCT
; NumDigits DWORD ?
; LeadingZero DWORD ?
; Grouping DWORD ?
; lpDecimalSep DWORD ?
; lpThousandSep DWORD ?
; NegativeOrder DWORD ?
; NUMBERFMTA ENDS
;
; NUMBERFMT equ <NUMBERFMTA>
;---------------------------------------------------------------------------------
.code
start:
;----------------------------------------------------------------------------------------------------
; Initialize structure for calling GetNumberFormat
;----------------------------------------------------------------------------------------------------
mov NumFmt.NumDigits, 0 ; 0 for No decimal digits
mov NumFmt.LeadingZero, 0 ; 0 = No leading zeroes
mov NumFmt.Grouping, 3 ; Groups of three numbers
mov NumFmt.lpDecimalSep, offset Sep ; Pointer to NULL terminated string with the decimal separator
mov NumFmt.lpThousandSep, offset Tsep ; Pointer to NULL terminated string with the thousand separator
mov NumFmt.NegativeOrder, 0 ; Negative number mode
;----------------------------------------------------------------------------------------------------
print "The number "
print ustr$(NumToFormat)
print " is string: "
mov PtrMyString, ustrv$(NumToFormat, offset MyString)
print PtrMyString,13,10,13,10
print "The formatted number is: "
invoke GetNumberFormat, NULL, 0, PtrMyString, offset NumFmt, offset Buffer, 255
; INVOKE FormatNum,PtrMyString ; <--------------- calling this PROC the program gives a GPF and freezes
print offset Buffer,13,10,13,10
inkey " -- ok --"
exit
;----------------------------------------------------------------------------------------------------
; Procedure for formatting a string with thousand comma/point separator
;----------------------------------------------------------------------------------------------------
FormatNum PROC PtrNumber:DWORD
invoke GetNumberFormat, NULL, 0, PtrNumber, offset NumFmt, offset Buffer, 255
FormatNum ENDP
;----------------------------------------------------------------------------------------------------
end start
No ret instruction
FormatNum PROC PtrNumber:DWORD
invoke GetNumberFormat, NULL, 0, PtrNumber, offset NumFmt, offset Buffer, 255
ret
FormatNum ENDP
Quote from: oex on September 04, 2010, 06:24:54 PM
No ret instruction
FormatNum PROC PtrNumber:DWORD
invoke GetNumberFormat, NULL, 0, PtrNumber, offset NumFmt, offset Buffer, 255
ret
FormatNum ENDP
Thanks oex, being an advanced n00bist I didn't figure it myself :lol
Frank
Yes, there is no ret instruction. The program just continues to execute random instructions passed the function, which may be filled up with 0 and NOP instructions, eventually crashing the program. The ret instruction corrects the stack, pops the return address off the stack (Which is the address of the next instruction after the initial call) and then continues normally. Technically speaking you don't need to use ret, you can also use pop and then return manually.
Using call instead of invoke help you to remember the stack. Invoke is good to use, but it make it easy to forget the nature of the stack.
Quote from: zemtex on September 04, 2010, 06:58:57 PM
Yes, there is no ret instruction. The program just continues to execute random instructions passed the function, which may be filled up with 0 and NOP instructions, eventually crashing the program. The ret instruction corrects the stack, pops the return address off the stack (Which is the address of the next instruction after the initial call) and then continues normally. Technically speaking you don't need to use ret, you can also use pop and then return manually.
Using call instead of invoke help you to remember the stack. Invoke is good to use, but it make it easy to forget the nature of the stack.
Interesting :U
Could you please post the variations to use call insted of invoke?
In this way I can "see" what you mean with push/pop the stack
instead of ret.
Thanks
It is possible, but I wouldnt do it. :bdg
You could just pop off the address and do a short or far jump to that address..
When using call, make sure you push the last argument first.
Function Arg1 Arg2 Arg3
push arg3
push arg2
push arg1
call [eax]
if you watch the program in olly you can see the pushes made. I assume you're no news so I wont take it further haha
Quote from: zemtex on September 04, 2010, 09:08:56 PM
It is possible, but I wouldnt do it. :bdg
You could just pop off the address and do a short or far jump to that address..
When using call, make sure you push the last argument first.
Function Arg1 Arg2 Arg3
push arg3
push arg2
push arg1
call [eax]
if you watch the program in olly you can see the pushes made. I assume you're no news so I wont take it further haha
Well done zemtex :U
As somebody once said:
Never begin something that you cannot finish.I'm used to finish what I start, by the way. :lol
:bg
Magic rule, never mess up your CALL / RET pairing, it will come back to bite (BYTE ?) you later.
Quote from: hutch-- on September 07, 2010, 05:57:36 AM
:bg
Magic rule, never mess up your CALL / RET pairing, it will come back to bite (BYTE ?) you later.
I agree as a general rule. But it is not an absolute MUST to do so. Here are a few samples where you dont need to pair them up:
1: If you're planning to run en eternal loop from program start to program end.
2: If the function is invoking exitprocess and returning to the operating system
3: If you manually correct the stack and jump back again
4: If the next instruction after the function is an int3 instruction / breakpoint
5: or if the next instruction after the function stalls the thread
On the exit from a program nothing matters much but for code executed in an environment where speed matters and code keeps running, it is a mistake to do this. It easy enough to code writing a location on the stack from either a CALL mnemonic or an absolute address and then jumping to it but if that algo gets run regularly you go beyond the depth of the call/ret cache and will pay a performance penalty.
It is not recommended at all, we're talking mere semantics of code execution. I never do that kind of stuff, or at least not on a regular basis.
I guess my main point is that one ought to get familiar with "going around" the standard way of doing things, it greatly helps to understand
the "wrapper" of masm so that you dont always look at the standard with a questionmark in your eye.
Gotta experiment and try different things once in a while to see how stuff works.
Quote from: zemtex on September 07, 2010, 12:30:31 PM
It is not recommended at all, we're talking mere semantics of code execution. I never do that kind of stuff, or at least not on a regular basis.
I guess my main point is that one ought to get familiar with "going around" the standard way of doing things, it greatly helps to understand
the "wrapper" of masm so that you dont always look at the standard with a questionmark in your eye.
Gotta experiment and try different things once in a while to see how stuff works.
Both of you agree to stick with standard rules in order not to get biten by unwanted stuff.
And at the same time, experimenting different ways of doing things can help to have
a wider look of the matter.
Thanks to both
Frank