Author Topic: Extending nasm problem: find_label  (Read 20994 times)

Offline sapero

  • Jr. Member
  • *
  • Posts: 9
Extending nasm problem: find_label
« on: January 18, 2010, 01:25:58 PM »
Hello, I have extended nasm 2.07, to make if more comfortable for functions, variables, interfaces (win32), plus some other tools.
The main problem lies after extended %local directive:

Code:

%macro tt 1
%%x:
jmp %%x
%endm

%proc xx public stdcall param1:dword
    %local pt:RECT; rect is a struct: left,top,right,bottom
    mov dword [pt.left],7
    tt 6
%endproc

Offline sapero

  • Jr. Member
  • *
  • Posts: 9
Re: Extending nasm problem: find_label
« Reply #1 on: January 20, 2010, 12:36:23 PM »
I have solved this problem by changing the expansion for macro local labels (ctx->number) with a custom counter, set to zero in pp_reset() and increased in do_directive(PP_PUSH), where 'unique' is incremented.

Offline sapero

  • Jr. Member
  • *
  • Posts: 9
Re: Extending nasm problem: find_label
« Reply #2 on: January 25, 2010, 12:34:27 AM »
Unfortunatelly this problem still appears, so I have a question: what to call/set, to notify the assembler that size of code has changed, and it should add one more pass?

I have two macros called by my custom made %proc and %endprc directives. The code for %proc directive uses two passes:
Pass 1: collect the size of all local variables. This is done by code handler for build-in %local directive.
Pass 2-* can generate the proper epilogue, but:
Code: [Select]
%macro PROC32_MACRO_NAME 5-*
   %if use_ebp_frame
      %if not_naked
         ... push ebp/mov ebp,esp
         %if size_of_locals>0 ; <-- here
            sub esp, size_of_locals
         %endif
In the first pass, size_of_locals is zero, so %proc handler puts zero to PROC32_MACRO_NAME macro and "sub esp" is not generated.
While processing %local directives in first pass, size_of_locals is updated dynamically.
In the second, size_of_locals is already known, and will be not adjusted by %local directives. If size_of_locals is not zero, the size of code generated by PROC32_MACRO_NAME macro will change.

If size of code is changes, other macros (if, while) are losing local labels, and nasm quits with undefined symbol ..@ error.

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Extending nasm problem: find_label
« Reply #3 on: January 25, 2010, 06:08:45 PM »
Sapero,

