NASM - Macro local label as parameter to another macro Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern) Data science time! April 2019 and salary with experience The Ask Question Wizard is Live!How to get length of long strings in x86 assembly to print on assertionAssembly GUI programming for Mac OS XHow to get window proc parameters?NASM x86_64 having trouble writing command line arguments, returning -14 in raxunable to read from file when user provides filename (x86 assembly program using nasm)Tracing call stack in disassembled code(VC++) Runtime Check for Uninitialized Variables: How is the test Implemented?NASM on linux: Using sys_read adds extra line at the endHow to use labels in Nasm macrosAvoiding the JMP in the JMP CALL POP technique for shellcode NASM?Memory allocation and addressing in Assembly

How much damage would a cupful of neutron star matter do to the Earth?

Is there hard evidence that the grant peer review system performs significantly better than random?

Why datecode is SO IMPORTANT to chip manufacturers?

As a dual citizen, my US passport will expire one day after traveling to the US. Will this work?

Why is the change of basis formula counter-intuitive? [See details]

A `coordinate` command ignored

How does light 'choose' between wave and particle behaviour?

Is it possible for an event A to be independent from event B, but not the other way around?

GDP with Intermediate Production

What is the origin of 落第?

Can an iPhone 7 be made to function as a NFC Tag?

Tannaka duality for semisimple groups

How can I save and copy a screenhot at the same time?

What does Turing mean by this statement?

Can two people see the same photon?

Project Euler #1 in C++

Why are vacuum tubes still used in amateur radios?

Weaponising the Grasp-at-a-Distance spell

Monty Hall Problem-Probability Paradox

Was Kant an Intuitionist about mathematical objects?

Google .dev domain strangely redirects to https

Resize vertical bars (absolute-value symbols)

Trying to understand entropy as a novice in thermodynamics

Universal covering space of the real projective line?



NASM - Macro local label as parameter to another macro



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)
Data science time! April 2019 and salary with experience
The Ask Question Wizard is Live!How to get length of long strings in x86 assembly to print on assertionAssembly GUI programming for Mac OS XHow to get window proc parameters?NASM x86_64 having trouble writing command line arguments, returning -14 in raxunable to read from file when user provides filename (x86 assembly program using nasm)Tracing call stack in disassembled code(VC++) Runtime Check for Uninitialized Variables: How is the test Implemented?NASM on linux: Using sys_read adds extra line at the endHow to use labels in Nasm macrosAvoiding the JMP in the JMP CALL POP technique for shellcode NASM?Memory allocation and addressing in Assembly



.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








0















I am trying to use a macro (as shown in this tutorial) to print a string. The macro PRINT creates local labels to define the string content (str) and length (strlen), and then passes these as parameters to a second macro _syscall_write which makes the syscall.



However running the code fails and I get a Segmentation fault (core dumped) message.



I suspect the problem to be this particular lines, but I don't understand why.



mov rsi, %1 ; str
mov rdx, %2 ; strln


Here is the full code:



%macro PRINT 1

; Save state
push rax
push rdi
push rsi
push rdx

%%str db %1, 0 ; arg0 + null terminator
%%strln equ $ - %%str ; current position - string start

; Write
_syscall_write %%str, %%strln

; Restore state
pop rdx
pop rsi
pop rdi
pop rax

%endmacro

%macro _syscall_write 2
mov rax, 1
mov rdi, 1
mov rsi, %1 ; str
mov rdx, %2 ; strln
syscall
%endmacro


global _start


section .data

SYS_EXIT equ 60
EXIT_CODE equ 0


section .text

_start:

PRINT "Hello World!"


exit:

mov rax, SYS_EXIT
mov rdi, EXIT_CODE
syscall




Here is a disassembly of the object file (from a version with the push/pop commented out).



Looking at the expanded code I still cannot see what is wrong. The bytes 0x0..0xC look like gibberish but correspond to the ascii code of the characters in Hello World!. Before the syscall to sys_write, rax and rdi seem to receive the expected value of 0x1, rsi the value of 0x0 which points to the string start, and rdx the value of 0xd which is the string length (12 + 1)...



Disassembly of section .text:

