Author Topic: Asmc source and binaries  (Read 33643 times)

nidud

  • Member
  • *****
  • Posts: 1824
    • https://github.com/nidud/asmc
Re: Asmc source and binaries
« Reply #240 on: December 27, 2019, 02:10:37 AM »
Added a fix for the delayed expansion of macro error in v2.31.05.

Regress:

    .x64
    .model flat, fastcall
    .code

_HRESULT_TYPEDEF_ macro val
    exitm<val>
    endm

E_OUTOFMEMORY EQU _HRESULT_TYPEDEF_ ( 8007000Eh )

    .code

    .if edx
        nop
    .elseif eax == E_OUTOFMEMORY
        nop
    .endif

    .while eax == E_OUTOFMEMORY
        nop
    .endw

    end

nidud

  • Member
  • *****
  • Posts: 1824
    • https://github.com/nidud/asmc
Re: Asmc source and binaries
« Reply #241 on: January 05, 2020, 01:46:27 AM »
More integration of PROC and MACRO.

The same functionality used by the CLASS directive which enables constructors and members to be declared as inline (macro) functions are now also available for regular PROTO definition of functions.

In HLL both of these are allowed to be declared in the same header:

_CRTIMP int __cdecl isalnum (int __c);
...
#define isalnum(c)  (_ctype[(unsigned char)(c) + 1] & (_DIGIT | _UPPER | _LOWER))

This is now also allowed in Asmc. If a PROTO is defined before a MACRO the latter will be stored as a sub-symbol of the PROTO definition. This means that the MACRO call will be handled by INVOKE. The parameters to the MACRO will then be exclusively registers sized up according to the PROTO definition.

foo proto :word, :byte, :real4

foo macro  a, b, c ; cx, dl, xmm2
    mov ax,a
    mov al,b
    exitm<movss xmm0,c>
    endm

So the second definition of foo will override the first and a third declaration (a PROC with the same name) will override the MACRO.

main proc

    foo(1,2,3.0)
    ret

main endp

   0:   48 83 ec 28             sub    rsp,0x28
   4:   b8 00 00 40 40          mov    eax,0x40400000
   9:   66 0f 6e d0             movd   xmm2,eax
   d:   ba 02 00 00 00          mov    edx,0x2
  12:   b9 01 00 00 00          mov    ecx,0x1
  17:   66 8b c1                mov    ax,cx
  1a:   8a c2                   mov    al,dl
  1c:   f3 0f 10 c2             movss  xmm0,xmm2
  20:   48 83 c4 28             add    rsp,0x28
  24:   c3                      ret   

...
foo proc a:word, b:byte, c:real4
    ret
foo endp

main proc

    foo(1,2,3.0)
    ret

main endp

   0:   55                      push   rbp
   1:   48 8b ec                mov    rbp,rsp
   4:   48 83 ec 20             sub    rsp,0x20
   8:   c9                      leave 
   9:   c3                      ret   
   a:   48 83 ec 28             sub    rsp,0x28
   e:   b8 00 00 40 40          mov    eax,0x40400000
  13:   66 0f 6e d0             movd   xmm2,eax
  17:   ba 02 00 00 00          mov    edx,0x2
  1c:   b9 01 00 00 00          mov    ecx,0x1
  21:   e8 da ff ff ff          call   0x0
  26:   48 83 c4 28             add    rsp,0x28
  2a:   c3                      ret   

jj2007

  • Member
  • *****
  • Posts: 9912
  • Assembler is fun ;-)
    • MasmBasic
Re: Asmc source and binaries
« Reply #242 on: January 05, 2020, 05:10:47 AM »
Just downloaded the latest version to do my occasional tests:
- works fine with the RichMasm source (21k lines)
- chokes several times with error A2006: undefined symbol : type with the MasmBasic source

I used option /Zne with both. Version 18 April 2019 works fine with both sources. Are you really using the keyword "type" somewhere in a non-Masm compatible way?

One of the errors is related to the second line, with dest being MbCat$ defined in .data? as MbCat$ dd ?, and is2 logically being zero:
         % is2 INSTR <dest>, <.>
         if is2 and type(dest) eq BYTE

nidud

  • Member
  • *****
  • Posts: 1824
    • https://github.com/nidud/asmc
Re: Asmc source and binaries
« Reply #243 on: January 06, 2020, 07:35:12 AM »
I failed to reproduce this so I will assume you may omitted the /Zne (or /Znk) switch in the second case?

This works with both /Znk and /Zne

    .486
    .model flat, c

    t macro dest
        local q
        % q INSTR <dest>,<.>
        if q and type(dest) eq byte
            exitm<eax>
        endif
        exitm<edx>
        endm

    .data?
    x dd ?

    .code

    mov ebx,t(x)

    end

