Search code examples
linuxassemblygdbnasm

x64 NASM Assembly program shows segmentation fault at the start of the program


I was writing a simple NASM x64 Assembly code program that adds two single-digit numbers from the user input like that. (My environment is WSL Ubuntu 22.04 on Windows 11, Intel i9-13900H CPU)

Enter the 1st digit: 2    <--- user input
Enter the 2nd digit: 5    <--- user input
1st digit + 2nd digit: 7

I wrote the following NASM x64 Assembly code and made executable files from that, but it only shows a segmentation fault.

; Nasm 2.15.05 (on Linux x64)

STDIN   equ     0x00
STDOUT  equ     0x01

section .data
        message1:       db      "Enter the 1st digit: "
        message1Length: equ     $ - message1

        message2:       db      "Enter the 2nd digit: "
        message2Length: equ     $ - message2

        message3:       db      "1st digit + 2nd digit: "
        message3Length: equ     $ - message3

section .bss
        number1:        RESB    0x02
        number2:        RESB    0x02
        result:         RESB    0x02

section .text:
        global _start

_start:

        ; write(STDOUT, "Enter the 1st digit: ", len);
        mov rax, 0x01
        mov rdi, STDOUT
        mov rsi, message1
        mov rdx, message1Length
        syscall

        ; read(STDIN, &number1, len)
        mov rax, 0x00
        mov rdi, STDIN
        mov rsi, number1
        mov rdx, 0x02           ; RESB
        syscall

        ; write(STDOUT, "Enter the 2nd digit: ", len);
        mov rax, 0x01
        mov rdi, STDOUT
        mov rsi, message2
        mov rdx, message2Length
        syscall

        ; read(STDIN, &number2, len)
        mov rax, 0x00
        mov rdi, STDIN
        mov rsi, number2
        mov rdx, 0x02           ; RESB
        syscall

        mov rax, [number1]
        sub rax, '0'            ; ASCII to integer
        mov rbx, [number2]
        sub rax, '0'            ; ASCII to integer
        add rax, rbx
        mov [result], rax

        ; write(STDOUT, "1st digit + second digit: ", len)
        mov rax, 0x01
        mov rdi, STDOUT
        mov rsi, message3
        mov rdx, message3Length
        syscall

        ; write(STDOUT, result, len)
        mov rax, 0x01
        mov rdi, STDOUT
        mov rsi, result
        mov rdx, 0x02
        syscall

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

I used the following commands to make the executable program.

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

And when I run, it shows only Segmentation fault message.

knightchaser@3rdfr13nds:~/assembly$ ./add_two_single_digits
Segmentation fault

When I try to debug the code with gdb-peda, I could only check that the error causes at the start of the program _start, so I couldn't get it where should I fix my code.

gdb-peda$ set logging enabled on
Copying output to gdb.txt.
Copying debug output to gdb.txt.

...

gdb-peda$ run
Starting program: /home/knightchaser/assembly/add_two_single_digits

Program received signal SIGSEGV, Segmentation fault.
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.

Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x0
RCX: 0x0
RDX: 0x0
RSI: 0x0
RDI: 0x0
RBP: 0x0
RSP: 0x7fffffffdc60 --> 0x1
RIP: 0x401000 --> 0x1bf00000001b8
R8 : 0x0
R9 : 0x0
R10: 0x0
R11: 0x0
R12: 0x0
R13: 0x0
R14: 0x0
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x400ffa:    add    BYTE PTR [rax],al
   0x400ffc:    add    BYTE PTR [rax],al
   0x400ffe:    add    BYTE PTR [rax],al
=> 0x401000:    mov    eax,0x1
   0x401005:    mov    edi,0x1
   0x40100a:    movabs rsi,0x4020d0
   0x401014:    mov    edx,0x15
   0x401019:    syscall
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdc60 --> 0x1
0008| 0x7fffffffdc68 --> 0x7fffffffdee8 ("/home/knightchaser/assembly/add_two_single_digits")
0016| 0x7fffffffdc70 --> 0x0
0024| 0x7fffffffdc78 --> 0x7fffffffdf1a ("SHELL=/bin/bash")
0032| 0x7fffffffdc80 --> 0x7fffffffdf2a ("WSL2_GUI_APPS_ENABLED=1")
0040| 0x7fffffffdc88 --> 0x7fffffffdf42 ("WSL_DISTRO_NAME=Ubuntu")
0048| 0x7fffffffdc90 --> 0x7fffffffdf59 ("WT_SESSION=a5f19504-8b1a-4025-b5b6-5ff73b6ebc09")
0056| 0x7fffffffdc98 --> 0x7fffffffdf89 ("NAME=3rdfr13nds")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV


