我正在尝试学习汇编,到目前为止我只使用了高级语言,如c或java。 我回顾了去年c中的一些作业,其中一个是制作命令行刽子手游戏,所以我想我会尝试在程序集中实现它。我正在尝试阅读.txt文件,但似乎并没有让它正常工作。出于测试目的,我只想将文件直接打印到终端,但由于某种原因,sys_read失败。
以下是代码:
SYS_EXIT equ 1 ; UNIX system call sys_exit
SYS_READ equ 3 ; UNIX System call sys_read
SYS_WRITE equ 4 ; UNIX System call sys_write
SYS_OPEN equ 5 ; UNIX System call sys_open
STDIN equ 0 ; File descriptor for Standard in stream
STDOUT equ 1 ; File descriptor for Standard out stream
; print to standard out macro
%macro print 2
pushad ; Save all regisers
mov eax, SYS_WRITE ; Write system call
mov ebx, STDOUT ; File descriptor for stdout
mov ecx, %1 ; Message to print as argument 1
mov edx, %2 ; Message length as argument 2
int 0x80 ; Call kernel
popad ; restore all registers
%endmacro
; print string to standard out macro
%macro print_str 1
section .data
%%str db %1 ; adress to hold string
%%strL equ $ - %%str ; length of string
section .text
print %%str, %%strL ; print string to stdout using print macro
%endmacro
; print newline
%macro println 0
section .data
%%strln db 0xA, 0xD ; adress to hold newline and carrige return
section .text
print %%strln, 2 ; print newline
%endmacro
; print string with trailing newline
%macro print_str_ln 1
section .data
%%str db %1 ; adress to hold string
%%strL equ $ - %%str ; length of string
section .text
print %%str, %%strL ; print string to stdout using print macro
println ; prints newline
%endmacro
; exit program
%macro exit 1
mov eax, SYS_EXIT ; Exit system call
mov ebx, $1 ; Return value
int 0x80 ; call kernel
%endmacro
section .text
global _start ; Required for linker (ld)
_start: ; Linker entry point
print_str_ln "Welcome to hangman" ; print message to user
println ; print newline
call open_file ; open file and read
exit 0 ; exit program
; Open the words list file
open_file:
mov eax, SYS_OPEN ; System call open
mov ebx, word_source_file ; Points to filepath
xor ecx, ecx ; O_RDONLY
xor edx, edx ; mode is ignored when O_CREATE isn't specified
int 0x80 ; call kernel
test eax, eax ; check output of SYS_OPEN
jns read_file ; If sign flag set, read file
print_str_ln "Could not open file" ; Print error message to user
exit 1 ; exit program
; read the file that was opened
read_file:
mov ebx, eax ; move file descriptor from eax to ebx
mov eax, SYS_READ ; system call SYS_READ
mov ecx, buffer ; The buffer
mov edx, bufferlen ; The length of the buffer
int 0x80 ; call kernel
test eax, eax ; check for errors
jz split_words ; If EOF return
print_str_ln "Counld not read file" ; Print error message
js exit 1 ; If read faild exit
; TESTING - Print contentsof buffer
split_words:
mov edx, eax ; The amount of bytes read, returned from sys_read
mov eax, SYS_WRITE ; System call sys_write
mov ebx, STDOUT ; File descriptor (stdout)
mov ecx, buffer ; The buffer
int 0x80 ; call kernel
ret ; return
section .bss
buffer resb 2048 ; A 2kb buffer ussed to read
section .data
bufferlen dw 2048 ; The length of buffer
newline db 0xA, 0xD ; Newline and carrige return
word_source_file db 'words.txt', 0 ; The path to the words file
现在,当我使用汇编程序和链接器并运行时,我得到:
$ nasm -f elf hangman.asm
$ ld -m elf_i386 -o hangman hangman.o
$ ./hangman
Welcome to hangman
Counld not read file
我不知道自己做错了什么,而且我还很擅长集会。 谢谢你的帮助。
答案 0 :(得分:1)
您应该学会使用调试器,这样您就可以修复自己的错误。但是,在这种情况下,打印的错误消息确切地指出了问题的位置,所以即使只是重新阅读你自己的评论,你也可以在头脑中做到这一点:
test eax, eax ; check for errors
jz split_words ; If EOF return
print_str_ln "Counld not read file" ; Print error message
js exit 1 ; If read faild exit
显然,读取会导致您认为错误以外的其他内容。它不是错误,系统调用返回读取的字节数。但是,鉴于split_words
处的代码块,您当然已经知道了。
长话短说:你可能想要jnz split_words
而不是jz split_words
。从长远来看,您可能需要多次read
次调用才能重复填充缓冲区。