How to Print a Character in Linux X86 Nasm

How to print a character in Linux x86 NASM?

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.

Can't get single character to print in Linux NASM

This line is incorrect:

mov    ecx, ebx  ; move ebx to print

write (int 80h / eax=4) expects ecx to contain the address of the data to write (see this table). But you're passing the data itself.

In your modified code you're placing the character on the stack and then passing its address in ecx, so that's correct.
However, you've already incremented ecx by the time you get to .printchar. That's why your code doesn't print the first character.

As a side note, your check for even/odd numbers is unncessarily complicated. It could be simplified to just:

test ecx,1      ; set EFLAGS based on ecx AND 1
jnz .printchar

NASM Print one Character at a Time

One of the reasons it's not printing is because ebx is supposed to hold the value 1 to specify stdin, and another is because sys_write takes a pointer (the address of your string) as an argument, not an actual character value.

Anyway, let me show you a simpler way of structuring your program:

section .data

SYS_EXIT equ 1
SYS_WRITE equ 4
STDOUT equ 1
TRAP equ 0x80
NUL equ 0

hello: db "Hello World",0xA,NUL ; 0xA is linefeed, terminate with NUL

section .text
global _start

_start:
nop ; for good old gdb
mov ecx, hello ; ecx is the char* to be passed to sys_write

read:
cmp byte[ecx], NUL ; NUL indicates the end of the string
je exit ; if reached the NUL terminator, exit

; setup the registers for a sys_write call
mov eax, SYS_WRITE ; syscall number for sys_write
mov ebx, STDOUT ; print to stdout
mov edx, 1 ; write 1 char at a time
int TRAP; ; execute the syscall

inc ecx ; increment the pointer to the next char
jmp read ; loop back to read

exit:
mov eax, SYS_EXIT ; load the syscall number for sys_exit
mov ebx, 0 ; return a code of 0
int TRAP ; execute the syscall

It can be simpler to NUL terminate your string as I did, or you could also do $-hello to get it's length at compile time. I also set the registers up for sys_write at each iteration in the loop (as you do), since sys_write doesn't preserve all the registers.

How to print a string to the terminal in x86-64 assembly (NASM) without syscall?

This is a good exercise. You will use syscall (you cannot access stdout otherwise), but you can do a "bare-metal" write without any external library providing the output routine (like calling printf). As an example of the basic "bare-metal" write to stdout in x86_64, I put together a example without any internal or system function calls:

section .data
string1 db 0xa, " Hello StackOverflow!!!", 0xa, 0xa, 0

section .text
global _start

_start:
; calculate the length of string
mov rdi, string1 ; string1 to destination index
xor rcx, rcx ; zero rcx
not rcx ; set rcx = -1
xor al,al ; zero the al register (initialize to NUL)
cld ; clear the direction flag
repnz scasb ; get the string length (dec rcx through NUL)
not rcx ; rev all bits of negative results in absolute value
dec rcx ; -1 to skip the null-terminator, rcx contains length
mov rdx, rcx ; put length in rdx
; write string to stdout
mov rsi, string1 ; string1 to source index
mov rax, 1 ; set write to command
mov rdi,rax ; set destination index to rax (stdout)
syscall ; call kernel

; exit
xor rdi,rdi ; zero rdi (rdi hold return value)
mov rax, 0x3c ; set syscall number to 60 (0x3c hex)
syscall ; call kernel

; Compile/Link
;
; nasm -f elf64 -o hello-stack_64.o hello-stack_64.asm
; ld -o hello-stack_64 hello-stack_64.o

output:

$ ./hello-stack_64

Hello StackOverflow!!!

For general use, I split the process into two parts (1) getting the length and (2) writing to stdout. Below the strprn function will write any string to stdout. It calls strsz to get the length while preserving the destination index on the stack. This reduces the task of writing a string to stdout and prevents a lot of repitition in your code.

; szstr computes the lenght of a string.
; rdi - string address
; rdx - contains string length (returned)
section .text
strsz:
xor rcx, rcx ; zero rcx
not rcx ; set rcx = -1 (uses bitwise id: ~x = -x-1)
xor al,al ; zero the al register (initialize to NUL)
cld ; clear the direction flag
repnz scasb ; get the string length (dec rcx through NUL)
not rcx ; rev all bits of negative -> absolute value
dec rcx ; -1 to skip the null-term, rcx contains length
mov rdx, rcx ; size returned in rdx, ready to call write
ret

