NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: Klod 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
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
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
-
Use %imacro instead of %macro.
-
This code compiles without errors but program crashes
Should display a warning about an orphan label though.
-
Quote from Bryant Keller
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 from cm Posted on: November 29, 2010
Should display a warning about an orphan label though
Could not agree more. Since The preprocessor is still being revamped... even small details...
-
Quote from Bryant Keller
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 from cm Posted on: November 29, 2010
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"?
-
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
-
Quote from Bryant Keller
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.
-
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.
-
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
Example:
mov eax,1
jmp example
error: symbol `example' undefined ? as I expected
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
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
%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
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:
%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 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.
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.
%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]
-
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
Right. So the manual contains examples that may make it more difficult to find actual errors.
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.
or something like this
%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:
label:
jmp label
jmp LABEL ; error because LABEL is not defined
%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).
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:
%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.
I believe the answer may be in this statement:
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.
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.
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.
%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.
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:
%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