我正在学习amd64汇编程序,并尝试实现一个简单的Unix过滤器。由于未知的原因,甚至简化为最低版本(下面的代码),它也会随机崩溃。
我试图在GNU调试器(gdb)中调试该程序。在gdb的默认配置下,该程序运行良好,但是如果启用地址随机化(set disable- randomization off),该程序将开始崩溃(SIGSEGV)。清单中标记了有问题的说明:
set disable- randomization off
format ELF64 executable sys_read = 0 sys_write = 1 sys_exit = 60 entry $ foo: label .inbuf at rbp - 65536 label .outbuf at .inbuf - 65536 label .endvars at .outbuf mov rbp, rsp mov rax, sys_read mov rdi, 0 lea rsi, [.inbuf] mov rdx, 65536 syscall xor ebx, ebx cmp eax, ebx jl .read_error jz .exit mov r8, rax ; r8 - count of valid bytes in input buffer xor r9, r9 ; r9 - index of byte in input buffer, that is being processed. xor r10, r10 ; r10 - index of next free position in output buffer. .next_byte: cmp r9, r8 jg .exit mov al, [.inbuf + r9] mov [.outbuf + r10], al ;; SIGSEGV here in GDB inc r10 inc r9 jmp .next_byte .read_error: mov rax, sys_exit mov rdi, 1 syscall .exit: mov rax, sys_write mov rdi, 1 lea rsi, [.outbuf] mov rdx, r10 syscall mov rax, sys_exit xor rdi, rdi syscall
该程序旨在从stdin读取最多64kB的数据,将其存储到堆栈中的缓冲区中,将读取的数据逐字节复制到输出缓冲区中,并将输出缓冲区的内容写入标准输出流。本质上,它应作为的受限版本cat。
cat
在我的计算机上,它要么按预期工作,要么因SIGSEGV崩溃,大约成功运行1次至崩溃4次。
amd64中的红色区域只有128个字节长,但是您使用的rsp以下是131072个字节。向下移动堆栈指针以包含要存储在堆栈上的缓冲区。