News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

MasmBasic

Started by jj2007, October 06, 2009, 08:24:57 PM

Previous topic - Next topic

jj2007

Hi Michael,
Could you please add the first line of the timing, i.e. the one that shows the SSE level?
As far as I know, the P3 has no SSE2, but I have somewhere in the Init procedure this snippet:
  db 0Fh, 0A2h ; cpuid 1
  bt edx, 26 ; edx bit 26, SSE2
  .if !Carry?
invoke MessageBox, 0, chr$("Sorry, MasmBasic needs SSE2"), 0, MB_OK
invoke ExitProcess, -99
  .endif

And for me the real surprise is that you don't see that box... ::)
Regards,
Jochen

MichaelW

The first line is:
☺☺☻♥ (SSE1)
Where the first characters are ASCII codes 1, 1, 2, and 3.

The message box does show up, but not until the case-insensitive tests so I assumed that the case-sensitive tests do not require SSE2.




eschew obfuscation

jj2007

#122
Quote from: MichaelW on April 03, 2010, 07:19:30 AM
The first line is:
☺☺☻♥ (SSE1)
Where the first characters are ASCII codes 1, 1, 2, and 3.

The message box does show up, but not until the case-insensitive tests so I assumed that the case-sensitive tests do not require SSE2.


Thanks, Michael. I'll have to do something about the brand string issue in the ShowCPU proc. [EDIT: done, see post above]

As to the tests: They are all SSE2, case-sensitive and in-sensitive, otherwise you can't explain the speed increase. See also the Compare two strings thread.

I checked why the 'SSE2 required' box didn't show up from the beginning: It's because I did not use any of the commands (Print, Let, Dim) that trigger the init procedure in which the SSE2 runtime test is hidden.

Does anybody know a way to force a macro execution before any other code is run, i.e. some automatic call after the start: label?

sinsi

>Does anybody know a way to force a macro execution before any other code is run, i.e. some automatic call after the start: label?


start:
RunMyMacro

By definition any macro run immediately after the 'END label" label is the first code to run...
Light travels faster than sound, that's why some people seem bright until you hear them.

jj2007

Quote from: sinsi on April 03, 2010, 10:30:45 AM
>Does anybody know a way to force a macro execution before any other code is run, i.e. some automatic call after the start: label?


start:
RunMyMacro

By definition any macro run immediately after the 'END label" label is the first code to run...

Yes, that is an option. But I was looking for something really fool-proof, i.e. ...
include \masm32\MasmBasic\MasmBasic.inc

.code
start: ; <<<< magic happens here
Exit
end start

... where the magic code is contained in the library. What does work is 'calling' a macro in the .const section, it does 'execute' but only in the sense that assembly time variables etc can be set.

oex

Maybe create a 'start' macro but I'm not aware of any way to execute code before .code start.... I have an init function of sorts that runs at the beginning of most of my apps to setup essential infos
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

dedndave

i don't see any problem with requiring an MBInit function call, Jochen
if you were to make MB a DLL, they would have to initialize that, too

jj2007

Quote from: oex on April 03, 2010, 02:49:16 PM
Maybe create a 'start' macro but I'm not aware of any way to execute code before .code start

Quote from: dedndave on April 03, 2010, 03:13:02 PM
i don't see any problem with requiring an MBInit function call, Jochen
if you were to make MB a DLL, they would have to initialize that, too

Ok, I'll make it optional. Normally, a Dim or Let or Print will trigger it automatically. For the new ShowCPU code taking account of pre-P4 processors, I have inserted a conditional call to the Mb init function (i.e. it remains compatible with 'normal' Masm32 code).

; select the two lines and press Control X to cut
; code for printing brand string and SSE level
   push 1
   call ShowCpu   ; print brand string and SSE level
ShowCpu proc ; mode:DWORD
COMMENT @ Usage:
  push 0, call ShowCpu ; simple, no printing, just returns SSE level
  push 1, call ShowCpu ; prints the brand string and returns SSE level@
  pushad
  sub esp, 80 ; create a buffer for the brand string
  mov edi, esp ; point edi to it
  xor ebp, ebp
  .Repeat
  lea eax, [ebp+80000002h]
db 0Fh, 0A2h ; cpuid 80000002h-80000004h
stosd
mov eax, ebx
stosd
mov eax, ecx
stosd
mov eax, edx
stosd
inc ebp
  .Until ebp>=3
  push 1
  pop eax
  db 0Fh, 0A2h ; cpuid 1
  xor ebx, ebx ; CpuSSE
  xor esi, esi ; add zero plus the carry flag
  bt edx, 25 ; edx bit 25, SSE1
  adc ebx, esi
  bt edx, 26 ; edx bit 26, SSE2
  adc ebx, esi
  bt ecx, esi ; ecx bit 0, SSE3
  adc ebx, esi
  bt ecx, 9 ; ecx bit 9, SSE4
  adc ebx, esi
  dec dword ptr [esp+4+32+80] ; dec mode in stack
  .if Zero?
mov edi, esp ; restore pointer to brand string
  .Repeat
.Break .if byte ptr [edi]!=32 ; mode was 1, so show a string but skip leading blanks
inc edi
.Until 0
.if byte ptr [edi]<32
print chr$("pre-P4")
.else
print edi ; CpuBrand
.endif
.if ebx
print chr$(32, 40, "SSE") ; info on SSE level, 40=(
print str$(ebx), 41, 13, 10 ; 41=)
.endif
  .endif
  add esp, 80 ; discard brand buffer (after printing!)
  mov [esp+32-4], ebx ; move ebx into eax stack position - returns eax to main for further use
  ifdef MbBufferInit
MbBufferInit
  endif
  popad
  ret 4
ShowCpu endp

Ghandi