; strprn writes a string to the file descriptor.
; rdi - string address
; rdx - contains string length
section .text
strprn:
push rdi ; push string address onto stack
call strsz ; call strsz to get length
pop rsi ; pop string to rsi (source index)
mov rax, 0x1 ; put write/stdout number in rax (both 1)
mov rdi, rax ; set destination index to rax (stdout)
syscall ; call kernel
ret

To further automate general output to stdout NASM macros provide a convenient solution. Example strn (short for string_n). It takes two arguments, the addresses of the string, and the number of characters to write:

%macro  strn    2
mov rax, 1
mov rdi, 1
mov rsi, %1
mov rdx, %2
syscall
%endmacro

Useful for indents, newlines or writing complete strings. You could generalize further by passing 3 arguments including the destination for rdi.

How to print a number in assembly NASM?

If you're already on Linux, there's no need to do the conversion yourself. Just use printf instead:

;
; assemble and link with:
; nasm -f elf printf-test.asm && gcc -m32 -o printf-test printf-test.o
;
section .text
global main
extern printf

main:

mov eax, 0xDEADBEEF
push eax
push message
call printf
add esp, 8
ret

message db "Register = %08X", 10, 0

Note that printf uses the cdecl calling convention so we need to restore the stack pointer afterwards, i.e. add 4 bytes per parameter passed to the function.

linux nasm print multiple characters

In the first time you enter the Print section, ecx is pointing to the start of the string and you use it to copy a single character to the start of the output string. But a few more instructions down, you overwrite ecx with the pointer to the output string, and never restore it, therefore you never manage to copy and print the rest of the string.

Also, why are you calling write() with a single character string with the aim to loop over it to print the entire string? Why not just pass num directly in instead of copying a single character to output and passing that?

Printing a character to standard output in Assembly x86

Sure, you can use any normal C function. Here's a NASM example that uses printf to print some output:

;
; assemble and link with:
; nasm -f elf test.asm && gcc -m32 -o test test.o
;
section .text

extern printf ; If you need other functions, list them in a similar way

global main

main:

mov eax, 0x21 ; The '!' character
push eax
push message
call printf
add esp, 8 ; Restore stack - 4 bytes for eax, and 4 bytes for 'message'
ret

message db 'The character is: %c', 10, 0

If you only want to print a single character, you could use putchar:

push eax
call putchar

If you want to print out a number, you could do it like this:

mov ebx, 8
push ebx
push message
call printf
...
message db 'The number is: %d', 10, 0

linux nasm assembly endlessly printing character

This is digging waaaay back into the deep dark recesses of my memory, but I think you want

mov eax, [other]      ; move other to eax
mov ebx, [data] ; move data to ebx

Note the brackets, which are missing in your code. You are loading the addresses of other and data into eax and ebx, not the values contained there.

x86 nasm assembly, how to print multiplication result correctly?

The AAM instruction could be useful for cases where the result would have at most 2 digits. In your case 12 x 12 = 144, so that's a no-go.

The conversion loop that you use is almost correct, but you are mixing sizes in relation to the DIV instruction. If you give a byte-sized operand to DIV then the operation will divide AX by that byte and the remainder will be in AH. If you give a word-sized operand to DIV then the operation will divide DX:AX by that word and the remainder will be in DX.

Because you're writing 32-bit code, better also write the conversion using 32-bit registers.

Instead of using a digits counter, use a sentinel on the stack. No need to preserve ECX while displaying.

The display function expects a pointer in ECX. Just use the stackpointer for this and pop the value post-printing.

    mov   al, 12
mov bl, 12
mul bl ; answer in AX
movzx eax, ax

mov ebx, 10 ; Divisor constant
push ebx ; Sentinel
.a: xor edx, edx
div ebx ; Divide EDX:EAX with EBX, quotient EAX, remainder EDX
add edx, '0' ; Add '0' to make it into character
push edx
test eax, eax ; If EAX (the quotient) is not zero, loop again.
jnz .a

.b: mov eax, 4
mov ebx, 1
mov ecx, esp
mov edx, 1
int 0x80
pop eax
cmp dword [esp], 10 ; Is it the sentinel ?
jne .b ; No, it's a digit
pop eax ; Remove sentinel

Although not 32-code, Displaying numbers with DOS has more info about converting numbers into text.



Related Topics



Leave a reply



Submit