我得到了一个函数描述:接受缓冲区地址和大小作为参数。从标准输入中读取下一个单词(跳过空白进入缓冲区)。如果字对于指定的缓冲区来说太大,则停止并返回0;否则返回缓冲区地址。此函数应将接受的字符串空终止。但是我写的代码不工作,当我试图输入像echo -n "" | ./read_word
或echo -n "\t " | ./read_word
。输出是
[3] 40467 done echo -n "\t " |
40468 segmentation fault (core dumped) ./read_word
我的代码中可能有什么错误?
这就是:
read_word:
xor r8, r8
xor r9, r9
mov r9, rdi
push rdi
push rsi
.whitespace_reader:
call read_char
mov rdi, rax
push rax
call .whitespace_checker
cmp rax, 2
jz .fail
cmp rax, 0
pop rax
jz .whitespace_reader
pop rsi
pop rdi
.word_reader:
inc r8
cmp r8, rsi
jnb .fail ; если >=, фейлим, иначе пишем в буфер
mov byte [rdi], al
inc rdi
push rdi
push rsi
call read_char
pop rsi
pop rdi
push rdi
mov rdi, rax
push rax
call .whitespace_checker
cmp rax, 0
pop rax
pop rdi
jz .success
jmp .word_reader
; возвращает 0, если символ пробельный, 1 если непробельный и 2, если нуль-терминатор
.whitespace_checker:
mov rax, rdi
cmp rax, 0x20
jz .ret_0
cmp rax, 0x9
jz .ret_0
cmp rax, 0xA
jz .ret_0
cmp rax, 0
jz .ret_2
mov rax, 1
ret
.ret_0:
mov rax, 0
ret
.ret_2:
mov rax, 2
ret
.fail:
xor rax, rax
ret
.success:
inc rdi
mov byte [rdi], 0
mov rax, r9
mov rdx, r8
ret`
1条答案
按热度按时间ajsxfq5m1#
你的两个例子都只包含空格和一个终止零。.whitespace_reader 将循环遍历空白,然后偶然发现终止零,它将跳转到 .fail。这里的
ret
指令将使用不平衡堆栈,因为返回地址被您压入的RDI、RSI和RAX寄存器阻塞。在您当前的代码中没有快速解决这个问题的方法,因为它包含其他问题。r12
、r13
、r14
、r15
、rbx
、rsp
和rbp
是保留调用的寄存器,因此不能保证R8和R9寄存器在调用 read_char 后仍然有效。cmp dl, 1
指令就可以覆盖所有可能的结果。inc rdi
会在缓冲区中留下一个未使用的字节,并可能将新的终止零放在缓冲区之外!这是我的重写,包含了以上所有内容: