News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

StrLen for Masm64 SDK

Started by jj2007, September 08, 2023, 07:38:38 AM

Previous topic - Next topic

jj2007

Quote from: lingo on September 09, 2023, 05:22:35 AMHi jj,
pls, try to explain to stoo23 my notes: to understand that i don't agree with your code and testing results but do not critisize you personaly because I know you from very long time ago...

Correct, we had some serious exchange of views in the past :badgrin:

Nonetheless, try to keep it civilised. Mutual respect is important. In this context, I'd like to remind everybody that Stewart keeps this forum running, and doesn't charge anything for his work despite the fact that he is not an assembly programmer. We should be grateful for that, and we owe him respect for this work.

Quote27%  faster with easy! :skrewy:

Well, well, .. for the typical 30-byte string, my algo seems a tick faster, but that's ok, I get practically the same timings. For longer strings, your algo is indeed faster, but: The x64 ABI says the first argument is passed in rcx, not in rax. Besides, I had wondered why you posted code that crashes, and now, looking at your makeit.bat, I've understood why: it doesn't crash with option /LARGEADDRESSAWARE:NO

That's called cheating - what's the purpose of x64 programs if you don't use the full address range? :biggrin:

Caché GB

Ok JJ, I was wrong and you were right. :thumbsup:

https://masm32.com/board/index.php?msg=123566

So what is the "dirty trick" as you mentioned in your StdOutNew.asm file.

Quoteinvoke StdOutExtreme, chr$("Hello World StdOutExtreme", 13, 10)    ; same but with a dirty trick

In an effort to find out for myself, I droped your exe into IDA Pro and it said "sp-analysis failed"
Caché GB's 1 and 0-nly language:MASM

jj2007

Quote from: Caché GB on September 11, 2023, 02:12:51 AMSo what is the "dirty trick" as you mentioned in your StdOutNew.asm file.

When a proc is called, the return address is on the stack. Above is the first argument, which you sometimes see used as mov eax, [esp+4] in procs without a stack frame.

So in line 2 we pop the return address to eax, then the argument to ecx. Directly after, we restore the ret address by pushing eax. Now the stack is set up as if no arguments had been passed. Thus, we can use the simple retn (a one-byte instruction) at the end, instead of the two-byter retn 4.

Push+pop reg32 are also just one byte long. Don't use this trick in a tight innermost loop, you might lose two or three cycles. WriteFile is horribly slow, so it doesn't matter here.

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
StdOutExtreme proc lpszText
  pop eax ; ret addr
  pop ecx ; string to print
  push eax ; ret addr
  push NULL ; we assume that WriteFile writes to bWritten only when
  push esp ; it's finished, so lpOverlapped can be misused here
  push rv(szLen, ecx) ; Len(lpszText): szLen does not trash ecx (even edx is not touched)
  push ecx  ; lpszText
  push rv(GetStdHandle, STD_OUTPUT_HANDLE)
  call WriteFile ; invoke WriteFile,hOutPut,lpszText,sl,ADDR bWritten,NULL
  retn
StdOutExtreme endp

The other trick is the push esp: we pushed NULL into the stack position of the lpOverlapped argument. WriteFile sees 0 and knows, early in the process, no overlapped writing. Afterwards, it doesn't need the argument any more. However, with the push esp we tell WriteFile the address of the bWritten variable; at the very end, when all bytes are written, WriteFile will misuse the overlapped variable to return the #bytes written.

28 bytes instead of 56 ;-)

Some senior member will now jump in and declare that this is "undocumented". Right :thumbsup:

Caché GB

#18
Hi JJ

Thank you for your explanation. I must say it hit me between the eyes with a hammer.

Two things I did note:

Using (push esp) for lpNumberOfBytesWritten. So if like in the original StdOut you want to return
the number of bytes written after the WriteFile call you would use (mov eax, [esp-4]).

And whatever string length function you use cannot scratch ecx. So the Win API call lstrlenA is a no go.

I would not call this a dirty trick. I would call it a forking™ (hutch--) clever trick.
Caché GB's 1 and 0-nly language:MASM

jj2007

Quote from: Caché GB on September 11, 2023, 11:27:31 AMUsing (push esp) for lpNumberOfBytesWritten. So if like in the original StdOut you want to return
the number of bytes written after the WriteFile call you would use (mov eax, [esp-4]).

Exactly: [esp-4], or, after the invoke:
  invoke StdOutExtreme, chr$("Hello World StdOutExtreme  ***", 13, 10)
  mov eax, [esp-8]
  print str$(eax), " bytes read", 13, 10

QuoteAnd whatever string length function you use cannot scratch ecx. So the Win API call lstrlenA is a no go.

Right, lstrlen would trash ecx, but szLen uses only eax :thumbsup:

NoCforMe

So we're pretending here that we're working on an ancient system that has 64K of memory available, so that every byte has to be justified, when really we're using a modren machine with tons (OK, tonnes if you prefer) of memory, disk space, etc. OK, got it.

But hey, don't let me rain on your parade; I admire your cleverness and how you can whip routines like this into submission. Good for you.

Here's my strlen(), by the way. It ain't going to win any prizes for speed nor for cleverness, but it's simple and works well for me. And it only trashes one register (EDX):

;====================================================================
; strlen()
;
; On entry,
;    EAX--> string to be measured
; On exit,
;    EAX = length of string
;====================================================================

strlen        PROC

    XOR    EDX, EDX            ;Len. counter
sl10:    CMP    BYTE PTR [EAX + EDX], NULL
    JE    sl88
    INC    EDX
    JMP    sl10
   
sl88:    MOV    EAX, EDX
    RET

strlen        ENDP
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on September 11, 2023, 09:16:26 PMSo we're pretending here that we're working on an ancient system that has 64K of memory available, so that every byte has to be justified, when really we're using a modren machine with tons (OK, tonnes if you prefer) of memory, disk space, etc.

I am running Win7-64 here, and it's incredibly slow. Next to me is a brand new Win10 notebook that I rarely use because, well, it's slow, and Windows 10 wants to be updated all the time.

A standalone "Hello World" written in the modern and popular QT framework needs roughly 8MB. Below a screenshot showing how much x64Dbg needs - it takes 9 endless seconds to load itself as JIT debugger in case of an exception.

Working with ML64 is a nightmare, it's so utterly slow. In case you have some spare time, and feel like downloading an attachment, try the StrLen64 project. On my machine, poor old ML64 needs over 10 seconds to assemble this tiny 200 lines source.

Windows suffers from bloatware. It suffers from all those programmers who think "we have plenty of space, we can waste it, who cares?".

I will waste space any time, but not in a library.
I will write slow code any time, but not in a library.

We are here because we are proud to be assembler programmers, different from the ignorant bunch of Python, Java and C++ guys. Of course, reducing the size of StdOut from 56 bytes to 28 bytes is a symbolic act. I even see it as a political act against the vandalism of the QT crowd who need 10MB to say "Hello World". They are destroying the fun of computing.

P.S.: Keep cultivating the art of thread drifting, David - it's fun, isn't it?  :thumbsup:

NoCforMe

I do admire your jousting with the evil forces of bloatware, JJ, I really do. Almost makes one long for the bad old days of 64K memory limits, which forced us to be agile and imaginative and make do with what we had. Many elegant and clever solutions back then. Instead today we have clueless, self-entitled programmers sitting in front of the most overpowered computing machines ever devised, with two monitors, who think it's normal to consume megabytes--hell, gigabytes--of "resources" to create a simple program.

Phooey on them.
Assembly language programming should be fun. That's why I do it.

jj2007

Great to see that we agree :thumbsup:

Over the last 30 years, my machines have become steadily slower. Any progress on the hardware side was eaten up by Windows bloat, and it's not only the OS.

Windows install Ghz/RAM/disk:
Atari ST 8/0.5/1 (for comparison)
Win 3.1 25/2mb/6mb
95 ?/4/50
98 66MHz/16mb/200mb
NT 33/16/110
ME 150/32/320
2000 133/64/0.65 of 2g
XP 300/128/1.5
Vista HP 1g/1g/15 of 40g
Win 7 1g/1g/16
Win 10 1g/2g/16

NoCforMe

