将用户输入字符转换为符号:x86_64 程序集

Convert User Input Character to Symbol: x86_64 Assembly

我正在尝试将输入字符转换为 x86 程序集中的输出符号。例如,如果用户输入 A 我希望输出以下内容:

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

对于B

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

等我目前的方法是设置一串 0 和 1,然后循环并将 0 转换为 space,将 1 转换为 $。我使用 b 作为换行符(即新行)和 x 作为字符串的结尾。

我下面的代码(只显示 A 运行 以缩短代码):

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

目前,我尝试调试,因为我在 _printChar 函数中得到 Segmentation fault (core dumped),但是,现在使用上面的代码我无法创建可执行文件,因为它返回以下错误:

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

在终端中尝试运行以下命令时:

ld filename.o -o filename

任何人都可以提出任何建议来帮助上面的代码实现我所追求的 objective 吗?

我假设你用

制作你的程序
nasm -f elf64 filename.asm -o filename.o -l filename.lst
ld filename.o -o filename

链接器在 .text+0xca 处报告了一个问题,因此您需要在 .text 部分的“filename.lst”中找到在该偏移量 0xca 处生成的指令:

    ....
   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
    ....

cmp cl, lbreak。查看定义 lbreak db "b" 很明显,您的指令错误地尝试将 cl 中的字节值与部分中变量 lbreakoffset 进行比较.data,正好是78。您可能打算将 cl 与存储在内存中的 value "b" 进行比较,使用 cmp cl, [lbreak] 或什至更好,使用 immediate 值:cmp cl,"b".

还可以考虑将大字母打印为一个以 0 结尾的字符串,使用单个 _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