Search code examples
assemblyx86macrosbytenasm

Define inline bytes to register in NASM; put db string in .data and get a pointer to it all with one source line?


Is there any way of passing bytes this way?

mov ecx, byte ["mybytes",0xa,0]

instead of:

section .data
    mybytes db "mybytes",0xa,0

section .text
    global main

main:
    mov ecx, mybytes

Solution

  • Based on an example from the NASM manual, I have created a perfect macro:

    %macro print 1+
            [section .rodata]        ; switch sections without updating the macro
                    %%data db %1          ; expand all the macro args
                    %%dataLen equ $- %%data
                   ; db 0    ; optional 0 terminator outside the calculated length
                             ; only useful if you need an implicit-length C string 
            __?SECT?__               ; switch back to the user's  section
                    mov eax, 4
                    mov ebx, 1
                    mov ecx, %%data
                    mov edx, %%dataLen
                    int 0x80
    %endmacro
    

    and now i can simply print "string" and it works!

    The 1+ number of params allows it to be used like print "string", 0xa to include a newline.


    To just put a pointer in a register, you could write a macro like

    %macro string_ptr 2+
            [section .rodata]
                    %%data db %2
                   ; db 0    ; optional 0 terminator baked into the macro
            __?SECT?__
                    mov %1, %%data   ; or lea %1, [rel %%data]  for 64-bit
    %endmacro
    
    ; use like this:
      string_ptr  ecx, "hello", 0xa, "world", 0
      push ecx
      call puts
    

    A fancier macro might allow push %%data to avoid wasting instructions getting it into a register first, for 32-bit stack-arg calling conventions. Or a separate macro that pushes, instead of making one flexible but complex macro.