You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NASM x64汇编调用函数后无法打印计算结果字符的问题排查

NASM x64汇编求和打印无数字输出问题

问题重现

我编写了一个NASM x64汇编程序,实现4和5的求和并打印结果,先完成了C原型:

#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;
}

随后改写为汇编程序:

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

预期输出为The sum is: 9,但实际仅输出The sum is: 。通过GDB调试确认_sum函数计算成功,RAX寄存器中存储了0x39(字符'9'的ASCII值),程序无段错误,编译命令为:

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

环境:Windows 11下的WSL Ubuntu 22.04,CPU为Intel i9-13900H。

错误原因

核心错误出在write系统调用的参数使用错误:

  • Linux x64的write系统调用(syscall号0x01)要求rsi寄存器传入的是要输出数据的内存地址,而非直接传入字符的ASCII值。
  • 你将存储字符'9'的RAX值(0x39)通过RCX中转后放到RSI,相当于让write去访问内存地址0x39的内容。这个地址属于未映射的低内存区域,write调用会失败(返回错误码,但程序直接执行exit,所以没有触发段错误),因此无法输出数字。

修正方案

需要将字符的ASCII值存储到可访问的内存区域(比如栈或.data段),再让write指向该内存地址。以下是两种可行的修正方式:

方式1:使用栈临时存储

利用栈的可写空间临时存放字符,无需修改.data段:

; 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

                ; 将字符值压入栈,栈顶就是字符的内存地址
                push rax
                mov rax, WRITE
                mov rdi, STDOUT
                mov rsi, rsp  ; RSI指向栈顶的字符
                mov rdx, 0x01
                syscall
                pop rax  ; 平衡栈,避免内存泄漏

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

方式2:使用.data段预留缓冲区

在.data段专门分配一个字节存储结果字符:

; 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
        result_char     db      0  ; 预留一个字节存储结果字符

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 [result_char], al  ; 只用低8位即可,因为是单字符
                mov rax, WRITE
                mov rdi, STDOUT
                mov rsi, result_char
                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)

验证

编译运行修正后的代码,即可得到预期输出The sum is: 9。

内容的提问来源于stack exchange,提问作者KnightChaser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 22:43:07