The MASM Forum

64 bit assembler => ASMC Development => Topic started by: nidud on January 10, 2017, 03:13:07 AM

Title: Asmc source and binaries
Post by: nidud on January 10, 2017, 03:13:07 AM
Source and binaries for Asmc is now available at GitHub:

https://github.com/nidud/asmc

The package is configured to work "out of the box" but it's recommended to tweak the console settings for optimal performance.

Console applications is best managed by simply adding a shortcut to the program, in this case to the file DZ.EXE in the root directory of the package. After the shortcut is created, right-click and select Properties. Open the Font tab and select a proper font and font size for the console window.

I didn't find the keyboard settings directly in the Win7 Control panel but the search[keyboard] option found the Keyboard Properties tab. The keyboard is normally slow in the console so the Keyboard Delay should be set to Short and Repeat Rate to Fast for best performance.

The environment for the shell is set as follows:
Code: [Select]
[Environ]
0=AsmcDir=%DZ%
1=LIB=%DZ%\lib
2=INCLUDE=%DZ%\include
3=WATCOM=C:\WATCOM

[Path]
0=%AsmcDir%\bin
1=C:\VC\bin
2=%WATCOM%\BINNT
3=%WATCOM%\BINW
4=C:\jWasm
5=%PATH%

Note that Watcom provide clones for some of the MS tools, so VC should for this reason be defined before Watcom.
Title: Re: Asmc source and binaries
Post by: caballero on January 10, 2017, 03:38:42 AM
What is asmc if I may ask?
Title: Re: Asmc source and binaries
Post by: nidud on January 10, 2017, 04:43:27 AM
What is asmc if I may ask?

Asmc is basically a modified version of JWasm made in 2011. It was used as a TASM clone to maintain some DOS tools at the time.

https://github.com/nidud/asmc/blob/master/source/dos/tasm/tasm.asm

I later added some enhancement to the HLL section and a few other things, so I have been playing with it for some time. However the features added so far seems stable so in that sense the playtime has come to a conclusion in a somewhat usable product.

Some more info from the help file:

Asmc Macro Assembler Reference

This lists some of the differences between Asmc, JWasm, and Masm.

Asmc Extensions

The main goal with Asmc is an attempt to provide more readability to the assembly language based on Masm syntax but at the same time keep compatibility with existing source code. In order to achieve this some of the main core of the assembler has to be rewritten and the HLL section enhanced as discussed below.

Parsing of labels

All expansions are pre-processed by the assembler and this may expand macros and other directives before labels. If a macro is added at the same line as a label this may fail.

Example:

Code: [Select]
foo macro reg
bswap reg
exitm <reg>
endm

do: mov eax,foo( eax )
...
mov ecx,"3210"
jmp do

As a result the code produced by the macro will be expanded above the label and thus the jump will fail.

Code: [Select]
bswap ecx
do: mov eax,ecx
...

Asmc will expand the line left to right in this case.

Expansion of macros

The label issue becomes a problem in the HLL section where labels are created later:

   .WHILE macro(...)

Asmc will for this reason delay expansion of macros in some of the HLL directives until labels are created. This include .WHILE, .ELSEIF, and .CASE.

The invoke directive

In Asmc a macro is handled at the same level as a procedure. The header file may then control the expansion:
Code: [Select]
ifdef __INLINE__
strlen macro string
...
endm
else
strlen proto :dword
endif

This is achieved by simply excluding invoke as appose to allow invocations of macros.

   strlen( esi )


Asmc sees the combination of a procedure followed by an open bracket as invoke. Empty brackets will be given special handling if the token in front is not a macro.
Code: [Select]
plabel proto
extern elabel:dword
clabel:
call eax
call plabel
call elabel
call clabel
call xlabel

eax()
plabel()
elabel()
clabel()
xlabel()
xlabel:

This simple solution avoids breaking any existing code with a few exceptions: Masm allows brackets to access memory.

   .if edx < foo( 1 )
   ; MASM: cmp edx,foo+1
   ; ASMC: invoke foo, 1 : cmp edx,eax

So square brackets should be used for accessing memory and round brackets to execute. However, an error must then be issued if Asmc extensions are turned off and labels are accessed using round brackets to ensure compatibility.

The inside of brackets may be recursive used at any length including C-strings. However, the return code for a procedure is [R|E]AX so there is a limit with regards to OR/AND testing of nested functions.

   .if foo( bar( 1 ), 2 ) == TRUE


Handling of strings

Given "quoted strings" may be used as arguments, or in general as a const value, C-strings are limited to be used inside brackets of a procedure.

   .if fopen( "readme.txt", "rt" )


@CStr( string )

Macro function that creates a string in the .DATA segment. The macro accepts C-escape characters in the string. Strings are added to a stack and reused if duplicated strings are found. The macro returns offset string.

Example:
Code: [Select]
mov eax,@CStr( "\tCreate a \"C\" string: %s%d\n" )
mov ebx,@CStr( "string: %s%d\n" )
mov ecx,@CStr( "%s%d\n" )
mov edx,@CStr( "%d\n" )
mov edi,@CStr( "\n" )

Generated code:
Code: [Select]
.data
DS0000 db 9,"Create a ",'"',"C",'"'," string: %s%d",10,0
.code
mov eax,offset DS0000
mov ebx,offset DS0000[14]
mov ecx,offset DS0000[22]
mov edx,offset DS0000[24]
mov edi,offset DS0000[26]

@Date

The system date in the format yyyy-mm-dd (text macro).

.SWITCH

The switch comes in three main variants: a structured switch, as in Pascal, which takes exactly one branch, an unstructured switch, as in C, which functions as a type of goto, and a control table switch with the added possibility of testing for combinations of input values, using boolean style AND/OR conditions, and potentially calling subroutines instead of just a single set of values.

The control table switch is declared with no arguments and each .CASE directive does all the testing.
Code: [Select]
    .switch
      .case strchr( esi, '<' )
      .case strchr( esi, '>' )
    jmp around
      ...
    .endsw

The unstructured switch works as a regular C switch where each .CASE directive is just a label.
Code: [Select]
    .switch eax
      .case 0: .repeat : movsb
      .case 7: movsb
      .case 6: movsb
      .case 5: movsb
      .case 4: movsb
      .case 3: movsb
      .case 2: movsb
      .case 1: movsb : .untilcxz
    .endsw

The structured switch works as a regular Pascal switch where each .CASE directive is a closed branch.
Code: [Select]
    .switch eax
      .case 1: printf("Gold medal")
      .case 2: printf("Silver medal")
      .case 3: printf("Bronze medal")
      .default
  printf("Better luck next time")
    .endsw

.CASE

Case opens a case statement. The case statement compares the value of an ordinal expression to each selector, which can be a constant, a subrange, or a list of them separated by commas.

The selector field is separated from action field by Colon or a new line.
Code: [Select]
.CASE 1: mov ax,2 : .ENDC
.CASE 2
      mov ax,3
      .ENDC
.CASE al
.CASE 0,1,4,7
.CASE 0..9

In the control table switch .CASE is equal to .IF:
Code: [Select]
.CASE al
.CASE ax <= 2 && !bx

.ENDC

.ENDC closes a .CASE statement.

The name was separated from BREAK to have more flexibility with regards to control flow of loops. However, ENDC have the same qualities as BREAK and thus can be used in combination with .IF:

   .ENDC .IF al == 2


.DEFAULT

.DEFAULT executes when none of the other cases match the control expression.

.ENDSW

.ENDSW closes a .SWITCH statement.
Title: Re: Asmc source and binaries
Post by: HSE on January 10, 2017, 06:12:10 AM
Hi Nidud!!

Just testing a ObjAsm32 project (wich have macros .for .switch, etc) I think /Xc is not disabling .switch. 

Of course if the option disable .if, .while, .repeat, etc there is another problem.

Regards.
Title: Re: Asmc source and binaries
Post by: nidud on January 10, 2017, 07:41:37 AM
Just testing a ObjAsm32 project (wich have macros .for .switch, etc) I think /Xc is not disabling .switch. 

The extended directives will be a problem if you use them in this way, so I have to look into that.

Code: [Select]
ifdef __ASMC__
    option renamekeyword: <.switch>=@@switch
    option renamekeyword: <.case>=@@case
    option renamekeyword: <.endsw>=@@endsw
endif

Or the reverse logic:
Code: [Select]
ifndef __ASMC__
    option dotname

.switch macro arg
...
endm
.case macro arg
...
endm
.endsw macro
...
endm
endif
Title: Re: Asmc source and binaries
Post by: nidud on January 10, 2017, 07:59:02 AM
So, the full list:
Code: [Select]
ifdef __ASMC__
    option asmc:off
    option nokeyword:<.switch>
    option nokeyword:<.case>
    option nokeyword:<.endc>
    option nokeyword:<.default>
    option nokeyword:<.endsw>
    option nokeyword:<.ifb>
    option nokeyword:<.ifw>
    option nokeyword:<.ifd>
    option nokeyword:<.assert>
    option nokeyword:<.assertb>
    option nokeyword:<.assertw>
    option nokeyword:<.assertd>
endif
Title: Re: Asmc source and binaries
Post by: nidud on January 10, 2017, 09:04:29 AM
I updated the source and binary

https://github.com/nidud/asmc/commit/571c0913123d57ba2320b263d82f664f6d274ad1

test case using the switch /Xc
Code: [Select]
.486
.model flat
.code

        option dotname

.switch macro
endm
.case macro
endm
.endc macro
endm
.default macro
endm
.endsw macro
endm
.ifb macro
endm
.ifw macro
endm
.ifd macro
endm
.assert macro
endm
.assertb macro
endm
.assertw macro
endm
.assertd macro
endm

END
Title: Re: Asmc source and binaries
Post by: HSE on January 10, 2017, 02:17:37 PM
/Xc work perfect now  :t

With that option ObjAsm32 work fantastic.  :eusa_clap: :eusa_clap:

Apparently full compatiblity with M$, no length line problems, nor macro nest levels problems.   

                              (http://www.thebort.com/www/Smileys/default/th_beer.gif)
Title: Re: Asmc source and binaries
Post by: nidud on January 10, 2017, 09:23:08 PM
 :t

This do however separate the switch /Xc from the OPTION ASMC:[ON|OFF]

The off option will keep the directives and the switch will still work, but using extended features will generate an error:
Code: [Select]
        foo proto
        option asmc:off
        .switch
          .case  (eax || edx) && ecx : nop : .endc
          .case !(eax || edx) && ecx : nop : .endc
          .case foo()
 error A2008: syntax error : )
Title: Re: Asmc source and binaries
Post by: HSE on January 12, 2017, 01:06:55 AM
Very interesting! With the nokeyword option it's posible to use the same command line options for M$ or HJwasm. In RadAsm I only change the assembler name  :t 
Title: Re: Asmc source and binaries
Post by: powershadow on January 15, 2017, 10:56:12 PM
Hi nidud.
Just downloaded asmc.exe for test it, and I already have a question.
Command-line /I - not supported anymore? I need use environment variable "include"?
I see asmc just add path from "/I" to the path of my project, this is incorrect.

Simple example:

.386
.model flat,stdcall
include windows.inc ; <<<< fatal error A1000: cannot open file: windows.inc

Command-line:
c:\jwasm\bin32\asmc.exe /c /coff /cp /I"c:\jwasm\Include" "test.asm"

It is bug or feature?
Title: Re: Asmc source and binaries
Post by: jj2007 on January 15, 2017, 11:00:13 PM
include windows.inc ; <<<< fatal error A1000: cannot open file: windows.inc

Use \masm32\include\windows.inc

Or, even better:
include \masm32\include\masm32rt.inc

There is a reason why (almost) everybody here uses the \full\path without the drive letters: it works.
Title: Re: Asmc source and binaries
Post by: powershadow on January 15, 2017, 11:15:44 PM
There is a reason why (almost) everybody here uses the \full\path without the drive letters: it works.

Thanks for reply. I know it. I just ask if this bug or feature. I just opened example from masm32 and can't compile them without modify.

masm - file found.
jwasm - file found.
hjwasm - file found.
asmc - file NOT found, strange.
Title: Re: Asmc source and binaries
Post by: jj2007 on January 15, 2017, 11:24:24 PM
OK, I see. This works:
Code: [Select]
C:\Masm32\MasmBasic\AscUser>\masm32\bin\asmc /c /coff /I"\Masm32\Include" testAsmC.asm
Doszip Macro Assembler Version 2.22
Portions Copyright (c) 1992-2002 Sybase, Inc. All Rights Reserved.

 Assembling: testAsmC.asm

... with this source:
Code: [Select]
.386
.model flat,stdcall
;include windows.inc ; <<<< fatal error A1000: cannot open file: windows.inc
.code
start:
  retn

end start

However, I get plenty of errors in all assemblers when trying to use both the command line include and the one after .model

Btw what's the state of play in your other thread (http://masm32.com/board/index.php?topic=5896.msg62670#msg62670)? All problems fixed?
Title: Re: Asmc source and binaries
Post by: nidud on January 16, 2017, 02:58:17 AM
Confirmed.

Quotes in command line arguments are not expanded in the same way in the RTL now used, so additional expansion was needed for switch -D, -I and -Fi used with -I"quoted text".

Link to the added changes:
https://github.com/nidud/asmc/commit/5471d03bbfced345c50b95dcecb1e6957fe18a95
Title: Re: Asmc source and binaries
Post by: powershadow on January 16, 2017, 07:55:04 PM
Confirmed.

Quotes in command line arguments are not expanded in the same way in the RTL now used, so additional expansion was needed for switch -D, -I and -Fi used with -I"quoted text".

Wow so fast, this project has better support then hjwasm! :t
Nidud, may I request a feature?
Can you add to the listing file (/Fl), dump for all used procedure protos.
Example:

Code: [Select]
...
.NOLIST
Include kernel32.inc
...
.code

TestProc1 proc Par1:HANDLE,Par2:DWORD,Par3:PVOID
xor eax,eax
ret

TestProc1 endp

start:

invoke CreateFile,SADD('file.txt'),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
invoke TestProc1,eax,11111111h,NULL
invoke ExitProcess,0
end start

Listing file:
...
Procedures protos:

                N a m e                 PROTO

TestProc1  . . . . . . . . . . .        PROTO Par1:HANDLE, Par2:DWORD, Par3:PVOID
CreateFileA  . . . . . . . . . .        PROTO lpFileName:PSTR ,dwDesiredAccess:DWORD ,dwShareMode:DWORD ,lpSecurityAttributes:PVOID ,dwCreationDisposition:DWORD ,dwFlagsAndAttributes:DWORD ,hTemplateFile:HANDLE
ExitProcess  . . . . . . . . . .        PROTO uExitCode:DWORD
...

Where TestProc1 generated from source, CreateFileA & ExitProcess - just copy used proto from inc file.
Title: Re: Asmc source and binaries
Post by: nidud on January 17, 2017, 03:12:40 AM
Nidud, may I request a feature?
Can you add to the listing file (/Fl), dump for all used procedure protos.

Unused functions have a '*' added to the list if that helps:
Code: [Select]
.386
.model flat,stdcall
.code

foo proto
bar proto

foo()

END

Code: [Select]
Procedures, parameters and locals:

                N a m e                 Type     Value    Segment  Length

bar  . . . . . . . . . . . . . .        P Near32 00000000 No Seg   00000000 *External STDCALL
foo  . . . . . . . . . . . . . .        P Near32 00000000 No Seg   00000000 External  STDCALL
Title: Re: Asmc source and binaries
Post by: powershadow on January 17, 2017, 03:21:56 AM
Unused functions have a '*' added to the list if that helps:
Thanks for reply nidud, unfortunately it's not help :(. I need PROTOs
Title: Re: Asmc source and binaries
Post by: nidud on January 17, 2017, 03:48:16 AM
Well, I can see the usefulness of this and the information to compile the list may also be available, so I may look into this someday.
Title: Re: Asmc source and binaries
Post by: nidud on March 02, 2017, 08:08:18 AM
Some imort libraries are added to the source base. I was hoping to do this the simple way by target the .dll files directly, at least the 64-bit without any decoration.
Code: [Select]
32 libw /n /c /l /b /fac /ii version.lib %windir%\system32\version.dll
64 libw /n /c /l /b /fac /i6 version.lib %windir%\system32\version.dll

However, this didn't work very well for some (unknown) reason, so I ended up using .def files for all of them. The command that works looks like this:
Code: [Select]
++_BlockWOWIdle@4.'NTVDM.exe'

Given this works (I assume), the import record for the simple approach should in theory also work, at least for C and FASTCALL.

I have also done some testing with using windows.inc for differnt targets. The same include files should now work for both 32 and 64.bit, unicode/ascii, C/stdcall/fastcall, creating PE (no libs), using msvcrt (C/fastcall), or using the local library with startup modules.

Some changes have also been added to MAKE to simplify the build process. If %AsmcDir% is set MAKE will use the .\lib directory as a common include directory for .mif files.

Well, parsing these includes is tidious work so the current state looks like this:
Code: [Select]
WIN32_LEAN_AND_MEAN equ 1
include windows.inc

I currently only need kernel32 and user32 in the source base, but as the parsing improves more files will be added. Depending on how these functions are decleared, some will be defined with return type and line breaks, others with a single line:

Code: [Select]
if (_WIN32_WINNT GE 0x0500)
;BOOL
InitializeCriticalSectionAndSpinCount proto _CType \
     lpCriticalSection: LPCRITICAL_SECTION,
   dwSpinCount: DWORD
;DWORD
SetCriticalSectionSpinCount proto _CType \
     lpCriticalSection: LPCRITICAL_SECTION,
   dwSpinCount: DWORD
endif

Code: [Select]
ifndef _WDIRECT_DEFINED

;; also declared in direct.h

_wchdir proto :ptr wchar_t
_wgetcwd proto :ptr wchar_t, :SINT
_wgetdcwd proto :SINT, :ptr wchar_t, :SINT
_wmkdir proto :ptr wchar_t
_wrmdir proto :ptr wchar_t

_WDIRECT_DEFINED equ 1
endif
Title: Re: Asmc source and binaries
Post by: Vortex on March 03, 2017, 07:01:57 AM
Hi nidud,

Regarding 64-bit coding, it's easy to create .def files and import libraries from DLLs :