Quote from: jj2007 on September 12, 2023, 06:39:05 AMWindows install Ghz/RAM/disk:
Atari ST    8/0.5/1 (for comparison)
Win 3.1    25/2mb/6mb
95    ?/4/50
98    66MHz/16mb/200mb
NT    33/16/110
ME    150/32/320
2000    133/64/0.65 of 2g
XP    300/128/1.5
Vista HP    1g/1g/15 of 40g
Win 7    1g/1g/16
Win 10    1g/2g/16

Then there was good old DOS: 4.77 mHz, maybe 256K RAM, and a 10 MB hard disk if you were lucky.
Assembly language programming should be fun. That's why I do it.

mikeburr

this may well be slightly off topic..
"A standalone "Hello World" written in the modern and popular QT framework needs roughly 8MB. "
unfortunately QT great as it is has copyright clauses so for instance if you develop and then sell the software QT, justifiably gets a cut, but heres the rub, if you don't then as i understand it QT require you expose the code you've written which is not really acceptable to many programmers
regards mike b

stoo23

Thinking of the Old days, I used to regularly buy a magazine that was popular at the time, that had a great Sub Title you may all remember,..
"Running Light Without Overbyte"  :smiley:  good old Dr Dobbs Journal

I used to thoroughly enjoy reading stuff by the regular contributors of the time, like Steve Wozniak, Gary Kildall, Jef Raskin and others and I remember one issue had the First real (in effect), call to arms by Richard Stallman with his GNU Manifesto.
There were some amazing people doing incredible things back then.

jj2007

Quote from: stoo23 on September 16, 2023, 03:35:39 PMgood old Dr Dobbs Journal

Old issues still available. I counted 422 occurrences of the word assembl in Vol 10 :rolleyes:

And this:
QuoteOne of the most irresponsible state-
ments I have ever read was that of
Edsger W. Dijkstra, in his " How Do
We Tell Truths That M ight H urt?" It
read: " It is practically impossible to
teach good programming to students
who have had prior exposure to BASIC:
as potential program m ers they are
mentally mutilated beyond hope of
regeneration."
QuoteMy personal theory about 8086/
88 assembly language is that what we
have here is a marketing coup on the
part of Intel. They had a ridiculous
processor, with the traditional inept
Intel approach to registers and ad�
dressing. Somehow, they sensed it
would be awfully embarrassing to ex�
pose this thing in all the stark sim�
plicity of their 'lxi h,7'-type assem�-
bler [for the 8080 am ong other
processors]. So they commissioned
the finest, most convoluted, Pascal-
ized minds in the software industry to
come up with an assembler so grand
and structured and incredibly intri�-
cate that no one would ever notice
how awful the thing was for which it
was assembling. Judging by the re�-
sults, they seem to have succeeded

Vortex

Hi Jochen,

Is there a way to assemble your source code with asmc?

asmc64.exe /Zne /Znk TimeStrLen64.asm
I get a lot of error messages :

Asmc Macro Assembler (x64) Version 2.34.37
Copyright (C) The Asmc Contributors. All Rights Reserved.

 Assembling: TimeStrLen64.asm
\masm32\include64\win64.inc(9572) : error A2008: syntax error : Rip
 \masm32\include64\win64.inc(9572): Included by
  \masm32\include64\masm64rt.inc(5): Included by
   TimeStrLen64.asm(1): Main line code
\masm32\macros64\vasily.inc(1000) : error A2154: syntax error in control-flow di
rective
 \masm32\macros64\vasily.inc(1000): Included by
  \masm32\include64\masm64rt.inc(6): Included by
   TimeStrLen64.asm(1): Main line code
\masm32\macros64\vasily.inc(1003) : error A2008: syntax error : J_POLY_COND
 \masm32\macros64\vasily.inc(1003): Included by
  \masm32\include64\masm64rt.inc(6): Included by
   TimeStrLen64.asm(1): Main line code
\masm32\macros64\vasily.inc(1004) : fatal error A1008: unmatched macro nesting

jj2007

Quote from: Vortex on September 16, 2023, 08:05:52 PMHi Jochen,

Is there a way to assemble your source code with asmc?

asmc64.exe /Zne /Znk TimeStrLen64.asm
I get a lot of error messages :

Well, unfortunately, NO. This is original Masm64 SDK code, and it will assemble only with ML64. Remember the discussions on the use of Vasily's macros with UAsm?