DDV
DDV

Reputation: 2384

Convert User Input Character to Symbol: x86_64 Assembly

I am trying to convert an input character to an output symbol in x86 assembly. As an example, if the user enters A I want the below to be output:

  $  
 $ $
$$$$$
$   $
$   $

And for B:

$$$$
$   $
$$$$
$   $
$$$$

etc. My current method is to set up a string of 0's and 1's and then loop through and convert a 0 to a space and a 1 to a $. I use a b as a line break (i.e. new line) and an x as end of string.

My code below (just showing A run through to shorten code):

section .data
    ; constants
    NULL        equ 0
    EXIT_SUCCESS    equ 0
    EXIT_FAIL   equ 1
    SYS_exit    equ 60
    SYS_read    equ 0
    SYS_write   equ 1
    STD_in      equ 0
    STD_out     equ 1

    ; other
    text1   db "Please enter an upper-case letter from A-E: ",0
    errmsg  db "Error: incorrect letter chosen.",0
    sucmsg  db "Success.",0
    symA    db "00100b01010b11111b10001b10001x ",0
    space   db " "
    dollar  db "$"
    lbreak  db "b"
    lend    db "x"

section .bss
    ; reserve space for user input
    letter resb 1

section .text
    global _start

_start: 
    ; print question
    mov rax, text1
    call _printText

    ; get user input
    ; sys_read (0, latter, 1)
    mov rax, SYS_read
    mov rdi, STD_in
    mov rsi, letter
    mov rdx, 1
    syscall

    ; dereference rsi
    movzx rsi, byte [letter]

    ; jump conditionals
    mov rdx, "A"
    cmp rsi, rdx
    je _printA

    ; default jump if no match
    ; print fail msg
    mov rax, errmsg
    call _printText
    jmp _exitFail

_printA:
    xor eax, eax
    ; sys_write (1, text, 1)
    mov rax, symA
    call _printText
    call _printChar
    jmp _exitSuccess

_exitFail:
    ; default error exit
    ; sys_exit (1)
    mov rax, SYS_exit
    mov rdi, EXIT_FAIL
    syscall

_exitSuccess:
    ; print success msg
    mov rax, sucmsg
    call _printText

    ; sys_exit (0)
    mov rax, SYS_exit
    mov rdi, EXIT_SUCCESS
    syscall

; functions
_printText:
    push rax
    mov rbx, 0

_ptLoop:
    inc rax
    inc rbx
    mov cl, [rax]
    cmp cl, 0
    jne _ptLoop

    mov rax, SYS_write
    mov rdi, STD_out
    pop rsi
    mov rdx, rbx
    syscall
    ret

_printChar:
    ;push rax
    mov rbx, 0
    
_pcLoop:
    inc rax
    inc rbx
    mov cl, [rax]
    ; if 0
    cmp cl, 0
    je _movSpace
    ; if 1
    cmp cl, 1
    je _movSymbol
    ; if newline
    cmp cl, lbreak
    je _movNewLine
    ; if end
    cmp cl, lend
    je _endPrint

_movSpace:
    mov rcx, space
    loop _pcLoop

_movSymbol:
    mov rcx, dollar
    loop _pcLoop    

_movNewLine:
    mov rcx, "\n"
    loop _pcLoop

_endPrint:
    mov rax, SYS_write
    mov rdi, STD_out
    mov rsi, rcx
    mov rdx, rbx
    syscall
    ret

Currently, I have tried to debug as I was getting Segmentation fault (core dumped) in the _printChar function, however, now with the above code I am unable to create the executable file as it is returning the below error:

(.text+0x10e): relocation truncated to fit: R_X86_64_8 against '.data'
(.text+0x113): relocation truncated to fit: R_X86_64_8 against '.data'

when trying to run the below command in terminal:

ld filename.o -o filename

Can anyone suggest anything to assist with code above to achieve the objective I am after?

Upvotes: 0

Views: 311

Answers (1)

vitsoft
vitsoft

Reputation: 5775

I assume that you make your program with

nasm -f elf64 filename.asm -o filename.o -l filename.lst
ld filename.o -o filename

Linker reports a problem at .text+0xca, so you need to find in the "filename.lst" what instruction was generated at this offset 0xca in the .text section:

    ....
   112 000000C3 80F901                      cmp cl, 1
   113 000000C6 7416                        je _movSymbol
   114                                      ; if newline
   115 000000C8 80F9[78]                    cmp cl, lbreak
   116 000000CB 741D                        je _movNewLine
   117                                      ; if end
   118 000000CD 80F9[79]                    cmp cl, lend
   119 000000D0 741F                        je _endPrint
    ....

It's the cmp cl, lbreak. Looking at the definition lbreak db "b" it obvious that your instruction incorrectly tried to compare a byte-value in cl with the offset of variable lbreak in section .data, which happens to be 78. You probably intended to compare cl with the value "b" stored in memory, using cmp cl, [lbreak] or even better, with the immediate value: cmp cl,"b".

Also consider printing the big letter as one 0-terminated string, using a single _printText:

  SECTION .data
  BigA  DB "  $  ",10
        DB " $ $ ",10
        DB "$$$$$",10
        DB "$   $",10
        DB "$   $",10
        DB 0
  BigB  DB "$$$$ ",10
        DB "$   $",10
        DB "$$$$ ",10
        DB "$   $",10
        DB "$$$$ ",10
        DB 0

Upvotes: 2

Related Questions