0000000000000000 <_start>:
0: 48 rex.W
1: 65 gs
2: 6c ins BYTE PTR es:[rdi],dx
3: 6c ins BYTE PTR es:[rdi],dx
4: 6f outs dx,DWORD PTR ds:[rsi]
5: 20 57 6f and BYTE PTR [rdi+0x6f],dl
8: 72 6c jb 76 <SYS_EXIT+0x3a>
a: 64 21 00 and DWORD PTR fs:[rax],eax

d: b8 01 00 00 00 mov eax,0x1
12: bf 01 00 00 00 mov edi,0x1
17: 48 be 00 00 00 00 00 movabs rsi,0x0
1e: 00 00 00
21: ba 0d 00 00 00 mov edx,0xd
26: 0f 05 syscall

0000000000000028 <exit>:
28: b8 3c 00 00 00 mov eax,0x3c
2d: bf 00 00 00 00 mov edi,0x0
32: 0f 05 syscall









share|improve this question



















  • 1





    When troubleshooting macros always look at the expansions. When troubleshooting segfaults always use a debugger. One obvious problem is that you define your string in the code path so the cpu will try to execute it as instructions and that will likely fault. Use a different section, normally .data or .rodata for your string or at the very least make sure your code jumps around it.

    – Jester
    Mar 8 at 23:17












  • @Jester How can I view the macro expansion? Edit: just remembered objdump

    – Jet Blue
    Mar 8 at 23:26












  • Use GDB's disassembly view to single-step through instructions, not source lines. e.g. layout reg. See the bottom of stackoverflow.com/tags/x86/info for debugging tips.

    – Peter Cordes
    Mar 8 at 23:51











  • @PeterCordes Ah, though the expansion is what I expect it to be, 0x48 ('H') 0x65 ('e') etc. aren't valid instructions... The tutorial had a jump to the syscall before these local definitions, which I ignored but now I understand why it was there. Thanks!

    – Jet Blue
    Mar 9 at 0:19












  • Your machine code doesn't match your source. Your macro uses 4x push instructions before the db, but your objdump starts with the string data. Also, if you were trying to preserve all regs, you forgot RCX and R11 (clobbered by syscall itself.)

    – Peter Cordes
    Mar 9 at 0:23


















0















I am trying to use a macro (as shown in this tutorial) to print a string. The macro PRINT creates local labels to define the string content (str) and length (strlen), and then passes these as parameters to a second macro _syscall_write which makes the syscall.



However running the code fails and I get a Segmentation fault (core dumped) message.



I suspect the problem to be this particular lines, but I don't understand why.



mov rsi, %1 ; str
mov rdx, %2 ; strln


Here is the full code:



%macro PRINT 1

; Save state
push rax
push rdi
push rsi
push rdx

%%str db %1, 0 ; arg0 + null terminator
%%strln equ $ - %%str ; current position - string start

; Write
_syscall_write %%str, %%strln

; Restore state
pop rdx
pop rsi
pop rdi
pop rax

%endmacro

%macro _syscall_write 2
mov rax, 1
mov rdi, 1
mov rsi, %1 ; str
mov rdx, %2 ; strln
syscall
%endmacro


global _start


section .data

SYS_EXIT equ 60
EXIT_CODE equ 0


section .text

_start:

PRINT "Hello World!"


exit:

mov rax, SYS_EXIT
mov rdi, EXIT_CODE
syscall




Here is a disassembly of the object file (from a version with the push/pop commented out).



Looking at the expanded code I still cannot see what is wrong. The bytes 0x0..0xC look like gibberish but correspond to the ascii code of the characters in Hello World!. Before the syscall to sys_write, rax and rdi seem to receive the expected value of 0x1, rsi the value of 0x0 which points to the string start, and rdx the value of 0xd which is the string length (12 + 1)...



Disassembly of section .text:

0000000000000000 <_start>:
0: 48 rex.W
1: 65 gs
2: 6c ins BYTE PTR es:[rdi],dx
3: 6c ins BYTE PTR es:[rdi],dx
4: 6f outs dx,DWORD PTR ds:[rsi]
5: 20 57 6f and BYTE PTR [rdi+0x6f],dl
8: 72 6c jb 76 <SYS_EXIT+0x3a>
a: 64 21 00 and DWORD PTR fs:[rax],eax

