装配新手。事实上,这是我的第一个 hello world 程序。 操作系统:Arch Linux(64位)
我有三个功能。
strlen
、stdin
和stdout
。
strlen
:
通过循环字节直到找到空字节来查找字符串的长度。
stdin
和 stdout
只需使用读写系统调用。
首先,我用
stdout
请求用户输入(不重要)
然后我使用 stdin
创建输入提示
stdin
将输入放入字符串中 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
必须进行两项更改: 首先,我需要修复
strlen
功能。 (我已将其重命名为_strlen
)
问题是我在开始计数之前忘记将 rcx
设置为零,
最后,在我们执行 syscall
中的 stdin
之后,我们会在缓冲区末尾添加一个空字节。
;##################################################################################################################################
;
; 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[Process finished with exit code $?]\n"
;
;##################################################################################################################################
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
push rcx ; Save whatever rcx has to the stack
mov rcx, 0
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 rcx ; Load whatever from the stack
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], 0
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