;===========INFORMACOES========================================
;
;	DUMP.ASM
;	Programa feito por PHDataflex
;	fev/2004
;	e-mail: phdataflex@hotmail.com
;	COMPILADOR: NASM / LINUX
;	LINKER: LD
;	nasm -f elf dump.asm
;	ld nasm.o -e _start -o dump
;
;==========DADOS================================================

section .data

	msg1		db 	"Usage dump <arquivo>",0xa
	len_msg1	equ 	$ - msg1
	msg2		db	"Erro ao abrir arquivo",0xa
	len_msg2	equ	$ - msg2
	NUM_ARG		equ 	1
	FD1		dd	0
	nome_arq	dd	0
	len_arq		dd	0
	nome_meu	dd	0
	len_meu		dd	0
	numread		dd	0
	offset		dd	0
	buffer:		times	16	db	0;	semelhante a 16 dup (?), aloca 16 bytes 	
	len_buffer	equ	$ - buffer
	hex_table	db	'0','1','2','3'
			db	'4','5','6','7'
			db	'8','9','A','B'
			db	'C','D','E','F'
	aux_hex_value	times	10	db	0
	hex_value	times	10	db	0

;==========CODIGO===============================================

section	.text

	global _start		;declarado devido ao linker (ld)

_start:				;ponto de entrada do programa
	pop	ecx		;pop argc
	dec	ecx     	;desconta o nome do programa
	cmp	ecx,NUM_ARG	;verifica se o numero de argumentos esta certo
	jne	near usage	;se nao esta certo cai fora
	pop	ecx		;pegamos nosso nome
	mov	[nome_meu],ecx	;salvamos nosso nome argv[0]
	mov	esi,ecx
	call	strlen		;calculamos o tamanho de argv[0]
	mov	[len_meu],eax
	pop	ecx		;pop o argumento
	mov	[nome_arq],ecx	;salvamos o argumento argv[1]
	mov	esi,ecx
	call	strlen		;calculamos o tamanho de argv[1]
	mov	[len_arq],eax
	mov	ebx,[nome_arq]
	mov	ecx,0
	mov	edx,0
	call	fopen		;abre o arquivo passado por parametro
	cmp	eax,0		;se não consegue abrir cai fora
	jl	near errarq
	mov 	[FD1],eax	;salva o FD (descritor) do arquivo
print_buffer:
	mov	ebx,[FD1]
	mov	ecx,buffer
	mov	edx,len_buffer
	call	fread		;le 16 bytes para o buffer
	mov	[numread],eax
	cmp	eax,0		;se nao leu nada cai fora
	jle	near end_print
	;-----------GERA A LISTAGEM (1 linha)----------------------------------------
	mov	eax,[offset]
	mov	ebx,8
	call	int_to_hex	;offset
	mov	bl,':'
	mov	ecx,1
	call	print_char	;':' depois do offset
	mov	bl,' '
	mov	ecx,3
	call	print_char      ;3 espacos
	mov	esi,buffer
	mov	ecx,[numread]	
print_hex_bytes:
	push	ecx		;salva ecx = numero de bytes para imprimir = NUMREAD
	push	esi		;salva esi = endereco de buffer
	xor	eax,eax
	mov	al,[esi]
	mov	ebx,2
	call	int_to_hex	;imprime o byte lido
	mov	bl,' '
	mov	ecx,1
	call	print_char	;1 espaco para separar
	pop	esi		;recupero o valor de esi = endereco do buffer
	inc	esi		;aponto para o proximo elemento do buffer
	pop	ecx		;recupero o numero de bytes lidos
	dec	ecx
	cmp	ecx,0		;verifica se tem bytes para imprimir ainda
	jg	print_hex_bytes
	push	ecx
	mov	bl,' '
	mov	ecx,3
	call	print_char	;separa com 3 espacos
	pop	ecx
	mov	ecx,[numread]
	sub	ecx,16
justifica:			;rotina pra alinhar com espacos
	cmp	ecx,0		;se le menos de 16 bytes imprime espacos pra alinhar
	jge	espacos_ok
	push	ecx
	mov	bl,' '
	mov	ecx,3
	call	print_char
	pop	ecx
	inc	ecx
	jmp	justifica
espacos_ok:
	mov	esi,buffer
	mov	ecx,[numread]
print_str_bytes:		;rotina pra imprimir em forma de ASCII
	mov	al,[esi]	;verifica se o caracter é imprimivel senao imprime "."
	cmp	al,0x20
	jl	not_printable	
	cmp	al,0x7f
	jge	not_printable
printable:
	push	ecx
	mov	bl,al
	mov	ecx,1
	call	print_char	;imprime o caracter ASCII
	inc	esi
	pop	ecx
	dec	ecx
	cmp	ecx,0
	jg	print_str_bytes
	jmp end_print_loop
	not_printable:
	mov	al,'.'
	jmp	printable
end_print_loop:
	mov	bl,0xa
	mov	ecx,1
	call	print_char	;quebra a linha
	;------------------------------------------------------------------------------
	mov	eax,[numread]
	cmp	eax,len_buffer	;o valor lido = tamanho do buffer?
	jne	end_print	;se não é igual sai do loop
	mov	ecx,16
	add	[offset],ecx	;offset += 16
	jmp	print_buffer
