assembly x86_64 nasm读取系统调用不是空终止的

isr3a4wc  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(123)

x86_64 nasm read syscall不是空终止的

新到装配。这是我的第一个Hello World程序。操作系统:Arch Linux(64位)

逻辑

我有三个功能。strlenstdinstdoutstrlen:通过循环字节直到找到空字节来查找字符串的长度。
stdinstdout只使用读和写系统调用。
首先,我用stdout请求用户的输入(不重要),然后我用stdinstdin创建一个输入提示,将输入放在字符串rl中,最后,stdout尝试打印输入。

问题

如果你还记得strlen是如何工作的。它循环直到找到一个空字节。但是stdin不会空终止它的输入。因此,当stdout去寻找输入的长度时,它不会在输入的末尾停止,并且会继续收集垃圾,直到遇到空字节。但到那时,你会看到这样的东西:

What is your name?
Logan
Logan
��
   @ @@%)@1+@7L@>a@O@J @V @]▒ @hello.asmstrrlstrlenstrlen_nextstrlen_nullstdinstdoutExitSuccess__bss_start_edata_end.symtab.strtab.shstrtab.text.datam! @ ▒ P
▒       h!b�!'

简单的解决方法应该是在字符串的末尾添加一个空字节。我怎么能这么做呢?就像我一开始说的,对组装来说很新...所以你的行话只会吓到我。

完整程序

global    _start

            section     .data
str:        db          "What is your name?", 10, 0     ; db: Define byte (8 bits)
                                                        ; Declare hw to be "Hello, world!"
                                                        ; 10 = "\n" (newline character)
rl:         db          0

            section     .text
_start:
            mov         rsi,    str
            call        stdout          ; Write to STDOUT
            call        stdin
            call        stdout

            jmp         ExitSuccess     ; Return with exit code 0
strlen:
            push        rsi             ; Save string to stack
strlen_next:
            cmp         [rsi], byte 0   ; Compare char to null byte
            jz          strlen_null     ; Jump if null byte

            inc         rcx             ; Char wasn't null, increment rcx (string length)
            inc         rsi             ; Next char
            jmp         strlen_next     ; Repeat, until we get a null byte
strlen_null:
            pop         rsi             ; Load string from the stack
            ret                         ; Return to call
stdin:
            mov         rax,    0
            mov         rdi,    0
            mov         rsi,    rl
            mov         rdx,    strlen
            syscall
            ret
stdout:
            mov         rax,    1       ; syscall write
            mov         rdi,    1       ; File descriptor STDOUT
            call        strlen          ; String length of rsi
            mov         rdx,    rcx     ; Move strlen of rsi into rdx
            syscall

            ret
ExitSuccess:
            mov         rax,    60      ; syscall exit
            mov         rdi,    0       ; Move exit code into rdi
            syscall
ghhkc1vu

ghhkc1vu1#

必须做出两项改变:首先,我需要修复strlen函数。(我已经重命名为_strlen)问题是,我忘记了设置rcx为零之前,我开始计数,最后,直接在我们做stdinsyscall,然后添加一个空字节在缓冲区的末尾。(mov byte [rsi+rax-1], 0

;##################################################################################################################################
;
; hello.asm
;
; 15/09/2023
;
; Logan Seeley
;
; Compiling:
;   Create object file:     $ nasm -f elf64 hello.asm
;   Link object file:       $ ld -m elf_x86_64 hello.o -o hello
;   Execute file:           $ ./hello
;   Print exit code:        $ printf "\n[Process finished with exit code $?]\n"
;
;   All in one command:
;   $ nasm -f elf64 hello.asm; ld -m elf_x86_64 hello.o -o hello; ./hello; printf "\n\n[Process finished with exit code $?]\n"
;
;   TODO:  Use call-preserved registers RBX, RBP, RSP, and R12-R15 for functions instead of using RDI, RSI, RDX, RCX, R8, R9
;           RBX, RBP and RSP should be used for args
;           R12-15 should be used for return values
;
;##################################################################################################################################

            global    _start

            section     .data
prompt:     db          "What is your name?", 10, 0     ; db: Define byte (8 bits)
                                                        ; Declare prompt to be "What is your name?"
                                                        ; 10 = "\n" (newline character)
                                                        ; 0  = null-byte (for zero-termination)
hello:     db         "Hello, ", 0

bufsize     equ         2048
rl:         resb        bufsize

            section     .text
_start:
            mov         rsi,    prompt  ; Move string into rsi to be written to STDOUT
            call        stdout          ; Write to STDOUT
            call        stdin
            mov         rsi,    hello
            call        stdout
            mov         rsi,    rl      ; Move input into rsi
            call        stdout

            jmp         ExitSuccess     ; Return with exit code 0
_strlen:
            xor         rcx,    rcx     ; Move 0 into rcx so we count up from 0
            push        rsi             ; Save string to stack
strlen_next:
            cmp         [rsi], byte 0   ; Compare char to null byte
            jz          strlen_null     ; Jump if null byte

            inc         rcx             ; Char wasn't null, increment rcx (string length)
            inc         rsi             ; Next char
            jmp         strlen_next     ; Repeat, until we get a null byte
strlen_null:
            pop         rsi             ; Load string from the stack
            ret                         ; Return to call
stdin:
            mov         rax,    0
            mov         rdi,    0
            mov         rsi,    rl
            mov         rdx,    _strlen
            syscall
            mov         byte [rsi+rax-1], 0     ; Setting last character of buffer to null-byte
                                                ; Replacing last character instead of concatting,
                                                ; because last character is a newline from user pressing enter
            ret
stdout:
            mov         rax,    1       ; syscall write
            mov         rdi,    1       ; File descriptor STDOUT
            call        _strlen         ; String length of rsi
            mov         rdx,    rcx     ; Move strlen of rsi into rdx
            syscall

            ret
ExitSuccess:
            mov         rax,    60      ; syscall exit
            mov         rdi,    0       ; Move exit code into rdi
            syscall

相关问题