问题描述
我已经在NASM x86中编写了以下程序,但是当我尝试运行该程序时,似乎得到的只有段错误(尝试打印时)和无限循环(当我停止打印时)。该代码设法一次成功调用printNumber
,然后进行段错误;因此,我被认为是在循环的第二次迭代中发生了某些事情。我在这里想念什么?我已经在源代码中添加了注释以解释正在发生的事情,但是我不明白为什么这会为应该是一个简单程序(目前无法访问valgrind或gdb)的程序抛出段错误。
这是输出:
0Segmentation fault: 11
SECTION .data
arraylen dd 10
num db 0
farewell: db "Blah"
SECTION .bss
array resq 8
SECTION .text
global start
start:
call fillArr
mov rax,0x02000001
mov rdi,0
syscall
printNum:
mov rsi,num
mov rdx,2
call print
ret
fillArr:
lea rsi,[rel array] ; needed for 64 bit on mac
xor rcx,rcx ; make this 0
arrayloop:
mov [rsi+rcx*8],rcx ; array element rcx updated with value
mov rbx,[rsi + rcx*8] ; grab value at index we just filled
add rbx,48 ; Now offset number by 48 to make it ascii'able
mov [rsi+rcx*8],rbx ; overwritten the value we saw as it's ascii
mov [rel num],rbx ; update storage var
call printNum ; print
inc rcx ; we don't need this anymore
cmp rcx,4
jne arrayloop
mov rsi,farewell
mov rdx,4
call print
ret
print:
mov rax,0x02000004
mov rdi,1
syscall
ret
解决方法
从printNum
调用时出现问题:
print:
mov rax,0x02000004
mov rdi,1
syscall
ret
就像@MichaelPrefetch和@PeterCordes在评论syscall
中提到的rcx和r11一样。请参阅also(这是Linux标记的答案,但是在这方面内核行为与x86-64中的MacOS相同)。如果您好奇under the hood的工作方式,而在syscall
之后没有使用调试器rcx单步执行时,它将包含其返回地址,它将作为程序的下一条指令(在这种情况下为ret
)
由于之后您的arrayloop
逻辑依赖于rcx,因此此行中的EXC_BAD_ACCESS
将失败:
arrayloop:
mov [rsi+rcx*8],rcx ; array element rcx updated with value
可能的修复可能如下所示:
print:
mov rax,1
push rcx
syscall
pop rcx
ret
将rcx值保留在堆栈上,并在syscall
之后立即恢复其值。
作为替代,@ PeterCordes建议重构循环,使其完全不依赖rcx。还有很多剩余的寄存器可供选择(上述用于返回syscall
的r11和rax,rdx除外)。