Menu

label: .if macro(...)

2012-09-19
2013-04-20
  • Hjort Nidudsson

    Hjort Nidudsson - 2012-09-19
    code    segment para 'code'
        assume  cs:code,ds:code
        org 100h
    entry:  jmp around
    func    macro p:VARARG
        invoke p
        exitm <ax>
        endm
    foo proc
        dec ax
        ret
    foo endp
    bar:    .if func(foo)
            inc ax
        .endif
        ret
    around: mov ax,1
        call    bar
        mov ah,4Ch
        int 21h
    code    ends
        end entry
    

    List file from MASM:

     0102               foo proc
     0102  48               dec ax
     0103  C3               ret
     0104               foo endp
     0104  E8 FFFB         *        call   foo
     0107               bar:    .if func(foo)
     0107  0B C0           *        or  ax, ax
     0109  74 01           *        je     @C0001
     010B  40                   inc ax
                        .endif
     010C              *@C0001:
     010C  C3               ret
    
     
  • japheth

    japheth - 2012-09-20

    O-kay … and what exactly is the problem?

     
  • Hjort Nidudsson

    Hjort Nidudsson - 2012-09-20

    Just some confusion to the fact that you end up behind the label: .if (you put some stuff here)..

     
  • japheth

    japheth - 2012-09-21

    > Just some confusion to the fact that you end up behind the label: .if (you put some stuff here).

    The "CALL foo" is located before the "bar:" label because expansion is done first. However, if the macro function is a macro argument, the "CALL foo" will be BEHIND the label:

    .model tiny
    .code
    foo proc
        ret
    foo endp
    func macro x:vararg
        invoke x
        exitm <ax>
    endm
    m1  macro arg
        echo arg
    endm
    bar: m1 func(foo)
         inc ax
    end
    
     
  • Hjort Nidudsson

    Hjort Nidudsson - 2012-09-21

    > The "CALL foo" is located before the "bar:" label because expansion is done first. However, if the macro function is a
    > macro argument, the "CALL foo" will be BEHIND the label:

    Maybe this should be parsed differently?

    The bar: .if upcode(expression) is equal to.elesif upcode(expression).

    bar: is low-level and .if is high-level, emulating the function:

     if (expression) {
    } elseif (expression) {
    } else {
    }
    

    A highlevel expression includes upcode like:

     if ((fp = fopen(…)) != NULL) {
    

    If upcode is allowed, as it is in the .elesif upcode(expression), then this is a bug.
    We then have this situation:

    upcode1
    bar: .if upcode(expression)
    upcode2
    .elseif (expression)
    .endif
    

    The upcode is expanded correctly so it is very close.

     
  • japheth

    japheth - 2012-09-22

    > Maybe this should be parsed differently?

    I don't think this is an option. The expansion part should match Masm's behavior. A deviation must have very good reasons.

     
  • Hjort Nidudsson

    Hjort Nidudsson - 2012-09-22

    > I don't think this is an option. The expansion part should match Masm's behavior.
    > A deviation must have very good reasons.

    The main argument is this: Masm’s behaviour is wrong.

    The opportunity is this:

    .if func(…)
    .elseif func(…)
    .endif
    

    The bar: .if func() is a miner issue, but it should generate a warning, same as using eax in invoke combined with a local address.

    The same thing goes for the .elseif func(), since this generates a bug, which is difficult to trace if you’re not familiar with the syntax.

    The only place you could expand code here is above the .if statement, so .while func() will not work, but it compile with no problems..

    Maybe the high level syntax was created first, and the possibility to expand code later, like the exitm <eax>.

    You don’t have to change the expansion part, or create a deviation from Masm’s behaviour, but you should be aware of the places where expansion of code is impossible.

    It was my thinking then that this awareness creates an opportunity :-)

    The options is then:
    - Expand the code and just pretend it’s snowing.
    - Generate an error/warning
    - Expand the code below the label, above (expression)

     
  • japheth

    japheth - 2012-09-23

    > - Generate an error/warning

    That's not feasible because there ARE macro functions that WILL WORK in a .ELSEIF, .WHILE or .UNTIL expressions. It's just that macro functions that generate code lines won't work - and to properly filter these case requires a few hacks.

    > - Expand the code below the label, above (expression)

    This would also require very ugly hacks. It's a Masm design bug. IMO the best "solution" is not to use macro functions in hll directives. The hll directives can always be replaced by simple code lines. A workaround may be to replace .ELSEIF by .ELSE and .IF.

     
  • Hjort Nidudsson

    Hjort Nidudsson - 2012-09-23

    > This would also require very ugly hacks.
    Yes, some real code is required to fix this hack, but it may be feasible.

    > It's just that macro functions that generate code lines won't work
    It is only these situations that create an opportunity, and the filter should be applied here.

    The lll: .hll(..) - in one line – only create problems, so these combinations should not be allowed:

    @@: .if
    @@: .elseif
    @@: .repeat
    @@: .until
    @@: .while

    Then

    .if
    works and expand code correctly

    .break .if
    works

    .continue .if
    works

    .elseif
    needs a minor label-fixup

    .until
    should work in theory, but .continue will probably bypass the expanded code.

    .while
    need some work, code must be expanded below
    before this happens
    .while func(findfirst)
    push eax
    invoke findnext
    .endw

    The main work will be the filter, and then some minor fixup on the expanded code.

    So, it requires some work, but it looks possible.

     
  • Hjort Nidudsson

    Hjort Nidudsson - 2012-09-26

    I had a brief look at the expansion of code done in expans.c.

    Here is some of the label:

     issues. The bold lines fail.
    [b]l0: dec func(foo)
    l1: mov edx,func(foo)[/b]
    l2: .if eax || edx
    l3: inc eax
    [b]l4: .elseif func(foo)[/b]
    l5: dec eax
    l6: .endif
    [b]l7: .while func(foo)
    l8: .continue[/b]
    l9: .break
    lA: .endw
    lB: .repeat
    [b]lC: .continue[/b]
    lD: .break
    lF: .until func(foo)
    l2 is one exception here, and I assume the label is pushed before code creation.
    The ones that fail include code expansion.
    The exception in this case is (token == label && token->next == directiv && ...)
    A general rule on a higher level could be this:
    if (token == label && next token is on the same line) PushLabel()
     ...
     PushMacro()
    I don't know how to do this, but I created a function to test the output.
    This was inserted in the function ExpandLine(..)
    [code]
        i = (tokenarray[1].token == T_COLON || tokenarray[1].token == T_DBL_COLON);
        if (Token_Count > 2 && i) {
        char *p,b[MAX_LINE_LEN];
        strcpy(b, tokenarray[0].string_ptr);
        strcat(b, tokenarray[1].string_ptr);
        p = string + strlen(b);
        *p++ = 0;
        while (*p == ' ') p++;
        AddLineQueue(p);
        AddTokens(tokenarray, 0, 2-Token_Count);
        return( STRING_EXPANDED );
        }
    [/code]
    Result:
    [code]
    00000001            l0:
    00000001             1  invoke foo
    00000001  E8FAFFFFFF        *1   call foo
    00000006  48            dec eax
    00000007            l1:
    00000007             1  invoke foo
    00000007  E8F4FFFFFF        *1   call foo
    0000000C  8BD0          mov edx,eax
    0000000E            l2:
    0000000E            .if eax || edx
    0000000E  23C0          *   and eax , eax
    00000010  7504          *   jnz @C0002
    00000012            *   @C0003:
    00000012  23D2          *   and edx, edx
    00000014  7408          *   jz  @C0001
    00000016            *   @C0002:
    00000016            l3:
    00000016  40            inc eax
    00000017            l4:
    00000017             1  invoke foo
    00000017  E8E4FFFFFF        *1   call foo
    0000001C            .elseif eax
    0000001C  EB05          *    jmp @C0004
    0000001E            *   @C0001:
    0000001E  23C0          *   and eax, eax
    00000020  7401          *   jz  @C0005
    00000022            l5:
    00000022  48            dec eax
    00000023            l6:
    00000023            .endif
    00000023            *   @C0005:
    00000023            *   @C0004:
    00000023            l7:
    00000023             1  invoke foo
    00000023  E8D8FFFFFF        *1   call foo
    00000028            .while eax
    00000028  EB04          *    jmp @C0006
    0000002A            *   @C0007:
    0000002A            l8:
    0000002A            .continue
    0000002A  EB02          *    jmp @C0006
    0000002C            l9:
    0000002C            .break
    0000002C  EB04          *    jmp @C0008
    0000002E            lA:
    0000002E            .endw
    0000002E            *   @C0006:
    0000002E  23C0          *   and eax, eax
    00000030  75F8          *   jnz @C0007
    00000032            *   @C0008:
    00000032            lB:
    00000032            .repeat
    00000032            *   @C000A:
    00000032            lC:
    00000032            .continue
    00000032  EB07          *    jmp @C0009
    00000034            lD:
    00000034            .break
    00000034  EB09          *    jmp @C000B
    00000036            lF:
    00000036             1  invoke foo
    00000036  E8C5FFFFFF        *1   call foo
    0000003B            .until eax
    0000003B            *   @C0009:
    0000003B  23C0          *   and eax, eax
    0000003D  74F3          *   jz  @C000A
    0000003F            *   @C000B:
    [/code]
    
     
  • japheth

    japheth - 2012-09-27

    Looks like you're using an old version of jwasm, because since v2.08, ExpandLine() won't return STRING_EXPANDED anymore.

    A proper solution will require that .ELSEIF, .WHILE and .UNTIL directives be split in a somewhat "pre-expansion" and a "post-expansion" part.  "pre-expansion" is kinda "somewhat", because it can't be called before any expansion, but must be called from inside expansion ( because a possible label in the very same line might require expansion ).

    These requirements make the adjustments ultra-ugly. Surely nothing that is to happen for v2.09.

     
  • Hjort Nidudsson

    Hjort Nidudsson - 2012-09-27

    > Looks like you're using an old version of jwasm, because since v2.08, ExpandLine() won't return STRING_EXPANDED anymore.
    I tried the v2.08, but none of my project will compile past the first file (se post below).

    > A proper solution will require that .ELSEIF, .WHILE and .UNTIL directives be split in a somewhat "pre-expansion" and a "post-expansion" part.
    I think the label: macro(..) issue must be fixed first by a PushLabel() function of some kind.

    > "pre-expansion" is kinda "somewhat", because it can't be called before any expansion, but must be called from inside expansion ( because a possible label in the very same line might require expansion ).
    The label is now removed: expand away.

    > These requirements make the adjustments ultra-ugly. Surely nothing that is to happen for v2.09.
    If you willing to do anything with this, the first release should at most contain a warning message. If the messages pop up correctly the next step should be an actual fix.

    The first fix should be:
    label: macro()
    label: dec macro()
    label: mov edx,macro()

    The knowledge you gain from solving this problem could then be applied to the hll section (same issue).

    With regards to the inserted function, this only serves as to show what happen if the label-issue is removed.

     

Log in to post a comment.