我在 Linux 机器上的 x86-64 程序集中遇到了一个小错误或意外行为。
在
.bss
部分,我在内存中保留了16个字节,我称之为name
当用户输入他们的名字时,它将通过一条问候消息输出回屏幕上。但是,当用户输入大于 16 个字符的内容时,其余字符将立即在控制台中运行。 问题
这就是人们所说的缓冲区溢出吗? 但是为什么首先运行的是16个字符之后的代码?我认为该应用程序会崩溃或根本无法工作。消息的其余部分保存在哪里?我的 shell(即 zsh)如何运行特别是该代码?
如果这些问题听起来很愚蠢,我很抱歉,但我昨天才开始使用汇编语言,我试图了解 Linux 内核在做什么。
我的程序的完整源代码是这样的:
section .data
question1 db "What is your name? "
greeting db "Hello, "
section .bss
name resb 16 ; Reserve 16 bytes in memory for "name"
section .text
global _start ; define at which label (address) the main program routine should start
_start:
call _printQuestion
call _getName
call _printGreeting
call _printName
; Define the next syscall to end the program
mov rax, 60 ; ID for sys_exit syscall
mov rdi, 0 ; rdi = errorcode value. 0 = No error
syscall ; run the syscall to exit
_getName:
mov rax, 0 ; Syscall 0 for sys_read
mov rdi, 0 ; Standard Input
mov rsi, name
mov rdx, 16
syscall
ret
_printQuestion:
mov rax, 1
mov rdi, 1
mov rsi, question1
mov rdx, 19
syscall
ret
_printGreeting:
mov rax, 1
mov rdi, 1
mov rsi, greeting
mov rdx, 7
syscall
ret
_printName:
mov rax, 1
mov rdi, 1
mov rsi, name
mov rdx, 16
syscall
ret
我知道该程序会做意想不到的事情,但我没想到会发生这种情况,我想了解这是否是一个常见问题以及如何解决它。
发生这种情况是因为您的程序不一定读取整行输入。如果用户输入的行长度超过 16 个字符,您将读取其中的前 16 个字符。其余的保留在终端驱动程序的缓冲区中,并将在下次调用
read()
时返回。当程序退出时,shell 调用 read()
来获取下一个命令行,这将返回输入行的其余部分,然后 shell 执行它。