d: b8 01 00 00 00 mov eax,0x1
12: bf 01 00 00 00 mov edi,0x1
17: 48 be 00 00 00 00 00 movabs rsi,0x0
1e: 00 00 00
21: ba 0d 00 00 00 mov edx,0xd
26: 0f 05 syscall

0000000000000028 <exit>:
28: b8 3c 00 00 00 mov eax,0x3c
2d: bf 00 00 00 00 mov edi,0x0
32: 0f 05 syscall









share|improve this question



















  • 1





    When troubleshooting macros always look at the expansions. When troubleshooting segfaults always use a debugger. One obvious problem is that you define your string in the code path so the cpu will try to execute it as instructions and that will likely fault. Use a different section, normally .data or .rodata for your string or at the very least make sure your code jumps around it.

    – Jester
    Mar 8 at 23:17












  • @Jester How can I view the macro expansion? Edit: just remembered objdump

    – Jet Blue
    Mar 8 at 23:26












  • Use GDB's disassembly view to single-step through instructions, not source lines. e.g. layout reg. See the bottom of stackoverflow.com/tags/x86/info for debugging tips.

    – Peter Cordes
    Mar 8 at 23:51











  • @PeterCordes Ah, though the expansion is what I expect it to be, 0x48 ('H') 0x65 ('e') etc. aren't valid instructions... The tutorial had a jump to the syscall before these local definitions, which I ignored but now I understand why it was there. Thanks!

    – Jet Blue
    Mar 9 at 0:19












  • Your machine code doesn't match your source. Your macro uses 4x push instructions before the db, but your objdump starts with the string data. Also, if you were trying to preserve all regs, you forgot RCX and R11 (clobbered by syscall itself.)

    – Peter Cordes
    Mar 9 at 0:23














0












0








0








I am trying to use a macro (as shown in this tutorial) to print a string. The macro PRINT creates local labels to define the string content (str) and length (strlen), and then passes these as parameters to a second macro _syscall_write which makes the syscall.



However running the code fails and I get a Segmentation fault (core dumped) message.



I suspect the problem to be this particular lines, but I don't understand why.



mov rsi, %1 ; str
mov rdx, %2 ; strln


Here is the full code:



%macro PRINT 1

; Save state
push rax
push rdi
push rsi
push rdx

%%str db %1, 0 ; arg0 + null terminator
%%strln equ $ - %%str ; current position - string start

; Write
_syscall_write %%str, %%strln

; Restore state
pop rdx
pop rsi
pop rdi
pop rax

%endmacro

%macro _syscall_write 2
mov rax, 1
mov rdi, 1
mov rsi, %1 ; str
mov rdx, %2 ; strln
syscall
%endmacro


global _start


section .data

SYS_EXIT equ 60
EXIT_CODE equ 0


section .text

_start:

PRINT "Hello World!"


exit:

mov rax, SYS_EXIT
mov rdi, EXIT_CODE
syscall




Here is a disassembly of the object file (from a version with the push/pop commented out).



Looking at the expanded code I still cannot see what is wrong. The bytes 0x0..0xC look like gibberish but correspond to the ascii code of the characters in Hello World!. Before the syscall to sys_write, rax and rdi seem to receive the expected value of 0x1, rsi the value of 0x0 which points to the string start, and rdx the value of 0xd which is the string length (12 + 1)...



Disassembly of section .text:

0000000000000000 <_start>:
0: 48 rex.W
1: 65 gs
2: 6c ins BYTE PTR es:[rdi],dx
3: 6c ins BYTE PTR es:[rdi],dx
4: 6f outs dx,DWORD PTR ds:[rsi]
5: 20 57 6f and BYTE PTR [rdi+0x6f],dl
8: 72 6c jb 76 <SYS_EXIT+0x3a>
a: 64 21 00 and DWORD PTR fs:[rax],eax

d: b8 01 00 00 00 mov eax,0x1
12: bf 01 00 00 00 mov edi,0x1
17: 48 be 00 00 00 00 00 movabs rsi,0x0
1e: 00 00 00
21: ba 0d 00 00 00 mov edx,0xd
26: 0f 05 syscall

