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
执行结果
- 使用
rsp作为地址时,控制台无输出:
console>
- 替换为
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
相关产品推荐
相关产品推荐