Fatal signal: Segmentation fault
----- Backtrace -----
0x56095bae8077 ???
0x56095bbea859 ???
0x56095bbeaa22 ???
0x7f690c71a51f ???
        ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0
0x56095be4b5ea ???
0x56095bb1307e ???
0x56095be442ff ???
0x56095be4438a ???
0x56095bdb538c ???
0x56095bdb8e58 ???
0x56095bdb94be ???
0x56095bc537f6 ???
0x56095be307a8 ???
0x56095bc56a1e ???
0x56095bc6375c ???
0x56095bf9c815 ???
0x56095bf9ccaa ???
0x56095bca836c ???
0x56095bcaa054 ???
0x56095ba4015f ???
0x7f690c701d8f __libc_start_call_main
        ../sysdeps/nptl/libc_start_call_main.h:58
0x7f690c701e3f __libc_start_main_impl
        ../csu/libc-start.c:392
0x56095ba45bf4 ???
0xffffffffffffffff ???
---------------------
A fatal error internal to GDB has been detected, further
debugging is not possible.  GDB will now terminate.

This is a bug, please report it.  For instructions, see:
<https://www.gnu.org/software/gdb/bugs/>.

Segmentation fault (core dumped)
gdb-peda$ where
#0  0x0000000000401000 in _start ()

Are there wrong points in my Assembly code? I'm a new learner of the Assembly language, so I need your help. Thanks in advance!


Solution

  • (Thanks to @ecm 's comment) I succeeded to fix the problem.

    The fixed x64 NASM Assembly code is here(Makefile and other elements are the same)

    ; Nasm 2.15.05 (on Linux x64)
    ; THE ENTIRE PROGRAM ONLY CAN HANDLE SINGLE DIGIT NUMBER
    
    STDIN   equ     0x00
    STDOUT  equ     0x01
    
    section .data
            message1:       db      "Enter the 1st digit: "
            message1Length: equ     $ - message1
    
            message2:       db      "Enter the 2nd digit: "
            message2Length: equ     $ - message2
    
            message3:       db      "1st digit + 2nd digit: "
            message3Length: equ     $ - message3
    
    section .bss
            number1:        RESB    0x02
            number2:        RESB    0x02
            result:         RESB    0x02
    
    section .text   ; <---- DELETE COLON (SHOULDN'T HAVE)
            global _start
    
    _start:
    
            ; write(STDOUT, "Enter the 1st digit: ", len);
            mov rax, 0x01
            mov rdi, STDOUT
            mov rsi, message1
            mov rdx, message1Length
            syscall
    
            ; read(STDIN, &number1, len)
            mov rax, 0x00
            mov rdi, STDIN
            mov rsi, number1
            mov rdx, 0x02           ; RESB
            syscall
    
            ; write(STDOUT, "Enter the 2nd digit: ", len);
            mov rax, 0x01
            mov rdi, STDOUT
            mov rsi, message2
            mov rdx, message2Length
            syscall
    
            ; read(STDIN, &number2, len)
            mov rax, 0x00
            mov rdi, STDIN
            mov rsi, number2
            mov rdx, 0x02           ; RESB
            syscall
    
            mov rax, [number1]
            sub rax, '0'            ; ASCII to integer
            mov rbx, [number2]
            sub rbx, '0'            ; ASCII to integer
            add rax, rbx
    
    
            add rax, '0'            ; <--- ADD '0' TO CONVERT THE SUM FROM THE ASCII (Except for this, the answer doesn't show properly)
    
            mov [result], rax
    
            ; write(STDOUT, "1st digit + second digit: ", len)
            mov rax, 0x01
            mov rdi, STDOUT
            mov rsi, message3
            mov rdx, message3Length
            syscall
    
            ; write(STDOUT, result, len)
            mov rax, 0x01
            mov rdi, STDOUT
            mov rsi, result
            mov rdx, 0x01
            syscall
    
            ; exit
            mov rax, 0x3C
            xor rdi, rdi
            syscall
    

    The limitation of the current program is that this only can handle a single-digit answer. So If you enter 9 at the first input and 8 at the second input are both the single digit input, the program won't show the proper value because its answer is 17 is not a single digit.

    Probably I could make the second Assembly program that is improved on that issue.