x86_64 汇编器读取文件并将其打印到控制台

问题描述 投票:0回答:1

我必须编写一个程序,该程序逐个字符地读取给定文本文件并对其执行某些操作。

首先,我想打印每个字符并在到达文件末尾时停止。这两件事都不起作用。在较旧的程序中,我使用 rax 来检测何时到达文件末尾,但这在该程序中不起作用。 我还有一个问题,当我一次读入 char 时,程序会在每个字符之间打印一个点。当我一次读取多个字符时,不会出现此问题。

文件:Arcu scelerisque aliquam。 Nullam viverra magna vitae leo。 (...)

控制台:$ ./wortzaehl

输出:A.r.c.u. .s.c.e.l.e.

这是我当前的代码: (我使用了r9,因为我无法检测到文件结尾) (我知道这段代码可能效率很低)

%define STDOUT      1
%define STDIN       0
%define READONLY        0
%define SYS_READ        0
%define SYS_WRITE   1
%define SYS_OPEN    2
%define SYS_CLOSE       3
%define SYS_EXIT    60

section .data
newline:
    db 0x0a
space:
        db 0x20
tab:
        db 0x09


invalid_argument_text:
        db "No Path given"

section .bss
input_buffer:
    resb 1

section .text
    global _start

;;;================= Read/Write Functions =============================
write_invalid_arg:
    ;; save registers that are used in the code
    push    rax
    push    rdi
    push    rdx
    mov rax, SYS_WRITE
    mov rdi, STDOUT
    mov rsi, invalid_argument_text
    mov rdx, 13
    call    make_syscall
    pop rdx
    pop rdi
    pop rax
    jmp finish
    
write_newline:
    ;; save registers that are used in the code
    push    rax
    push    rdi
    push    rsi
    push    rdx
    ;; prepare arguments for write syscall
    mov rax, SYS_WRITE  ; write syscall
    mov rdi, STDOUT ; fd = 1 (stdout)
    mov rsi, newline    ; string
    mov rdx, 1      ; length

        call make_syscall

    ;; restore registers (in opposite order)
    pop rdx
    pop rsi
    pop rdi
    pop rax
    ret

write_char:
    push    rsi         ; speicher rsi
    mov rax, SYS_WRITE      ; Syscall Typ
    mov rdi, STDOUT     ; Out
    mov rsi, input_buffer   ; Aktuelle Zeile
    mov rdx, 1          ; Laenge der Zeile
    call    make_syscall        ; syscall
    pop rsi         ; Hol rsi zurueck
    ret

open_file:
        push    rdi
    push    rsi
    push    rdx
        mov     rax, SYS_OPEN      ; Datei oeffnen
        mov     rdi, rsi           ; Pfad zur Datei
        mov     rsi, READONLY      ; Nur lesen
        call    make_syscall
        mov     r11, rax
        pop     rdx
    pop     rsi
    pop     rdi
    ret

read_char:
        push    rdi
        push    rsi
        push    rdx
        mov     rdi, r11          ; Geoeffnete Datei
        mov     rax, SYS_READ
        mov     rsi, input_buffer
        mov     rdx, 1
        call    make_syscall
        pop     rdx
        pop     rsi
        pop     rdi

make_syscall:
        push    rcx     ; clobbered by syscall
    push    r11     ; clobbered by syscall
    syscall         ; system call
        pop r11
    pop rcx
    ret
; ======================================================


count_text:
        mov     r8, 0       ; Zeichen
        mov     r9, 0       ; Worte
        mov     r10, 0      ; Zeilen
        call    open_file
next_char:
        call    read_char
    
        cmp     r8, 10
        je      text_finished
    
        ;cmp        rax, 0
        ;jne        text_finished
        ;call    write_invalid_arg

        call    write_char
    
        inc     r8
    
        jmp     next_char
text_finished:
        ; Text schliessen
        mov     rax, SYS_CLOSE
        mov     rdi, r10
        call    make_syscall
        ret



;========================
_start:
    pop rbx         ; argc (>= 1 guaranteed) Anzahl Args
    
    dec rbx         ; remove command
    jz  write_invalid_arg   ; when no arg after command
    pop rsi         ; remove letters of command
    
    pop rsi         ; Pfad
    
    call   count_text
finish:
    call    write_newline
    ;; exit program via syscall exit (necessary!)
    mov rax, SYS_EXIT   ; exit syscall
    mov rdi, 0      ; exit code 0 (= "ok")
    syscall         ; kernel interrupt: system call

我做了一些测试,我认为输入缓冲区不仅包含读取的字符。当我执行以下操作时:

        mov     r15b, byte [input_buffer]
    mov rsi, r15            ; Aktuelle Zeile

唯一的输出是点

编辑:我忘记了 read_char 中的返回。现在唯一的问题是文件末尾的检测

linux assembly x86-64
1个回答
0
投票

我有两个问题:

  1. 程序在每个字符后打印出点
  2. 我无法检测到文件结尾

这两个问题都被一个错误解决了:我忘记了 read_char 中的“ret”。

cmp        rax, 0
jne        text_finished

我现在可以检测是否到达文件末尾。

© www.soinside.com 2019 - 2024. All rights reserved.