ASM:Seg循环出错,不确定原因

问题描述

我已经在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除外)。