ASM:循环中出现段错误,不确定原因

ASM: Seg faults on loop, unsure why

我在 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 (it's a linux tagged answer but in this regard the kernel behavior is identical to MacOS in x86-64). If you're curious how it works 当不使用调试器 rcx 单步执行时 syscall 将包含其 return 地址,这将是您程序的下一条指令(在本例中为 ret)。

因为你的 arrayloop 逻辑之后依赖于 rcx 这将失败并在这一行中显示 EXC_BAD_ACCESS:

arrayloop:
    mov [rsi+rcx*8], rcx ; array element rcx updated with value

可能的修复方法如下所示:

print:
    mov rax, 0x02000004
    mov rdi, 1
    push rcx
    syscall
    pop rcx
    ret

它在堆栈上保留 rcx 值并在 syscall 之后立即恢复其值。

作为 替代方案 @PeterCordes 建议重构循环以完全不依赖 rcx。还有很多剩余的寄存器可供选择(除了前面提到的 r11 和 rax,rdx 用于 syscall return 值)。