我正在编写一个简单的NASM x64汇编代码程序,该程序将用户输入的两个一位数相加.(我的环境是Windows 11上的WSL Ubuntu 22.04,Intel i9-13900H CPU)

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

我编写了以下NASM x64汇编代码,并从中生成了可执行文件,但它只显示了一个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

我使用了以下命令来生成可执行程序.

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

当我运行时,它只显示Segmentation fault条消息.

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

当我try 用gdb-peda调试代码时,我只能在程序_start开始时判断错误是否导致,所以我无法得到它,我应该在哪里修复我的代码.

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 ()

我的汇编代码中有错误的地方吗?我是汇编语言的新手,所以我需要你们的帮助.提前谢谢!

推荐答案

(感谢@ECM的S comments ) 我成功地解决了这个问题.

固定的x64 NASM汇编代码在此(Makefile和其他元素相同)

; 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

当前程序的限制是,这只能处理个位数的答案.因此,如果您在第一个输入中输入9,在第二个输入中输入8,则程序不会显示正确的值,因为它的答案是17不是一位数.

也许我可以制作在这个问题上得到改进的第二个汇编程序.

Linux相关问答推荐

git别名函数可以用单引号写吗?

Bash:将带有新行的字符串转换为带有逗号、内联的唯一值的字符串

使用awk命令将以:分隔的两个文件合并的方法

如何启用或切换现有的Flutter 项目(仅限移动设备)到 MacOS 或 WEB 或 Linux 或 Windows?

Bash 更新 yaml 文件中的图像值

有没有办法定义自定义隐式 GNU Make 规则?

当接收端未从套接字读取时,通过 Unix 套接字发送的消息会发生什么情况?

使用打印命令 Select 子域

编译过度对齐的动态分配变量时出现 icpc 错误

Ubuntu 上 Java 应用程序中的丑陋字体

如何以另一个用户的身份使用 sudo 在 bash 子shell 中执行一系列命令?

使用单个命令打开 .tar.gz 文件

如何在 Linux 中使用单行命令获取 Java 版本

如何在 Linux 上查找不包含文本的文本文件?

如何更改 tmux 会话的起始目录?

在 Ubuntu 中学习 OpenGL

当将信号量减为零的进程崩溃时,如何恢复信号量?

事件驱动和异步有什么区别?在 epoll 和 AIO 之间?

使用 WGET 运行 cronjob PHP

如何始终以 GB 为单位获取 df linux 命令输出