Search code examples
linuxassemblygdb64-bitnasm

x64 NASM Assembly print a single character returned from the function


I was writing a simple NASM x64 Assembly program that adds two single-digit numbers(4 and 5 respectively) and print it on the screen. However, I wanted to use a procedure call(function). So I designed the the program in C language first.

#include <stdio.h>

int sum(int x, int y) {

        int result = x + y;
        return result;

}

int main(void) {

        int x = 4;
        int y = 5;

        int result = sum(x, y);

        printf("The sum is: %d\n", result);

        return 0;

}

And I rewrote the program in NASM x64 Assembly program like below. The expected output from the program was The sum is: 9. However, I only could see the result except for the calculation result, just The sum is: .

; Nasm 2.15.05 (on Linux x64)

STDOUT  equ     0x01    ; for RDI (file descriptor)
WRITE   equ     0x01    ; for RAX (for syscall itself)

section .data
        message         db      "The sum is: "
        messageLength   equ     $ - message

section .text
        global _start

        _start:
                mov rax, WRITE
                mov rdi, STDOUT
                mov rsi, message
                mov rdx, messageLength
                syscall

                mov rdi, 0x4
                mov rsi, 0x5

                call _sum

                mov rcx, rax            ; The result of the _sum (stored in RAX register)
                mov rax, WRITE
                mov rdi, STDOUT
                mov rsi, rcx
                mov rdx, 0x01
                syscall

                ; exit
                mov rax, 0x3C
                mov rdi, 0x00
                syscall

        _sum:
                mov rax, rdi
                add rax, rsi
                add rax, '0'            ; To make it printable ASCII
                ret                     ; Result: 0x39 (A single character '9' in ASCII)

(My environment is WSL Ubuntu 22.04 on Windows 11, Intel i9-13900H CPU)

knightchaser@3rdfr13nds:~/assembly$ ./procedures_x64
The sum is: knightchaser@3rdfr13nds:~/assembly$

With GDB(GNU Debugger), I checked the calculation of _sum was successful so 0x39(9 in ASCII character) was stored in RAX register and the program doesn't show any explicit errors like segmentation fault.

I used the following commands to make the executable program.

nasm -f elf64 -o procedures_x64.o procedures_x64.asm
ld -o procedures_x64 procedures_x64.o

But I can't see the result. Are there wrong points in my Assembly code? Thanks in advance!


Solution

  • To print your character you do

    mov rcx, rax            ; The result of the _sum (stored in RAX register)
    ;...
    mov rsi, rcx
    

    The problem is that the value returned in rax is a single character, and you move that single character value into rsi. The write system call expects the value in rsi to be a pointer to a character, not the actual character value itself.

    You need to store the character in memory, and then pass a pointer to that memory to the write function.

    If you wrote an exact equivalent in C it would be very obvious when you have to use the pointer-to operator & to print the returned character (or used a character array). I highly recommend that you get the proper C Program working, with the system calls and a proper sum function and conversion from int to a string, and use that as the blueprint for the assembly program.