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 值)。
我在 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 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 值)。