Сборка как подсчитать количество символов в файле и распечатать его на терминале

#linux #assembly #x86 #nasm

# #linux #сборка #x86 #nasm

Вопрос:

Я пытаюсь написать небольшую программу на ассемблере, которая получает имя файла и выводит содержимое файла на терминал или выводит количество символов в этом файле, если задан флаг «-c». печать содержимого файла работает отлично, но счетчик символов не работает — он ничего не печатает, и я не могу понять, почему.

Код:

 section .bss 
    array: resb 16 ; reserve byte - size 16
    buffer: resb 256;

section .data
    buffer_size: dw 256 

section .text
    global _start
    global read
    global write
    global open
    global close
    global strlen
    global utoa
    global read_file
    global print
    global read_file_with_flag
    global count_chars
    global open_with_flag
    global count

_start:
    pop  eax ;argc
    pop  eax ;argv[0]
    pop  eax ;argv[1]
    cmp eax ,'-c'
    je open_with_flag  
    push eax
    call open 

read_file:
    push buffer_size
    push buffer
    push eax
    call read
    cmp eax,0
    jg print
    call close
exit:
    mov ebx,eax
    mov eax,1
    int 0x80

print:
    push buffer_size
    push buffer
    push 1 ; flag descriptor of stdout
    call write
    call read_file

read:
    push ebp
    mov ebp,esp
    sub esp,4
    pushad
    mov eax, 3 ;  file descriptor 3 = read 
    ; EBX, ECX, EDX, ESI, EDI, and EBP. These registers take the consecutive arguments
    mov ebx, [ebp 8] ; file descriptor
    mov ecx, [ebp 12] ; buffer
    mov edx, [ebp 16] ; size
    int 0x80 ; transfer control to operating system 
    mov [ebp-4],eax ; save the result of the system call
    popad
    mov eax,[ebp-4] ; place returne value to eax so caller can use it 
    add esp,4       
    pop ebp
    ret ; eax hold how much was it read




write:
    push ebp
    mov ebp,esp
    sub esp,4
    pushad
    mov eax, 4 ;  file descriptor 4 = write 
    ; EBX, ECX, EDX, ESI, EDI, and EBP. These registers take the consecutive arguments
    mov ebx, [ebp 8] ; file descriptor
    mov ecx, [ebp 12] ; buffer
    mov edx, [ebp 16] ; size
    int 0x80 ; transfer control to operating system 
    mov [ebp-4],eax ; save the result of the system call
    popad
    mov eax,[ebp-4] ; place returne value to eax so caller can use it 
    add esp,4       
    pop ebp
    ret



open:
    push ebp
    mov ebp,esp
    sub esp,4 ; save 4 bits 
    pushad
    mov ebx, [ebp 8] ; move the file name into ebx
    mov ecx,[ebp 12] ; flags
    mov eax, 5 ; file descriptor 5 = open 
    int 0x80 ; transfer control to operating system 
    mov [ebp-4],eax ; save the result of the system call
    popad
    mov eax,[ebp-4] ; place returne value to eax so caller can use it 
    add esp,4 
    pop ebp
    ret

close:
    push ebp
    mov ebp,esp
    sub esp,4 ; save 4 bits 
    pushad
    mov ebx, [ebp 8]  ; move the file name into ebx
    mov eax, 6  ; file descriptor 5 = close 
    int 0x80 ; transfer control to operating system 
    mov [ebp-4],eax ; save the result of the system call
    popad
    mov eax,[ebp-4] ; place retunr value to eax so caller can use it 
    add esp,4          
    pop ebp
    ret

strlen:
    push ebp
    mov ebp, esp
    ;push ebx
    mov eax,-1

.L2:
    add eax, 1
    mov ebx, eax
    add ebx, [ebp 8]
    movzx ebx, BYTE [ebx]
    test bl,bl ; bl is the name of the low 8 bits (bits 7-0) in the ebx register
    jne .L2
    ;pop ebx
    mov esp, ebp
    pop ebp
    ret

; convert unsigned int to string
utoa:
    push ebp
    mov ebp,esp
    pushad ; push EAX, ECX, EDX, EBX, EBP, ESP (original value), EBP, ESI, and EDI
    mov ebx, 0 ; put 0 to ebx
    mov eax, [ebp 8] ; hold pointer to i 
    mov ebx, 10  ; divider 
    mov ecx, 0 ;counter num of divs

int_to_char:
    mov edx, 0 ; put 0 to edx to "clean" it        
    div ebx     ; div eax at 10(ebx), put the remain in edx
    add edx,'0' ; add 48 to the ASCII value - convert int to string
    push edx ;push the digit to the stack
    inc ecx  ; counter  
    test eax,eax ;check if end of num eax, if eax==0 - end of string
    jne int_to_char ; continu to next digit
    mov ebx,0 ;initial ebx
    mov edx,0   ;initial edx
chars_to_array:
    add ebx,array ; ebx point to the curr byte of the array 
    pop eax ;take first num from stack
    inc edx ; counter
    mov [ebx],eax ; copy the current char into the right place in the arrray  
    mov ebx,edx ; move the counter to ebx
    loop chars_to_array ; equals to dec ecs amp; JNZ l1 
    popad
    mov eax,array
    pop ebp
    ret

open_with_flag:
    pop  eax ; argv[2] - the file name 
    push eax ; put the -c flag to the button of the stack 
    call open
    mov ebx,0 ; clear ebx
    mov ecx,0 ; clear ecx
    mov edx,-1 ; reset edx to -1 

read_file_with_flag:
    push buffer_size
    push buffer
    push eax ; passing the File descriptor - 0 - no file, 1 - ok -1 - error open file
    call read
    cmp eax,0 ; check if read something
    jg count_chars
    push eax ; the num of chars in the file
    call utoa
    push 4 ; file descriptor 4 = write
    push array
    push 1 ; stdout
    call write
    call close
    mov ebx,eax
    mov eax,1
    int 0x80

count_chars:
    add edx,1 ; index of the buffer 
    mov ebx,edx ; ebx stores the address of the currnet buffer index 
    add ebx,buffer ; move to the next buffer address (buffer  ) 
    movzx ebx , BYTE[ebx] ; copy 1 char from the buffer to ebx
    dec eax ; eax hold how much left to read, eax--
    jmp count
    test eax, eax
    je read_file_with_flag

count:
    add ecx,1
    push ecx
    jmp count_chars
 

Комментарии:

1. Что происходит при подсчете символов? Нет вывода? Сбой? Неправильный подсчет?

2. @user176692 нет вывода, он печатает пустую строку.

3. После jmp count того, как у вас есть две инструкции, которые никогда не будут достигнуты. Почему они там?

4. @Michael это мой способ проверить, осталось ли еще что-то для подсчета, но я думаю, вы правы, это будет перезаписано функцией count . так что, может быть, мне нужно переместить это значение в другой регистр перед строкой подсчета jmp?

5. Я хотел сказать, что jmp это безусловно. Таким образом, две инструкции между jmp count и count: никогда не будут достигнуты. Это мертвый код. Так почему они там?