end_print:
	mov	ebx,[FD1]
	call	fclose		;fecha o arquivo aberto
	jmp	exit
errarq:				;mensagem erro ao abrir arquivo
	mov	ecx,msg2
	mov	edx,len_msg2
	call	print
	jmp	exit
usage:				;mensagem usage se o numero de parametro é invalido
	mov	ecx,msg1
	mov	edx,len_msg1
	call	print
exit:
	mov	eax,1		;system call (sys_exit)
	int	0x80

;================SUBROTINAS=====================================

int_to_hex:

	;--- Imprime um inteiro  em formato hex
	;--- eax --> contem o inteiro pra imprimir
	;--- ebx --> tamanho maximo da string de HEX, preenchida c/"0"s a esq.
	;--- Retorna nada
	push	ecx
	push	edx
	push	esi
	push	edi
	xor	edi,edi			;edi =  numero de caractreres impressos
	mov	esi,aux_hex_value	;esi contem o endereco de hex_value
	dec	esi
	L3:
	inc	esi
	inc	edi
	xor	edx,edx
	mov	ecx,16
	div	ecx
	push	eax
	mov	al,[hex_table+edx]	;edx contem eax % 16 (resto)
	mov	[esi],al		;salvo o char em aux_hex_value
	pop	eax
	cmp	eax,0			;a divisao resulta em zero?
	jg	L3
	L4:	
	cmp	edi,ebx			;loop para mascarar com '0' a esquerda
	jge	L5
	inc	esi
	mov	al,'0'
	mov	[esi],al
	inc	edi
	jmp	L4
	L5:
	push	edi			;salvo edi = strlen(aux_hex_value)
	mov	ecx,edi
	dec	ecx			;ecx = indice em aux_hex_value
	xor	ebx,ebx			;ebx = indice em hex_value = 0
	mov	esi,aux_hex_value	;esi = endereco de aux_hex_value
	mov	edi,hex_value		;edi = endereco de hex_value
	L6:				;loop pra inveter aux_hex_value
	mov	al,[esi+ecx]		;vai pegando char de aux_hex_value do final pra tras
	mov	[edi+ebx],al		;e colocando em hex_value do comeco pra frente
	dec	ecx
	inc	ebx
	cmp	ecx,0			;o indice em aux_hex_value = 0? 
	jge	L6			;se indice > 0 continua o loop ;********
	pop	edi
	mov	ecx,hex_value		;finalmente imprime a string que contem o hex
	mov	edx,edi
	call	print
	pop	edi
	pop	esi
	pop	edx
	pop	ecx
	ret

print_char:
	;--- Imprime um char N vezes
	;--- Parametros
	;--- bl  --> byte para imprimir 
	;--- ecx --> numero de repeticoes
	;--- Retorna nada
	
	MAX_REP	equ	255

	cmp	ecx,MAX_REP		;verifica se nao ultrapassa o tamanho maximo
	jg	end_print_char
	push	ebp
	mov	ebp,esp
	push	edx
	push	ecx
	push	edi
	sub	esp,MAX_REP
	mov	edi,esp
	push	ecx			;salvo ecx = numero de repeticoes
	push	edi			;endereco da string alocada
	L7:				;loop pra copiar o caracter N vezes na string alocada
	mov	[edi],bl
	inc	edi
	dec	ecx
	cmp	ecx,0
	jg	L7
	pop	edi
	pop	ecx
	mov	edx,ecx
	mov	ecx,edi
	call	print			;imprimo a string alocada
	add	esp,MAX_REP
	pop	edi
	pop	ecx
	pop	edx
	pop	ebp
	end_print_char:
	ret

print:

	;--- Imprime uma string
	;--- Parametros
	;--- ecx --> endereco da string
	;--- edx --> tamanho da string
	;--- Retorna nada
	push	eax
	push	ebx
	mov	eax,4
	mov	ebx,1
	int	0x80
	pop	ebx
	pop	eax
	ret

strlen:

	;--- Parametro
	;--- esi --> endereco da string
	;--- Retorna em eax o tamanho da string
	push	ecx
	push	edi
	xor ecx,ecx
	L1:
	lodsb
	cmp	al,0
	je 	L2
	inc	ecx
	jmp	L1
	L2:
	mov	eax,ecx
	pop	edi
	pop	ecx
	ret

fopen:

	;--- Parametro
	;--- ebx --> nome do arquivo
	;--- ecx --> flags
	;--- edx --> modo
	;--- Retorna FD em AX ou erro ( <0 )
	mov	eax,5
	int	0x80
	ret

fread:
	;--- Parametro
	;--- ebx --> FD descritor do arquivo
	;--- ecx --> Buffer pra leitura
	;--- edx --> numero de bytes para ler
	;--- Retorna em eax o numero de bytes lido ou erro ( <0 )
	mov	eax,3
	int	0x80
	ret

fclose:
	
	;--- Parametro
	;--- ebx --> descritor de arquivo
	;--- retorna eax = 0 se sucesso
	;--- retorna eax < 0 se erro
	mov	eax,6
	int	0x80
	ret

;==============EOF=============================================