0000000000000028 <exit>:
28: b8 3c 00 00 00 mov eax,0x3c
2d: bf 00 00 00 00 mov edi,0x0
32: 0f 05 syscall









share|improve this question
















I am trying to use a macro (as shown in this tutorial) to print a string. The macro PRINT creates local labels to define the string content (str) and length (strlen), and then passes these as parameters to a second macro _syscall_write which makes the syscall.



However running the code fails and I get a Segmentation fault (core dumped) message.



I suspect the problem to be this particular lines, but I don't understand why.



mov rsi, %1 ; str
mov rdx, %2 ; strln


Here is the full code:



%macro PRINT 1

; Save state
push rax
push rdi
push rsi
push rdx

%%str db %1, 0 ; arg0 + null terminator
%%strln equ $ - %%str ; current position - string start

; Write
_syscall_write %%str, %%strln

; Restore state
pop rdx
pop rsi
pop rdi
pop rax

%endmacro

%macro _syscall_write 2
mov rax, 1
mov rdi, 1
mov rsi, %1 ; str
mov rdx, %2 ; strln
syscall
%endmacro


global _start


section .data

SYS_EXIT equ 60
EXIT_CODE equ 0


section .text

_start:

PRINT "Hello World!"


exit:

mov rax, SYS_EXIT
mov rdi, EXIT_CODE
syscall




Here is a disassembly of the object file (from a version with the push/pop commented out).



Looking at the expanded code I still cannot see what is wrong. The bytes 0x0..0xC look like gibberish but correspond to the ascii code of the characters in Hello World!. Before the syscall to sys_write, rax and rdi seem to receive the expected value of 0x1, rsi the value of 0x0 which points to the string start, and rdx the value of 0xd which is the string length (12 + 1)...



Disassembly of section .text:

0000000000000000 <_start>:
0: 48 rex.W
1: 65 gs
2: 6c ins BYTE PTR es:[rdi],dx
3: 6c ins BYTE PTR es:[rdi],dx
4: 6f outs dx,DWORD PTR ds:[rsi]
5: 20 57 6f and BYTE PTR [rdi+0x6f],dl
8: 72 6c jb 76 <SYS_EXIT+0x3a>
a: 64 21 00 and DWORD PTR fs:[rax],eax

d: b8 01 00 00 00 mov eax,0x1
12: bf 01 00 00 00 mov edi,0x1
17: 48 be 00 00 00 00 00 movabs rsi,0x0
1e: 00 00 00
21: ba 0d 00 00 00 mov edx,0xd
26: 0f 05 syscall

0000000000000028 <exit>:
28: b8 3c 00 00 00 mov eax,0x3c
2d: bf 00 00 00 00 mov edi,0x0
32: 0f 05 syscall






assembly x86 macros x86-64 nasm






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 9 at 1:36









Peter Cordes

136k19208349




136k19208349










asked Mar 8 at 23:11









Jet BlueJet Blue

2,2271825




