NASM 程序集:检查字符串长度+确认字符串是否只由'0'、'1'、'2'组成?

NASM Assembly: checking length of string + confirming string is only made up of '0', '1', and '2' 's?

我对汇编比较陌生,我正在尝试编写一个程序,将 2 个命令行参数作为输入(第二个命令行参数是一个字符串)并检查其长度在 1 到 30 之间。它还检查字符串是否仅由字符 0、1 和 2 组成。任何其他字符,它终止。当我 运行 程序时,它只是输出 "Segmentation fault"。从我收集到的信息来看,当我处理我不应该处理的一部分内存时,就会发生这种情况。我知道我的问题出在循环中的某个地方,但我不知道在哪里或为什么。任何关于我的代码错误的建议将不胜感激。

代码如下:

%include "asm_io.inc"
global asm_main

SECTION .data
  lenError: db "Length of string must be between 1 and 30 (inclusive).",10,0
  argError: db "Only 2 command line arguments accepted.",10,0
  charError: db "Only characters '0', '1', and '2' are accepted.",10,0

SECTION .text
  global asm_main
  extern strlen
  extern printf

asm_main:
  enter 0,0
  pusha
  mov eax, dword [ebp+8]        ; argc
  cmp eax, dword 2              ; if argc == 2
  jne ERR_ARG
  popa
  mov ebx, dword [ebp+12]
  mov eax, [ebx+4]         ;eax has the string in it now  
  mov ecx, 0               ;initialize a counter
  LOOP1:
    cmp byte[eax], 0       ;end of string
    je DONE
    cmp byte[eax], '0'     ;check if char == 0
    je GO
    cmp byte[eax], '1'
    je GO
    cmp byte[eax], '2'
    je GO
    jmp ERR_CHAR
  GO:
    inc ecx       ; increase counter
    inc eax       ;next position in string
    cmp ecx, 30   
    jg ERR_LEN
  jmp LOOP1

  DONE:
    call print_string      ;there's more to come,
    jmp asm_main_end       ;but i want to find the error first

  ERR_CHAR:
    mov eax, charError
    call print_string
    jmp asm_main_end
  ERR_LEN:
    pop eax
    mov eax, lenError
    call print_string
    jmp asm_main_end

  ERR_ARG:
    mov eax, argError
    call print_string
    jmp asm_main_end

    asm_main_end:
      popa
      leave
      ret

更新:我相信我已经将分段错误隔离到 asm_main_end,我终止程序的方式有什么问题吗?

导致分段错误的问题是 jne ERR_ARG 之后靠近函数开头的 popa 指令。如果不采用分支,则寄存器从那里的堆栈中弹出,然后在 asm_main_end 处再次弹出。

asm_main:
  enter 0,0
  pusha
  mov eax, dword [ebp+8]       
  cmp eax, dword 2    
  jne ERR_ARG
  popa                   ; Do not pop here
  ;
  ;
  ;
  asm_main_end:
      popa               ; when popping here
      leave
      ret

第二个popa然后将从堆栈中删除return地址(除了用不相关的值填充大部分寄存器),使函数return成为任意位置很可能不属于您的程序。如果给定了错误数量的参数,程序应该会正确运行。

顺便说一句:在您的代码中不需要推送寄存器(除了 enter 完成的推送 ebp 之外)。