Author Topic: Preprocessor testing (case sensitive not enforced)  (Read 15983 times)

Klod

  • Guest
Preprocessor testing (case sensitive not enforced)
« on: November 28, 2010, 04:25:51 AM »
Consider the following example:

;Windows XP service pack 2
;\nasm\bin\NASM -f win32
;\nasm\bin\golink  @\nasm\bin\GFL.txt  /console /entry Start
Code: [Select]
2.10rc2-20101123
%macro ccall 1-*                       
%define _fname %1
%assign _params %0-1
%rep %0-1
    %rotate -1
    %ifstr %1
    pushstring  %1
    %else
    push %1
    %endif
%endrep
EXTERN _fname
    call _fname
    %assign _params _params * 4
    add esp, _params
%endmacro

%macro pushstring 1
[SECTION .rdata]
        %%str  db %1,0  ;cr lf
__SECT__
        push dword %%str
%endm

%macro PROC 1-9
%push PROC
GLOBAL %1
%1:
%assign %$params 0
push ebp
mov ebp,esp
%assign %$i 8
%rep %0-1
%rotate 1
%xdefine @%1 ebp+%$i
%assign %$i %$i+4
%assign %$params %$params+1
%endrep
%endmacro


%macro ENDP 0-1
.@End_of_Proc:
%ifctx PROC
mov esp,ebp
pop ebp
%assign %$params %$params*4
ret %$params
%pop
%endif

%endmacro



[Section .data]
NewLine db 10,13,0


[Section .text]
Start:
ccall printf,'%s',NewLine
call first
call second
ccall scanf
ccall ExitProcess,0 ;forgive me its the last call

PROC first
ccall printf,'string1: %s %s','the first string',NewLine
ENDp ;<---- wrong case

PROC second
ccall printf,'string2: %s %s','the first string',NewLine
ENDP

This code compiles without errors but program crashes
Quote
0040102E  /$ 55             PUSH EBP
0040102F  |. 89E5           MOV EBP,ESP
00401031  |. 68 00204000    PUSH CaseSens.00402000                   
00401036  |. 68 03304000    PUSH CaseSens.00403003                   
0040103B  |. 68 14304000    PUSH CaseSens.00403014                   
00401040  |. E8 C12F0000    CALL <JMP.&CRTDLL.printf>               
00401045  |. 83C4 0C        ADD ESP,0C                  ;<--- ret instruction missing
00401048  |$ 55             PUSH EBP                                                ;begin of proc second
00401049  |. 89E5           MOV EBP,ESP
0040104B  |. 68 00204000    PUSH CaseSens.00402000                 
00401050  |. 68 23304000    PUSH CaseSens.00403023                 
00401055  |. 68 34304000    PUSH CaseSens.00403034                   
0040105A  |. E8 A72F0000    CALL <JMP.&CRTDLL.printf>               
0040105F  |. 83C4 0C        ADD ESP,0C
00401062  |. 89EC           MOV ESP,EBP
00401064  |. 5D             POP EBP
00401065  \. C2 0000        RETN 0

Change ENDp to ENDP and all is well

Regards,
Klod

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Preprocessor testing (case sensitive not enforced)
« Reply #1 on: November 29, 2010, 12:49:12 AM »
Use %imacro instead of %macro.

About Bryant Keller
bkeller@about.me

Offline cm

  • Jr. Member
  • *
  • Posts: 65
Re: Preprocessor testing (case sensitive not enforced)
« Reply #2 on: November 29, 2010, 12:57:45 PM »
This code compiles without errors but program crashes

Should display a warning about an orphan label though.
C. Masloch

Klod

  • Guest
Re: Preprocessor testing (case sensitive not enforced)
« Reply #3 on: November 30, 2010, 04:00:12 AM »
Quote
Quote from Bryant Keller
Quote
Use %imacro instead of %macro.