2,2271825







  • 1





    When troubleshooting macros always look at the expansions. When troubleshooting segfaults always use a debugger. One obvious problem is that you define your string in the code path so the cpu will try to execute it as instructions and that will likely fault. Use a different section, normally .data or .rodata for your string or at the very least make sure your code jumps around it.

    – Jester
    Mar 8 at 23:17












  • @Jester How can I view the macro expansion? Edit: just remembered objdump

    – Jet Blue
    Mar 8 at 23:26












  • Use GDB's disassembly view to single-step through instructions, not source lines. e.g. layout reg. See the bottom of stackoverflow.com/tags/x86/info for debugging tips.

    – Peter Cordes
    Mar 8 at 23:51











  • @PeterCordes Ah, though the expansion is what I expect it to be, 0x48 ('H') 0x65 ('e') etc. aren't valid instructions... The tutorial had a jump to the syscall before these local definitions, which I ignored but now I understand why it was there. Thanks!

    – Jet Blue
    Mar 9 at 0:19












  • Your machine code doesn't match your source. Your macro uses 4x push instructions before the db, but your objdump starts with the string data. Also, if you were trying to preserve all regs, you forgot RCX and R11 (clobbered by syscall itself.)

    – Peter Cordes
    Mar 9 at 0:23













  • 1





    When troubleshooting macros always look at the expansions. When troubleshooting segfaults always use a debugger. One obvious problem is that you define your string in the code path so the cpu will try to execute it as instructions and that will likely fault. Use a different section, normally .data or .rodata for your string or at the very least make sure your code jumps around it.

    – Jester
    Mar 8 at 23:17












  • @Jester How can I view the macro expansion? Edit: just remembered objdump

    – Jet Blue
    Mar 8 at 23:26












  • Use GDB's disassembly view to single-step through instructions, not source lines. e.g. layout reg. See the bottom of stackoverflow.com/tags/x86/info for debugging tips.

    – Peter Cordes
    Mar 8 at 23:51











  • @PeterCordes Ah, though the expansion is what I expect it to be, 0x48 ('H') 0x65 ('e') etc. aren't valid instructions... The tutorial had a jump to the syscall before these local definitions, which I ignored but now I understand why it was there. Thanks!

    – Jet Blue
    Mar 9 at 0:19












  • Your machine code doesn't match your source. Your macro uses 4x push instructions before the db, but your objdump starts with the string data. Also, if you were trying to preserve all regs, you forgot RCX and R11 (clobbered by syscall itself.)

    – Peter Cordes
    Mar 9 at 0:23








1




1





When troubleshooting macros always look at the expansions. When troubleshooting segfaults always use a debugger. One obvious problem is that you define your string in the code path so the cpu will try to execute it as instructions and that will likely fault. Use a different section, normally .data or .rodata for your string or at the very least make sure your code jumps around it.

– Jester
Mar 8 at 23:17






When troubleshooting macros always look at the expansions. When troubleshooting segfaults always use a debugger. One obvious problem is that you define your string in the code path so the cpu will try to execute it as instructions and that will likely fault. Use a different section, normally .data or .rodata for your string or at the very least make sure your code jumps around it.

– Jester
Mar 8 at 23:17














@Jester How can I view the macro expansion? Edit: just remembered objdump

– Jet Blue
Mar 8 at 23:26






@Jester How can I view the macro expansion? Edit: just remembered objdump

– Jet Blue
Mar 8 at 23:26














Use GDB's disassembly view to single-step through instructions, not source lines. e.g. layout reg. See the bottom of stackoverflow.com/tags/x86/info for debugging tips.

– Peter Cordes
Mar 8 at 23:51





Use GDB's disassembly view to single-step through instructions, not source lines. e.g. layout reg. See the bottom of stackoverflow.com/tags/x86/info for debugging tips.

– Peter Cordes
Mar 8 at 23:51













@PeterCordes Ah, though the expansion is what I expect it to be, 0x48 ('H') 0x65 ('e') etc. aren't valid instructions... The tutorial had a jump to the syscall before these local definitions, which I ignored but now I understand why it was there. Thanks!

– Jet Blue
Mar 9 at 0:19






@PeterCordes Ah, though the expansion is what I expect it to be, 0x48 ('H') 0x65 ('e') etc. aren't valid instructions... The tutorial had a jump to the syscall before these local definitions, which I ignored but now I understand why it was there. Thanks!

– Jet Blue
Mar 9 at 0:19














Your machine code doesn't match your source. Your macro uses 4x push instructions before the db, but your objdump starts with the string data. Also, if you were trying to preserve all regs, you forgot RCX and R11 (clobbered by syscall itself.)

– Peter Cordes
Mar 9 at 0:23






Your machine code doesn't match your source. Your macro uses 4x push instructions before the db, but your objdump starts with the string data. Also, if you were trying to preserve all regs, you forgot RCX and R11 (clobbered by syscall itself.)

– Peter Cordes
Mar 9 at 0:23













1 Answer
1






active

oldest

votes


















2














rex.W gs ins is a privileged instruction, and faults in user-space. This is the first instruction of your program, from the expansion of %%str db %1, 0 in your macro without changing sections.



Don't put data where it will be executed as instructions; use section .rodata for read-only data.



GAS would let you do .pushsection .rodata / .popsection to expand the macro correctly inside any section, but for NASM I'm not sure if we can do better than unconditionally switch to section .text after the data.



