与数组的交互导致段错误

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