与数组的交互导致段错误
Interaction with array results in a segfault
我正在尝试实现一个简单的加法计算器,但我无法将输入存储在我的数组中。我正在尝试逐个读取一个字符,因为我想稍后使用它来为我的 B 编译器实现后端(它具有从标准输入逐个读取一个字符的 getchar 函数)。我的代码是休闲的:
segment .data
numb db 0, 0, 0, 0
indx db 0
char db '0'
newl db 0ah
msg1 db 'enter a number: '
len1 equ $ - msg1
segment .text
global _start ; defines the entry point
print: ; push msg; push len
pop eax ; removes caller address from stack
pop edx ; gets length
pop ecx ; gets msg
push eax ; pushes CA to stack again
mov ebx , 01h ; tells that it's an output call
mov eax , 04h ; system call (write)
int 80h ; calls it
ret
getc: ; push add; push len
pop eax ; removes caller address from stack
pop ecx ; gets ouput addrress
push eax ; pushes CA to stack again
mov edx , 01h
mov ebx , 00h ; tells that it's an input call
mov eax , 03h ; system call (read)
int 80h ; calls it
ret
exit:
mov ebx , 0 ; sets exit code
mov eax , 01h ; system call (exit)
int 80h ; calls it
_start:
push msg1
push len1
call print
read:
push char
call getc
mov eax , numb
add eax , indx
mov [eax], dword char
inc byte [indx]
mov eax , char
cmp eax , newl
jne read
jmp exit ; exits program
现在我只是试图存储输入,因为我从完整代码中得到了段错误,所以我开始剥离代码直到找到错误原因。
您可能不想在数组中插入换行符,所以从检查换行符开始:
read:
push char
call getc
mov al, [char]
cmp al, 10
je done
然后将字节大小的索引加载到地址寄存器中,记住 AL
已经包含数据,所以选择另一个寄存器而不是 EAX
。另外,不要自己添加数组地址 numb 和索引 indx,而是让 CPU 使用寻址模式为您做这件事具有位移分量 ([numb + ebx]
):
movzx ebx, byte [indx]
mov [numb + ebx], al
inc byte [indx]
jmp read
done:
jmp exit
也可以将索引 indx 定义为带有 indx dd 0
的双字。那么代码就变成了:
read:
push char
call getc
mov al, [char]
cmp al, 10
je done
mov ebx, [indx]
mov [numb + ebx], al
inc dword [indx]
jmp read
done:
jmp exit
这里的教训是 NASM 在寻址内存的方式上与 MASM 不同:
MASM
mov eax, offset MyVar ; Load address of MyVar
mov eax, MyVar ; Load value stored in MyVar
NASM
mov eax, MyVar ; Load address of MyVar
mov eax, [MyVar] ; Load value stored in MyVar
我正在尝试实现一个简单的加法计算器,但我无法将输入存储在我的数组中。我正在尝试逐个读取一个字符,因为我想稍后使用它来为我的 B 编译器实现后端(它具有从标准输入逐个读取一个字符的 getchar 函数)。我的代码是休闲的:
segment .data
numb db 0, 0, 0, 0
indx db 0
char db '0'
newl db 0ah
msg1 db 'enter a number: '
len1 equ $ - msg1
segment .text
global _start ; defines the entry point
print: ; push msg; push len
pop eax ; removes caller address from stack
pop edx ; gets length
pop ecx ; gets msg
push eax ; pushes CA to stack again
mov ebx , 01h ; tells that it's an output call
mov eax , 04h ; system call (write)
int 80h ; calls it
ret
getc: ; push add; push len
pop eax ; removes caller address from stack
pop ecx ; gets ouput addrress
push eax ; pushes CA to stack again
mov edx , 01h
mov ebx , 00h ; tells that it's an input call
mov eax , 03h ; system call (read)
int 80h ; calls it
ret
exit:
mov ebx , 0 ; sets exit code
mov eax , 01h ; system call (exit)
int 80h ; calls it
_start:
push msg1
push len1
call print
read:
push char
call getc
mov eax , numb
add eax , indx
mov [eax], dword char
inc byte [indx]
mov eax , char
cmp eax , newl
jne read
jmp exit ; exits program
现在我只是试图存储输入,因为我从完整代码中得到了段错误,所以我开始剥离代码直到找到错误原因。
您可能不想在数组中插入换行符,所以从检查换行符开始:
read:
push char
call getc
mov al, [char]
cmp al, 10
je done
然后将字节大小的索引加载到地址寄存器中,记住 AL
已经包含数据,所以选择另一个寄存器而不是 EAX
。另外,不要自己添加数组地址 numb 和索引 indx,而是让 CPU 使用寻址模式为您做这件事具有位移分量 ([numb + ebx]
):
movzx ebx, byte [indx]
mov [numb + ebx], al
inc byte [indx]
jmp read
done:
jmp exit
也可以将索引 indx 定义为带有 indx dd 0
的双字。那么代码就变成了:
read:
push char
call getc
mov al, [char]
cmp al, 10
je done
mov ebx, [indx]
mov [numb + ebx], al
inc dword [indx]
jmp read
done:
jmp exit
这里的教训是 NASM 在寻址内存的方式上与 MASM 不同:
MASM
mov eax, offset MyVar ; Load address of MyVar
mov eax, MyVar ; Load value stored in MyVar
NASM
mov eax, MyVar ; Load address of MyVar
mov eax, [MyVar] ; Load value stored in MyVar