The NASM preprocessor has %push [optional context-name] / %pop to save/restore preprocessor context, e.g. for nested repeat-until preprocessor stuff. But that's only for the preprocessor, and doesn't include restoring the old section.



%macro PRINT 1
...
section .rodata
%%str db %1, 0 ; arg0 + null terminator
%%strln equ $ - %%str ; current position - string start
section .text
... rest of the macro


So after using the macro, you're unconditionally in the .text section, not in .text.cold, or whatever other custom section.




Also note that equ directives don't care what section they're in (unless they use $ in their definition). So strln needs to be in the same section as str, but SYS_EXIT has nothing to do with section .data. It's an assemble-time constant that turns into an immediate when you use it.




mov r64, imm64 is an inefficient way to put an absolute address in a register. It needs a load-time fixup in a PIE executable, and is longer than position-independent lea rsi, [rel %%str]. NASM assembles mov rsi, str into 10-byte mov r64, imm64, while YASM uses mov r/m64, sign_extended_imm32 (which doesn't even work in a PIE executable). https://nasm.us/doc/nasmdo11.html#section-11.2



You could maybe write a macro that uses %ifidn string-identical condition to check for rsi as the string arg, and in that case do nothing (the pointer is already in RSI), otherwise use lea rsi, [rel %%str]. That won't work for a pointer in memory, where mov rsi, [rbx] would have worked, though. Depends how fancy you want your macro to be. You could maybe %if a condition that looked for [ in the arg string and use mov instead of lea.




If you want to save/restore all the registers you clobber, remember that syscall itself clobbers RCX (saved RIP) and R11 (saved RFLAGS).



Normally you'd just document which registers a macro clobbers; those are all call-clobbered registers in x86-64 System V. But if you want a debug-print macro, you probably want it to save/restore everything? Except push/pop destroy the red-zone below RSP. I don't think I've ever used debug-prints in asm, just setting breakpoints with a debugger and hitting "continue" to see which breakpoint is hit next. Or just single-step and watch register values change, e.g. with GDB's layout reg.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55072277%2fnasm-macro-local-label-as-parameter-to-another-macro%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    rex.W gs ins is a privileged instruction, and faults in user-space. This is the first instruction of your program, from the expansion of %%str db %1, 0 in your macro without changing sections.



    Don't put data where it will be executed as instructions; use section .rodata for read-only data.



    GAS would let you do .pushsection .rodata / .popsection to expand the macro correctly inside any section, but for NASM I'm not sure if we can do better than unconditionally switch to section .text after the data.



    The NASM preprocessor has %push [optional context-name] / %pop to save/restore preprocessor context, e.g. for nested repeat-until preprocessor stuff. But that's only for the preprocessor, and doesn't include restoring the old section.



    %macro PRINT 1
    ...
    section .rodata
    %%str db %1, 0 ; arg0 + null terminator
    %%strln equ $ - %%str ; current position - string start
    section .text
    ... rest of the macro


    So after using the macro, you're unconditionally in the .text section, not in .text.cold, or whatever other custom section.




    Also note that equ directives don't care what section they're in (unless they use $ in their definition). So strln needs to be in the same section as str, but SYS_EXIT has nothing to do with section .data. It's an assemble-time constant that turns into an immediate when you use it.




    mov r64, imm64 is an inefficient way to put an absolute address in a register. It needs a load-time fixup in a PIE executable, and is longer than position-independent lea rsi, [rel %%str]. NASM assembles mov rsi, str into 10-byte mov r64, imm64, while YASM uses mov r/m64, sign_extended_imm32 (which doesn't even work in a PIE executable). https://nasm.us/doc/nasmdo11.html#section-11.2



    You could maybe write a macro that uses %ifidn string-identical condition to check for rsi as the string arg, and in that case do nothing (the pointer is already in RSI), otherwise use lea rsi, [rel %%str]. That won't work for a pointer in memory, where mov rsi, [rbx] would have worked, though. Depends how fancy you want your macro to be. You could maybe %if a condition that looked for [ in the arg string and use mov instead of lea.




    If you want to save/restore all the registers you clobber, remember that syscall itself clobbers RCX (saved RIP) and R11 (saved RFLAGS).



    Normally you'd just document which registers a macro clobbers; those are all call-clobbered registers in x86-64 System V. But if you want a debug-print macro, you probably want it to save/restore everything? Except push/pop destroy the red-zone below RSP. I don't think I've ever used debug-prints in asm, just setting breakpoints with a debugger and hitting "continue" to see which breakpoint is hit next. Or just single-step and watch register values change, e.g. with GDB's layout reg.






    share|improve this answer





























      2














      rex.W gs ins is a privileged instruction, and faults in user-space. This is the first instruction of your program, from the expansion of %%str db %1, 0 in your macro without changing sections.



      Don't put data where it will be executed as instructions; use section .rodata for read-only data.



      GAS would let you do .pushsection .rodata / .popsection to expand the macro correctly inside any section, but for NASM I'm not sure if we can do better than unconditionally switch to section .text after the data.



      The NASM preprocessor has %push [optional context-name] / %pop to save/restore preprocessor context, e.g. for nested repeat-until preprocessor stuff. But that's only for the preprocessor, and doesn't include restoring the old section.



      %macro PRINT 1
      ...
      section .rodata
      %%str db %1, 0 ; arg0 + null terminator
      %%strln equ $ - %%str ; current position - string start
      section .text
      ... rest of the macro


      So after using the macro, you're unconditionally in the .text section, not in .text.cold, or whatever other custom section.




      Also note that equ directives don't care what section they're in (unless they use $ in their definition). So strln needs to be in the same section as str, but SYS_EXIT has nothing to do with section .data. It's an assemble-time constant that turns into an immediate when you use it.




      mov r64, imm64 is an inefficient way to put an absolute address in a register. It needs a load-time fixup in a PIE executable, and is longer than position-independent lea rsi, [rel %%str]. NASM assembles mov rsi, str into 10-byte mov r64, imm64, while YASM uses mov r/m64, sign_extended_imm32 (which doesn't even work in a PIE executable). https://nasm.us/doc/nasmdo11.html#section-11.2



      You could maybe write a macro that uses %ifidn string-identical condition to check for rsi as the string arg, and in that case do nothing (the pointer is already in RSI), otherwise use lea rsi, [rel %%str]. That won't work for a pointer in memory, where mov rsi, [rbx] would have worked, though. Depends how fancy you want your macro to be. You could maybe %if a condition that looked for [ in the arg string and use mov instead of lea.




      If you want to save/restore all the registers you clobber, remember that syscall itself clobbers RCX (saved RIP) and R11 (saved RFLAGS).



      Normally you'd just document which registers a macro clobbers; those are all call-clobbered registers in x86-64 System V. But if you want a debug-print macro, you probably want it to save/restore everything? Except push/pop destroy the red-zone below RSP. I don't think I've ever used debug-prints in asm, just setting breakpoints with a debugger and hitting "continue" to see which breakpoint is hit next. Or just single-step and watch register values change, e.g. with GDB's layout reg.






      share|improve this answer



























        2












        2








        2







        rex.W gs ins is a privileged instruction, and faults in user-space. This is the first instruction of your program, from the expansion of %%str db %1, 0 in your macro without changing sections.



        Don't put data where it will be executed as instructions; use section .rodata for read-only data.



        GAS would let you do .pushsection .rodata / .popsection to expand the macro correctly inside any section, but for NASM I'm not sure if we can do better than unconditionally switch to section .text after the data.



        The NASM preprocessor has %push [optional context-name] / %pop to save/restore preprocessor context, e.g. for nested repeat-until preprocessor stuff. But that's only for the preprocessor, and doesn't include restoring the old section.



        %macro PRINT 1
        ...
        section .rodata
        %%str db %1, 0 ; arg0 + null terminator
        %%strln equ $ - %%str ; current position - string start
        section .text
        ... rest of the macro


        So after using the macro, you're unconditionally in the .text section, not in .text.cold, or whatever other custom section.




        Also note that equ directives don't care what section they're in (unless they use $ in their definition). So strln needs to be in the same section as str, but SYS_EXIT has nothing to do with section .data. It's an assemble-time constant that turns into an immediate when you use it.




        mov r64, imm64 is an inefficient way to put an absolute address in a register. It needs a load-time fixup in a PIE executable, and is longer than position-independent lea rsi, [rel %%str]. NASM assembles mov rsi, str into 10-byte mov r64, imm64, while YASM uses mov r/m64, sign_extended_imm32 (which doesn't even work in a PIE executable). https://nasm.us/doc/nasmdo11.html#section-11.2



        You could maybe write a macro that uses %ifidn string-identical condition to check for rsi as the string arg, and in that case do nothing (the pointer is already in RSI), otherwise use lea rsi, [rel %%str]. That won't work for a pointer in memory, where mov rsi, [rbx] would have worked, though. Depends how fancy you want your macro to be. You could maybe %if a condition that looked for [ in the arg string and use mov instead of lea.




        If you want to save/restore all the registers you clobber, remember that syscall itself clobbers RCX (saved RIP) and R11 (saved RFLAGS).



        Normally you'd just document which registers a macro clobbers; those are all call-clobbered registers in x86-64 System V. But if you want a debug-print macro, you probably want it to save/restore everything? Except push/pop destroy the red-zone below RSP. I don't think I've ever used debug-prints in asm, just setting breakpoints with a debugger and hitting "continue" to see which breakpoint is hit next. Or just single-step and watch register values change, e.g. with GDB's layout reg.






        share|improve this answer















        rex.W gs ins is a privileged instruction, and faults in user-space. This is the first instruction of your program, from the expansion of %%str db %1, 0 in your macro without changing sections.



        Don't put data where it will be executed as instructions; use section .rodata for read-only data.



        GAS would let you do .pushsection .rodata / .popsection to expand the macro correctly inside any section, but for NASM I'm not sure if we can do better than unconditionally switch to section .text after the data.



        The NASM preprocessor has %push [optional context-name] / %pop to save/restore preprocessor context, e.g. for nested repeat-until preprocessor stuff. But that's only for the preprocessor, and doesn't include restoring the old section.



        %macro PRINT 1
        ...
        section .rodata
        %%str db %1, 0 ; arg0 + null terminator
        %%strln equ $ - %%str ; current position - string start
        section .text
        ... rest of the macro


        So after using the macro, you're unconditionally in the .text section, not in .text.cold, or whatever other custom section.




        Also note that equ directives don't care what section they're in (unless they use $ in their definition). So strln needs to be in the same section as str, but SYS_EXIT has nothing to do with section .data. It's an assemble-time constant that turns into an immediate when you use it.




        mov r64, imm64 is an inefficient way to put an absolute address in a register. It needs a load-time fixup in a PIE executable, and is longer than position-independent lea rsi, [rel %%str]. NASM assembles mov rsi, str into 10-byte mov r64, imm64, while YASM uses mov r/m64, sign_extended_imm32 (which doesn't even work in a PIE executable). https://nasm.us/doc/nasmdo11.html#section-11.2



        You could maybe write a macro that uses %ifidn string-identical condition to check for rsi as the string arg, and in that case do nothing (the pointer is already in RSI), otherwise use lea rsi, [rel %%str]. That won't work for a pointer in memory, where mov rsi, [rbx] would have worked, though. Depends how fancy you want your macro to be. You could maybe %if a condition that looked for [ in the arg string and use mov instead of lea.




        If you want to save/restore all the registers you clobber, remember that syscall itself clobbers RCX (saved RIP) and R11 (saved RFLAGS).



        Normally you'd just document which registers a macro clobbers; those are all call-clobbered registers in x86-64 System V. But if you want a debug-print macro, you probably want it to save/restore everything? Except push/pop destroy the red-zone below RSP. I don't think I've ever used debug-prints in asm, just setting breakpoints with a debugger and hitting "continue" to see which breakpoint is hit next. Or just single-step and watch register values change, e.g. with GDB's layout reg.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Mar 9 at 1:35

























        answered Mar 9 at 0:18









        Peter CordesPeter Cordes

        136k19208349




        136k19208349





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55072277%2fnasm-macro-local-label-as-parameter-to-another-macro%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            1928 у кіно

            Захаров Федір Захарович

            Ель Греко