How to print a character in Linux x86 NASM?
I'm trying to print a single character or a number using NASM, targeting an x86 GNU/Linux architecture.
Here's the code I'm using:
section .text
global _start
_start:
; Linux printing preparation
mov eax,4
mov ebx,1
; Print 'A' character
mov ecx,'A' ; ecx should contain the value to print
mov edx,1 ; edx should contain how many characters to print
int 80h
; System exit
mov eax,1
mov ebx,0
int 80h
Running this code, however, prints nothing. What am I doing wrong?
Solution 1:
ecx
should contain a pointer to the start of your char buffer. So you have to have your buffer in memory. You can do the following:
; Print 'A' character
mov eax, 4 ; __NR_write from asm/unistd_32.h (32-bit int 0x80 ABI)
mov ebx, 1 ; stdout fileno
push 'A'
mov ecx, esp ; esp now points to your char
mov edx, 1 ; edx should contain how many characters to print
int 80h ; sys_write(1, "A", 1)
; return value in EAX = 1 (byte written), or error (-errno)
add esp, 4 ; restore esp if necessary
You can mov byte [esp], 'A'
or whatever other address if it's OK to overwrite whatever is on the stack.
Or you can have a character array in section .rodata
instead of storing on the fly.
Making a write()
system call with the const void *buf
arg being some small number (like 'A'
) will make it return -EFAULT
without printing anything. The kernel has to check the pointer anyway, and system calls return an error instead of raising SIGSEGV on bad pointers.
Use strace ./my_program
to trace the system calls you actually made, including decoding the return values.
Solution 2:
The system call you are executing expects ecx
to contain an address in memory. This can be an arbitrary literal address (i.e. in your code, "A"
translates to the address 041h
), an address on the stack, or an address defined by a label in the program.
Here's an example of defining a byte in memory and writing it to the standard output stream of your terminal:
section .rodata ; This section contains read-only data
buffer: db 'A' ; Define our single character in memory
section .text
global start
_start:
; Prints the letter 'A', then exits
mov eax, 4 ; sys_write()
mov ebx, 1 ; ... to STDOUT
mov ecx, buffer ; ... using the following memory address
mov edx, 1 ; ... and only print one character
int 80h ; SYSCALL
mov eax, 1 ; Return to system
mov ebx, 0 ; Exit zero, success
int 80h ; SYSCALL