It will however produce an error without:

type.asm(18) : error A2006: undefined symbol : type

jj2007

  • Member
  • *****
  • Posts: 9912
  • Assembler is fun ;-)
    • MasmBasic
Re: Asmc source and binaries
« Reply #244 on: January 06, 2020, 09:42:29 AM »
Option /Zne used to solve the problem, now it doesn't. I also added /Znk, just for fun - no success. With option /Fl and .listall, I get a *.lst file with 616,865 lines, but there is no error A in the whole 36MB file. And no A2006 either (I used case-insensitive search).

It works fine with UAsm, ML 6.15 and ML 10.0
It chokes with ML 14.0, saying xEnd is a syntax error - that was apparently because I had used it as a local var in one proc but as a label in another proc. Which wasn't a problem for UAsm, AsmC, ML 6.15 and ML 10.0

I changed the var xEnd to xxEnd, and voilĂ , ML 14.0 is happy.
But ML 15.0 wasn't, it still choked on the remaining xEnd, so I suppose they misuse it as a keyword somewhere. Solved by calling it @xEnd - but the exe crashes, probably that "jump one byte too short" MASM bug :cool:

So it builds with ML 6.15, 10.0, 14.0, 15.0, UAsm and AsmC of April 2019 but not with the current AsmC. Oh well...

The good news is that the RichMasm editor and a number of simpler sources build just fine :thumbsup:

nidud

  • Member
  • *****
  • Posts: 1824
    • https://github.com/nidud/asmc
Re: Asmc source and binaries
« Reply #245 on: January 10, 2020, 02:42:23 AM »
Added some changes to the implementation above. It still a bit hackish but the general idea is to skip all the probing of parameters normally done in a macro.

The .NEW directive also allow stack allocation within a macro which extend the functionality even further.

SystemDirectory macro

    .new buffer[_MAX_PATH]:char_t

    GetSystemDirectory(&buffer, _MAX_PATH)
    lea rax,buffer
    retm<rax>
    endm

WindowsDirectory macro

    .new buffer[_MAX_PATH]:char_t

    GetWindowsDirectory(&buffer, _MAX_PATH)
    lea rax,buffer
    retm<rax>
    endm

This will reduce the use of static .data as done in HLL where objects normally are dynamically created. Using the same label (buffer) as done above will then share the same address.

main proc
   printf( "WindowsDirectory: %s\n", WindowsDirectory() )
   printf( "SystemDirectory:  %s\n", SystemDirectory() )
   return( 0 )
main endp

The RETURN directive is now hooked up to ENDP so it may be used as above and also in a macro. The DOT is still needed thought, so RETURN equ <.RETURN> here.

        push    rbp
        mov     rbp, rsp
        sub     rsp, 304                               
        mov     edx, 260                               
        lea     rcx, [rbp-104H]                         
        call    GetWindowsDirectoryA                   
        lea     rax, [rbp-104H]                         
        mov     rdx, rax                               
        lea     rcx, [DS0000]                           
        call    printf                                 
        mov     edx, 260                               
        lea     rcx, [rbp-104H]                         
        call    GetSystemDirectoryA                     
        lea     rax, [rbp-104H]                         
        mov     rdx, rax                               
        lea     rcx, [DS0001]                           
        call    printf                                 
        xor     eax, eax                               
        leave                                           
        ret                                             

Some of the ctype functions are implemented as inline which illustrate the use of RETM versus EXITM.

ctype_inline macro char, flags
    lea rax,_ctype
    mov al,[rax+rcx*2+2]
    and eax,flags
    retm<eax>
    endm

isupper macro char
    exitm<ctype_inline(char,_UPPER)>
    endm

The RETM directive skips the returned value if the macro is the first token which makes a function-macro more flexible or (more to the point) more equal to a PROC.

   isupper('A')
   return( 0 )

        sub     rsp, 40
        mov     ecx, 65
        lea     rax, [_ctype]
        mov     al, byte ptr [rax+rcx*2+2H]
        and     eax, 01H                   
        xor     eax, eax                   
        add     rsp, 40                   
        ret                               

   printf( "isupper('A'): %d\n", isupper('A') )
   return( 0 )

        sub     rsp, 40
        mov     ecx, 65
        lea     rax, [_ctype]
        mov     al, byte ptr [rax+rcx*2+2H]
        and     eax, 01H                   
        mov     rdx, rax                   
        lea     rcx, [DS0000]             
        call    printf                     
        xor     eax, eax                   
        add     rsp, 40                   
        ret