Search code examples
linuxassemblygnu-assembler

Read Multiple bytes from stack into single register


I am using 64-bit linux and programming in assembler using gas. The issue I am having is I let the user enter lets say "1 + 12" using the system call read, and saving it as follows.

My read function:

    .type _read, @function
_read:
    pushq  %rbp                     # Save old base pointer
    movq   %rsp,%rbp

    movq   $200,%rdx                # MAX characters to retrieve
    movq   $equation,%rsi           # Buffer for equation string
    movq   $0,%rdi                  # STDIN
    movq   $0,%rax                  # SYS_READ
    syscall

    movq   %rbp,%rsp                # Restore base pointer
    popq   %rbp
    ret                             # Return from function

equation is declared as:

.section .bss
.lcomm equation, 200

So I parse through each byte of equation trying to save the numbers, but if they enter "12" than I would first get 1 and than 2, I need to somehow save 12 on the stack and be able to just popq %rax and have "12" in there. I am not sure how to go about this? Any input would be greatly appreciated.


Solution

  • You'll have to write some sort of parser. Here's an example (I'm using 16-bit assembly in Intel syntax, but you get the gist of it):

    ; Parses the zero-terminated string 'equation', converts any numbers
    ; found in that string from strings to integers and pushes them on
    ; the stack.
    parse_equation:
      pop di        ; pop the return address
      lea si,[equation]
      cld
      xor cl,cl     ; # of chars in the currently parsed number
    skip_non_number:
      lodsb
      test al,al
      jz end_of_equation
      cmp al,'0'
      jb skip_non_number
      cmp al,'9'
      ja skip_non_number
      sub al,'0'        ; convert '0'..'9' -> 0..9
      movzx bx,al       ; zero-extend to word and store in bx
    parse_number:
      inc cl
      lodsb
      test al,al
      jz end_of_equation
      cmp al,'0'
      jb end_of_number
      cmp al,'9'
      ja end_of_number
      sub al,'0'
      mov ch,al
      mov ax,10
      mul bx        
      movzx bx,ch
      add bx,ax     ; bx = bx*10 + (word)al
      jmp parse_number
    end_of_number:
      push bx       ; store the parsed number on the stack
      xor cl,cl
      jmp skip_non_number   ; start over again
    end_of_equation:
      test cl,cl
      jz nothing_to_push
      push bx       ; the string ended with a number; push it
    nothing_to_push:
      jmp di        ; return
    


    My code ignores anything that isn't a number (like arithmetic operators), and doesn't handle signed numbers. I'll leave it to you to figure out how to handle such things.