NASM 你能解释一下为什么我的代码会返回一个分段错误吗?
NASM Can you explain to me why my code is returning a segmentation fault?
我的代码 returns 第二次调用子例程 prntlf
时出现分段错误。
_start:
mov ecx, msg
call prntlf
call prntlf ; Here is where the issue is
经过实验,我发现只有当我没有将ecx
的值设置回我想要它打印的字符串时才会出现,但我想知道的是为什么我必须这样做那。鉴于我从保存的堆栈中弹出寄存器的值,ecx
不应该仍然保留要打印的有效字符串吗?
完整来源:
文件hello.asm
:
; RUN WITH `nasm -f elf32 hello.asm -o hello.o && ld -m elf_i386 hello.o -o hello && ./hello`
%include 'subroutines.inc'
section .data
msg db "Hello, World!", 0x0
msg2 db "Goodbye, Moon!", 0x0
linefeed db 0xA, 0xD
section .text
global _start:
_start:
mov ecx, msg
call prntlf
call prntlf
jmp end
文件:subroutines.inc
; subroutines.inc
;===============================================================================
; getstrlen | Gets String Length and pushes the value to register edx
;===============================================================================
getstrlen:
push eax
push ebx
mov eax, ebx
findnterm:
cmp byte [eax], 0
jz gotstrlen
inc eax
jmp findnterm
gotstrlen:
sub eax, ebx
mov edx, eax
pop eax
pop ebx
ret
;===============================================================================
; printstr | Prints a String using a dynamic algorithm to find null terminator
;===============================================================================
printstr:
push eax
push ebx
push edx
mov ebx, ecx
call getstrlen
mov ebx, 0x01
mov eax, 0x04
int 0x80
pop eax
pop ebx
pop edx
ret
;===============================================================================
; prntlf | Prints a String and appends a Linefeed.
;===============================================================================
prntlf:
push eax
push ebx
push ecx
push edx
mov eax, ecx
movetoendloop:
cmp byte [eax], 0
jz donemoving
inc eax
jmp movetoendloop
donemoving:
call printstr
mov ecx, linefeed
call printstr
pop eax
pop ebx
pop ecx
pop edx
ret
;===============================================================================
; end | calls kernel and tells it to End the program
;===============================================================================
end:
mov eax, 0x01
mov ebx, 0x00
int 0x80
栈是后进先出的结构,意思是你最后入栈的东西会最先出栈,不管你入栈的是哪个寄存器。
prntlf:
push eax
push ebx
push ecx
push edx
...
pop edx ; Pop them back from the stack in the reverse order in which you pushed them.
pop ecx
pop ebx
pop eax
ret
我的代码 returns 第二次调用子例程 prntlf
时出现分段错误。
_start:
mov ecx, msg
call prntlf
call prntlf ; Here is where the issue is
经过实验,我发现只有当我没有将ecx
的值设置回我想要它打印的字符串时才会出现,但我想知道的是为什么我必须这样做那。鉴于我从保存的堆栈中弹出寄存器的值,ecx
不应该仍然保留要打印的有效字符串吗?
完整来源:
文件hello.asm
:
; RUN WITH `nasm -f elf32 hello.asm -o hello.o && ld -m elf_i386 hello.o -o hello && ./hello`
%include 'subroutines.inc'
section .data
msg db "Hello, World!", 0x0
msg2 db "Goodbye, Moon!", 0x0
linefeed db 0xA, 0xD
section .text
global _start:
_start:
mov ecx, msg
call prntlf
call prntlf
jmp end
文件:subroutines.inc
; subroutines.inc
;===============================================================================
; getstrlen | Gets String Length and pushes the value to register edx
;===============================================================================
getstrlen:
push eax
push ebx
mov eax, ebx
findnterm:
cmp byte [eax], 0
jz gotstrlen
inc eax
jmp findnterm
gotstrlen:
sub eax, ebx
mov edx, eax
pop eax
pop ebx
ret
;===============================================================================
; printstr | Prints a String using a dynamic algorithm to find null terminator
;===============================================================================
printstr:
push eax
push ebx
push edx
mov ebx, ecx
call getstrlen
mov ebx, 0x01
mov eax, 0x04
int 0x80
pop eax
pop ebx
pop edx
ret
;===============================================================================
; prntlf | Prints a String and appends a Linefeed.
;===============================================================================
prntlf:
push eax
push ebx
push ecx
push edx
mov eax, ecx
movetoendloop:
cmp byte [eax], 0
jz donemoving
inc eax
jmp movetoendloop
donemoving:
call printstr
mov ecx, linefeed
call printstr
pop eax
pop ebx
pop ecx
pop edx
ret
;===============================================================================
; end | calls kernel and tells it to End the program
;===============================================================================
end:
mov eax, 0x01
mov ebx, 0x00
int 0x80
栈是后进先出的结构,意思是你最后入栈的东西会最先出栈,不管你入栈的是哪个寄存器。
prntlf:
push eax
push ebx
push ecx
push edx
...
pop edx ; Pop them back from the stack in the reverse order in which you pushed them.
pop ecx
pop ebx
pop eax
ret