I new that would work, but I tend to do things like ADDR and addr to access data section vrs stack. This looks intuitive to me, since both instructions basically have the same purpose except its done differently, so %imacro would not work.
Since The preprocessor is still being revamped... even small details...

Quote
Quote from cm Posted on: November 29, 2010
Quote
Should display a warning about an orphan label though

Could not agree more. Since The preprocessor is still being revamped... even small details...



Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: Preprocessor testing (case sensitive not enforced)
« Reply #4 on: November 30, 2010, 09:33:24 PM »
Quote
Quote from Bryant Keller
Quote
Use %imacro instead of %macro.

I new that would work, but I tend to do things like ADDR and addr to access data section vrs stack. This looks intuitive to me, since both instructions basically have the same purpose except its done differently, so %imacro would not work.
Since The preprocessor is still being revamped... even small details...

Quote
Quote from cm Posted on: November 29, 2010
Quote
Should display a warning about an orphan label though

Could not agree more. Since The preprocessor is still being revamped... even small details...


Didn't it yields the "warning: label alone on a line without a colon might be in error"?

Klod

  • Guest
Re: Preprocessor testing (case sensitive not enforced)
« Reply #5 on: December 01, 2010, 04:16:42 AM »
Quote
from Cyrill Gorcunov
Didn't it yields the "warning: label alone on a line without a colon might be in error"?

Yes
CaseSensitive.asm:71: warning: label alone on a line without a colon might be in error

So does this
.loop
        ; some more code

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Preprocessor testing (case sensitive not enforced)
« Reply #6 on: December 01, 2010, 01:31:06 PM »
Quote
Quote from Bryant Keller
Quote
Use %imacro instead of %macro.

I new that would work, but I tend to do things like ADDR and addr to access data section vrs stack. This looks intuitive to me, since both instructions basically have the same purpose except its done differently, so %imacro would not work.
Since The preprocessor is still being revamped... even small details...

I think you missed my point, or maybe I've missed yours. Using %imacro for making PROC/ENDP macros won't affect your ADDR/addr macros/defines. It simply makes those specific macros created with the %imacro variant case insensitive.

About Bryant Keller
bkeller@about.me

Offline cm

  • Jr. Member
  • *
  • Posts: 65
Re: Preprocessor testing (case sensitive not enforced)
« Reply #7 on: December 01, 2010, 04:37:04 PM »
Yes
CaseSensitive.asm:71: warning: label alone on a line without a colon might be in error

So does this
.loop
        ; some more code


You're supposed to use a colon, that's why. The warning is intended to let you catch cases like with your mismatched macro invocation.
C. Masloch

Klod

  • Guest
Re: Preprocessor testing (case sensitive not enforced)
« Reply #8 on: December 05, 2010, 03:30:07 AM »
Quote
2.2.1 NASM Is Case-Sensitive
One simple difference is that NASM is case-sensitive. It makes a difference whether you call your label foo, Foo or FOO

Code: [Select]
Example:
mov eax,1
jmp example
error: symbol `example' undefined   ?  as I expected

Quote
3.9 Local Labels
NASM gives special treatment to symbols beginning with a period. A label beginning with a single period is treated as a local label, which means that it is associated with the previous non-local label. So, for example:
label1  ; some code    
.loop    
        ; some more code

        jne     .loop
        ret

label2  ; some code
.loop    
        ; some more code

        jne     .loop
        ret
In the above code fragment, each JNE instruction jumps to the line immediately before it, because the two definitions of .loop are kept separate by virtue of each being associated with the previous non-local label...

No mention of  the use of a :(colon) nor that each label will produce warning: label alone on a line without a colon might be in error

Quote
4.3 Multi-Line Macros: %macro
….
Multi-line macros, like single-line macros, are case-sensitive, unless you define them using the alternative directive %imacro.

My Deduction: If Multi-line macros and   single-line macros are defined with %macro directive they are case sensitive!
Therefore ENDP is not equal to ENDp and should give  error: symbol `ENDp' undefined

