【问题标题】:Interaction with array results in a segfault与数组的交互导致段错误
【发布时间】:2021-11-01 23:44:08
【问题描述】:

我正在尝试实现一个简单的加法计算器,但我无法将输入存储在我的数组中。我正在尝试逐个字符地读取字符,因为我想稍后使用它来为我的 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

现在我只是尝试存储输入,因为我从完整代码中得到了段错误,所以我开始剥离代码,直到找到错误原因。

【问题讨论】:

  • add eax , indx - 您将两个地址相加,而不是对存储在那里的字节值进行零扩展。使用调试器单步执行,记住indx[indx] 之间的区别。您需要将 movzx 加载到另一个 reg 中,因为 db 比指针窄。
  • @PeterCordes 我想我明白了,但我无法检查,因为我收到了另一个问题(cmp/jne 没有按预期工作),我应该编辑帖子还是打开另一个问题?

标签: arrays assembly input x86 nasm


【解决方案1】:

您可能不想在数组中插入换行符,所以从检查换行符开始:

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

【讨论】:

  • 它有效,但首先我尝试在没有将索引定义为双字的情况下进行组装。这是段错误,但后来我修复了它并工作了。为什么会这样?
  • @mateus.md 没有看到你的代码,我只能猜测。段错误的一种方法是保留 indx 一个字节,但在我的答案中使用最后一个代码 sn-p。 NASM 不关心大小(太多),并且会愉快地组装 mov ebx, [indx] 导致偏移量对于 .data 段来说太大。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 2017-02-25
相关资源
最近更新 更多