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

Ubuntu系统中使用INT80无法打印栈地址指向字符的问题

问题:无法通过栈地址打印字符,.data段标签打印正常

现象说明

  • 使用栈指针rsp作为打印缓冲区地址时,程序执行后控制台无输出
  • 将缓冲区地址替换为.data段的break标签后,程序能正常打印字符'a'

原始汇编代码

section .data
    break   db  "a"

section .text

global _start
_start:
    mov rax, qword 'a'
    push rax
    ; push 'a' to stack

    mov rax,4
    mov rbx,1

    ; get stack top pointer and mov to rcx register
    mov rcx,rsp
    ; If replace rsp with label <break> that can print newlines character
    ; mov rcx,break

    mov rdx,1
    int 80h

    pop rax

    call quit

quit:
    mov     rbx, 0      
    mov     rax, 1      
    int 80h
    ret

执行结果

  1. 使用rsp作为地址时,控制台无输出:
console>
  1. 替换为break标签时,控制台输出:
console>a#

对应的Makefile

.PHONY: test
test:
    nasm -f elf64 test.asm
    ld -s -o test test.o
    ./test

.PHONY: test_debug
test_debug:
    nasm -f elf64 -F dwarf -g test.asm
    ld -g -o test test.o
    gdb test

问题原因

你用了32位系统调用指令int 80h,但编译的是64位程序(nasm -f elf64),两者调用规范不兼容:

  • 64位环境下调用int 80h时,系统会把寄存器截断为32位使用。而64位系统的栈通常位于高于4GB的虚拟地址空间,rsp的低32位是无效的用户态地址,导致sys_write无法读取正确字符,因此无输出。
  • .data段的地址处于低32位地址范围内,使用break标签时,32位寄存器能拿到有效地址,sys_write可以正常读取并打印。

修复方案

改用64位系统调用规范(使用syscall指令),64位系统调用的参数寄存器和调用号与32位不同:

section .data
    break   db  "a"

section .text

global _start
_start:
    mov rax, qword 'a'
    push rax
    ; push 'a' to stack

    mov rax, 1          ; 64位sys_write的系统调用号
    mov rdi, 1          ; stdout的文件描述符(1对应标准输出)
    mov rsi, rsp        ; 栈顶地址作为打印缓冲区
    mov rdx, 1          ; 打印字符长度
    syscall             ; 执行64位系统调用

    pop rax

    call quit

quit:
    mov     rdi, 0      ; 程序退出码
    mov     rax, 60     ; 64位sys_exit的系统调用号
    syscall
    ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 18:10:48