64 bit assembler > ASMC Development

Asmc source and binaries

(1/29) > >>

Source and binaries for Asmc is now available at GitHub:


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: ---[Environ]


--- End code ---

Note that Watcom provide clones for some of the MS tools, so VC should for this reason be defined before Watcom.

What is asmc if I may ask?


--- Quote from: caballero on January 10, 2017, 03:38:42 AM ---What is asmc if I may ask?

--- End quote ---

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.


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.


--- Code: ---foo macro reg
bswap reg
exitm <reg>

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

--- End code ---

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

--- Code: --- bswap ecx
do: mov eax,ecx

--- End code ---

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: ---ifdef __INLINE__
strlen macro string
strlen proto :dword

--- End code ---

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: ---plabel proto
extern elabel:dword
call eax
call plabel
call elabel
call clabel
call xlabel


--- End code ---

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.


--- Code: --- 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" )

--- End code ---

Generated code:

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

--- End code ---


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


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: ---    .switch
      .case strchr( esi, '<' )
      .case strchr( esi, '>' )
    jmp around

--- End code ---

The unstructured switch works as a regular C switch where each .CASE directive is just a label.

--- Code: ---    .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

--- End code ---

The structured switch works as a regular Pascal switch where each .CASE directive is a closed branch.

--- Code: ---    .switch eax
      .case 1: printf("Gold medal")
      .case 2: printf("Silver medal")
      .case 3: printf("Bronze medal")
  printf("Better luck next time")

--- End code ---


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: --- .CASE 1: mov ax,2 : .ENDC
      mov ax,3
.CASE al
.CASE 0,1,4,7
.CASE 0..9

--- End code ---

In the control table switch .CASE is equal to .IF:

--- Code: --- .CASE al
.CASE ax <= 2 && !bx

--- End code ---


.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 executes when none of the other cases match the control expression.


.ENDSW closes a .SWITCH statement.

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.



--- Quote from: HSE on January 10, 2017, 06:12:10 AM ---Just testing a ObjAsm32 project (wich have macros .for .switch, etc) I think /Xc is not disabling .switch. 

--- End quote ---

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

--- Code: ---ifdef __ASMC__
    option renamekeyword: <.switch>=@@switch
    option renamekeyword: <.case>=@@case
    option renamekeyword: <.endsw>=@@endsw

--- End code ---

Or the reverse logic:

--- Code: ---ifndef __ASMC__
    option dotname

.switch macro arg
.case macro arg
.endsw macro

--- End code ---


[0] Message Index

[#] Next page

Go to full version