I'm not 100% sure I understand exactly what your problem is. From what I've gathered (and unfortunately I'm on pain meds so I could be way off base here, lol) but I would suggest that you create a Sub-Context for each proc which manages only the number of passes. For example, create your context for the base %Proc/%EndProc then upon successfully completing your variable stuff at %Proc, push a new context and figure out the pass count, then push yet another context so that the user code can exist in it's own area. Finally, when the %EndProc is reached you can pop the context, store the number of passes in a global variable, pop again to reach your shutdown code which will use the number of passes to unwind everything then finally clear your global pass count variable when the procedure ends. The only reason I don't suggest using a global variable for storing the pass count initially is that some users might want to play with nested procedures. In this case you want the pass count to be stored in the context stack system. The use of a global variable at %EndProc is to allow you to "carry" the variable across the bounds of the context while the whole thing shuts down.

I hope I'm on target with what you are doing here, I am kind of out of it at the second and I'm sort of talking "tongue and cheak" (an expression meaning "off the top of my head" or "without any planning or correcting"). I would like to find out more about what your doing, maybe at a later time, as I played around with the standard macros system quite a bit to try and "embed" NASMX into the assembler itself. The reason I chose to use standard macros is because I wanted to add a build option to the compiler which enabled or disabled builds with the NASMX extensions. This actually never got off the ground because it slowed processing down quite a lot when using a NASMX extended build. I think your definitely going in a very positive direction with this and I'm anticipating the final product of your work will be very popular.


Regards,
Bryant Keller

About Bryant Keller
bkeller@about.me

Offline sapero

  • Jr. Member
  • *
  • Posts: 9
Re: Extending nasm problem: find_label
« Reply #4 on: January 25, 2010, 07:12:55 PM »
I have not explained all before. The handler for %proc directive initially was coded inside tokenize(). After processing it, the whole line was replaced with a macro call, so instead returning tokenized %proc ... it returned the line below, tokenized:
Code: [Select]
proc32 public, name, naked, sizeOfLocals, frameRegister{, registers}
But I have it now working. The handler for %proc directive (after adding the function to linked list) enters a loop, where the input file is read line by line, until %endproc, so in the first pass I have all the local variables in a linked list. When the loop quits, I do call fseek to restore file pointer, and return back to passive processing mode.

So, find_label was not the problem, but the size of code generated in first and second pass.
I'm going back to coding :) My next todo is to check in a macro, if a string parameter is utf32, utf16 or an ansi string (having small troubles in do_directive).

Offline sapero

  • Jr. Member
  • *
  • Posts: 9
Re: Extending nasm problem: find_label
« Reply #5 on: January 25, 2010, 11:17:50 PM »
.. Troubles, for example: I have a macro called _pushstring used by invoke macro. If an argument of invoke is an string, I call _pushstring, to allocate it in user defined section (.data, .rdata), and generate "push label" or "mov register,label" instructions (mov is used if the target function is fastcall or thiscall).

The main function:
Code: [Select]
%proc main public
invoke testproc, __utf16__("11"), __utf32__("22"), L"33", "44"
%endproc

This is a part of _pushstring macro which generates the label for a string:
Code: [Select]
%assign %$utf 8

%ifutf32 %1
%assign %$utf 32
%endif
%ifutf16 %1
%assign %$utf 16
%endif

%if %$utf=32
..@STR %+ __asm_str_index__ : dd %1, 0
%warning: ******* utf 32: %1
%elif %$utf=16
..@STR %+ __asm_str_index__ : dw %1, 0
%warning: ******* utf 16: %1
%else
..@STR %+ __asm_str_index__ : db %1, 0
%warning: ******* utf 8: %1
%endif
It is compiling nice:
Quote
warning: (_pushstring:51) : ******* utf 8: "44"
warning: (_pushstring:48) : ******* utf 16: __utf16__("33")
warning: (_pushstring:45) : ******* utf 32: __utf32__("22")
warning: (_pushstring:48) : ******* utf 16: __utf16__("11")

When I add %ifntoken to the preselector for %$utf variable, nasm is losing %if somewhere:
Code: [Select]
%ifntoken %1 ; not a single token
%ifutf32 %1
%assign %$utf 32
%endif
%ifutf16 %1
%assign %$utf 16
%endif
%endif
Quote
fatal: `%endif': no matching `%if'

Another (not an) error, more a bug, when using if+elif+else:
Code: [Select]
%ifutf32 %1
%assign %$utf 32
%elifutf16 %1
%assign %$utf 16
%else
%fatal : not utf 16, nor utf 32 ; <- this is active for __utf16__()
%endif
The log is:
Quote
warning: (_pushstring:50) : ******* utf 8: "44"
warning: (_pushstring:50) : ******* utf 8: __utf16__("33")   // ERROR
warning: (_pushstring:44) : ******* utf 32: __utf32__("22")
warning: (_pushstring:50) : ******* utf 8: __utf16__("11")   // ERROR
It looks like "%if false" denies anything until %endif, or different conditions (ifdef + eliftoken) are not supported. This is interesting, because the following in another macro is working well:
Code: [Select]
%iffastcall %$funcname
...
%elifthiscall %$funcname
...
%else
... ; code for stdcall or cdecl

Please note that all the custom IF-like (if* / ifn* / elif* / elifn*) directives are handled between "i=pp_token_hash()" and switch(i) in the do_directive subroutine. Each custom if* sets the 'i' variable to PP_IF, ifn* sets it to PP_IFN ... leaving single TOK_INTEGER in the list of parameters, so the switch() block sees "%IFUTF16" as "%IF integer".