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