or something like this
Code: [Select]
%define label LABEL:
label
mov eax,1
jmp LABEL
;jmp label <--  error: invalid combination of opcode and operands
[code/]

throws an error when jmp label

[code]
%macro defint 0
[section .data]
db 10
%endm

defInt should not produce warning: label alone on a line without a colon might be in error. Nasm should be able to distinguish between labels and macros and should be treated as Symbol not defined if otherwise

Quote
4.3.1 Overloading Multi-Line Macros
As with single-line macros, multi-line macros can be overloaded by defining the same macro name several times with different numbers of parameters. This time, no exception is made for macros with no parameters at all. So you could define:

Code: [Select]
%imacro End 1
;some code
%endm

%imacro END 1
;some code
%endm

and invoked
ENd 1
EnD 2
eND 3

compiles without error or warning
I do not know if this is a bug or not but it sure looks like a testicle fracture to me!

I believe the answer may be in this statement:
Quote
Quote from the docs: NASM is very simple by comparison: everything is a label.

Therefore:
label1 ;could be a label could be a macro invocation with 0 parameters? We don't know so we throw a error and treat it as an orphan label. Shouldn't an orphan have had parents at some point?

If Label: or .label: would have to be defined like this then Enp in my original example could not possibly be an orphan label? And error: symbol `ENDp' undefined could be genereated without ambiguity.

Quote
I think you missed my point, or maybe I've missed yours. Using %imacro for making PROC/ENDP macros won't affect your ADDR/addr macros/defines. It simply makes those specific macros created with the %imacro variant case insensitive.

Code: [Select]
%idefine ADDR dword

%imacro addr 1
mov eax,ff
%endm

mov eax,addr val  ;<-- should give error: comma, colon or end of line expected
mov eax,ADDR val

This is a short and meaningless example that compiles without error and runs but both variants produce the same code (mov eax,dword val)

About a year ago I have made drastic changes to my macro system that are not backward compatible. I'm still in the tweaking stage and need to jump back and forth between implementations without modifying code or defines so the old proggies continue to work. Simple solution would be to have old macro version in lowercase and new version in upper case in the same file. And then using Proc for new procedures vers proc for old procedures.

Regards
Klod

[/code]

Offline cm

  • Jr. Member
  • *
  • Posts: 65
Re: Preprocessor testing (case sensitive not enforced)
« Reply #9 on: December 05, 2010, 07:24:21 PM »
Quote
3.9 Local Labels
NASM gives special treatment to symbols beginning with a period. A label beginning with a single period is treated as a local label, which means that it is associated with the previous non-local label. So, for example:

Code: [Select]
label1  ; some code
.loop
        ; some more code

        jne     .loop
        ret

label2  ; some code
.loop
        ; some more code

        jne     .loop
        ret

In the above code fragment, each JNE instruction jumps to the line immediately before it, because the two definitions of .loop are kept separate by virtue of each being associated with the previous non-local label...

No mention of  the use of a :(colon) nor that each label will produce warning: label alone on a line without a colon might be in error

Right. So the manual contains examples that may make it more difficult to find actual errors.

Quote
Quote
4.3 Multi-Line Macros: %macro
….
Multi-line macros, like single-line macros, are case-sensitive, unless you define them using the alternative directive %imacro.

My Deduction: If Multi-line macros and   single-line macros are defined with %macro directive they are case sensitive!
Therefore ENDP is not equal to ENDp and should give  error: symbol `ENDp' undefined

But it does display "warning: label alone on a line without a colon might be in error". "ENDp" (alone on a line) is not a usage of a symbol named "ENDp", it is the definition. (Multiple such lines (if in the same case) will cause an error for re-defining the label.) Arguably, NASM could provide an option to make such a label definition an error. But it should not display "symbol undefined" in that case.

