#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:
никогда не будут достигнуты. Это мертвый код. Так почему они там?