Search code examples
assemblyarm64gnu-assembler

GNU AS assembly cannot convert user input to a decimal


I am trying to learn assembly by writing a simple calculator in aarch64 assembly (GNU AS) I succeed on prompting user input but I cannot check if the user input is a number or even a char like '+' Here is the code:



.global main

.section .data

op_plus: .byte '+'

temp: .skip 1

debug_msg1: .asciz "True"

debug_msg1_len = . - debug_msg1

message_0:

    .asciz "Hello, World!\n"

message_0_len = . - message_0

message_1:

    .asciz "Enter mode +,-,*,/: "

message_1_len = . - message_1

message_2: 

    .asciz "enter the first num: "

message_2_len = . - message_2

message_3: 

    .asciz "enter the second num: "

message_3_len = . - message_3

message_4: 

    .asciz "results is "

message_4_len = . - message_4

.section .bss

    .lcomm num1,10

    .lcomm num2, 10

    operator: .skip 1

.section .text

main:

    // Writes "Hello, world!"

    ldr x1, =message_0  // Load the address of the message

    ldr x2, =message_0_len       // Length of the message

    bl print

    

    /* prompts mode */

    ldr x1, =message_1

    ldr x2, =message_1_len

    bl print

    // takes input

    ldr x1, =operator

    ldr x2, =10

    bl input

    

    ldr w0, [x1]

    /* fake input to handle enter press

    ldr x1, =temp

    ldr x2, =1

    bl input*/

    /* end prompt mode */

    /* prompts first num */

    ldr x1, =message_2

    ldr x2, =message_2_len

    bl print

    

    // takes input

    ldr x1, =num1

    ldr x2, =10

    bl input

    /* end prompt first num */

    /* prompts second num */

    ldr x1, =message_3

    ldr x2, =message_3_len

    bl print

    

    // takes input

    ldr x1, =num2

    ldr x2, =10

    bl input

    ldrb w2,[x1]

    /* end prompt second num */

    //prints operator

    /* results */

    ldr x1, =operator

    

    sub x1, x1, '0'

    //prints x1 to make sure its correct

    ldr x2, =20

    bl print

    

    cmp x1, 1

    

    beq add

    /* end results */

    // Exit the program

    bl exit

print:

    mov x0, 1 // file descriptor STDOUT

    mov w8, 64 // sys call sys write

    svc #0 // invoke syscall

    

    ret // branch back to [lr](in this case its _start)

input: 

    mov x0, 0 // file descriptor STDIN

    mov w8, #63 // syscall sys read

    svc #0

    

    

    ret

succes_res: 

    ldr x1, =message_4

    ldr x2, = message_4_len

    bl print

    ret

add: 

    add w3, w1, w2

    bl succes_res

    bl exit

exit: 

    mov w8, #93 // syscall exit

    mov x0, #0 // exit status

    svc #0

true:

    ldr x1, =debug_msg1

    ldr x2, =debug_msg1_len

    bl print

    ret

exit_err:

    mov w8, #93

    mov x0, #1

    svc #0
  • converting input to a decimal by doing sub {register},{register}, '0' it deletes everything from the register
  • directly checking for input by using cmp {register}, {value} where value is immediate or not && is in [1,'+'] even tried to make a data to put the value inside like this op_plus: .ascii "+"
  • removing new line by making input only 1 char long ldr x2, =1 and taking another fake input to handle enter press...

Solution

  • Fixed this by doing ldrb instead of ldr Like this:

    ldr X1, =operator
    ldrb w0, [X1]
    
    
    ldr X1, =num1
    ldrb W1, [X1]
    sub w1, w1, '0' // converts to an int
    ...
    cmp w0, '+' //works
    

    NOTE: You have to do that at the end because sometimes w registers have the same value as x registers so if an x changed a w can change (not sure why I don't want to provide false information)

    X1 = value
    W1 == value
    W1 = another_value
    X1 = another_value
    X1 = new_value
    W1 == new_value