Quote
or something like this
Code: [Select]
%define label LABEL:
label
mov eax,1
jmp LABEL
;jmp label <--  error: invalid combination of opcode and operands

throws an error when jmp label

The colon is only used for defining a label, not for referring to it. Therefore:

Code: [Select]
label:
jmp label
jmp LABEL   ; error because LABEL is not defined

Quote
Code: [Select]
%macro defint 0
[section .data]
db 10
%endm

defInt should not produce warning: label alone on a line without a colon might be in error. Nasm should be able to distinguish between labels and macros and should be treated as Symbol not defined if otherwise

No macro or label of the name "defInt" exists with that macro definition. Therefore, interpreting it as a label definition is right (if error-prone).

Quote
Quote
4.3.1 Overloading Multi-Line Macros
As with single-line macros, multi-line macros can be overloaded by defining the same macro name several times with different numbers of parameters. This time, no exception is made for macros with no parameters at all. So you could define:

Code: [Select]
%imacro End 1
;some code
%endm

%imacro END 1
;some code
%endm

and invoked
ENd 1
EnD 2
eND 3

compiles without error or warning
I do not know if this is a bug or not

Guess it should display the "re-defining macro" warning (it doesn't), but all of the invocations are correct. Note that you defined a case-insensitive macro (%imacro) therefore its name is matched case insensitively.

Quote
I believe the answer may be in this statement:
Quote
Quote from the docs: NASM is very simple by comparison: everything is a label.

No, I believe this statement refers to memory referencing operands. In that section of the manual NASM's semantics are compared to other assemblers; these other assemblers know several kinds of labels. This issue is not relevant here.

Quote
Therefore:
label1 ;could be a label could be a macro invocation with 0 parameters? We don't know so we throw a error and treat it as an orphan label.

Yes, except NASM only throws a warning for compatibility.

Quote
If Label: or .label: would have to be defined like this then Enp in my original example could not possibly be an orphan label? And error: symbol `ENDp' undefined could be genereated without ambiguity.

No, "orphan label" means a label where you missed the colon. Therefore, if the colon was enforced orphan labels would not exist. As I mentioned, the missing colon will only cause a warning for compatibility.

But if you define every real label with a colon, then you can treat every "orphan label" warning to indicate that you have to investigate that particular line, because either you missed the colon (if it is really intended to be a label) or you misspelled something else (an instruction, a macro invocation). Like in your "ENDp" example.

You are free to define labels without colons. But every such label will then display the "orphan label" warning (if that warning is enabled) which makes the warning a lot less useful. Therefore, I would advise you to use colons for defining labels.

Quote
Code: [Select]
%idefine ADDR dword

%imacro addr 1
mov eax,ff
%endm

mov eax,addr val  ;<-- should give error: comma, colon or end of line expected
mov eax,ADDR val

This is a short and meaningless example that compiles without error and runs but both variants produce the same code (mov eax,dword val)

In this case, the position of the "addr" and "ADDR" terms in your instruction indicate that it cannot be a multi-line macro (%macro) invocation. Therefore, the preprocessor treats it as a single-line macro (%define) Actually, it is sufficient to say that single-line macros (%define) are processed first in any given line. Therefore, your (case-insensitive) single-line macro was expanded. The multi-line macro is never expanded.

Quote
About a year ago I have made drastic changes to my macro system that are not backward compatible. I'm still in the tweaking stage and need to jump back and forth between implementations without modifying code or defines so the old proggies continue to work. Simple solution would be to have old macro version in lowercase and new version in upper case in the same file. And then using Proc for new procedures vers proc for old procedures.

If by "simple", you mean "failure-prone", yes that would be the simple solution. But the preprocessor does allow you to do that anyway:

Code: [Select]
%macro Proc 0+
%warning New version of the procedure macro.
%endm

%macro proc 0+
%warning Old version of the procedure macro.
%endm

proc
proc
Proc
C. Masloch