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



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

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

对于B:

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

等等。我目前的方法是设置一个0和1的字符串,然后循环并将0转换为空间,将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

有人能对上面的代码提出一些建议来帮助实现我想要的目标吗?

我假设您使用制作程序

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

Linker在.text+0xca报告了一个问题,因此您需要在";filename.lst";在.text段中的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中的字节值与.data部分中变量lbreak偏移量进行比较,恰好是78。您可能打算将cl与存储在内存中的"b"进行比较,使用cmp cl, [lbreak],甚至更好,使用立即值cmp cl,"b"

还可以考虑使用单个_printText:将大写字母打印为一个以0结尾的字符串

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

最新更新