Creating include files and import libraries for ml64 (http://masm32.com/board/index.php?topic=5496.0)
Title: Re: Asmc source and binaries
Post by: nidud on March 03, 2017, 10:25:40 AM
Hey Vortex

The problem here is that LIBW (https://github.com/nidud/asmc/tree/master/source/linkw/libw) is capable of creating a working import record from the command line but fail to do so from a .dll file. Asmc also use the same code for the /pe switch. This means that the problem is fixable within the source for LIBW, but I haven't looked into this yet.

The include files used in the Asmc package is the same for both 32 and 64-bit, so I need the arguments for all the functions as well. In addition to this I also need the type and size of each of them as oppose to just flip from DWORD to QWORD.

It would have been possible to just flip :DWORD to :PTR in the MASM32 package as well as appose to create a new set of files, but having the correct size and types makes a huge difference with regards to debugging.

What I'm doing now is moving (and adding) declarations to the correct MS header files to get them better organized and thereby easier yo use for those more familiar with these. So there is a C/ASM merger of sorts going on here.

As for the decorated symbols for 32-bit they available here:
https://github.com/open-watcom/open-watcom-v2/tree/master/bld/w32api/lib

It's possible parse these to create simple .inc files for both 32 and 64-bit.
.def 32:
AddConsoleAliasA@12
.def 64:
AddConsoleAliasA
.inc 32/64
AddConsoleAliasA proto :ptr, :ptr, :ptr

This is currently how the imports are created.
32-bit:
https://github.com/nidud/asmc/blob/master/lib/makefile
64-bit:
https://github.com/nidud/asmc/blob/master/lib/x64/makefile

Given no libraries exist at this point and the .def files needs parsing, the parser is made using the includes with the /pe switch.
32-bit:
https://github.com/nidud/asmc/blob/master/lib/def/lbc.asm
64-bit:
https://github.com/nidud/asmc/blob/master/lib/def/lbc64.asm
Title: Re: Asmc source and binaries
Post by: nidud on March 04, 2017, 06:35:13 AM
A sample on how to use TCHAR.INC (https://github.com/nidud/asmc/blob/master/include/tchar.inc) for multiple targets. Most of the samples used by MS (https://msdn.microsoft.com/en-us/library/windows/desktop/aa364963(v=vs.85).aspx) apply this methood for unicode/ascii.
Code: [Select]
include stdio.inc
include stdlib.inc
include tchar.inc

.code

_tmain proc _CDecl argc:SINT, argv:PVOID

.for RSI = argv, edi = argc, ebx = 0: edi: edi--, ebx++, RSI += size_t

_tprintf("[%d]: %s\n", ebx, [RSI])
.endf
xor eax,eax
ret

_tmain endp

end _tstart

The command line for Asmc /pe:
asmc -pe -D__PE__ $*.asm
asmc -pe -ws -D_UNICODE -D__PE__ $*.asm
asmc -pe -D_WIN64 -D__PE__ $*.asm
asmc -pe -ws -D_UNICODE -D_WIN64 -D__PE__ $*.asm

The same code may also be built using the local library (https://github.com/nidud/asmc/tree/master/source/test/tchar), but only the 32-bit ASCII version has the appropriate startup module to handle the the main arguments for now.

Thus it may not be recommendable to mix 32 and 64-bit code in this way the possibility to do just that is at least within reach. The CALL directive is somewhat limited for this approach so you have to use INVOKE on function calls to handle the local/import declarations (_imp_*) correctly.

The startup module is now defined in the tchar.inc file for the /pe switch, so the _tstart macro is either <> or <mainCRTStartup>. The Rxx registers are define in up-case chars so they become case sensitive in 32-bit.
Title: Re: Asmc source and binaries
Post by: Vortex on March 04, 2017, 06:39:21 AM
Hi nidud,

I am fine with the DWORD to QWORD conversion but knowing the size and the type of the arguments is useful while debugging as you said.

The same include files supporting both 32-bit and 64-bit coding is a good idea. Creating the module definition files is not a problem, I do it with my lib2def tool. Pelle's library manager polib can be used for the same task.

Keep up the good work nidud :t
Title: Re: Asmc source and binaries
Post by: jj2007 on March 04, 2017, 07:06:06 AM
The same include files supporting both 32-bit and 64-bit coding is a good idea.

I agree, see 64-bit assembly with RichMasm (http://masm32.com/board/index.php?topic=5314.msg59884#msg59884). It is pretty easy, actually, mainly because Microsoft needs it for the transition from 32-bit to 64-bit ("The header files for the Windows API enable you to create 32- and 64-bit applications." (https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs.85).aspx)). My solution works fine, not a single extra library or header needed, but it is limited to the most important WinAPIs. Currently, I can't find enough enthusiasm to develop it further, simply because I don't see a convincing reason to go 64-bit 8)
Title: Re: Asmc source and binaries
Post by: nidud on March 11, 2017, 05:48:07 AM
Code: [Select]
WIN32_LEAN_AND_MEAN equ 1
include windows.inc

The rest of the include files are now added but not tested: no assembly error.
Title: Re: Asmc source and binaries
Post by: nidud on April 04, 2017, 03:02:50 AM
The Machine Architectures defined in windows.inc:
     _M_IX86      32-bit
     _M_AMD64   32/64-bit
     _M_IA64      64-bit

I added two directives: .amd64 and .win64. This to enable source level control as oppose to be depended on command line switches. I added this to simplify testing but I'm not sure how useful this will be elsewhere.

.win64 is the same as /win64 and .asm64 is equal to .x64.
I may add some options to the .win64 directive later.
.win64[: rsp | rbp | align | ...]

.win64 should be the first directive used since it needs to reset the assembler. The /win64 switch is similar to the /LARGEADDRESSAWARE switch, using "real" 64-bit.

Code: [Select]
.win64
.code

Code: [Select]
; Disassembly of file: win64.obj
; Mon Apr 03 18:46:46 2017
; Mode: 64 bits
; Syntax: MASM/ML64
; Instruction set: 8086, x64

Code: [Select]
.amd64
.model flat, fastcall
.code

Code: [Select]
; Disassembly of file: win64.obj
; Mon Apr 03 18:13:50 2017
; Mode: 32 bits
; Syntax: MASM/ML
; Instruction set: 80386

.386
.model flat
Title: Re: Asmc source and binaries
Post by: nidud on April 06, 2017, 11:57:33 PM
Quote
I may add some options to the .win64 directive later.
.win64[: rsp | rbp | align | ...]

I added the following syntax:

.WIN64 [: RSP | RBP | ALIGN | NOALIGN | SAVE | NOSAVE | AUTO | NOAUTO | FRAME | NOFRAME]

This may also be used with .X64 and .AMD64

RBP:
   STACKBASE = RBP
   FRAME = AUTO
   W64F_AUTOSTACKSP = 1
   W64F_SAVEREGPARAMS = 1
RSP:
   STACKBASE = RSP
   W64F_AUTOSTACKSP = 1
ALIGN:
   IF WIN64 == 0
      W64F_AUTOSTACKSP = 1
   W64F_STACKALIGN16 = 1
NOALIGN:
   W64F_STACKALIGN16 = 0
SAVE:
   W64F_SAVEREGPARAMS = 1
NOSAVE:
   W64F_SAVEREGPARAMS = 0
AUTO:
   W64F_AUTOSTACKSP = 1
NOAUTO:
   W64F_AUTOSTACKSP = 0
FRAME:
   FRAME = AUTO
NOFRAME:
   FRAME = NOAUTO

Code: [Select]
.win64: rbp align
.code

foo proc uses rdi a1:byte, a2:word, a3:dword, a4:qword

  local l1: byte,
l2: xmmword,
l3: byte,
l4: ymmword,
l5: byte

lea rax,l1
lea rax,l2
lea rax,l3
lea rax,l4
lea rax,l5

mov al,a1
mov ax,a2
mov eax,a3
mov rax,a4

ret
foo endp

Code: [Select]
00000000  48894C2408        *   mov [rsp+8], rcx
00000005  4889542410        *   mov [rsp+16], rdx
0000000A  4C89442418        *   mov [rsp+24], r8
0000000F  4C894C2420        *   mov [rsp+32], r9
00000014  55                *   push rbp
00000015  488BEC            *   mov rbp, rsp
00000018  57                *   push rdi
00000019  4881EC88000000    *   sub rsp, 104 + @ReservedStack
00000020  488D45F7              lea rax,l1
00000024  488D45E0              lea rax,l2
00000028  488D45DF              lea rax,l3
0000002C  488D45A0              lea rax,l4
00000030  488D459F              lea rax,l5

00000034  8A4510                mov al,a1
00000037  668B4518              mov ax,a2
0000003B  8B4520                mov eax,a3
0000003E  488B4528              mov rax,a4

00000042                        ret
00000042  4881C488000000    *   add rsp, 104 + @ReservedStack
00000049  5F                *   pop rdi
0000004A  C9                *   leave
0000004B  C3                *   retn

   .win64: rsp

Code: [Select]
00000000  57                *   push rdi
00000001  4881EC80000000    *   sub rsp, 96 + @ReservedStack
00000008  488D44247F            lea rax,l1
0000000D  488D442468            lea rax,l2
00000012  488D442467            lea rax,l3
00000017  488D442430            lea rax,l4
0000001C  488D44242F            lea rax,l5

00000021  8A842490000000        mov al,a1
00000028  668B842498000000      mov ax,a2
00000030  8B8424A0000000        mov eax,a3
00000037  488B8424A8000000      mov rax,a4
0000003F                        ret
0000003F  4881C480000000    *   add rsp, 96 + @ReservedStack
00000046  5F                *   pop rdi
00000047  C3                *   retn
Title: Re: Asmc source and binaries
Post by: Vortex on April 07, 2017, 05:28:31 AM
Hi nidud,

.win64:rbp align works fine, thanks :t

Code: [Select]
.win64:rbp align
option casemap:none

include    Window.inc

.data

ClassName  db "WndClass",0
AppName    db "Window",0

.code

start PROC

LOCAL hInstance:QWORD
   
    invoke  GetModuleHandle,0
    mov     hInstance,rax
   
    invoke  GetCommandLine
   
    invoke  WinMain,hInstance,0,rax,SW_SHOWDEFAULT
    invoke  ExitProcess,rax

start ENDP

WinMain PROC hInst:QWORD,hPrevInst:QWORD,CmdLine:QWORD,CmdShow:QWORD

    LOCAL   wc:WNDCLASSEX
    LOCAL   msg:MSG
    LOCAL   hwnd:QWORD

    mov     wc.cbSize,SIZEOF WNDCLASSEX
    mov     wc.style,CS_HREDRAW or CS_VREDRAW
    mov     rax,OFFSET WndProc
    mov     wc.lpfnWndProc,rax

    xor     rax,rax
    mov     wc.cbClsExtra,eax
    mov     wc.cbWndExtra,eax
    mov     wc.hInstance,rcx
    mov     wc.hbrBackground,COLOR_WINDOW+1
    mov     wc.lpszMenuName,rax

    lea     rax,ClassName
    mov     wc.lpszClassName,rax
    invoke  LoadIcon,0,IDI_APPLICATION
    mov     wc.hIcon,rax
    mov     wc.hIconSm,rax
    invoke  LoadCursor,0,IDC_ARROW
    mov     wc.hCursor,rax
    invoke  RegisterClassEx,ADDR wc

    mov     rax,CW_USEDEFAULT

    invoke  CreateWindowEx,0,ADDR ClassName,\
            ADDR AppName,\
            WS_OVERLAPPEDWINDOW,\
            rax,rax,rax,rax,0,0,\
            hInst,0

    mov     hwnd,rax

    invoke  ShowWindow,hwnd,SW_SHOWNORMAL
    invoke  UpdateWindow,hwnd

@@:
    invoke  GetMessage,ADDR msg,0,0,0
    test    rax,rax
    jz      @f
    invoke  TranslateMessage,ADDR msg
    invoke  DispatchMessage,ADDR msg
    jmp     @b
@@:
    mov     rax,msg.wParam
    ret

WinMain ENDP

WndProc PROC hWnd:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD

    cmp     edx,WM_DESTROY
    jne     @f

    invoke  PostQuitMessage,0
    jmp     _exit
@@:   
    invoke  DefWindowProc,hWnd,uMsg,wParam,lParam
    ret

_exit:

    xor     rax,rax
    ret

WndProc ENDP

END
Title: Re: Asmc source and binaries
Post by: nidud on April 07, 2017, 07:09:54 AM
Thanks for the sample Vortex  :t

I will try to use windows.inc and see how that goes..
Title: Re: Asmc source and binaries
Post by: nidud on April 07, 2017, 08:12:51 AM
Yep, that failed  :biggrin:

Updated winuser.inc (https://github.com/nidud/asmc/commit/99135b4e8ddb12249679b744059b41a817d2860a)..

New source: Note that align is only needed for xmm/ymmword locals.
Code: [Select]
include windows.inc

.win64: rbp
.code

start proc

    mov rbx,GetModuleHandle(0)
    ExitProcess(WinMain(rbx, 0, GetCommandLine(), SW_SHOWDEFAULT))

start endp

WinMain PROC hInstance: HINSTANCE,
hPrevInstance: HINSTANCE,
     lpCmdLine: LPSTR,
      nShowCmd: SINT

    LOCAL   wc:WNDCLASSEX
    LOCAL   msg:MSG
    LOCAL   hwnd:QWORD

    mov     wc.cbSize,SIZEOF WNDCLASSEX
    mov     wc.style,CS_HREDRAW or CS_VREDRAW
    mov     rax,OFFSET WndProc
    mov     wc.lpfnWndProc,rax

    xor     rax,rax
    mov     wc.cbClsExtra,eax
    mov     wc.cbWndExtra,eax
    mov     wc.hInstance,rcx
    mov     wc.hbrBackground,COLOR_WINDOW+1
    mov     wc.lpszMenuName,rax

    lea     rax,@CStr("WndClass")
    mov     wc.lpszClassName,rax
    mov     wc.hIcon,LoadIcon(0,IDI_APPLICATION)
    mov     wc.hIconSm,rax
    mov     wc.hCursor,LoadCursor(0,IDC_ARROW)
    RegisterClassEx(ADDR wc)

    mov     eax,CW_USEDEFAULT
    mov     hwnd,CreateWindowEx(0,"WndClass","Window",WS_OVERLAPPEDWINDOW,
eax,eax,eax,eax,0,0,hInstance,0)

    ShowWindow(hwnd,SW_SHOWNORMAL)
    UpdateWindow(hwnd)

    .while GetMessage(ADDR msg,0,0,0)

TranslateMessage(ADDR msg)
DispatchMessage(ADDR msg)
    .endw

    mov rax,msg.wParam
    ret

WinMain ENDP

WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    .if edx == WM_DESTROY

PostQuitMessage(0)
xor rax,rax
    .else
DefWindowProc(hWnd,uMsg,wParam,lParam)
    .endif
    ret

WndProc ENDP

END

The typing reduce the source with around 50 byte, however the linker increase the size of the exe to 4096.

Using rsp also works, but this extends the code a bit:
Code: [Select]
.win64: rsp save
00000208                    *   _TEXT ends
.win64: rbp
000001CF                    *   _TEXT ends
Title: Re: Asmc source and binaries
Post by: nidud on April 08, 2017, 01:43:00 AM
The Windows 64 ABI may seem complicated and messy, at least in assembly, but by using a standard stack-frame it basically behaves just like a STDCALL function.

There is however the possibility to simplify the mess as compilers do, but it becomes an open question then how far you have to stretch this before you end up compiling as oppose to just assemble the source. I tend to support the latter in this case, using the safe settings for all and apply manual optimization later.

The two normal optimization options are:
- if the function don't make any calls: skip the frame
- if the function can use the regs instead of the arguments: skip save.

Both of these could have been compiled I guess, but as for now this have to be done manually.

Example:

The last proc in the above sample may be optimized as follow:
Code: [Select]
.win64: rsp nosave

WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    .if edx == WM_DESTROY

PostQuitMessage(0)
xor rax,rax
    .else
DefWindowProc(rcx, edx, r8, r9)
    .endif
    ret

WndProc ENDP

Standard version:
Code: [Select]
WndProc PROC
        mov     qword ptr [rsp+8H], rcx                 ; 0185 _ 48: 89. 4C 24, 08
        mov     qword ptr [rsp+10H], rdx                ; 018A _ 48: 89. 54 24, 10
        mov     qword ptr [rsp+18H], r8                 ; 018F _ 4C: 89. 44 24, 18
        mov     qword ptr [rsp+20H], r9                 ; 0194 _ 4C: 89. 4C 24, 20
        push    rbp                                     ; 0199 _ 55
        mov     rbp, rsp                                ; 019A _ 48: 8B. EC
        sub     rsp, 32                                 ; 019D _ 48: 83. EC, 20
        cmp     edx, 2                                  ; 01A1 _ 83. FA, 02
        jnz     ?_003                                   ; 01A4 _ 75, 0F
        mov     ecx, 0                                  ; 01A6 _ B9, 00000000
        call    PostQuitMessage                         ; 01AB _ E8, 00000000(rel)
        xor     rax, rax                                ; 01B0 _ 48: 33. C0
        jmp     ?_004                                   ; 01B3 _ EB, 14

?_003:  mov     rcx, qword ptr [rbp+10H]                ; 01B5 _ 48: 8B. 4D, 10
        mov     edx, dword ptr [rbp+18H]                ; 01B9 _ 8B. 55, 18
        mov     r8, qword ptr [rbp+20H]                 ; 01BC _ 4C: 8B. 45, 20
        mov     r9, qword ptr [rbp+28H]                 ; 01C0 _ 4C: 8B. 4D, 28
        call    DefWindowProcA                          ; 01C4 _ E8, 00000000(rel)
?_004:  add     rsp, 32                                 ; 01C9 _ 48: 83. C4, 20
        leave                                           ; 01CD _ C9
        ret                                             ; 01CE _ C3
WndProc ENDP

Optimized version:
Code: [Select]
WndProc PROC
        sub     rsp, 40                                 ; 0185 _ 48: 83. EC, 28
        cmp     edx, 2                                  ; 0189 _ 83. FA, 02
        jnz     ?_003                                   ; 018C _ 75, 0F
        mov     ecx, 0                                  ; 018E _ B9, 00000000
        call    PostQuitMessage                         ; 0193 _ E8, 00000000(rel)
        xor     rax, rax                                ; 0198 _ 48: 33. C0
        jmp     ?_004                                   ; 019B _ EB, 05

?_003:  call    DefWindowProcA                          ; 019D _ E8, 00000000(rel)
?_004:  add     rsp, 40                                 ; 01A2 _ 48: 83. C4, 28
        ret                                             ; 01A6 _ C3
WndProc ENDP
Title: Re: Asmc source and binaries
Post by: nidud on June 06, 2017, 10:33:44 AM
Hi nidud,

Regarding 64-bit coding, it's easy to create .def files and import libraries from DLLs :

Creating include files and import libraries for ml64 (http://masm32.com/board/index.php?topic=5496.0)

Hi Vortex,

I tested Dll2definc.exe/def2lib64.exe but the LIB file only include 32-bit imports. The problem is that Dll2definc is a 32-bit EXE, so LoadLibrary() will load the 32-bit version of kernel32.dll.

Code: [Select]
include stdio.inc
include winnt.inc
include winbase.inc

.code

main proc argc:dword, argv:ptr
local dll
    .if argc == 2
mov esi,argv
.if LoadLibrary([esi+4])
    mov dll,eax
    mov edi,eax
    add edi,[eax+0x3C]
    mov edi,[edi].IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress
    add edi,eax
    mov ebx,[edi+0x18]
    mov esi,[edi+0x20]
    add esi,eax
    .while ebx
mov eax,[esi]
add eax,dll
printf("%s\n", eax)
add esi,4
dec ebx
    .endw
    FreeLibrary(dll)
.endif
    .endif
    xor eax,eax
    ret
main endp

    end

Some missing functions:
- RtlUnwindEx
- RtlVirtualUnwind

So here's a 64-bit version:
Code: [Select]
;
; Build: asmc -pe -D__PE__ -D_WIN64 dlldef.asm
;
include string.inc
include stdio.inc
include stdlib.inc
include winbase.inc
include tchar.inc

    .code

main proc
    .if rcx == 2
mov rdi,[rdx+8]
        .if LoadLibrary(rdi)
            mov r12,rax
            mov rbx,strcpy(strrchr(rdi,'.'),".def")
            .if fopen(rdi,"wt")
                mov r13,rax
                mov byte ptr [rbx],0
                fprintf(r13,"LIBRARY %s\nEXPORTS\n",rdi)
mov eax,[r12+0x3C]
mov eax,[r12+rax].IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress
mov ebx,[r12+rax+0x18]
mov esi,[r12+rax+0x20]
                add rsi,r12
                .while ebx
                    lodsd
    fprintf(r13,"\"%s\"\n",addr [rax+r12])
                    dec ebx
                .endw
                fclose(r13)
            .endif
            FreeLibrary(r12)
        .endif
    .else
        printf("\nUsage: DLLDEF <dllname>.dll\n\n")
    .endif
    xor eax,eax
    ret
main endp

    end _tstart

I only tested with kernel32 using def2lib64 and that seems to work.
Title: Re: Asmc source and binaries
Post by: Vortex on June 09, 2017, 03:57:31 AM
Hi nidud,

Thanks for your tests and the tool. My assumption considering that both of the 32-bit and 64-bit versions of a DLL are exporting the same functions was wrong.
Title: Re: Asmc source and binaries
Post by: nidud on June 09, 2017, 09:19:18 AM
My assumption considering that both of the 32-bit and 64-bit versions of a DLL are exporting the same functions was wrong.

I sort of assumed the same.

The problem here is that LIBW (https://github.com/nidud/asmc/tree/master/source/linkw/libw) is capable of creating a working import record from the command line but fail to do so from a .dll file. Asmc also use the same code for the /pe switch. This means that the problem is fixable within the source for LIBW, but I haven't looked into this yet.

Well, now we know why but the lib creation from the list produced works thought so no changes is needed there. I updated the makefiles for building the import libraries so that should work now.

https://github.com/nidud/asmc/blob/master/lib/
Title: Re: Asmc source and binaries
Post by: coder on June 15, 2017, 05:32:08 PM
The Windows 64 ABI may seem complicated and messy, at least in assembly, but by using a standard stack-frame it basically behaves just like a STDCALL function.
No, it is not. It looks messy because people don't have a clear understanding of the ABI itself. If you read the spec carefully, the ABI requires only 3 general criteria;

1. allocate shadow space
2. align the stack to 16 (everybody must ensure that this is done in their function bodies before calling out others)
3. XMMs for floating point, GPRs for integers (rcx,rdx...)

That's it. Everything else is not considered part of the ABI spec. For example, saving the volatile registers (rcx... r9) is never part of the ABI. It's up to the user's code whether to save them or not. YMM registers are not part of the ABI either. The code below shows your confusion in implementing the ABI. This my friend, indeed looks messy, because your're attempting to implement BOTH legacy STDCALL and FASTCALL on top of each other. It has nothing to do with optimized vs standard code.

Quote from: nidud
Standard version:
Code: [Select]
WndProc PROC
        mov     qword ptr [rsp+8H], rcx                 ; 0185 _ 48: 89. 4C 24, 08
        mov     qword ptr [rsp+10H], rdx                ; 018A _ 48: 89. 54 24, 10
        mov     qword ptr [rsp+18H], r8                 ; 018F _ 4C: 89. 44 24, 18   ;saving volatile registers part of the ABI?
        mov     qword ptr [rsp+20H], r9                 ; 0194 _ 4C: 89. 4C 24, 20
        push    rbp                                     ; 0199 _ 55                                   ;STDCALL?
        mov     rbp, rsp                                ; 019A _ 48: 8B. EC
        sub     rsp, 32                                 ; 019D _ 48: 83. EC, 20
        cmp     edx, 2                                  ; 01A1 _ 83. FA, 02
        jnz     ?_003                                   ; 01A4 _ 75, 0F
        mov     ecx, 0                                  ; 01A6 _ B9, 00000000
        call    PostQuitMessage                         ; 01AB _ E8, 00000000(rel)
        xor     rax, rax                                ; 01B0 _ 48: 33. C0
        jmp     ?_004                                   ; 01B3 _ EB, 14

?_003:  mov     rcx, qword ptr [rbp+10H]                ; 01B5 _ 48: 8B. 4D, 10
        mov     edx, dword ptr [rbp+18H]                ; 01B9 _ 8B. 55, 18
        mov     r8, qword ptr [rbp+20H]                 ; 01BC _ 4C: 8B. 45, 20
        mov     r9, qword ptr [rbp+28H]                 ; 01C0 _ 4C: 8B. 4D, 28
        call    DefWindowProcA                          ; 01C4 _ E8, 00000000(rel)
?_004:  add     rsp, 32                                 ; 01C9 _ 48: 83. C4, 20
        leave                                           ; 01CD _ C9
        ret                                             ; 01CE _ C3
WndProc ENDP

Title: Re: Asmc source and binaries
Post by: nidud on June 15, 2017, 10:05:53 PM
No, it is not. It looks messy because people don't have a clear understanding of the ABI itself. If you read the spec carefully, the ABI requires only 3 general criteria;

1. allocate shadow space

So the shadow space is part of the Application binary interface (https://en.wikipedia.org/wiki/Application_binary_interface) then.

Quote
For example, saving the volatile registers (rcx... r9) is never part of the ABI.

The first four integer or pointer parameters are passed in the rcx, rdx, r8, and r9 registers. The caller reserves space on the stack for arguments passed in registers. This is what the shadow space is used for.

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture

Quote
The code below shows your confusion in implementing the ABI. This my friend, indeed looks messy, because your're attempting to implement BOTH legacy STDCALL and FASTCALL on top of each other. It has nothing to do with optimized vs standard code.

Yes, the ABI may look a bit complicated, messy and confusing in assembly.
Title: Re: Asmc source and binaries
Post by: coder on June 15, 2017, 11:16:40 PM
No, it is not. It looks messy because people don't have a clear understanding of the ABI itself. If you read the spec carefully, the ABI requires only 3 general criteria;

1. allocate shadow space

So the shadow space is part of the Application binary interface (https://en.wikipedia.org/wiki/Application_binary_interface) then.

Quote
For example, saving the volatile registers (rcx... r9) is never part of the ABI.

The first four integer or pointer parameters are passed in the rcx, rdx, r8, and r9 registers. The caller reserves space on the stack for arguments passed in registers. This is what the shadow space is used for.

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture

Quote
The code below shows your confusion in implementing the ABI. This my friend, indeed looks messy, because your're attempting to implement BOTH legacy STDCALL and FASTCALL on top of each other. It has nothing to do with optimized vs standard code.

Yes, the ABI may look a bit complicated, messy and confusing in assembly.
I don't know. It's up to you to interpret my statements and suggestions. Maybe my terminologies are wrong, but your codes look funnier. If you think that stacking both fastcall and stdcall at the same entry point is a 'standard' code and practice, then enjoy it.

 
Title: Re: Asmc source and binaries
Post by: nidud on June 16, 2017, 12:33:15 AM
I don't know. It's up to you to interpret my statements and suggestions. Maybe my terminologies are wrong, but your codes look funnier.

Well, the sample you refer to is not "code" but the disassembled output from the object created by the assembler. The tool used is Agner Fog's objconv.exe.
Code: [Select]
Object file converter version 2.38 for x86 and x86-64 platforms.
Copyright (c) 2014 by Agner Fog. Gnu General Public License.

The original code was written by Vortext in Reply #28 (http://masm32.com/board/index.php?topic=5929.msg65018#msg65018), and I used this as a test case for the windows.inc project (https://github.com/nidud/asmc/tree/master/include) in Reply #30 (http://masm32.com/board/index.php?topic=5929.msg65021#msg65021).

Quote
If you think that stacking both fastcall and stdcall at the same entry point is a 'standard' code and practice, then enjoy it.

That may be confusing if your not familiar with the STDCALL calling convention. The 64-bit ABI is not "pure" FASTCALL but a combination of passing some arguments as registers and the rest on the stack. In addition to this stack is allocated (by the caller) for the arguments passed in registers.

The point of comparing STDCALL/FASTCALL has to do with the PROC and INVOKE directives and how this is handled by the assembler.

Code for Windows 32 ABI (stdcall)
Code: [Select]
WinMain PROC hInstance: HINSTANCE,
hPrevInstance: HINSTANCE,
     lpCmdLine: LPSTR,
      nShowCmd: SINT

strlen(lpCmdLine)

Code for Windows 64 ABI (fastcall)
Code: [Select]
WinMain PROC hInstance: HINSTANCE,
hPrevInstance: HINSTANCE,
     lpCmdLine: LPSTR,
      nShowCmd: SINT

strlen(lpCmdLine)

To see the code produced the object files are disassembled.
Title: Re: Asmc source and binaries
Post by: coder on June 16, 2017, 01:41:05 AM
I don't understand your point, Nidud. I questioned the validity of what you called as 'standard' vs 'optimized'. There's no way that the first output can be called a standard of any kind. Standard against what? Saving the volatile registers has never been part of any 64-bit ABI 'standard'. And you're wrong about the shadow space being used to save the volatile registers because it is not. It's the responsibility of the users / callers to save them, hence you don't see them in the second output. Do you see the second output making attempts to save RCX to R9? No. So do the Win64 APIs. They don't save the registers for you because it's not part of the ABI requirement. You, the callers, do it yourself. It's not "optimized". It's how it should be in a tight 64-bit ABI environment.

So it comes down to this;

Code: [Select]
;align the stack (this is requirement)
sub rsp,020h   ;---> this is requirement
mov [rsp],rcx  ;---> these are NOT.
...
...
mov [rsp+...],r9
call aWin64API  ;---> then you call the function. Not saving the volatile registers inside it.
Title: Re: Asmc source and binaries
Post by: nidud on June 16, 2017, 02:23:21 AM
I don't understand your point, Nidud.

The point is that this is not a help-desk for confused coders. If your confused (which you clearly are) about how the Windows 64 ABI works you should read up on the subject, ask Microsoft or post a question in the Campus.
Title: Re: Asmc source and binaries
Post by: coder on June 16, 2017, 02:38:32 AM
The first four integer or pointer parameters are passed in the rcx, rdx, r8, and r9 registers. The caller reserves space on the stack for arguments passed in registers. This is what the shadow space is used for.

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture

No, simpleton. I am talking with proof! If you're smart, you don't listen to anything that MS tells you. You didn't read hard enough. The shadow space is indeed required but to put the volatile registers (rcx-r9) in there is optional, and in many occasions, it is used as a spill area for a functions own code, corrupting what you've put in there. Here's one example, one attempt to preserve r8, as per 'Microsoft recommendation';

Code: [Select]
externdef Sleep:proc
externdef printf:proc
option casemap:none

dseg segment page 'DATA'
  isr8 db 'R8 preserved? = %llX',0ah,0
dseg ends

cseg segment para 'CODE'
main proc
        sub     rsp,8     ;align stack (requirement)

        mov     r8,0CCh   ;we'll see about it

        sub     rsp,20h   ;allocate space (requirement)
        mov     [rsp],rcx
        mov     [rsp+8],rdx
        mov     [rsp+16],r8
        mov     [rsp+24],r9

        mov     rcx,500   ;integer argument (requirement)
        call    Sleep     ;call a WinAPI

        mov     rcx,[rsp]
        mov     rdx,[rsp+8]
        mov     r8,[rsp+16]
        mov     r9,[rsp+24]
        add     rsp,20h

        sub     rsp,20h
        mov     rdx,r8    ;is r8 preserved by Sleep
        mov     rcx,offset isr8
        call    printf
        add     rsp,28h   ;restore all

        ret

main endp
cseg ends
end

The output shows that R8 (RSP+16) is corrupted. Here's the output.
Code: [Select]
D:\MASM\MYCODE>ml64 /c prog.asm
Microsoft (R) Macro Assembler (x64) Version 14.10.25019.0
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: prog.asm

D:\MASM\MYCODE>gcc -m64 prog.obj -s -o prog.exe

D:\MASM\MYCODE>prog
R8 preserved? = 0

Title: Re: Asmc source and binaries
Post by: coder on June 16, 2017, 02:47:26 AM
I don't understand your point, Nidud.

The point is that this is not a help-desk for confused coders. If your confused (which you clearly are) about how the Windows 64 ABI works you should read up on the subject, ask Microsoft or post a question in the Campus.

One thing for sure, you're confusing the stack area for something else. Instead of dumping data there like everybody else do, you're stacking up two calling conventions there and call it "standard". Your "standard" is funny.

 

 
Title: Re: Asmc source and binaries
Post by: coder on June 19, 2017, 04:27:12 AM
Hi Nidud. I hope you're not offended in any way from what I said. Keep up the good work!
Title: Re: Asmc source and binaries
Post by: nidud on June 19, 2017, 05:36:31 AM

 :biggrin:

No problem coder but you may consider tone down your rhetoric a bit.

Do you understand now why the arguments passed in registers needs to be saved in WinMain() but not in WndProc() in the example above?
Title: Re: Asmc source and binaries
Post by: nidud on July 15, 2017, 01:00:24 AM
Here's another version of the dll-to-lib tools. This converts all dll-files in the system32 directory by default. There was more than 2000 files there (Win7-64).
Code: [Select]
SYSDLL creates import from %windir%/system32/[<mask>|*].dll

Usage: SYSDLL <options> [<mask>]

 /def - create .def files
 /lib - create .lib files
 /inc - create .inc files

Example:
Code: [Select]
ifdef __PE__
    .x64
    .model flat, fastcall
endif
include inc\msvcrt.inc

    .code

main proc

    .if fopen("test.asm", "rt")
        mov rsi,rax
        .if malloc(512)
            mov rdi,rax
            .while fgets(rdi, 512, rsi)
                printf(rdi)
            .endw
            free(rdi)
        .endif
        fclose(rsi)
    .endif
    exit(0)

main endp

    end main

Create library and include file (and directories):
Code: [Select]
SYSDLL /lib msvcrt
SYSDLL /inc msvcrt

Assemble:
Code: [Select]
asmc /win64 test.asm

inc\msvcrt.inc(1010) : error A2034: must be in segment block
 inc\msvcrt.inc(1010): Included by
  test.asm(11): Main line code
inc\msvcrt.inc(1014) : error A2034: must be in segment block
 inc\msvcrt.inc(1014): Included by
  test.asm(11): Main line code

Fixing the include file:
Code: [Select]
difftime proto :vararg
;div proto :vararg
exit proto :vararg
exp proto :vararg
expf proto :vararg
;fabs proto :vararg
fclose proto :vararg

Assemble and link:
Code: [Select]
asmc /win64 test.asm
linkw lib lib\msvcrt.lib file test.obj

Assemble and link:
Code: [Select]
asmc /pe /D__PE__ test.asm
Title: Re: Asmc source and binaries
Post by: nidud on October 07, 2017, 10:03:26 PM
Added __PE__ to the -pe switch

makefile (https://github.com/nidud/asmc/blob/master/source/test/windows/7/makefile)
Code: [Select]
#
#  __PE__ auto defined if switch -pe used
#
test.exe:
    asmc /q /pe $*.asm
    $@
    del $@
    asmc /q /pe /D_WIN64 $*.asm
    $@
    del $@

This build a 32 and 64-bit version of the Tutorial 16: Event Object (http://win32assembly.programminghorizon.com/tut16.html) sample.

Code: [Select]
include windows.inc
include winres.inc
ifdef _WIN64
option win64:3
APPNAME   equ <"Win64 ASM Event Example">
CLASSNAME equ <"Win64ASMEventClass">
else
rax equ <eax>
rbx equ <ebx>
rcx equ <ecx>
APPNAME   equ <"Win32 ASM Event Example">
CLASSNAME equ <"Win32ASMEventClass">
endif

IDM_START_THREAD    equ 1
IDM_STOP_THREAD     equ 2
IDM_EXIT            equ 3
IDR_MAINMENU        equ 30
WM_FINISH           equ WM_USER+100h

.data
EventStop   BOOL FALSE
hMenu       HANDLE ?
hwnd        HANDLE ?
hEventStart HANDLE ?
hThread     HANDLE ?
ThreadID    dd ?

.code

ThrdProc proc

    .while 1

        WaitForSingleObject(hEventStart, INFINITE)

        mov ecx,600000000

        .while ecx

            .if EventStop != TRUE

                add eax,eax
                dec ecx
            .else

                MessageBox(hwnd, "The thread is stopped",
                        "The calculation is completed!", MB_OK)

                mov EventStop,FALSE
                .continue(1)
            .endif
        .endw

        PostMessage(hwnd, WM_FINISH, 0, 0)
        EnableMenuItem(hMenu, IDM_START_THREAD, MF_ENABLED)
        EnableMenuItem(hMenu, IDM_STOP_THREAD, MF_GRAYED)
    .endw
    ret

ThrdProc endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    .switch uMsg

      .case WM_DESTROY
        PostQuitMessage(NULL)
        xor eax,eax
        .endc

      .case WM_COMMAND

        .if !lParam ; menu commands

            movzx eax,word ptr wParam
            .switch eax

              .case IDM_START_THREAD
                SetEvent(hEventStart)
                EnableMenuItem(hMenu, IDM_START_THREAD, MF_GRAYED)
                EnableMenuItem(hMenu, IDM_STOP_THREAD, MF_ENABLED)
                .endc

              .case IDM_STOP_THREAD
                mov EventStop,TRUE
                EnableMenuItem(hMenu, IDM_START_THREAD, MF_ENABLED)
                EnableMenuItem(hMenu, IDM_STOP_THREAD, MF_GRAYED)
                .endc

              .case IDM_EXIT
                DestroyWindow(hWnd)
                .endc
            .endsw
        .endif
        xor eax,eax
        .endc

      .case WM_CREATE
        mov hEventStart,CreateEvent(NULL, FALSE, FALSE, NULL)
        mov hThread,CreateThread(NULL, NULL, &ThrdProc, NULL, NORMAL_PRIORITY_CLASS, &ThreadID)
        CloseHandle(hThread)
        xor eax,eax
        .endc

      .case WM_FINISH
        MessageBox(0, "The calculation is completed!", APPNAME, MB_OK)
        xor eax,eax
        .endc

      .default
        DefWindowProc(hWnd, uMsg, wParam, lParam)
    .endsw
    ret

WndProc endp

WinMain proc WINAPI hInst: HINSTANCE,
     hPrevInstance: HINSTANCE,
         lpCmdLine: LPSTR,
          nShowCmd: SINT

    local wc:WNDCLASSEX
    local msg:MSG

    mov wc.cbSize,SIZEOF WNDCLASSEX
    mov wc.style,CS_HREDRAW or CS_VREDRAW
    mov wc.lpfnWndProc,WndProc
    mov rcx,hInst
    xor eax,eax
    mov wc.cbClsExtra,eax
    mov wc.cbWndExtra,eax
    mov wc.hInstance,rcx
    mov wc.hbrBackground,COLOR_WINDOW
    mov wc.lpszMenuName,IDR_MAINMENU
ifdef _WIN64
    lea rax,@CStr("Win64ASMEventClass")
else
    lea rax,@CStr("Win32ASMEventClass")
endif
    mov wc.lpszClassName,rax
    mov wc.hIcon,LoadIcon(0, IDI_APPLICATION)
    mov wc.hIconSm,rax
    mov wc.hCursor,LoadCursor(0, IDC_ARROW)
    RegisterClassEx(&wc)

    mov hwnd,CreateWindowEx(WS_EX_CLIENTEDGE, CLASSNAME,
        APPNAME, WS_OVERLAPPEDWINDOW or WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, 0, 0, hInst, 0)

    ShowWindow(hwnd, SW_SHOWNORMAL)
    UpdateWindow(hwnd)
    mov hMenu,GetMenu(hwnd)

    .while GetMessage(&msg, NULL, 0, 0)

        TranslateMessage(&msg)
        DispatchMessage(&msg)
    .endw
    mov rax,msg.wParam
    ret

WinMain endp

WinStart proc
    mov rbx,GetModuleHandle(0)
    ExitProcess(WinMain(rbx, 0, GetCommandLine(), SW_SHOWDEFAULT))
WinStart endp

RCBEGIN

    RCTYPES 1
    RCENTRY RT_MENU
    RCENUMN 1
    RCENUMX IDR_MAINMENU
    RCLANGX LANGID_US

    MENUBEGIN
      MENUNAME "&Thread", MF_END
        MENUITEM IDM_START_THREAD, "&Run Thread"
        MENUITEM IDM_STOP_THREAD,  "&Stop Thread"
        SEPARATOR
        MENUITEM IDM_EXIT, "E&xit", MF_END
    MENUEND

RCEND

    end WinStart

Some stats from the current source base:
Code: [Select]
2457 .ASM files - 194530 lines
 153 .INC files - 115220 lines
 276 .C   files - 121254 lines
 783 .LIB files
1425 macros
Title: Re: Asmc source and binaries
Post by: nidud on October 27, 2017, 01:23:18 AM
Some new updates.

Added a simple Hex editor to Doszip assigned to Ctrl-F4. In addition to the standard mode there is also a Class mode with the possibility to define a line-based struct of data. This may be a string or byte (hex) array, or integer value of size 1 to 8, signed/unsigned or hex.

Formatted struct's may be saved and loaded from disk at specific offsets.
Code: [Select]
00000068    PE···············································  CHAR[2]
0000006A    00006486                                           BYTE[4]
0000006E    0002                                               WORD(hexadecimal)
00000070    1509026722                                         DWORD(unsigned)
00000074    0                                                  DWORD(signed)
00000078    0                                                  DWORD(signed)
0000007C    00F0                                               WORD(hexadecimal)
0000007E    012F                                               WORD(hexadecimal)
00000080    0B02                                               BYTE[2]
00000082    5                                                  BYTE(signed)
00000083    1                                                  BYTE(signed)
00000084    512                                                DWORD(unsigned)
00000088    0                                                  DWORD(unsigned)
0000008C    0                                                  DWORD(unsigned)
00000090    4096                                               DWORD(unsigned)
00000094    4096                                               DWORD(unsigned)
00000098    0000000140000000                                   QWORD(hexadecimal)
000000A0    4096                                               DWORD(signed)
000000A4    512                                                DWORD(signed)
000000A8    4                                                  WORD(signed)
000000AA    0                                                  WORD(signed)
000000AC    0                                                  WORD(signed)
000000AE    0                                                  WORD(signed)
000000B0    4                                                  WORD(signed)
000000B2    0                                                  WORD(signed)
000000B4    0                                                  DWORD(signed)
000000B8    12288                                              DWORD(signed)
000000BC    512                                                DWORD(signed)
000000C0    0                                                  DWORD(signed)
000000C4    0003                                               WORD(hexadecimal)
000000C6    0000                                               WORD(hexadecimal)
000000C8    1048576                                            QWORD(unsigned)
000000D0    4096                                               QWORD(unsigned)
000000D8    1048576                                            QWORD(unsigned)

Added two switches to Asmc for using -pe.
-cui -- same as LINK /subsystem:console (default)
-gui -- same as LINK /subsystem:windows

This sets .Subsystem to IMAGE_SUBSYSTEM_WINDOWS_CUI or IMAGE_SUBSYSTEM_WINDOWS_GUI.

The combination of -pe -win64 will also set the .ImageBase to 0x140000000, default is 0x400000.

Asmc now adapts to ml64 if a simplified segment or a function prototype is found and no model or language defined. Additional [x|y]mm16..31 and zmm registers with a NASM-style {evex} prefix and implementation are also added.

This will now assemble to 64-bit fastcall:
Code: [Select]
    .code

    vaddps  xmm0,xmm1,[rax]     ; normal
    vpaddsb xmm0,xmm1,xmm2
    vcomisd xmm0,xmm1

    vaddps  xmm16,xmm1,[rax]    ; prefix
    vpaddsb xmm20,xmm0,xmm1
    vcomisd xmm0,xmm31

    {evex} vaddps  xmm0,xmm1,[rax]
    {evex} vpaddsb xmm0,xmm1,xmm2
    {evex} vcomisd xmm0,xmm1

    end

Code: [Select]
   0: c5 f0 58 00          vaddps xmm0,xmm1,XMMWORD PTR [rax]
   4: c5 f1 ec c2          vpaddsb xmm0,xmm1,xmm2
   8: c5 f9 2f c1          vcomisd xmm0,xmm1
   c: 62 e1 74 08 58 00    vaddps xmm16,xmm1,XMMWORD PTR [rax]
  12: 62 e1 7d 08 ec e1    vpaddsb xmm20,xmm0,xmm1
  18: 62 91 fd 08 2f c7    vcomisd xmm0,xmm31
  1e: 62 f1 74 08 58 00    vaddps xmm0,xmm1,XMMWORD PTR [rax]
  24: 62 f1 75 08 ec c2    vpaddsb xmm0,xmm1,xmm2
  2a: 62 f1 fd 08 2f c1    vcomisd xmm0,xmm1
Title: Re: Asmc source and binaries
Post by: nidud on November 13, 2017, 06:18:50 AM
Had a hardware meltdown here so now I have a cute little Fujitsu box installed. Well, been working on the AVX-512 implementation and finally get GitHup up and pushed the latest changes.

I wrote a lengthy test case (https://github.com/nidud/asmc/blob/master/source/asmc/regress/src/bin/avx_512.asm) for the implementation mostly taken from GAS and NASM. The binary output is bit-compatible with NASM and thus disassemble correctly with objdump.

There's not much code added for the implementation but it does however add a lot of instructions and inflate the tables. The hash tables is now increased but now all sizes are set to a power of two for convenience. Also, the reserved word table is now forced low-case to skip case testing on symbols. A simple benchmark of the 7000-lines test case compare to NASM:
Code: [Select]
   31 ClockTicks: asmc -q -bin a.asm
  156 ClockTicks: nasm n.asm

The math test compare to previous version:
Code: [Select]
3806 ClockTicks: asmc225.exe -q real_math.asm
3651 ClockTicks: \asmc\bin\asmc.exe -q real_math.asm
6287 ClockTicks: \jwasm\jwasm.exe -q real_math.asm

Added code:
312832 - version 2.25
333312 - version 2.26

A few types are added in addition to ZMMWORD:
Code: [Select]
8 16 32 64 128 256 512

1 2 4 8 10 16 32 64

AL AX EAX RAX XMM0 YMM0 ZMM0

  REAL10

REAL4 REAL8 REAL16 YMMWORD ZMMWORD

BYTE WORD DWORD QWORD OWORD YWORD ZWORD
Title: Re: Asmc source and binaries
Post by: nidud on November 16, 2017, 10:29:27 AM
Added public label::

A label is defined public if declared outside a procedure with a double colon. This simplify bear-bone  declarations, especially in 64-bit.

Code: [Select]
.code

public_label::

    nop
    ret

    end

Code: [Select]
; Mode: 64 bits
; Syntax: MASM/ML64
; Instruction set: 8086, x64

public public_label


_text   SEGMENT PARA 'CODE'                             ; section number 1

public_label PROC
        nop                                             ; 0000 _ 90
        ret                                             ; 0001 _ C3
public_label ENDP

_text   ENDS
Title: Re: Asmc source and binaries
Post by: Vortex on November 17, 2017, 06:09:38 AM
Hi nidud,

Sorry for the late reply. Testing sysdll :

Code: [Select]
sysdll.exe /def C:\WINDOWS\SysWOW64\msvcrt.dll

sysdll.exe /def C:\WINDOWS\System32\msvcrt.dll

sysdll.exe /inc C:\WINDOWS\SysWOW64\msvcrt.dll

sysdll.exe /inc C:\WINDOWS\System32\msvcrt.dll

sysdll.exe /lib C:\WINDOWS\SysWOW64\msvcrt.dll

sysdll.exe /lib C:\WINDOWS\System32\msvcrt.dll

I get three empty folders named def, inc and lib.  OS : Win XP 64-bit  Same problem on Win 7 64-bit
Title: Re: Asmc source and binaries
Post by: nidud on November 17, 2017, 06:32:35 AM
Looking at the source code (https://github.com/nidud/asmc/tree/master/source/tools/sysdll/sysdll.asm#L244) the wild arg seems to be the actual file name:
Code: [Select]
        sprintf(rdi, "%s\\system32\\%s.dll", rax, &wild)

This seems to work:

sysdll /inc msvcrt
sysdll /def msvcrt
sysdll /lib msvcrt

./def/msvcrt.def:
Code: [Select]
LIBRARY msvcrt
EXPORTS
"_CrtCheckMemory"
"_CrtDbgBreak"

./inc/msvcrt.inc:
Code: [Select]
includelib msvcrt.lib

_CrtCheckMemory proto :vararg
_CrtDbgBreak proto :vararg
_CrtDbgReport proto :vararg
Title: Re: Asmc source and binaries
Post by: Vortex on November 17, 2017, 06:58:34 AM
Hi nidud,

Thanks for the info. The tool works as you explained.
Title: Re: Asmc source and binaries
Post by: nidud on November 28, 2017, 02:59:20 AM
Did some cleanup in the GitHup source directory (https://github.com/nidud/asmc/tree/master/source) so some of the direct links posted may now fail. This was done to organize and improve the regression test for the libraries.

Wininc (https://github.com/nidud/asmc/tree/master/source/test/wininc) related source are now tested separately where most of the samples do not use libc and assembles with the -pe switch. Some more features are added both for LINKW and the include files to separate console/gui builds.

The -gui switch will now define __GUI__ and this will create a startup (https://github.com/nidud/asmc/blob/master/include/tchar.inc#L1009) calling [w]WinMain() as oppose to [w]main() in console mode. In addition to this the switch -ws now defines _UNICODE.

Some additional changes to Asmc:

Title: Re: Asmc source and binaries
Post by: nidud on December 06, 2017, 09:42:33 AM
Added some more support for invoking function pointers.

struct.funcptr(...)
[reg].struct.funcptr(...)
assume reg:ptr struct
[reg].funcptr(...)


Example (https://github.com/nidud/asmc/tree/master/source/test/wininc/D3D9):
Code: [Select]
;
; http://ube43.wix.com/directxers/apps/blog/directx-9-tutorial-1-ein-fenster
;

;; Every windows application needs to include this
include windows.inc
include tchar.inc

;; Every Direct3D application this
include d3d9.inc

.data
g_bContinue dd TRUE

.code


;; Besides the main function, there must be a message processing function
MsgProc proc WINAPI hWnd:HWND, msg:UINT, wParam:WPARAM, lParam:LPARAM

    .switch(msg)
      .case WM_DESTROY:
        PostQuitMessage( 0 )
        mov g_bContinue,FALSE
        .endc
      .default
        DefWindowProc( hWnd, msg, wParam, lParam )
    .endsw
    ret

MsgProc endp

;; The entry point of a windows application is the WinMain function
WinMain proc WINAPI uses rsi rdi rbx r12 hInstance:HINSTANCE, hPrevInstance:HINSTANCE, lpCmdLine:LPSTR, nShowCmd:SINT

    ;; Create a window class.
    local wc:WNDCLASSEX
    local hWnd:HWND
    ;local pD3D:LPDIRECT3D9
    local d3dpp:D3DPRESENT_PARAMETERS
    local pd3dDevice:LPDIRECT3DDEVICE9
    local msg:MSG

    xor eax,eax
    mov pd3dDevice,rax
    lea rdi,wc
    mov ecx,sizeof(WNDCLASSEX)
    rep stosb
    mov wc.cbSize,sizeof(WNDCLASSEX)
    mov wc.style,CS_CLASSDC
    lea rax,MsgProc
    mov wc.lpfnWndProc,rax
    lea rax,@CStr("Direct3D Window")
    mov wc.lpszClassName,rax
    mov wc.hInstance,GetModuleHandle(NULL)

    ;;Register the window class.
    RegisterClassEx( &wc );

    ;; Create the application's window.
    mov hWnd,CreateWindowEx(0, "Direct3D Window", "DirectXers - D3D9 Tutorial 1",
        WS_OVERLAPPEDWINDOW, 100, 100, 400, 400, GetDesktopWindow(), NULL, wc.hInstance, NULL )

    ShowWindow(hWnd,SW_SHOW)

    .repeat

        ;; Create the Direct3D Object

        .if !Direct3DCreate9(D3D_SDK_VERSION)

            mov eax,E_FAIL
            .break
        .endif

        mov rbx,rax
        mov rdi,[rax]
        assume rdi: ptr IDirect3D9

        ;; Setup the device presentation parameters

        ZeroMemory( &d3dpp, sizeof(d3dpp) )
        mov d3dpp.Windowed,TRUE
        mov d3dpp.SwapEffect,D3DSWAPEFFECT_DISCARD
        mov d3dpp.BackBufferFormat,D3DFMT_UNKNOWN

        ;; The final step is to use the IDirect3D9::CreateDevice method to create the Direct3D device, as illustrated in the
        ;; following code example.

        .ifs [rdi].CreateDevice(rbx, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice ) < 0

            MessageBox(hWnd, "No HAL HARDWARE_VERTEXPROCESSING! Sample will exit!", NULL, 0);
            [rdi].Release(rbx)
            mov eax,E_FAIL
            .break
        .endif

        mov rax,pd3dDevice
        mov rsi,[rax]
        mov r12,rax
        assume rsi: ptr IDirect3DDevice9

        .while ( g_bContinue )

            ;; Clear render region with blue
            [rsi].Clear( r12, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0, 0 )

            ;; before rendering something, you have to call this
            [rsi].BeginScene( r12 );

            ;;
            ;; rendering of scene objects happens her
            ;;

            ;; now end the scene
            [rsi].EndScene( r12 );

            ;; update screen = swap front and backbuffer
            [rsi].Present( r12, NULL, NULL, NULL, NULL)

            ;; A window has to handle its messages.
            TranslateMessage( &msg );
            DispatchMessage( &msg );
            PeekMessage(&msg, 0, 0, 0, PM_REMOVE)
        .endw

        ;; Do not forget to clean up here

        [rsi].Release( r12 );
        [rdi].Release( rbx )
        xor eax,eax
    .until 1
    ret

WinMain endp

    end _tstart

The C expansion of the interface class:
Code: [Select]
typedef struct IClassFactory
{
     const struct IClassFactoryVtbl FAR* lpVtbl;
} IClassFactory;

#define IDirect3D9_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)

This means the current macro implementation (https://github.com/nidud/asmc/blob/master/include/d3d9.inc#L246) will not work in assembly. Not sure what or how to do this, maybe add a register:
Code: [Select]
IDirect3D9_QueryInterface macro p,a,b
mov rax,[p] ; assuming register
exitm<[rax].IDirect3D9.QueryInterface(p,a,b)>
endm

Well, the assembler will now handle the calls but the include files needs some update. The direct access as in the sample may also be simpler than using the macros but I need to do some more testing to see how it plays out.
Title: Re: Asmc source and binaries
Post by: nidud on December 09, 2017, 02:27:23 AM
Added direct usage of pointers and removed the macros. Using registers will still work as above but this seems to be simpler.
Code: [Select]
    p.QueryInterface(1, 2)

Expands to:
Code: [Select]
    mov     rcx, qword ptr [p]
    mov     rdx, 1           
    mov     r8, 2             
    mov     rax, qword ptr [rcx]
    call    qword ptr [rax]     

32-bit:
Code: [Select]
    push    2                 
    push    1                 
    push    dword ptr [_p]     
    mov     eax, dword ptr [_p]
    mov     eax, dword ptr [eax]
    call    dword ptr [eax]

Added d3dx9 include files and a few more examples. There seems to be a lot of these dll-files. The sample worked using d3dx9_40.dll so this is used as default import (assuming this is the version number).

The test samples was taken from this site:
http://ube43.wix.com/directxers/apps/blog/directx-9-tutorial-1-ein-fenster

Second sample using pointers:
Code: [Select]
;; Every windows application needs to include this
include windows.inc
include tchar.inc

;; Every Direct3D application this
include d3d9.inc
include d3dx9.inc

.data
g_lpEffect  LPD3DXEFFECT NULL
g_lpVertexBuffer LPDIRECT3DVERTEXBUFFER9 NULL
g_ShaderMatrix D3DXMATRIX <>
g_bContinue dd TRUE


;;Definition of the Vertex Format including position and diffuse color
D3DFVF_COLOREDVERTEX equ (D3DFVF_XYZ or D3DFVF_DIFFUSE)

COLORED_VERTEX STRUC
x           FLOAT ?     ;; Position
y           FLOAT ?
z           FLOAT ?
color       dd ?        ;; Color
COLORED_VERTEX ENDS

.code


;; Besides the main function, there must be a message processing function
MsgProc proc WINAPI hWnd:HWND, msg:UINT, wParam:WPARAM, lParam:LPARAM

    .switch(msg)
      .case WM_DESTROY:
        PostQuitMessage( 0 )
        mov g_bContinue,FALSE
        .endc
      .default
        DefWindowProc( hWnd, msg, wParam, lParam )
    .endsw
    ret

MsgProc endp

;; The entry point of a windows application is the WinMain function
WinMain proc WINAPI uses rdi hInstance:HINSTANCE, hPrevInstance:HINSTANCE, lpCmdLine:LPSTR, nShowCmd:SINT

    ;; Create a window class.
    local wc:WNDCLASSEX
    local hWnd:HWND
    local pD3D:LPDIRECT3D9
    local d3dpp:D3DPRESENT_PARAMETERS
    local pd3dDevice:LPDIRECT3DDEVICE9
    local msg:MSG
    local uiBufferSize:UINT
    local pVertices:ptr COLORED_VERTEX
    local uiPasses:UINT

    xor eax,eax
    mov pd3dDevice,rax
    lea rdi,wc
    mov ecx,sizeof(WNDCLASSEX)
    rep stosb
    mov wc.cbSize,sizeof(WNDCLASSEX)
    mov wc.style,CS_CLASSDC
    lea rax,MsgProc
    mov wc.lpfnWndProc,rax
    lea rax,@CStr("Direct3D Window")
    mov wc.lpszClassName,rax
    mov wc.hInstance,GetModuleHandle(NULL)

    ;;Register the window class.
    RegisterClassEx( &wc );

    ;; Create the application's window.
    mov hWnd,CreateWindowEx(0, "Direct3D Window", "DirectXers - D3D9 Tutorial 2",
        WS_OVERLAPPEDWINDOW, 100, 100, 400, 400, GetDesktopWindow(), NULL, wc.hInstance, NULL )

    ShowWindow( hWnd, SW_SHOW )

    .repeat

        ;; Create the Direct3D Object

        .if !Direct3DCreate9( D3D_SDK_VERSION )

            mov eax,E_FAIL
            .break
        .endif
        mov pD3D,rax

        ;; Setup the device presentation parameters

        ZeroMemory( &d3dpp, sizeof(d3dpp) )
        mov d3dpp.Windowed,TRUE
        mov d3dpp.SwapEffect,D3DSWAPEFFECT_DISCARD
        mov d3dpp.BackBufferFormat,D3DFMT_UNKNOWN

        ;; The final step is to use the IDirect3D9::CreateDevice method to create the Direct3D device, as illustrated in the
        ;; following code example.

        .ifd pD3D.CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice )

            MessageBox(hWnd, "No HAL HARDWARE_VERTEXPROCESSING! Sample will exit!", NULL, 0);
            pD3D.Release()
            mov eax,E_FAIL
            .break
        .endif

        ;; set the vertex buffer size 4 vertices * vertex structure size
        mov uiBufferSize,4*sizeof(COLORED_VERTEX)

        ;; create the buffer
        .ifd pd3dDevice.CreateVertexBuffer( uiBufferSize,
            D3DUSAGE_WRITEONLY, D3DFVF_COLOREDVERTEX, D3DPOOL_DEFAULT, &g_lpVertexBuffer, NULL )

            mov eax,E_FAIL
            .break
        .endif

        ;; lock the buffer for writing
        .ifd g_lpVertexBuffer._Lock( 0, uiBufferSize, &pVertices, 0 )

            mov eax,E_FAIL
            .break
        .endif

        ;; write the vertices. Here a simple rectangle
        mov rcx,pVertices
        assume rcx: ptr COLORED_VERTEX
        mov [rcx].x,-1.0    ;; left
        mov [rcx].y,-1.0    ;; bottom
        mov [rcx].z,0.0
        mov [rcx].color,0xffff0000  ;; red
        add rcx,COLORED_VERTEX
        mov [rcx].x,-1.0    ;; left
        mov [rcx].y,1.0     ;; top
        mov [rcx].z,0.0
        mov [rcx].color,0xff0000ff  ;; blue
        add rcx,COLORED_VERTEX
        mov [rcx].x,1.0     ;; right
        mov [rcx].y,-1.0    ;; bottom
        mov [rcx].z,0.0
        mov [rcx].color,0xff00ff00  ;; green
        add rcx,COLORED_VERTEX
        mov [rcx].x,1.0     ;; right
        mov [rcx].y,1.0     ;; top
        mov [rcx].z,0.0
        mov [rcx].color,0xffffffff  ;; white
        assume rcx: nothing

        ;; unlock the buffer
        g_lpVertexBuffer.Unlock()

        ;; set the Vertex Format
        pd3dDevice.SetFVF( D3DFVF_COLOREDVERTEX )

        ;; transfer the buffer to the gpu
        pd3dDevice.SetStreamSource( 0, g_lpVertexBuffer, 0, sizeof(COLORED_VERTEX) )

        ;; create an effect
        .ifd D3DXCreateEffectFromFile( pd3dDevice, "Effect.fx", NULL,
            NULL, D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, NULL, &g_lpEffect, NULL )
            mov eax,E_FAIL
            .break
        .endif
        lea rcx,g_ShaderMatrix
        D3DXMatrixIdentity(rcx)
        g_lpEffect.SetMatrix( "ShaderMatrix", &g_ShaderMatrix )

        .while ( g_bContinue )

            ;; Clear render region with blue
            pd3dDevice.Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0, 0 )

            ;; before rendering something, you have to call this
            pd3dDevice.BeginScene()

            ;; rendering of scene objects happens her

            mov uiPasses,0
            g_lpEffect.Begin( &uiPasses, 0 )

            .for ( edi = 0: edi < uiPasses: edi++ )

                ;; render an effect pass
                g_lpEffect.BeginPass( edi )
                ;; render the rectangle
                pd3dDevice.DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 )
                g_lpEffect.EndPass()
            .endf

            g_lpEffect._End()

            ;; now end the scene
            pd3dDevice.EndScene()

            ;; update screen = swap front and backbuffer
            pd3dDevice.Present( NULL, NULL, NULL, NULL )

            ;; A window has to handle its messages.
            TranslateMessage( &msg );
            DispatchMessage( &msg );
            PeekMessage(&msg, 0, 0, 0, PM_REMOVE)
        .endw

        ;; Do not forget to clean up here

        pd3dDevice.Release()
        pD3D.Release()
        g_lpEffect.Release()
        g_lpVertexBuffer.Release()

        xor eax,eax
    .until 1
    ret

WinMain endp

    end _tstart
Title: Re: Asmc source and binaries
Post by: Vortex on December 10, 2017, 11:28:40 PM
Hi nidud,

I am trying to convert a COM example from Masm to the new Asmc syntax supporting the invocation of function pointers ( testing Asmc Version 2.27C ) :

Code: [Select]
.386
.model flat,stdcall
option casemap:none
option wstring:on

include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\ole32.inc
include     SetWallpaper.inc

includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\ole32.lib

; LPActDesk TYPEDEF PTR IActiveDesktop

.data

CLSID_IActiveDesktop    GUID sCLSID_IActiveDesktop
IID_IActiveDesktop      GUID sIID_IActiveDesktop

DesktopImg dw 'test.bmp',0

.data?

wpo         WALLPAPEROPT <>
pAD         dd ?

.code

start:

    invoke      CoInitialize,NULL

    invoke      CoCreateInstance,ADDR CLSID_IActiveDesktop,NULL,\
                CLSCTX_INPROC_SERVER,ADDR IID_IActiveDesktop,ADDR pAD           

    mov         edx,OFFSET wpo
    mov         WALLPAPEROPT.dwSize[edx],SIZEOF(WALLPAPEROPT)
    mov         WALLPAPEROPT.dwStyle[edx],WPSTYLE_CENTER
    mov         eax,pAD

    [eax].IActiveDesktop.SetWallpaper(ADDR DesktopImg,0)

    coinvoke    pAD,IActiveDesktop,SetWallpaper,OFFSET DesktopImg,0

    coinvoke    pAD,IActiveDesktop,SetWallpaperOptions,OFFSET wpo,0

    coinvoke    pAD,IActiveDesktop,ApplyChanges,AD_APPLY_ALL

    coinvoke    pAD,IActiveDesktop,Release

    invoke      CoUninitialize
   
    invoke      ExitProcess,0

END start

I get the following error message :

Code: [Select]
[eax].IActiveDesktop.SetWallpaper(ADDR DesktopImg,0)
Code: [Select]
SetWallpaper.asm(42) : error A2190: INVOKE requires prototype for procedure
Also as an alternative syntax, is it possible to use this expression with some modifications in the source code?

Code: [Select]
pAD.SetWallpaper(ADDR DesktopImg,0)
My intention is to preserve the definition of the IActiveDesktop interface like the following while using the new function pointer invocation syntax  :

Code: [Select]
IActiveDesktop STRUCT

    QueryInterface          dd ?
    AddRef                  dd ?
    Release                 dd ?
    ApplyChanges            dd ?
    GetWallpaper            dd ?
    SetWallpaper            dd ?
    GetWallpaperOptions     dd ?
    SetWallpaperOptions     dd ?
    GetPattern              dd ?
    SetPattern              dd ?
    GetDesktopItemOptions   dd ?
    SetDesktopItemOptions   dd ?
    AddDesktopItem          dd ?
    AddDesktopItemWithUI    dd ?
    ModifyDesktopItem       dd ?
    RemoveDesktopItem       dd ?
    GetDesktopItemCount     dd ?
    GetDesktopItem          dd ?
    GetDesktopItemByID      dd ?
    GenerateDesktopItemHtml dd ?
    AddUrl                  dd ?
    GetDesktopItemBySource  dd ?

IActiveDesktop ENDS
Title: Re: Asmc source and binaries
Post by: nidud on December 14, 2017, 05:42:51 AM
I'v updated and added more include files using the STDMETHOD (https://github.com/nidud/asmc/blob/master/include/rpc.inc#L19) macro and added a SetWallpaper (https://github.com/nidud/asmc/tree/master/source/test/wininc/SetWallpaper) sample from the code above.
Code: [Select]
include windows.inc
include wininet.inc
include shlobj.inc

BITMAP0 equ <L"%SystemRoot%\\web\\wallpaper\\Windows\\img0.jpg">
BITMAP1 equ <L"%AsmcDir%\\source\\test\\wininc\\SetWallpaper\\test.bmp">

.data

CLSID_ActiveDesktop GUID _CLSID_ActiveDesktop
IID_IActiveDesktop  GUID _IID_IActiveDesktop

.code

main proc

  local w:WALLPAPEROPT
  local p:LPACTIVEDESKTOP

    CoInitialize(NULL)
    CoCreateInstance(&CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, &IID_IActiveDesktop, &p)
    p.SetWallpaper( BITMAP0, 0 )
    mov w.dwSize,sizeof(WALLPAPEROPT)
    mov w.dwStyle,WPSTYLE_CENTER
    p.SetWallpaperOptions( &w, 0 )
    p.ApplyChanges( AD_APPLY_ALL )
    p.Release()
    CoUninitialize()
    ret

main endp

    end

Also as an alternative syntax, is it possible to use this expression with some modifications in the source code?

Code: [Select]
pAD.SetWallpaper(ADDR DesktopImg,0)
My intention is to preserve the definition of the IActiveDesktop interface like the following while using the new function pointer invocation syntax  :

Code: [Select]
  local p:LPDIRECT3D9

    p.QueryInterface(1, 2)

*   invoke [rax].IDirect3D9.QueryInterface, p, 1, 2

The struct name is extracted from what the pointer points to and invoke needs a prototype so the functions needs to be defined.
Code: [Select]
IActiveDesktop STRUC

STDMETHOD QueryInterface, :REFIID, :ptr
STDMETHOD AddRef
STDMETHOD Release
STDMETHOD ApplyChanges, :DWORD
STDMETHOD GetWallpaper, :LPWSTR, :UINT, :DWORD
STDMETHOD SetWallpaper, :LPCWSTR, :DWORD
STDMETHOD GetWallpaperOptions, :LPWALLPAPEROPT, :DWORD
STDMETHOD SetWallpaperOptions, :LPCWALLPAPEROPT, :DWORD
STDMETHOD GetPattern, :LPWSTR, :UINT, :DWORD
Title: Re: Asmc source and binaries
Post by: Vortex on December 14, 2017, 05:55:11 AM
Hi nidud,

Thanks for the info and for the update :t 
Title: Re: Asmc source and binaries
Post by: nidud on December 17, 2017, 12:47:43 AM
Here's a PE COM-version using IShellFolder (https://github.com/nidud/asmc/tree/master/source/test/wininc/IShellFolder)
Code: [Select]
;
; https://msdn.microsoft.com/en-us/library/windows/desktop/bb762114(v=vs.85).aspx
;
include windows.inc
include wininet.inc
include shlobj.inc
include shlwapi.inc
include stdio.inc
include tchar.inc

.data
IID_IShellFolder  GUID _IID_IShellFolder

ifdef __PE__
GUID_NULL GUID <0>
IID_IOleDocument GUID _IID_IOleDocument
IID_IOleDocumentView GUID _IID_IOleDocumentView
IID_IOleDocumentSite GUID _IID_IOleDocumentSite
IID_IOleCommandTarget GUID _IID_IOleCommandTarget
IID_IExplorerPaneVisibility GUID _IID_IExplorerPaneVisibility
IID_IBandHost GUID _IID_IBandHost
IID_INameSpaceTreeControl GUID _IID_INameSpaceTreeControl
IID_INewMenuClient GUID _IID_INewMenuClient
IID_IEnumerableView GUID _IID_IEnumerableView
IID_IWebWizardExtension GUID _IID_IWebWizardExtension
IID_IWizardSite GUID _IID_IWizardSite
IID_IProfferService GUID _IID_IProfferService
IID_ICommDlgBrowser GUID _IID_ICommDlgBrowser
IID_IFolderView GUID _IID_IFolderView
IID_IShellTaskScheduler GUID _IID_IShellTaskScheduler
IID_IWebBrowserApp GUID _IID_IWebBrowserApp
IID_IProtectFocus GUID _IID_IProtectFocus
IID_IEnumOleDocumentViews GUID _IID_IEnumOleDocumentViews
endif

.code

main proc

  local psfParent:LPIShellFolder
  local pidlRelative:ptr PCUITEMID_CHILD
  local pidlItem:PIDLIST_ABSOLUTE
  local szDisplayName[MAX_PATH]:TCHAR
  local strret:STRRET

    mov pidlItem,ILCreateFromPath("C:\\")
    .ifd !SHBindToParent(pidlItem, &IID_IShellFolder, &psfParent, &pidlRelative)

psfParent.GetDisplayNameOf(pidlRelative, SHGDN_NORMAL, &strret)
psfParent.Release()
StrRetToBuf(&strret, pidlRelative, &szDisplayName, MAX_PATH)
printf("%s\n", &szDisplayName)
    .endif

    ILFree(pidlItem)
    xor eax,eax
    ret

main endp

    end _tstart
Title: Re: Asmc source and binaries
Post by: nidud on December 23, 2017, 08:02:27 AM
Some more COM stuff.

Code: [Select]
- added support for Class::Method proto
- added support for Class::Method proc
- added support for Class::Method(...)
- added support for com_ptr[Vtbl].proc_ptr(...)

Class::Method proto Class@Method proto :ptr Class

The conflict between Class and ClassVtbl.

I remove the Vtbl structs in the Windows include files to simplify declarations and usage. On creation of new classes this may however not be a good idea but still possible.

Normal C declaration:
Code: [Select]
ClassVtbl struct
   Method()
ClassVtbl ends

Class struct
   lpVtbl PClassVtbl ?
Class ends

Alternate declaration:
Code: [Select]
Class union
struct
   lpVtbl PClassVtbl ?
ends
struct
   Method()
ends
Class ends

The assembler will now search for ClassVtbl when pointers are expanded and use it if available. Expansion of p.Method() will in the latter be [rax].Class.Method and [rax].ClassVtbl.Method in the former.

Well, it's a very spesific word this «Vtbl», but the implementation was also spesific: to target the C implementation of a COM interface. This in turn dictates the general rules for usage.

Code: [Select]
METHOD macro entry, args:vararg
    local __type, __ptr
    ifnb <args>
        __type typedef proto :ptr, &args
    else
        __type typedef proto :ptr
    endif
    __ptr typedef ptr __type
    entry __ptr ?
    endm

Use Class::Class(Class*) as constructor
Code: [Select]
DEFINE_CLASS macro Class, args:vararg
    P&Class& typedef ptr Class
    P&Class&Vtbl typedef ptr &Class&Vtbl
    ifnb <args>
        exitm<&Class&::&Class& proto :P&Class&, &args>
    else
        exitm<&Class&::&Class& proto :P&Class&>
    endif
    endm

Code: [Select]
DEFINE_CLASS(TWindow)

TWindowVtbl struct
    METHOD  IsInsideX, :SINT
    METHOD  IsInsideY, :SINT
    METHOD  IsInsideXY, :SINT, :SINT
    METHOD  Release
TWindowVtbl ends

TWindow struct
    lpVtbl  PTWindowVtbl ?

    Flags   UINT ?
    Window  PCHAR_INFO ?
    rc     SMALL_RECT <>
TWindow ends

Code: [Select]
TWindow::IsInsideX proc x:SINT

    xor eax,eax
    .repeat

        .break .if dx > [rcx].rc.Right
        .break .if dx < [rcx].rc.Left

        mov eax,edx
        sub ax,[rcx].rc.Left
        inc eax

    .until 1
    ret

TWindow::IsInsideX endp

TWindow::IsInsideXY proc x:SINT, y:SINT

    .if TWindow::IsInsideX(rcx, edx)
        TWindow::IsInsideY(rcx, r8d)
    .endif
    ret

TWindow::IsInsideXY endp
Title: Re: Asmc source and binaries
Post by: AssemblyChallenge on January 06, 2018, 12:55:32 AM
Hi nidud.

I have been following your great work with Asmc. One thing I would like to see from your project is some sort of page and/or manual, something like the one from Uasm's guys.

The info included in Git/Readme, for example, is very short IMHO. In the first page of this post someone asked "What is Asmc?" and then you replied with some features (handling of strings, .SWITCH, etc). Could you please create some sort of PDF with all the details? I was tempted to simply copy/paste that post in a file but it would be -probably- incomplete as Asmc has a lot more under the hood.

Regards.
Title: Re: Asmc source and binaries
Post by: nidud on January 06, 2018, 02:13:13 AM
The text you refer to is taken from the Asmc help file included in the package. In addition to this there are a few thousand ASM-files with test cases and samples including all extensions and features of the assembler.
Title: Re: Asmc source and binaries
Post by: AssemblyChallenge on January 06, 2018, 03:05:40 AM
Let me spare some time -and embarrassment- to the newcomers of Asmc. The help file is located at:

asmc-master\source\asmc\asmc.chm

Thank you, I was looking everywhere... except in the source code :icon_redface:
Title: Re: Asmc source and binaries
Post by: AssemblyChallenge on January 12, 2018, 06:35:21 AM
Hi Nidud.

After my adventures while trying Asmc and the cvpack.exe building error, maybe you should include that file in Asmc's tree, or perhaps explain in the help file that you must download it from Jwasm's site. I got this tip from good friend Ramon.

Regards.

PD: In my next project I will be using your compiler.
Title: Re: Asmc source and binaries
Post by: nidud on March 25, 2018, 04:23:49 AM
After my adventures while trying Asmc and the cvpack.exe building error, maybe you should include that file in Asmc's tree, or perhaps explain in the help file that you must download it from Jwasm's site.

This is a Microsoft executable. Think there are a few clones included in the Open Watcom package.

Quote
PD: In my next project I will be using your compiler.

 :t
Title: Re: Asmc source and binaries
Post by: nidud on March 25, 2018, 05:11:27 AM
A few new changes.

- convert MOV REG,0 to XOR for args.
- some unnecessary stack adjustments was removed in 64-bit if LEAVE used.
- added use of PROC in struct member declarations.
- added .classdef directive.
- added .ends directive
- added .pragma directive

Code: [Select]
.classdef Class

    Read proc :ptr, :ptr, :ptr

    .ends

foo proc

  local d:Class

    d.Read(0,0,1)
    ret

foo endp

Code: [Select]
   0: 55                    push   rbp
   1: 48 8b ec              mov    rbp,rsp
   4: 48 83 ec 30          sub    rsp,0x30
   8: 48 8d 4d f8          lea    rcx,[rbp-0x8]
   c: 48 33 d2              xor    rdx,rdx
   f: 4d 33 c0              xor    r8,r8
  12: 49 c7 c1 01 00 00 00 mov    r9,0x1
  19: 48 8b 01              mov    rax,QWORD PTR [rcx]
  1c: ff 50 08              call   QWORD PTR [rax+0x8]
  1f: c9                    leave 
  20: c3                    ret   

Test case for .classdef and .pragma:
https://github.com/nidud/asmc/tree/master/source/test/classdef/0

User registers prohibit this optimization but the -Cs switch will fix that.
Code: [Select]
foo proc uses rsi rdi
Code: [Select]
   0: 55                    push   rbp
   1: 48 8b ec              mov    rbp,rsp
   4: 56                    push   rsi
   5: 57                    push   rdi
   6: 48 83 ec 30          sub    rsp,0x30
   a: 48 8d 4d e8          lea    rcx,[rbp-0x18]
   e: 48 33 d2              xor    rdx,rdx
  11: 4d 33 c0              xor    r8,r8
  14: 49 c7 c1 01 00 00 00 mov    r9,0x1
  1b: 48 8b 01              mov    rax,QWORD PTR [rcx]
  1e: ff 50 08              call   QWORD PTR [rax+0x8]
  21: 48 83 c4 30          add    rsp,0x30
  25: 5f                    pop    rdi
  26: 5e                    pop    rsi
  27: c9                    leave 
  28: c3                    ret   

Using -Cs
Code: [Select]
   0: 56                    push   rsi
   1: 57                    push   rdi
   2: 55                    push   rbp
   3: 48 8b ec              mov    rbp,rsp
   6: 48 83 ec 30          sub    rsp,0x30
   a: 48 8d 4d f8          lea    rcx,[rbp-0x8]
   e: 48 33 d2              xor    rdx,rdx
  11: 4d 33 c0              xor    r8,r8
  14: 49 c7 c1 01 00 00 00 mov    r9,0x1
  1b: 48 8b 01              mov    rax,QWORD PTR [rcx]
  1e: ff 50 08              call   QWORD PTR [rax+0x8]
  21: c9                    leave 
  22: 5f                    pop    rdi
  23: 5e                    pop    rsi
  24: c3                    ret   
Title: Re: Asmc source and binaries
Post by: nidud on April 07, 2018, 02:39:27 AM
Added more include files (https://github.com/nidud/asmc/tree/master/include) for D3D10/11.

A simple test case (https://github.com/nidud/asmc/tree/master/source/test/wininc/D3D11/1) for D3D11CreateDevice (https://msdn.microsoft.com/en-us/library/windows/desktop/ff476082(v=vs.85).aspx)():
Code: [Select]
include windows.inc
include SpecStrings.inc
include d3d11.inc
include tchar.inc

    .code

MsgProc proc WINAPI hWnd:HWND, msg:UINT, wParam:WPARAM, lParam:LPARAM

    .switch(msg)
      .case WM_DESTROY:
        PostQuitMessage( 0 )
        .endc
      .default
        DefWindowProc( hWnd, msg, wParam, lParam )
    .endsw
    ret

MsgProc endp

WinMain proc WINAPI uses rdi hInstance:HINSTANCE, hPrevInstance:HINSTANCE, lpCmdLine:LPSTR, nShowCmd:SINT

    local wc:WNDCLASSEX
    local hWnd:HWND
    local msg:MSG

    local createDeviceFlags:UINT
    local featureLevel:D3D_FEATURE_LEVEL
    local device:ptr ID3D11Device
    local context:ptr ID3D11DeviceContext

    xor eax,eax
    lea rdi,wc
    mov ecx,sizeof(WNDCLASSEX)
    rep stosb
    mov wc.cbSize,sizeof(WNDCLASSEX)
    mov wc.style,CS_CLASSDC
    lea rax,MsgProc
    mov wc.lpfnWndProc,rax
    lea rax,@CStr("Direct3D Window")
    mov wc.lpszClassName,rax
    mov wc.hInstance,GetModuleHandle(NULL)
    RegisterClassEx( &wc )
    mov hWnd,CreateWindowEx(0, "Direct3D Window", "D3D11 Test 1",
        WS_OVERLAPPEDWINDOW, 100, 100, 400, 400, GetDesktopWindow(), NULL, wc.hInstance, NULL )
    ShowWindow( hWnd, SW_SHOW )

    .repeat

        mov createDeviceFlags,0
ifdef _DEBUG
        mov createDeviceFlags,D3D11_CREATE_DEVICE_DEBUG
endif
        .ifd D3D11CreateDevice(
                0,
                D3D_DRIVER_TYPE_HARDWARE,
                0,
                createDeviceFlags,
                0,
                0,
                D3D11_SDK_VERSION,
                &device,
                &featureLevel,
                &context) != S_OK

            MessageBox(0, "D3D11CreateDevice Failed.", "D3D11 Test 1", 0)
            mov eax,E_FAIL
            .break
        .else
            device.Release()
            MessageBox(0, "D3D11CreateDevice Success.", "D3D11 Test 1", 0)
        .endif
        xor eax,eax
    .until 1
    ret

WinMain endp

    end _tstart
Title: Re: Asmc source and binaries
Post by: nidud on April 08, 2018, 10:25:27 PM
Added two more samples from the Direct3D-Tutorial-Win32 package. The default build for these samples are 64-bit. To build a 32-bit version just remove the -win64 switch from the makefile.

The tutorial can be downloaded from here:
https://code.msdn.microsoft.com/windowsdesktop/Direct3D-Tutorial-Win32-829979ef

The first sample is a Unicode build demonstrating the basic setup of a Direct3D 11 device.
Code: [Select]
;;--------------------------------------------------------------------------------------
;; File: Tutorial01.cpp
;;
;; This application demonstrates creating a Direct3D 11 device
;;
;; http://msdn.microsoft.com/en-us/library/windows/apps/ff729718.aspx
;;
;; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
;; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
;; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
;; PARTICULAR PURPOSE.
;;
;; Copyright (c) Microsoft Corporation. All rights reserved.
;;--------------------------------------------------------------------------------------

include windows.inc
include SpecStrings.inc
include d3d11_1.inc
include gdipluscolor.inc
include tchar.inc
ifndef _WIN64
    .686
    .xmm
endif

    .data
;;--------------------------------------------------------------------------------------
;; Global Variables
;;--------------------------------------------------------------------------------------
g_hInst HINSTANCE NULL
g_hWnd HWND NULL
g_driverType D3D_DRIVER_TYPE D3D_DRIVER_TYPE_NULL
g_featureLevel D3D_FEATURE_LEVEL D3D_FEATURE_LEVEL_11_0
g_pd3dDevice LPID3D11Device NULL
g_pd3dDevice1 LPID3D11Device1 NULL
g_pImmediateContext LPID3D11DeviceContext NULL
g_pImmediateContext1 LPID3D11DeviceContext1 NULL
g_pSwapChain LPIDXGISwapChain NULL
g_pSwapChain1 LPIDXGISwapChain1 NULL
g_pRenderTargetView LPID3D11RenderTargetView NULL

IID_IDXGIFactory1 GUID _IID_IDXGIFactory1
IID_IDXGIDevice GUID _IID_IDXGIDevice
IID_IDXGIFactory2 GUID _IID_IDXGIFactory2
IID_ID3D11Device1 GUID _IID_ID3D11Device1
IID_ID3D11DeviceContext1 GUID _IID_ID3D11DeviceContext1
IID_IDXGISwapChain GUID _IID_IDXGISwapChain
IID_ID3D11Texture2D GUID _IID_ID3D11Texture2D

    .code
;;--------------------------------------------------------------------------------------
;; Forward declarations
;;--------------------------------------------------------------------------------------
ifdef __PE__
option dllimport:none
endif
InitWindow proto :HINSTANCE, :SINT
InitDevice proto
CleanupDevice proto
WndProc proto :HWND, :UINT, :WPARAM, :LPARAM
Render proto

;;--------------------------------------------------------------------------------------
;; Entry point to the program. Initializes everything and goes into a message processing
;; loop. Idle time is used to render the scene.
;;--------------------------------------------------------------------------------------
wWinMain proc WINAPI hInstance:HINSTANCE, hPrevInstance:HINSTANCE, lpCmdLine:LPWSTR, nCmdShow:SINT

    local msg:MSG

    .repeat

.ifd InitWindow( hInstance, nCmdShow ) != S_OK

    xor eax,eax
    .break
.endif

.ifd InitDevice() != S_OK

    CleanupDevice()
    xor eax,eax
    .break
.endif

;; Main message loop
mov msg.message,0
.while( msg.message != WM_QUIT )

    .ifd PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )

TranslateMessage( &msg )
DispatchMessage( &msg )
    .else
Render()
    .endif
.endw

CleanupDevice()
mov rax,msg.wParam

    .until 1
    ret

wWinMain endp

;;--------------------------------------------------------------------------------------
;; Register class and create window
;;--------------------------------------------------------------------------------------
InitWindow proc uses rsi rdi hInstance:HINSTANCE, nCmdShow:SINT

    local wcex:WNDCLASSEX
    local rc:RECT

    ;; Register class
    mov wcex.cbSize,sizeof( WNDCLASSEX )
    mov wcex.style,CS_HREDRAW or CS_VREDRAW
    lea rax,WndProc
    mov wcex.lpfnWndProc,rax
    mov wcex.cbClsExtra,0
    mov wcex.cbWndExtra,0
    mov rax,hInstance
    mov wcex.hInstance,rax
    mov wcex.hIcon,LoadIcon( hInstance, IDI_APPLICATION )
    mov wcex.hIconSm,rax
    mov wcex.hCursor,LoadCursor( NULL, IDC_ARROW )
    mov wcex.hbrBackground,COLOR_WINDOW + 1
    mov wcex.lpszMenuName,NULL
    lea rax,@CStr("TutorialWindowClass")
    mov wcex.lpszClassName,rax

    .repeat

.if !RegisterClassEx( &wcex )

    mov eax,E_FAIL
    .break
.endif

;; Create window
mov rax,hInstance
mov g_hInst,rax

mov rc.left,0
mov rc.top,0
mov rc.right,800
mov rc.bottom,600

AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE )

mov esi,rc.right
sub esi,rc.left
mov edi,rc.bottom
sub edi,rc.top

.if CreateWindow("TutorialWindowClass", "Direct3D 11 Tutorial 1: Direct3D 11 Basics",
WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, esi, edi, NULL, NULL, hInstance, NULL)

    mov g_hWnd,rax
    ShowWindow( rax, nCmdShow )
    mov eax,S_OK
.else
    mov eax,E_FAIL
.endif
    .until 1
    ret

InitWindow endp

;;--------------------------------------------------------------------------------------
;; Called every time the application receives a message
;;--------------------------------------------------------------------------------------
WndProc proc hWnd:HWND, message:UINT, wParam:WPARAM, lParam:LPARAM

    local ps:PAINTSTRUCT
    local hdc:HDC

    .repeat

.switch( message )
.case WM_PAINT
    mov hdc,BeginPaint( hWnd, &ps )
    EndPaint( hWnd, &ps )
    .endc

.case WM_DESTROY
    PostQuitMessage( 0 )
    .endc

    ;; Note that this tutorial does not handle resizing (WM_SIZE) requests,
    ;; so we created the window without the resize border.

.default
    DefWindowProc( hWnd, message, wParam, lParam )
    .break
.endsw
xor eax,eax
    .until 1
    ret

WndProc endp

;;--------------------------------------------------------------------------------------
;; Create Direct3D device and swap chain
;;--------------------------------------------------------------------------------------
InitDevice proc uses rsi rdi rbx

    local hr:HRESULT
    local rc:RECT
    local _width:UINT
    local height:UINT
    local vp:D3D11_VIEWPORT
    local numFeatureLevels:UINT
    local numDriverTypes:UINT
    local driverTypes[3]:D3D_DRIVER_TYPE
    local featureLevels[4]:D3D_FEATURE_LEVEL
    local dxgiFactory:LPIDXGIFactory1
    local dxgiDevice:LPIDXGIDevice
    local pBackBuffer:ptr ID3D11Texture2D
    local adapter:ptr IDXGIAdapter
    local dxgiFactory2:ptr IDXGIFactory2
    local sd:DXGI_SWAP_CHAIN_DESC1
    local sd2:DXGI_SWAP_CHAIN_DESC
    local createDeviceFlags:UINT

    GetClientRect( g_hWnd, &rc )

    mov eax,rc.right
    sub eax,rc.left
    mov _width,eax
    mov eax,rc.bottom
    sub eax,rc.top
    mov height,eax

    mov createDeviceFlags,0
ifdef _DEBUG
    mov createDeviceFlags,D3D11_CREATE_DEVICE_DEBUG
endif

    mov driverTypes[0],D3D_DRIVER_TYPE_HARDWARE
    mov driverTypes[4],D3D_DRIVER_TYPE_WARP
    mov driverTypes[8],D3D_DRIVER_TYPE_REFERENCE
    mov numDriverTypes,3;ARRAYSIZE( driverTypes )

    mov featureLevels[0],D3D_FEATURE_LEVEL_11_1
    mov featureLevels[4],D3D_FEATURE_LEVEL_11_0
    mov featureLevels[8],D3D_FEATURE_LEVEL_10_1
    mov featureLevels[12],D3D_FEATURE_LEVEL_10_0
    mov numFeatureLevels,4;ARRAYSIZE( featureLevels )

    .for( ebx = 0: ebx < numDriverTypes: ebx++ )

lea rsi,driverTypes
mov eax,[rsi+rbx*4]
mov g_driverType,eax

.ifd D3D11CreateDevice(
NULL,
g_driverType,
NULL,
createDeviceFlags,
&featureLevels,
numFeatureLevels,
D3D11_SDK_VERSION,
&g_pd3dDevice,
&g_featureLevel,
&g_pImmediateContext ) == E_INVALIDARG

    ;; DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1
    ;; so we need to retry without it
    mov edi,numFeatureLevels
    dec edi
    lea rsi,featureLevels
    add rsi,4

    D3D11CreateDevice(
NULL,
g_driverType,
NULL,
createDeviceFlags,
rsi,
edi,
D3D11_SDK_VERSION,
&g_pd3dDevice,
&g_featureLevel,
&g_pImmediateContext )
.endif

.break .if eax == S_OK
    .endf

    .repeat

.break .if eax != S_OK

;; Obtain DXGI factory from device (since we used nullptr for pAdapter above)
mov dxgiFactory,NULL
mov dxgiDevice,NULL

.ifd g_pd3dDevice.QueryInterface(
    &IID_IDXGIDevice,
    &dxgiDevice ) == S_OK

    mov hr,eax
    mov adapter,NULL
    .ifd dxgiDevice.GetAdapter(&adapter) == S_OK

adapter._GetParent( &IID_IDXGIFactory1, &dxgiFactory )
mov hr,eax
adapter.Release()
    .endif
    dxgiDevice.Release()
.else
    mov hr,eax
.endif
mov eax,hr
.break .if eax != S_OK

;; Create swap chain
mov dxgiFactory2,NULL
dxgiFactory.QueryInterface( &IID_IDXGIFactory2, &dxgiFactory2 )
mov hr,eax
.if ( dxgiFactory2 )

    ;; DirectX 11.1 or later
    g_pd3dDevice.QueryInterface( &IID_ID3D11Device1, &g_pd3dDevice1 )
    mov hr,eax
    .if eax == S_OK

g_pImmediateContext.QueryInterface( &IID_ID3D11DeviceContext1, &g_pImmediateContext1 )
    .endif

    ZeroMemory(&sd, sizeof(sd))
    mov eax,_width
    mov sd._Width,eax
    mov eax,height
    mov sd.Height,eax
    mov sd.Format,DXGI_FORMAT_R8G8B8A8_UNORM
    mov sd.SampleDesc.Count,1
    mov sd.SampleDesc.Quality,0
    mov sd.BufferUsage,DXGI_USAGE_RENDER_TARGET_OUTPUT
    mov sd.BufferCount,1

    dxgiFactory2.CreateSwapChainForHwnd( g_pd3dDevice, g_hWnd, &sd, NULL, NULL, &g_pSwapChain1 )
    mov hr,eax
    .if eax == S_OK

g_pSwapChain1.QueryInterface( &IID_IDXGISwapChain, &g_pSwapChain )
    .endif

    dxgiFactory2.Release()

.else

    ;; DirectX 11.0 systems

    ZeroMemory(&sd2, sizeof(sd2))
    mov sd2.BufferCount,1
    mov eax,_width
    mov sd2.BufferDesc._Width,eax
    mov eax,height
    mov sd2.BufferDesc.Height,eax
    mov sd2.BufferDesc.Format,DXGI_FORMAT_R8G8B8A8_UNORM
    mov sd2.BufferDesc.RefreshRate.Numerator,60
    mov sd2.BufferDesc.RefreshRate.Denominator,1
    mov sd2.BufferUsage,DXGI_USAGE_RENDER_TARGET_OUTPUT
    mov rax,g_hWnd
    mov sd2.OutputWindow,rax
    mov sd2.SampleDesc.Count,1
    mov sd2.SampleDesc.Quality,0
    mov sd2.Windowed,TRUE

    dxgiFactory.CreateSwapChain( g_pd3dDevice, &sd2, &g_pSwapChain )
    mov hr,eax
.endif

;; Note this tutorial doesn't handle full-screen swapchains so we block
;; the ALT+ENTER shortcut
dxgiFactory.MakeWindowAssociation( g_hWnd, DXGI_MWA_NO_ALT_ENTER )
dxgiFactory.Release()

mov eax,hr
.break .if eax != S_OK

;; Create a render target view
mov pBackBuffer,NULL
.break .ifd g_pSwapChain.GetBuffer(0, &IID_ID3D11Texture2D, &pBackBuffer ) != S_OK

g_pd3dDevice.CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView )
mov hr,eax
pBackBuffer.Release()
mov eax,hr
.break .if eax != S_OK

g_pImmediateContext.OMSetRenderTargets( 1, &g_pRenderTargetView, NULL )

;; Setup the viewport

pxor xmm0,xmm0
cvtsi2ss xmm0,_width
movss vp._Width,xmm0
pxor xmm0,xmm0
cvtsi2ss xmm0,height
movss vp.Height,xmm0
mov vp.MinDepth,0.0
mov vp.MaxDepth,1.0
mov vp.TopLeftX,0.0
mov vp.TopLeftY,0.0
g_pImmediateContext.RSSetViewports( 1, &vp )

mov eax,S_OK
    .until 1
    ret

InitDevice endp


;;--------------------------------------------------------------------------------------
;; Render the frame
;;--------------------------------------------------------------------------------------

Render proc

  local ColorRGBA[4]:FLOAT

    mov ColorRGBA[0],ARGB_MidnightBlue
    mov ColorRGBA[4],ARGB_MintCream
    mov ColorRGBA[8],ARGB_MistyRose
    mov ColorRGBA[12],ARGB_Moccasin

    ;; Just clear the backbuffer
    g_pImmediateContext.ClearRenderTargetView( g_pRenderTargetView, &ColorRGBA )
    g_pSwapChain.Present( 0, 0 )
    ret

Render endp

;;--------------------------------------------------------------------------------------
;; Clean up the objects we've created
;;--------------------------------------------------------------------------------------
CleanupDevice proc

    .if ( g_pImmediateContext )
g_pImmediateContext.ClearState()
    .endif
    .if ( g_pRenderTargetView )
g_pRenderTargetView.Release()
    .endif
    .if ( g_pSwapChain1 )
g_pSwapChain1.Release()
    .endif
    .if ( g_pSwapChain )
g_pSwapChain.Release()
    .endif
    .if ( g_pImmediateContext1 )
g_pImmediateContext1.Release()
    .endif
    .if ( g_pImmediateContext )
g_pImmediateContext.Release()
    .endif
    .if ( g_pd3dDevice1 )
g_pd3dDevice1.Release()
    .endif
    .if ( g_pd3dDevice )
g_pd3dDevice.Release()
    .endif
    ret

CleanupDevice endp

    end _tstart

The second sample (https://github.com/nidud/asmc/tree/master/source/test/wininc/D3D11/3) displays a triangle. The shape is a bit off for some reason but it works. The additional header files added was taken mingw so the parser seems to skip some of the arguments from the methods. I corrected the ones used in the samples but there may be a few more problems there. I may add a few more later to see how this plays out.
Title: Re: Asmc source and binaries
Post by: Greenhorn on April 16, 2018, 06:42:13 AM
Hi nidud,

in asmc's windows include files some macros are missing or not working at runtime.

These are:
winuser.inc
windef.inc    (min/max deactivated by condition NOMINMAX, remaining macros are missing)
stdlib.inc    (macros are not included here)


However, here is what I did to get these macros working:

winuser.inc
Code: [Select]
POINTSTOPOINT macro pt,pts
;//exitm <{ ( pt ) .x = LOWORD ( *  and  pts ) ; ( pt ) .y = HIWORD ( *  and  pts ) ; } >
movsx pt.POINT.x, LOWORD(pts)
movsx pt.POINT.y, HIWORD(pts)
endm
POINTTOPOINTS macro pt
exitm <( MAKELONG ( ( pt.POINT.x ) , ( pt.POINT.y ) ) ) >
endm
MAKEWPARAM macro l,h
ifdef _WIN64
if ((OPATTR (l)) and 00000100b) and ((OPATTR (h)) and 00000100b) ;; first and second argument are constants
mov r8, MAKELONG ( l , h )
else
movsxd r8, MAKELONG ( l , h )
endif
exitm <r8>
else
exitm <( MAKELONG ( l , h ) ) >
endif
endm
MAKELPARAM macro l,h
ifdef _WIN64
if ((OPATTR (l)) and 00000100b) and ((OPATTR (h)) and 00000100b) ;; first and second argument are constants
mov r9, MAKELONG ( l , h )
else
movsxd r9, MAKELONG ( l , h )
endif
exitm <r9>
else
exitm <( MAKELONG ( l , h ) ) >
endif
endm
MAKELRESULT macro l,h
ifdef _WIN64
if ((OPATTR (l)) and 00000100b) and ((OPATTR (h)) and 00000100b) ;; first and second argument are constants
mov rax, MAKELONG ( l , h )
else
movsxd rax, MAKELONG ( l , h )
endif
exitm <rax>
else
exitm <( MAKELONG ( l , h ) ) >
endif
endm

windef.inc
Code: [Select]
ifndef NOMINMAX
ifndef max
max macro a:REQ,b:REQ
local bSign
if ((OPATTR (a)) and 00000100b) and ((OPATTR (b)) and 00000100b) ;;// first and second argument are constants
if a gt b
exitm <a>
else
exitm <b>
endif
elseif ((OPATTR (a)) and 00010000b) ;;// argument is register
if (((INSTR ((SIZESTR <a>) - 2), <a>, <ax>) ge 0) or ((INSTR ((SIZESTR <a>) - 2), <a>, <ah>) ge 0) or ((INSTR ((SIZESTR <a>) - 2), <a>, <al>) ge 0))
cmp  a, b ;// macro max(a,b) from include WinDef.h
else
cmp     a, b ;// macro max(a,b) from include WinDef.inc
if     (SIZE (TYPE (a))) EQ 1
mov     al, a
elseif (SIZE (TYPE (a))) EQ 2
mov     ax, a
elseif (SIZE (TYPE (a))) EQ 4
mov     eax, a
elseif (SIZE (TYPE (a))) EQ 8
mov     rax, a
endif
endif
elseif ((OPATTR (a)) and 00000100b) ;;// constant
mov     eax, a
cmp     eax, b ;// macro max(a,b) from include WinDef.inc
else
if     (SIZE (TYPE (a))) EQ 1
mov  al, a
cmp  al, b ;// macro max(a,b) from include WinDef.inc
elseif (SIZE (TYPE (a))) EQ 2
mov     ax, a
cmp     ax, b ;// macro max(a,b) from include WinDef.inc
elseif (SIZE (TYPE (a))) EQ 4
mov     eax, a
cmp     eax, b ;// macro max(a,b) from include WinDef.inc
elseif (SIZE (TYPE (a))) EQ 8
mov     rax, a
cmp     rax, b ;// macro max(a,b) from include WinDef.inc
endif
endif

bSign = 0
if (@SizeStr(<a>) ge 9)
ifidni @SubStr(<a>, 1, 7),<sdword > ;;// check parameter "a"
bSign = 1
else
ifidni @SubStr(<a>, 1, 6),<sword >
bSign = 1
else
ifidni @SubStr(<a>, 1, 6),<sbyte >
bSign = 1
endif
endif
endif
endif
if (@SizeStr(<b>) ge 9)
ifidni @SubStr(<b>, 1, 7),<sdword > ;;// check parameter "b"
bSign = 1
else
ifidni @SubStr(<b>, 1, 6),<sword >
bSign = 1
else
ifidni @SubStr(<b>, 1, 6),<sbyte >
bSign = 1
endif
endif
endif
endif
if bSign
if     (SIZE (TYPE (a))) EQ 1
cmovge  al, b ;// signed comparison
exitm <al>
elseif (SIZE (TYPE (a))) EQ 2
cmovge  ax, b ;// signed comparison
exitm <ax>
elseif (SIZE (TYPE (a))) EQ 4
cmovge  eax, b ;// signed comparison
exitm <eax>
elseif (SIZE (TYPE (a))) EQ 8
cmovge  rax, b ;// signed comparison
exitm <rax>
endif
else
if     (SIZE (TYPE (a))) EQ 1
cmovae  al, b ;// unsigned comparison
exitm <al>
elseif (SIZE (TYPE (a))) EQ 2
cmovae  ax, b ;// unsigned comparison
exitm <ax>
elseif (SIZE (TYPE (a))) EQ 4
cmovae  eax, b ;// unsigned comparison
exitm <eax>
elseif (SIZE (TYPE (a))) EQ 8
cmovae  rax, b ;// unsigned comparison
exitm <rax>
endif
endif
endm
endif
ifndef min
min macro a:REQ,b:REQ
local bSign
if ((OPATTR (a)) and 00000100b) and ((OPATTR (b)) and 00000100b) ;;// first and second argument are constants
if a gt b
exitm <a>
else
exitm <b>
endif
elseif ((OPATTR (a)) and 00010000b) ;;// argument is register
if (((INSTR ((SIZESTR <a>) - 2), <a>, <ax>) ge 0) or ((INSTR ((SIZESTR <a>) - 2), <a>, <ah>) ge 0) or ((INSTR ((SIZESTR <a>) - 2), <a>, <al>) ge 0))
cmp  a, b ;// macro min(a,b) from include WinDef.h
else
cmp     a, b ;// macro min(a,b) from include WinDef.inc
if     (SIZE (TYPE (a))) EQ 1
mov     al, a
elseif (SIZE (TYPE (a))) EQ 2
mov     ax, a
elseif (SIZE (TYPE (a))) EQ 4
mov     eax, a
elseif (SIZE (TYPE (a))) EQ 8
mov     rax, a
endif
endif
elseif ((OPATTR (a)) and 00000100b) ;// constant
mov     eax, a
cmp     eax, b ;// macro max(a,b) from include WinDef.inc
else
if     (SIZE (TYPE (a))) EQ 1
mov     al, a ;//
cmp     al, b ;// macro min(a,b) from include WinDef.inc
elseif (SIZE (TYPE (a))) EQ 2
mov     ax, a ;//
cmp     ax, b ;// macro min(a,b) from include WinDef.inc
elseif (SIZE (TYPE (a))) EQ 4
mov     eax, a ;//
cmp     eax, b ;// macro min(a,b) from include WinDef.inc
elseif (SIZE (TYPE (a))) EQ 8
mov     rax, a
cmp     rax, b ;// macro min(a,b) from include WinDef.inc
endif
endif
bSign = 0
if (@SizeStr(<a>) ge 9)
ifidni @SubStr(<a>, 1, 7),<sdword > ;;// check parameter "a"
bSign = 1
else
ifidni @SubStr(<a>, 1, 6),<sword >
bSign = 1
else
ifidni @SubStr(<a>, 1, 6),<sbyte >
bSign = 1
endif
endif
endif
endif
if (@SizeStr(<b>) ge 9)
ifidni @SubStr(<b>, 1, 7),<sdword > ;;// check parameter "b"
bSign = 1
else
ifidni @SubStr(<b>, 1, 6),<sword >
bSign = 1
else
ifidni @SubStr(<b>, 1, 6),<sbyte >
bSign = 1
endif
endif
endif
endif
if bSign
if     (SIZE (TYPE (a))) EQ 1
cmovle  al, b ;// signed comparison
exitm <al>
elseif (SIZE (TYPE (a))) EQ 2
cmovle  ax, b ;// signed comparison
exitm <ax>
elseif (SIZE (TYPE (a))) EQ 4
cmovle  eax, b ;// signed comparison
exitm <eax>
elseif (SIZE (TYPE (a))) EQ 8
cmovle  rax, b ;// signed comparison
exitm <rax>
endif
else
if     (SIZE (TYPE (a))) EQ 1
cmovbe  al, b ;// unsigned comparison
exitm <al>
elseif (SIZE (TYPE (a))) EQ 2
cmovbe  ax, b ;// unsigned comparison
exitm <ax>
elseif (SIZE (TYPE (a))) EQ 4
cmovbe  eax, b ;// unsigned comparison
exitm <eax>
elseif (SIZE (TYPE (a))) EQ 8
cmovbe  rax, b ;// unsigned comparison
exitm <rax>
endif
endif
endm
endif
endif ;/* NOMINMAX */


MAKEWORD macro a:REQ,b:REQ
if ((OPATTR (a)) and 00000100b) and ((OPATTR (b)) and 00000100b) ;;// first and second argument are constants
exitm <( ( ( ( a )  and  0ffh )  or  ( ( b )  and  0ffh )  shl  8 ) ) >
elseif ((OPATTR (a)) and 00000100b) ;;// first argument is a constant
mov  eax, a ;// macro MAKEWORD(a,b)
if (SIZE (TYPE (b))) EQ 1
mov  cl, b
elseif (SIZE (TYPE (b))) EQ 2
mov  cx, b
elseif (SIZE (TYPE (b))) EQ 4
mov  ecx, b
elseif (SIZE (TYPE (b))) EQ 8
mov  rcx, b
endif
and  eax, 0FFh
and  ecx, 0FFh
shl  ecx, 8
or   eax, ecx
exitm <ax>
elseif ((OPATTR (b)) and 00000100b) ;;// second argument is a constant
mov  ecx, b ;// macro MAKEWORD(a,b)
if (SIZE (TYPE (a))) EQ 1
mov  al, a
elseif (SIZE (TYPE (a))) EQ 2
mov  ax, a
elseif (SIZE (TYPE (a))) EQ 4
mov  eax, a
elseif (SIZE (TYPE (a))) EQ 8
mov  rax, a
endif
and  eax, 0FFh
and  ecx, 0FFh
shl  ecx, 8
or   eax, ecx
exitm <ax>
else
if (SIZE (TYPE (a))) EQ 1
mov  al, a
elseif (SIZE (TYPE (a))) EQ 2
mov  ax, a
elseif (SIZE (TYPE (a))) EQ 4
mov  eax, a
elseif (SIZE (TYPE (a))) EQ 8
mov  rax, a
endif
if (SIZE (TYPE (b))) EQ 1
mov  cl, b
elseif (SIZE (TYPE (b))) EQ 2
mov  cx, b
elseif (SIZE (TYPE (b))) EQ 4
mov  ecx, b
elseif (SIZE (TYPE (b))) EQ 8
mov  rcx, b
endif
and eax, 0FFh ;// macro MAKEWORD(a,b)
and ecx, 0FFh
shl ecx, 8
or  eax, ecx
exitm <ax>
endif
endm

MAKELONG macro a:REQ,b:REQ
if ((OPATTR (a)) and 00000100b) and ((OPATTR (b)) and 00000100b) ;;// first and second argument are constants
exitm <( ( ( ( a )  and  0ffffh )  or  ( ( b )  and  0ffffh )  shl  16 ) ) >
elseif ((OPATTR (a)) and 00000100b) ;;// first argument is a constant
mov  eax, a ;// macro MAKELONG(a,b)
if (SIZE (TYPE (b))) EQ 1
mov  cl, b
elseif (SIZE (TYPE (b))) EQ 2
mov  cx, b
elseif (SIZE (TYPE (b))) EQ 4
mov  ecx, b
elseif (SIZE (TYPE (b))) EQ 8
mov  rcx, b
endif
and  eax, 0FFFFh
and  ecx, 0FFFFh
shl  ecx, 16
or   eax, ecx
exitm <eax>
elseif ((OPATTR (b)) and 00000100b) ;;// second argument is a constant
mov  ecx, b ;// macro MAKELONG(a,b)
if (SIZE (TYPE (a))) EQ 1
mov  al, a
elseif (SIZE (TYPE (a))) EQ 2
mov  ax, a
elseif (SIZE (TYPE (a))) EQ 4
mov  eax, a
elseif (SIZE (TYPE (a))) EQ 8
mov  rax, a
endif
and  eax, 0FFFFh
and  ecx, 0FFFFh
shl  ecx, 16
or   eax, ecx
exitm <eax>
else
if (SIZE (TYPE (a))) EQ 1
mov  al, a
elseif (SIZE (TYPE (a))) EQ 2
mov  ax, a
elseif (SIZE (TYPE (a))) EQ 4
mov  eax, a
elseif (SIZE (TYPE (a))) EQ 8
mov  rax, a
endif
if (SIZE (TYPE (b))) EQ 1
mov  cl, b
elseif (SIZE (TYPE (b))) EQ 2
mov  cx, b
elseif (SIZE (TYPE (b))) EQ 4
mov  ecx, b
elseif (SIZE (TYPE (b))) EQ 8
mov  rcx, b
endif
and  eax, 0FFFFh ;// macro MAKELONG(a,b)
and  ecx, 0FFFFh
shl  ecx, 16
or   eax, ecx
exitm <eax>
endif
endm

LOWORD macro l:REQ
if (OPATTR (l)) and 00000100b ;;// argument is constant
exitm <( ( ( ( l ) )  and  0ffffh ) ) >
else
if (OPATTR (l)) and 00010000b ;;// argument is register
if (SIZE (TYPE (l))) EQ 4
ifdifi <l>, <eax>
mov  eax, l ;// macro LOWORD(l)
endif
elseif (SIZE (TYPE (l))) EQ 8
ifdifi <l>, <rax>
mov  rax, l ;// macro LOWORD(l)
endif
else
.err <Wrong argument size in macro LOWORD.>
endif
else
if (SIZE (TYPE (l))) EQ 4
mov  eax, l ;// macro LOWORD(l)
elseif (SIZE (TYPE (l))) EQ 8
mov  rax, l ;// macro LOWORD(l)
else
.err <Wrong argument size in macro LOWORD.>
endif
endif
and  eax, 0FFFFh ;// macro LOWORD(l)
exitm <ax>
endif
endm

HIWORD macro l:REQ
if (OPATTR (l)) and 00000100b ;;// argument is constant
exitm <( ( ( ( ( l ) )  shr  16 )  and  0ffffh ) ) >
else
if (OPATTR (l)) and 00010000b ;;// argument is register
if (SIZE (TYPE (l))) EQ 4
ifdifi <l>, <eax>
mov  eax, l ;// macro HIWORD(l)
endif
elseif (SIZE (TYPE (l))) EQ 8
ifdifi <l>, <rax>
mov  rax, l ;// macro HIWORD(l)
endif
else
.err <Wrong argument size in macro HIWORD.>
endif
else
if (SIZE (TYPE (l))) EQ 4
mov  eax, l ;// macro HIWORD(l)
elseif (SIZE (TYPE (l))) EQ 8
mov  rax, l ;// macro HIWORD(l)
else
.err <Wrong argument size in macro HIWORD.>
endif
endif
shr  eax, 16 ;// macro HIWORD(l)
and  eax, 0FFFFh ;// macro HIWORD(l)
exitm <ax>
endif
endm

LOBYTE macro w:REQ
if (OPATTR (w)) and 00000100b ;;// argument is constant
exitm <( ( ( ( w ) )  and  0ffh ) ) >
else
if (OPATTR (w)) and 00010000b ;;// argument is register
if (SIZE (TYPE (w))) EQ 2
ifdifi <w>, <ax>
mov  ax, w ;// macro LOBYTE(w)
endif
elseif (SIZE (TYPE (w))) EQ 4
ifdifi <w>, <eax>
mov  eax, w ;// macro LOBYTE(w)
endif
elseif (SIZE (TYPE (w))) EQ 8
ifdifi <w>, <rax>
mov  rax, w ;// macro LOBYTE(w)
endif
else
.err <Wrong argument size in macro LOBYTE.>
endif
else
if (SIZE (TYPE (w))) EQ 2
mov  ax, w ;// macro LOBYTE(w)
elseif (SIZE (TYPE (w))) EQ 4
mov  eax, w ;// macro LOBYTE(w)
elseif (SIZE (TYPE (w))) EQ 8
mov  rax, w ;// macro LOBYTE(w)
else
.err <Wrong argument size in macro LOBYTE.>
endif
endif
and  ax, 0FFh ;// macro LOBYTE(w)
exitm <al>
endif
endm

HIBYTE macro w:REQ
if (OPATTR (w)) and 00000100b ;;// argument is constant
exitm <( ( ( ( ( w ) )  shr  8 )  and  0ffh ) ) >
else
if (OPATTR (w)) and 00010000b ;;// argument is register
if (SIZE (TYPE (w))) EQ 2
ifdifi <w>, <ax>
mov  ax, w ;// macro HIBYTE(w)
endif
elseif (SIZE (TYPE (w))) EQ 4
ifdifi <w>, <eax>
mov  eax, w ;// macro HIBYTE(w)
endif
elseif (SIZE (TYPE (w))) EQ 8
ifdifi <w>, <rax>
mov  rax, w ;// macro HIBYTE(w)
endif
else
.err <Wrong argument size in macro HIBYTE.>
endif
else
if (SIZE (TYPE (w))) EQ 2
mov  ax, w ;// macro HIBYTE(w)
elseif (SIZE (TYPE (w))) EQ 4
mov  eax, w ;// macro HIBYTE(w)
elseif (SIZE (TYPE (w))) EQ 8
mov  rax, w ;// macro HIBYTE(w)
else
.err <Wrong argument size in macro HIBYTE.>
endif
endif
shr  ax, 8 ;// macro HIBYTE(w)
and  ax, 0FFh ;// macro HIBYTE(w)
exitm <al>
endif
endm


stdlib.inc
Code: [Select]
Inserted min/max from above.
Regards
Greenhorn
Title: Re: Asmc source and binaries
Post by: nidud on April 16, 2018, 09:18:01 PM
The parser is simply not clever enough to handle all these macros so this needs some manhandling. I fixed some of them used in the test directory and removed some with conflicting names. Think most of them may work with immediate values but most likely fail on hard metal so I will look into the macros addressed above.
Title: Re: Asmc source and binaries
Post by: nidud on April 26, 2018, 02:02:20 AM
The include files uses .XLIST and .LIST to handle the listing output which is rather extensive using the windows include files. This turns the listing on regardless of the previous state so LIST(push/pop) is added to the .PRAGMA directive.

    .pragma(list(push, [0|1]))
        .pragma list(push, 0)
        .pragma list push 0

    .pragma(list(pop))
        .pragma list(pop)
        .pragma list pop

This gives an error on mismatch of push-pop as in if-endif.
I also added PACK for field alignment.

    .pragma(pack(push, <alignment>))
    .pragma(pack(pop))
Title: Re: Asmc source and binaries
Post by: nidud on May 11, 2018, 01:16:11 AM
Added CREF(push/pop) to the .PRAGMA directive for .cref/.nocref.
Title: Re: Asmc source and binaries
Post by: nidud on May 12, 2018, 06:13:03 AM
Small Windows include (https://github.com/nidud/asmc/tree/master/include) update.

Added one more COM sample (https://github.com/nidud/asmc/tree/master/source/test/wininc/IShellLink) using IShellLink from Raymond Chen (https://blogs.msdn.microsoft.com/oldnewthing/20180509-00/?p=98715).

Build 32/64-bit PE:
asmc -pe -ws test.asm
asmc -pe -ws -win64 test.asm

Code: [Select]
include windows.inc
include shlobj.inc
include stdio.inc
include tchar.inc

.data

CLSID_ShellLink                 IID _CLSID_ShellLink
IID_IShellLink                  IID _IID_IShellLinkW
IID_IPersistFile                IID _IID_IPersistFile
IID_IShellFolderViewCB          IID _IID_IShellFolderViewCB

.code

wmain proc

  local link:ptr IShellLinkW
  local file:ptr IPersistFile

    CoInitialize(NULL)
    .ifd CoCreateInstance(&CLSID_ShellLink, NULL,
            CLSCTX_INPROC_SERVER, &IID_IShellLink, &link) != S_OK

        wprintf("error: %x\n", eax)
    .else
        link.QueryInterface(&IID_IPersistFile, &file)
        link.SetPath("N:\\dir\\some file that doesn't exist.txt")
        file.Save("test.lnk", TRUE)
    .endif
    xor eax,eax
    ret

wmain endp

    end _tstart

32-bit:
Code: [Select]
_wmain  PROC NEAR
        push    ebp                                     ; 0000 _ 55
        mov     ebp, esp                                ; 0001 _ 8B. EC
        sub     esp, 8                                  ; 0003 _ 83. EC, 08
        push    0                                       ; 0006 _ 6A, 00
        call    _CoInitialize@4                         ; 0008 _ E8, 00000000(rel)
        lea     eax, [ebp-4H]                           ; 000D _ 8D. 45, FC
        push    eax                                     ; 0010 _ 50
        push    offset _IID_IShellLinkA                 ; 0011 _ 68, 00000000(d)
        push    1                                       ; 0016 _ 6A, 01
        push    0                                       ; 0018 _ 6A, 00
        push    offset _CLSID_ShellLink                 ; 001A _ 68, 00000000(d)
        call    _CoCreateInstance@20                    ; 001F _ E8, 00000000(rel)
        test    eax, eax                                ; 0024 _ 85. C0
        jz      ?_001                                   ; 0026 _ 74, 10
        push    eax                                     ; 0028 _ 50
        push    offset _DS0000                          ; 0029 _ 68, 00000000(d)
        call    _wprintf                                ; 002E _ E8, 00000000(rel)
        add     esp, 8                                  ; 0033 _ 83. C4, 08
        jmp     ?_002                                   ; 0036 _ EB, 35

?_001:  lea     eax, [ebp-8H]                           ; 0038 _ 8D. 45, F8
        push    eax                                     ; 003B _ 50
        push    offset _IID_IPersistFile                ; 003C _ 68, 00000000(d)
        push    dword ptr [ebp-4H]                      ; 0041 _ FF. 75, FC
        mov     eax, dword ptr [ebp-4H]                 ; 0044 _ 8B. 45, FC
        mov     eax, dword ptr [eax]                    ; 0047 _ 8B. 00
        call    dword ptr [eax]                         ; 0049 _ FF. 10
        push    offset _DS0001                          ; 004B _ 68, 00000000(d)
        push    dword ptr [ebp-4H]                      ; 0050 _ FF. 75, FC
        mov     eax, dword ptr [ebp-4H]                 ; 0053 _ 8B. 45, FC
        mov     eax, dword ptr [eax]                    ; 0056 _ 8B. 00
        call    dword ptr [eax+50H]                     ; 0058 _ FF. 50, 50
        push    1                                       ; 005B _ 6A, 01
        push    offset _DS0002                          ; 005D _ 68, 00000000(d)
        push    dword ptr [ebp-8H]                      ; 0062 _ FF. 75, F8
        mov     eax, dword ptr [ebp-8H]                 ; 0065 _ 8B. 45, F8
        mov     eax, dword ptr [eax]                    ; 0068 _ 8B. 00
        call    dword ptr [eax+18H]                     ; 006A _ FF. 50, 18
?_002:  xor     eax, eax                                ; 006D _ 33. C0
        mov     esp, ebp                                ; 006F _ 8B. E5
        pop     ebp                                     ; 0071 _ 5D
        ret                                             ; 0072 _ C3
_wmain  ENDP

64-bit:
Code: [Select]
wmain   PROC
        push    rbp                                     ; 0000 _ 55
        mov     rbp, rsp                                ; 0001 _ 48: 8B. EC
        sub     rsp, 64                                 ; 0004 _ 48: 83. EC, 40
        xor     rcx, rcx                                ; 0008 _ 48: 33. C9
        call    CoInitialize                            ; 000B _ E8, 00000000(rel)
        lea     rcx, [CLSID_ShellLink]                  ; 0010 _ 48: 8D. 0D, 00000000(rel)
        xor     rdx, rdx                                ; 0017 _ 48: 33. D2
        mov     r8d, 1                                  ; 001A _ 41: B8, 00000001
        lea     r9, [IID_IShellLinkA]                   ; 0020 _ 4C: 8D. 0D, 00000000(rel)
        lea     rax, [rbp-8H]                           ; 0027 _ 48: 8D. 45, F8
        mov     qword ptr [rsp+20H], rax                ; 002B _ 48: 89. 44 24, 20
        call    CoCreateInstance                        ; 0030 _ E8, 00000000(rel)
        test    eax, eax                                ; 0035 _ 85. C0
        jz      ?_001                                   ; 0037 _ 74, 10
        mov     edx, eax                                ; 0039 _ 8B. D0
        lea     rcx, [DS0000]                           ; 003B _ 48: 8D. 0D, 00000000(rel)
        call    wprintf                                 ; 0042 _ E8, 00000000(rel)
        jmp     ?_002                                   ; 0047 _ EB, 3F

?_001:  mov     rcx, qword ptr [rbp-8H]                 ; 0049 _ 48: 8B. 4D, F8
        lea     rdx, [IID_IPersistFile]                 ; 004D _ 48: 8D. 15, 00000000(rel)
        lea     r8, [rbp-10H]                           ; 0054 _ 4C: 8D. 45, F0
        mov     rax, qword ptr [rcx]                    ; 0058 _ 48: 8B. 01
        call    qword ptr [rax]                         ; 005B _ FF. 10
        mov     rcx, qword ptr [rbp-8H]                 ; 005D _ 48: 8B. 4D, F8
        lea     rdx, [DS0001]                           ; 0061 _ 48: 8D. 15, 00000000(rel)
        mov     rax, qword ptr [rcx]                    ; 0068 _ 48: 8B. 01
        call    qword ptr [rax+0A0H]                    ; 006B _ FF. 90, 000000A0
        mov     rcx, qword ptr [rbp-10H]                ; 0071 _ 48: 8B. 4D, F0
        lea     rdx, [DS0002]                           ; 0075 _ 48: 8D. 15, 00000000(rel)
        mov     r8d, 1                                  ; 007C _ 41: B8, 00000001
        mov     rax, qword ptr [rcx]                    ; 0082 _ 48: 8B. 01
        call    qword ptr [rax+30H]                     ; 0085 _ FF. 50, 30
?_002:  xor     eax, eax                                ; 0088 _ 33. C0
        leave                                           ; 008A _ C9
        ret                                             ; 008B _ C3
wmain   ENDP
Title: Re: Asmc source and binaries
Post by: nidud on May 24, 2018, 02:11:07 AM
The newer version of Visual C use __ImageBase for a relative offset calculation. This symbol is provided by the linker:

    extern IMAGE_DOS_HEADER __ImageBase;

The address is then __ImageBase + imagerel(label).

        lea     rdx, [__ImageBase]
        cmove   r8d, eax
        movsxd  rax, ecx
        cmp     r8d, dword ptr [imagerel(maxid)+rdx+rax*4]
        jge     ?_016
        mov     rax, qword ptr [imagerel(table)+rdx+rax*8]


The same using LINKW:

    .code
    ;
    ;--- define __ImageBase at the DOS "MZ" header
    ;
public __ImageBase

    org -0x1000
    __ImageBase label byte

    end


The object has to be the first linked:
    linkw system con_64 file { Image\Base.obj *.obj }

Address        Symbol
=======        ======

Module: base.obj(base.asm)
00400000       __ImageBase
Module: test.obj(test.obj)
00403d60       main
00404010*      ??_C@_0L@FLNMPOK@argc?5?$DN?5?$CFd?6?$AA@
00404020*      ??_C@_0O@JENCBAMC@argv?$FL1?$FN?5?$DN?5?$CFs?6?$AA@
00404030*      ??_C@_0O@IDKJAEIB@argv?$FL0?$FN?5?$DN?5?$CFs?6?$AA@


Test case using CL version 18 (https://github.com/nidud/asmc/tree/master/source/test/libc/CL18).
Title: Re: Asmc source and binaries
Post by: nidud on May 27, 2018, 07:26:06 PM
Microsoft sample using __ImageBase.
Code: [Select]
    page    ,132
    title   memset - set sections of memory all to one byte
;***
;memset.asm - set a section of memory to all one byte
;
;   Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
;   contains the memset() routine
;
;*******************************************************************************

include ksamd64.inc
        subttl  "memset"
;***
;char *memset(dst, value, count) - sets "count" bytes at "dst" to "value"
;
;Purpose:
;   Sets the first "count" bytes of the memory starting
;   at "dst" to the character value "value".
;
;   Algorithm:
;   char *
;   memset (dst, value, count)
;       char *dst;
;       char value;
;       size_t count;
;       {
;       char *start = dst;
;
;       while (count--)
;           *dst++ = value;
;       return(start);
;       }
;
;Entry:
;   char *dst - pointer to memory to fill with value
;   char value - value to put in dst bytes
;   size_t count - number of bytes of dst to fill
;
;Exit:
;   returns dst, with filled bytes
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************
    extrn   __favor:dword
    extrn   __ImageBase:byte

__FAVOR_ENFSTRG equ 1
__FAVOR_SMSTRG  equ 2

        LEAF_ENTRY_ARG3 memset, _TEXT, buf:ptr byte, value:byte, count:dword

        OPTION PROLOGUE:NONE, EPILOGUE:NONE

        mov     r11, rcx                        ; save destination address
        movzx   edx, dl                         ; set fill pattern
        mov     r9, 0101010101010101h           ; replicate fill over 8 bytes
        imul    r9, rdx
        cmp     r8, 16
        jbe     SetBytes16                      ; if count <= 15 use GPR stores to set
        movd    xmm0, r9                        ; bytes to store in bits [0:63]
        punpcklbw xmm0, xmm0                    ; dup bytes to [127:64]

;
; Check if strings should be used
;
        cmp     r8, 128                         ; is this a small set, size <= 128?
        ja      XmmSet                          ; if large set, use XMM set
        bt      __favor, __FAVOR_SMSTRG         ; check if string set should be used
        jnc     XmmSetSmall                     ; otherwise, use a 16-byte block set

StringSet:
        mov     eax, edx                        ; set byte to move
        mov     rdx, rdi                        ; save rdi
        mov     rdi, rcx                        ; set destination
        mov     rcx, r8                         ; set count
        rep     stosb                           ; store the bytes
        mov     rdi, rdx                        ; restore rdi
        mov     rax, r11
        ret                                     ; return

;
; Fill using SSE instructions - size must be 16 or more.
;
        ; xmm0 has the byte to store replicated to all byte positions
        ; rcx has the destination, can be overwritten
        ; r11 has the destination, must be preserved for return value
        ; r8  has the count
        align   16
XmmSet:
        bt      __favor, __FAVOR_ENFSTRG        ; check if string set should be used
        jc      StringSet

        ; Aligned stores are much faster on AMD hardware. We need to do an unaligned
        ; store of (16 - (dest mod 16)) bytes, but it's faster to just store 16 bytes
        ; and then start the aligned loop as usual at ((dest + 16) - (dest mod 16)).
        ; This results in (dest mod 16) bytes being stored twice. This is a lot faster
        ; than a bunch of code to store maybe 8 then maybe 4 then maybe 2 then maybe 1
        ; byte to achieve alignement. It could cause data breakpoints to trigger twice,
        ; but they will hit here first and hopefully you will read this comment.
        ; The fastest way to subtract (16 - (dest mod 16)) from the length is to add
        ; (original dest - aligned dest). This avoids having to calculate the value.

        movups  [rcx], xmm0                     ; store 16 unaligned from start
        add     r8, rcx                         ; r8 = dest + length
        add     rcx, 16                         ; dest = (dest + 16)
        and     rcx, -16                        ; dest = (dest + 16) - (dest mod 16)
        sub     r8, rcx                         ; r8 = remaining length

; Attempt to set 128-byte blocks.
;
XmmSetLarge:
        mov     r9, r8                          ; copy count of bytes remaining
        shr     r9, 7                           ; compute number of 128-byte blocks
        jz      XmmSetSmall                     ; if z, no 128-byte blocks to fill
;
; Set 128-byte blocks
        align   16
XmmSetLargeLoop:
        movaps  0[rcx], xmm0
        movaps  16[rcx], xmm0
        add     rcx, 128                        ; advance destination address early
        movaps  (32 - 128)[rcx], xmm0
        movaps  (48 - 128)[rcx], xmm0
        dec     r9                              ; dec block counter (set cc for jnz)
        movaps  (64 - 128)[rcx], xmm0
        movaps  (80 - 128)[rcx], xmm0
        movaps  (96 - 128)[rcx], xmm0
        movapd  (112 - 128)[rcx], xmm0
        ; to avoid generating a one-byte NOP for the 'align 16' below the previous
        ; instruction is movapd instead of movaps which is one byte longer but
        ; performs exactly the same operation.
        jnz     XmmSetLargeLoop                 ; loop if more blocks

        and     r8, 127                         ; compute remaining byte count
;
; Attempt to set 16-byte blocks
        align   16
XmmSetSmall:
        mov     r9, r8                          ; copy count of bytes remaining
        shr     r9, 4                           ; compute number of 16-byte blocks
        jz      short XmmSetTrailing

        ; This generates an 8-byte nop, which we execute once. This will change only if
        ; any of the code from msetxmm30 down is modified. The following loop thus is
        ; completely contained within one instruction decode buffer on AMD hardware.
        align   16

;
; Set 16-byte blocks
;
XmmSetSmallLoop:
        movups  [rcx], xmm0
        add     rcx, 16
        dec     r9
        jnz     short XmmSetSmallLoop

XmmSetTrailing:
        and     r8, 15                          ; compute remaining length
        jz      XmmSetReturn                    ; skip over movups if done, we could just do it anyway

        ; As at the start, we are going to do an unaligned store of 16 bytes which will overwrite
        ; some bytes already stored. The math is easier, rcx+r8 is one byte past the end, just
        ; back up 16 from there and store 16.

        movups  [rcx+r8-16], xmm0               ; write remainder, overwriting 16-r8 bytes we already wrote

XmmSetReturn:
        mov     rax, r11                        ; must return original dest that we saved in r11
        ret

;
; Jump table for fills of 15 bytes or fewer
;
        align 4
MsetTab dd  IMAGEREL msetTab00
        dd  IMAGEREL msetTab01
        dd  IMAGEREL msetTab02
        dd  IMAGEREL msetTab03
        dd  IMAGEREL msetTab04
        dd  IMAGEREL msetTab05
        dd  IMAGEREL msetTab06
        dd  IMAGEREL msetTab07
        dd  IMAGEREL msetTab08
        dd  IMAGEREL msetTab09
        dd  IMAGEREL msetTab10
        dd  IMAGEREL msetTab11
        dd  IMAGEREL msetTab12
        dd  IMAGEREL msetTab13
        dd  IMAGEREL msetTab14
        dd  IMAGEREL msetTab15
        dd  IMAGEREL msetTab16

        ; Set blocks that are less than 16 bytes long.
        ; Preconditions:
        ; rdx has the byte to fill and has been zero extended (ready for imul)
        ; rcx has dest
        ; r8 has len, r8 < 16
        ; r11 has the dest
        align   16
SetBytes16:
        mov     rdx, r9
        lea     r9, OFFSET __ImageBase
        mov     eax, [(IMAGEREL  MsetTab) + r9 +r8*4]
        add     r9, rax
        add     rcx, r8                         ; rcx is now 1 past last byte to set
        mov     rax, r11                        ; set return value
        jmp     r9


        align   16

        ; Code for setting various sized blocks up to 15 bytes long.
        ; preconditions:
        ; rcx points 1 byte beyond end of bytes to set
        ; rax has the correct return value (the original dest)
        ; each byte of the rdx reg is set to the byte to store
msetTab15:
        mov     (-15)[rcx], rdx
        ; fallthrough to 7
msetTab07:
        mov     (-7)[rcx], edx
        ;; fallthrough to 3
msetTab03:
        mov     (-3)[rcx], dx
        ; fallthrough to 1
msetTab01:
        mov     (-1)[rcx], dl
msetTab00:
        ret

        align   16
msetTab12:
        mov     (-12)[rcx], rdx
        ; fallthrough to 4
msetTab04:
        mov     (-4)[rcx], edx
        ret

msetTab09:
        mov     (-9)[rcx], rdx
        mov     (-1)[rcx], dl
        ret

        align   16
msetTab13:
        mov     (-13)[rcx], rdx
        ; fallthrough to 5
msetTab05:
        mov     (-5)[rcx], edx
        mov     (-1)[rcx], dl
        ret

        align   16
msetTab14:
        mov     (-14)[rcx], rdx
        ; fallthrough to 6
msetTab06:
        mov     (-6)[rcx], edx
        ; fallthrough to 2
msetTab02:
        mov     (-2)[rcx], dx
        ret

msetTab08:
        mov     [rax], rdx
        ret

msetTab11:
        mov     [rax], rdx
        mov     (8)[rax], dx
        mov     (10)[rax], dl
        ret

        align   16
msetTab10:
        mov     [rax], rdx
        mov     (8)[rax], dx
        ret

msetTab16:
        mov     [rax], rdx
        mov     (8)[rax], rdx
        ret

        LEAF_END memset, _TEXT

    end
Title: Re: Asmc source and binaries
Post by: jj2007 on May 27, 2018, 09:18:23 PM
Let me spare some time -and embarrassment- to the newcomers of Asmc. The help file is located at:

asmc-master\source\asmc\asmc.chm

Is there another version? https://github.com/nidud/asmc/raw/master/source/asmc/asmc.chm looks a bit empty :(
Title: Re: Asmc source and binaries
Post by: nidud on May 27, 2018, 10:17:51 PM
Think the OS puts a block on the file if you download it directly. Try right-click->property->General and see if there is a "Remove Block" option there.
Title: Re: Asmc source and binaries
Post by: jj2007 on May 27, 2018, 10:32:08 PM
It's not that empty, actually. The table of contents is there, but no content. Do you have a proper installer for AsmC which puts inc and lib files into their proper folders etc?

P.S.: This is odd. I just re-opened asmc-master\source\asmc\asmc.chm, and now it shows content, too ::)
No mentioning of the includes and libraries, though - is there a separate help file? Examples?
Title: Re: Asmc source and binaries
Post by: nidud on May 27, 2018, 10:45:02 PM
No.
Title: Re: Asmc source and binaries
Post by: nidud on May 27, 2018, 11:50:54 PM
No mentioning of the includes and libraries, though - is there a separate help file? Examples?

Assuming you have downloaded and unzipped the archive you should have something like this:

.\asmc-master
  bin
  include
  lib
  source
  dz.exe


- the include files are in the include directory
- the lib files are in the lib directory
- the source files are in the source directory

The simplest way to build the import libraries is to run the shell (dz.exe). This will setup the environment for the base directory wherever that may be.

From the shell, enter into the lib directory and select the makefile(s) and hit enter. To build the static libraries browse into the source directory and repeat the above. The examples are in the ./source/test directory.
Title: Re: Asmc source and binaries
Post by: nidud on June 13, 2018, 11:16:23 PM
Added a few updates in an attempt to build a 64-bit version of Asmc using the 64-bit library. This uses CL.EXE version 18 (Visual Studio 12) by adding the __ImageBase logic as explain above.

I converted a few of the bottleneck-function from the Asmc source, mostly ASCII to binary (numbers) and HASH algos.

The benchmark for the C/ASM implementation:

19532 ClockTicks: Asmc  32-bit asmc-lib 342K
21871 ClockTicks: Asmc  64-bit asmc-lib 448K
28392 ClockTicks: JWasm 32-bit watcom   345K
30327 ClockTicks: Uasm  64-bit windows  844K
40466 ClockTicks: Uasm  32-bit windows  723K
49375 ClockTicks: Asmc  64-bit windows  531K

Uasm uses a newer version of VS so it optimizes better than the C version of Asmc. Did a fatal mistake when installing Windows on the new (lunch) box, opted for the partition of C/D with the default size and ended up with a rather small C drive. This in turn prohibit the installation of the newest version of Visual Studio.

Asmc do not use any registers in a .switch unless the option REGAX is added. Some changes is added for the 64-bit version where R11 is used instead of RAX.

A direct jump without testing (NOTEST) is not really possible given the code is unknown at the top so the switch will always start with a jump to the test label at the end of the switch. However, it is possible to use the list file to get the name of the label for the jump-table and use this directly:

Code: [Select]
    .code

memcpy::
memmove::

    mov rax,rcx

    .if r8 < 32

        option switch:table, switch:notest, switch:regax

        lea r11,@C0024
        jmp qword ptr [r8*8+r11]

        .switch r8

          .case 0
            ret

          .case 1
            mov cl,[rdx]
            mov [rax],cl
            ret

          .case 2,3
            mov cx,[rdx]
            mov dx,[rdx+r8-2]
            mov [rax+r8-2],dx
            mov [rax],cx
            ret

          .case 4,5,6,7
            mov ecx,[rdx]
            mov edx,[rdx+r8-4]
            mov [rax+r8-4],edx
            mov [rax],ecx
            ret

          .case 8,9,10,11,12,13,14,15
            movq xmm0,[rdx]
            movq xmm1,[rdx+r8-8]
            movq [rax],xmm0
            movq [rax+r8-8],xmm1
            ret

          .case 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
            movdqu xmm0,[rdx]
            movdqu xmm1,[rdx+r8-16]
            movups [rax],xmm0
            movups [rax+r8-16],xmm1
            ret
        .endsw
    .endif

    movdqu xmm2,[rdx]
    movdqu xmm3,[rdx+16]
    movdqu xmm4,[rdx+r8-16]
    movdqu xmm5,[rdx+r8-32]
    .if r8 < 64
        movups [rax],xmm2
        movups [rax+16],xmm3
        movups [rax+r8-16],xmm4
        movups [rax+r8-32],xmm5
        ret
    .endif

    mov ecx,eax
    neg ecx
    and ecx,32-1
    add rdx,rcx
    mov r9,r8
    sub r9,rcx
    add rcx,rax
    and r9b,-32

    .if rcx > rdx

        .repeat
            sub r9,32
            movups xmm0,[rdx+r9]
            movups xmm1,[rdx+r9+16]
            movaps [rcx+r9],xmm0
            movaps [rcx+r9+16],xmm1
        .untilz
        movups [rax],xmm2
        movups [rax+16],xmm3
        movups [rax+r8-16],xmm4
        movups [rax+r8-32],xmm5
        ret
    .endif

    lea rcx,[rcx+r9]
    lea rdx,[rdx+r9]
    neg r9
    .repeat
        movups xmm0,[rdx+r9]
        movups xmm1,[rdx+r9+16]
        movaps [rcx+r9],xmm0
        movaps [rcx+r9+16],xmm1
        add r9,32
    .untilz
    movups [rax],xmm2
    movups [rax+16],xmm3
    movups [rax+r8-16],xmm4
    movups [rax+r8-32],xmm5
    ret

    end