Another option with regards to running code before the app is executed would be to make a boilerplate entrypoint routine which is set as the entrypoint of the application (/ENTRY:WinMBStartup) and then have the user set their entrypoint as a MasmBasic variable. Then they can code as if nothing else had happened and you can run your checks or initializations in a small startup stub then thunk over to the declared entrypoint. There is one more thing though, if you did it this way you would have to tell the user not to call ExitProcess (unless absolutely necessary) so you can perform cleanup after their code is finished executing.

I know it is possible to manually create a TLS directory in a MASM built executable but is there any way we can do it from a source level? If so, you could place your initialization code inside the TLS callback and it would be called and notified of process attach/detach and thread attach/detach so you could handle any other code (if need be) in there as well. The benefit of a TLS callback is that the coder would just code like normal and when the app is run the TLS gets called and then their entrypoint with no need to interact, thunk or otherwise jump/call/push ret to the entrypoint.

I saw a tool over on WinASM forum which offers to update a TLS entry in an executable by searching for a byte sequence which precedes the TLS information and then updating the PE header. I suppose if it were something you were really determined to achieve, you could always code your own tool which passes on the ml and link.exe calls and when the file is produced, update the PE header and checksum so that the process is transparent to the end user (ofc making them fully aware that such a thing will happen if they so choose).  Just more conjecture mate, discard it as you see fit. :)

Seeing as im typing at 2:19am i suppose i can say Happy Whatever to everybody (replace whatever with your holiday/season), hopefully everybody has a good time with family and friends without overindulging too much.

HR,
Ghandi

qWord

Quote from: jj2007 on April 03, 2010, 02:39:22 PMinclude \masm32\MasmBasic\MasmBasic.inc

.code
start: ; <<<< magic happens here
Exit
end start

maybe this is enough magic for you  :bg:
_ EQU init()
init macro
@init:
xor eax,eax
xor edx,edx
jmp $+4; ret
EXITM <jmp @init> ; or <call ...>
endm

start:_

FPU in a trice: SmplMath
It's that simple!

jj2007

Quote from: qWord on April 03, 2010, 04:15:27 PM
maybe this is enough magic for you  :bg:

start:_


No, that's horribly complicated, my friend :bg

Ok, after thoroughly balancing your contributions, I have updated the library. This is a valid MasmTM app now:

include \masm32\MasmBasic\MasmBasic.inc
Init
Inkey Str$("Your puter has run %3f hours since the last boot, give it a break!", rv(GetTickCount)/3600000)
Exit
end start

Ghandi

A valid *Masm*  or a valid *MasmBasic* app? :P

HR,
Ghandi

jj2007

Quote from: Ghandi on April 03, 2010, 05:42:49 PM
A valid *Masm*  or a valid *MasmBasic* app? :P

HR,
Ghandi

The code assembles with ml.exe version 6.15 and higher, and with JWasm. The only difference to a "standard" Masm app is that you include 11 libraries instead of 10...

\masm32\include\masm32rt.inc:

      include \masm32\include\dialogs.inc       ; macro file for dialogs
      include \masm32\macros\macros.asm         ; masm32 macro file
      includelib \masm32\lib\masm32.lib
      includelib \masm32\lib\gdi32.lib
      includelib \masm32\lib\user32.lib
      includelib \masm32\lib\kernel32.lib
      includelib \masm32\lib\Comctl32.lib
      includelib \masm32\lib\comdlg32.lib
      includelib \masm32\lib\shell32.lib
      includelib \masm32\lib\oleaut32.lib
      includelib \masm32\lib\ole32.lib
      includelib \masm32\lib\msvcrt.lib

jj2007

Over the weekend I found some time to fix the MovVal bug, and to add a few goodies. So I reset the counter and call it now the Release Candidate ;-)

For major changes, check the help file (see top of thread, open in RichMasm, WordPad or MsWord); inter alia, look for:

- two-dimensional string arrays: Dim My$(ebx+1000, 255), then Let My$(2, 3)="Hello World"+... is now valid MASM syntax.
- assigning strings to Mid$ etc.: Let Left$(My$, 5)="Hallo" is valid MASM syntax, and works as expected.
- ASCII to number conversion: Several number formats added, see the Valid Number Formats thread for detail.
- Val(), MovVal, Str$(): xmm registers, qwords, Real10/8/4, dwords, reg32, reg8 now supported
- easy-to-use float comparisons:
QuoteMyPI_low   REAL10   3.14159
; MyPI_low   dd    3   ; you could use dwords, real4/8/10, or, as second arg only, reg32 and immediate values

         Fcmp MyPI_low, PI, medium  ; the "medium" (or high/low) precision is optional
         .if Carry?
            Print Str$("MyPI_low at %f is lower than the real PI\n", MyPI_low)
         .elseif Zero?
            Print Str$("MyPI_low at %f is exact\n", MyPI_low)
         .else
            Print Str$("MyPI_low at %f is higher than the real PI\n", MyPI_low)
         .endif
Output: MyPI_low at 3.141590 is lower than the real PI

I have done some bug testing, but you can never be entirely sure. For the time being, you can find the library as MasmBasicRC.zip at the top of this thread. Feedback welcome, as always.

Quote- Preservation of xmm registers:
  xmm0 and xmm1 are frequently used in the library - don't rely on them; you can use a plain Print Str$(xmm0),
  but other Print or Let statements may trash xmm0/xmm1, since the two regs are needed for Len().
  xmm2 is used by Fcmp, StringsDiffer and FilesDiffer
  xmm3 to xmm7 will never be trashed

frktons

Great job  :U
As soon as I move a little into ASM I'll give a try to your lib.
Hoping it will be a stable release when I'll get to that point.  :P

Thanks
Mind is like a parachute. You know what to do in order to use it :-)