Any chance there's a QWORD (to ASCII) converter somewhere in the MASM32 stuff? I looked in the help file but only found info on DWORD routines. Suppose I could write one myself, but why reinvent that particular wheel?
http://masm32.com/board/index.php?topic=221.0
If speed is not an issue:
include \masm32\include\masm32rt.inc
.data
MyQ QWORD 12345678901234567890
.code
start:
printf("The value of MyQ is %llu\n", MyQ)
inkey "hit any key"
exit
end start
If speed is important, try MasmBasic Str$(MyQ), it's a factor 3.6 faster than CRT printf().
Quote from: jj2007 on July 12, 2022, 09:20:18 AM
http://masm32.com/board/index.php?topic=221.0
Regarding just that thread, I took a look at it, but I won't look any further. Why? Because the people who wrote that stuff do something that I really really really really HATE. Which is to use totally cryptic, un-understandable references to local variables like
[esp+0*4] instead of just creating a goddamn readable LOCAL VARIABLE like everyone else does. ("Dedndave" is particularly guilty of this crime.) Why do this? It buys you absolutely nothing in terms of execution speed. All it does is make your code unintelligible. Sheesh.
Quote from: jj2007 on July 12, 2022, 09:20:18 AM
If speed is not an issue:
include \masm32\include\masm32rt.inc
.data
MyQ QWORD 12345678901234567890
.code
start:
printf("The value of MyQ is %llu\n", MyQ)
inkey "hit any key"
exit
end start
If speed is important, try MasmBasic Str$(MyQ), it's a factor 3.6 faster than CRT printf().
But I don't want
printf(); I want something like
wsprintf(), that formats to memory. Got anything like that? (Not MasmBasic, since I'm still not yet a user.)
Quote from: NoCforMe on July 12, 2022, 09:35:53 AMtotally cryptic, un-understandable references to local variables like [esp+0*4]
I use this syntax over 250 times in my library, and don't feel guilty. Just get used to it :cool:
Simple example, coded tonight:
destx equ [esp-16]
desty equ [esp-12]
destw equ [esp-8]
desth equ [esp-4]
srcx equ [esp]
srcy equ [esp+4]
srcw equ [esp+8]
srch equ [esp+12]
xor ebx, ebx
push ebx ; callback data
push ebx ; callback
push ebx ; attributes
push UnitPixel ; unit=2
push edx ; src height
; fild stack
push eax ; src width
; fild stack
push ebx ; src y slot
push ebx ; src x slot
.DATA
align 16
cropdata dw 20, 20, -20, -20 ; x, y, w, h
.CODE
pmovsxwd xmm0, qword ptr cropdata
movups xmm1, oword ptr [esp]
PADDD xmm0, xmm1
movups oword ptr [esp], xmm0
fild stack[3*4] ; h
fild stack[2*4] ; w
deb 4, "A", ST(0), ST(1)
fld st ; copy of width
fmul [edi.GuiImageZOOM].gizX ; width*percentX
fiadd stack
deb 4, "srcX", ST(0)
nops 2
fistp stack ; new src X
fmul [edi.GuiImageZOOM].gizW ; width*percentW
fisubr stack[8] ; subtract from old width
fisub stack ; subtract left offset
fistp stack[8] ; new src width
fld st ; copy of height
fmul [edi.GuiImageZOOM].gizY ; height*percentY
fiadd stack[4]
fistp stack[4] ; new src Y
fmul [edi.GuiImageZOOM].gizH ; width*percentH
fisubr stack[12] ; subtract from old height
fisub stack[4] ; subtract top offset
fistp stack[12] ; new src height
But why? Why on earth would you want to code something cryptically like that instead of using symbolic names like [insert name of deity here] intended? is it that much trouble to come up with names? How in the world do you look at that and know just what the hell [esp-8] refers to?
Like they say, smh ...
Short answer: nobody forces me to use (for example) fild stack[3*4]...
I did find what looks like a usable (and simple) routine in that thread you linked to, and it's from "dedndave". I've reformatted it to my liking here:
.data
Q2Abuffer DB "01234567890123456789",0 ;20 ASCII digits
.code
;====================================================================
; Convert 64-bit unsigned integer (QWORD) to ASCII decimal string
;
; On entry,
; EDX:EAX = QWORD value to convert
;
; Returns:
; EAX--> buffer containing numeric string
;====================================================================
Q2A PROC
PUSH EBX
PUSH EDI
STD ;No, not a venereal disease:
;set direction flag to go backwards.
MOV EDI, OFFSET Q2Abuffer + 18
MOV ECX, EDX
XCHG EAX, ESI
MOV EBX, 100 ;Load with divisor.
qloop: XOR EDX, EDX
XCHG EAX, ECX
DIV EBX
XCHG EAX, ECX
XCHG EAX, ESI
DIV EBX
XCHG EAX, ESI
XCHG EAX, EDX
AAM
XCHG AL, AH ;Swap bytes.
OR AX, 3030h ;Convert to ASCII.
STOSW ;Store 2 digits.
MOV EAX, ECX
OR EAX, ESI
JNZ qloop
ADD EDI, 2
CLD ;Be sure to clear direction flag!
CMP BYTE PTR [EDI], '0' ;Leading zero?
JNE exit99 ; No, done.
INC EDI ; Yep, increment past it.
exit99: MOV EAX, EDI ;Return with pointer to buffer.
POP EDI
POP EBX
RET
Q2A ENDP
Haven't tested it out yet, but I'm sure it'll do nicely.
:biggrin:
Everybody has a theory, I get to see code that is regularly unintelligible, its the name of the game. I am an addict of clarity but you don't get to see it all that much.
Quote from: NoCforMe on July 12, 2022, 10:51:10 AMHaven't tested it out yet, but I'm sure it'll do nicely.
Not bad indeed, but you have two very slow DIV instructions in your code...
MyQ=12345678901234567890
2547 ms for Q2A
1264 ms for Str$()
MOV EDI, OFFSET Q2Abuffer + 18
If that line was my code, it would be
mov edi, offset Q2aBuffer+18
- ALL CAPS would drive me crazy
- a tab between mov and edi? No thanks, my eyes don't like jumping around
- Q2Abuffer looks like an inconsistent half camel case; Q2aBuffer is much more readible
- I don't need spaces around + and minus signs, they distract
As you can see, it's all a question of taste - as Hutch writes, "Everybody has a theory" ;-)
Quote from: jj2007 on July 12, 2022, 05:11:57 PM
Quote from: NoCforMe on July 12, 2022, 10:51:10 AMHaven't tested it out yet, but I'm sure it'll do nicely.
Not bad indeed, but you have two very slow DIV instructions in your code...
Don't care. Speed matters not here. It's just used for some end-of-run reporting. Rather have small, simple code here.
BTW, regarding program formatting, I realize this is a religious issue ...
Quote from: NoCforMe on July 12, 2022, 06:11:30 PMBTW, regarding program formatting, I realize this is a religious issue ...
Amen :tongue:
Hello,
Anyone who tried crt_sprintf with %I64u ? That function does not seem to support 64-bit integers.
Same as %llu in reply #1, Erol:
include \masm32\include\masm32rt.inc
.data
MyQ QWORD 12345678901234567890
buffer db 80 dup(?)
.code
start:
cls
invoke crt_sprintf, addr buffer, chr$("A: The value of MyQ is %I64u", 13, 10), MyQ
printf("B: The value of MyQ is %I64u\n", MyQ)
inkey addr buffer
exit
end start
Hi Jochen,
Thanks, the code below works fine. The specifier %I64u works with wsprintf too.
include \masm32\include\masm32rt.inc
.data
x dq 12345678901234567890
f1 db '%I64u',0
.data?
buffer db 128 dup(?)
.code
start:
invoke crt_sprintf,\
ADDR buffer,ADDR f1,x
invoke StdOut,ADDR buffer
invoke ExitProcess,0
END start
:biggrin:
> know just what the hell [esp-8] refers to?
Just what it says, the memory address in esp with a minus offset of 8 bytes.
This is the normal Intel "complex addressing mode".
When you have a reason to work in QWORD size data in 32 bit, you do it the old fashioned hard way, the low DWORD is read like normal, the high DWORD is read separately and added to the first with a multiplier. The other option is to write it in 64 bit. :biggrin:
You're missing the point.
Yes, I know what [esp-n] means. But I don't know what it means when I'm looking at code, meaning that I have no idea what variable it refers to. So why use it instead of a recognizable name? That's why we use a macro assembler, isn't it? Otherwise we'd still be flipping front-panel switches and coding in binary (or even worse, octal). Why use [esp-8] when you can use "pintsDrank" or whatever?
Someone pointed out to me that that notation is useful when using a debugger like Olly which displays stuff that way, but even there it would be a lot nicer to use a meaningful symbolic name rather than some offset from a register, which tells me nothing about what that data is, unless you're some kind of idiot savant who can memorize all that crap.
Writing no stack frame code comes with practice, you should know what you are passing to a procedure and using direct stack addressing is part of that type of code. The solution of course is to actually comment your code and you will always know what it is. Thank God 64 bit is clearer but under the hood is a joy to behold. It has to be aligned correctly ALA M$ ABI and its written in reverse order below the current stack location.
Now if you want to write no stack frame code with the lowest overhead, if you need temporary locations for what would be LOCAL values in a stackframe procedure, you write it below the stack and this is in 32 bit.
Hi NoCforMe,
Hutch's latest post is a nice explanation. If you wish to code an optimized procedure, you need to turn off stack framing and use the complex addressing mode.
Hi NoCforMe,
Here is a quick example for you :
include \masm32\include\masm32rt.inc
subs PROTO :DWORD,:DWORD
.data
msg db '120 - 40 = %u',0
.data?
buffer db 32 dup(?)
.code
start:
invoke subs,120,40
invoke wsprintf,ADDR buffer,\
ADDR msg,eax
invoke StdOut,ADDR buffer
invoke ExitProcess,0
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
align 4
subs PROC x:DWORD,y:DWORD
mov eax,DWORD PTR [esp+4]
sub eax,DWORD PTR [esp+8]
ret 2*4 ; balance the stack manually
subs ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
END start
OK, so compare to the way I would do it:
;***** Subroutine using easy-to-understand arguments instead of [esp+4], etc.: *****
Subtract PROC minuend:DWORD, subtrahend:DWORD
MOV EAX, minuend
SUB EAX, subtrahend
RET
Subtract ENDP
I fail to see the advantage of your way. What have you gained? Sure, the tiny overhead of the prologue/epilogue code. Is that all? Seems like a small price to pay for readability. Or is there something else I'm missing here?
See, this way I, the human, don't have to keep track of [esp+n] offsets; that's what computers are for ...
Quote from: NoCforMe on July 15, 2022, 07:36:16 AMWhat have you gained? Sure, the tiny overhead of the prologue/epilogue code.
That's correct. It's tiny, but if the proc itself is tiny, omitting the overhead may be an advantage.
Here is a more readable alternative: equates.
include \masm32\include\masm32rt.inc
.code
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
subxy proc x0, y0
x equ [esp+4] ; define your argument
y equ [esp+8] ; names with equates
mov eax, x
sub eax, y
retn 8
subxy endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
start:
invoke subxy, 456, 123
MsgBox 0, cat$(str$(eax), " is the result"), "Hello:", MB_OK
exit
end start
Same code but different syntax:
include \masm32\include\masm32rt.inc
.code
subxy:
x equ [esp+4] ; define your argument
y equ [esp+8] ; names with equates
mov eax, x
sub eax, y
retn 8
start:
push 123
push 456
call subxy
MsgBox 0, cat$(str$(eax), " is the result"), "Hello:", MB_OK
exit
end start