;compilar:   nasm -f elfx readfileFix.asm  onde x=32 ou x=64
;linkeditar: gcc -no-pie readfileNewFix.o  -o readfileNewFix
;executar:   ./readfileNewFix


;=========================================================================================================  
;AS MACROS DEVEM SER DECLARADAS ANTES DOS section
;=========================================================================================================  
;extern printf 

%include "mymacros.inc"   ;INCLUI UM ARQUIVO DE MACROS DE NOME mymacros.inc

section .data
  ;=========================================================================================================
  ;Na plataforma windows, o pulo de linha deveria ser a junção do codigo 10 (0xA) e o codigo 13 (0xD)
  ;No linux, só precisa do 10

  msgLendo              db 'Lendo o arquivo',10   ;definição de uma string
                          
  ;=========================================================================================================  
  ;CALCULO DO TAMANHO DE UMA STRING
  ;O $ é entendido pelo nasm como posicao após a string msgLendo. msgLendo tem tamanho 16, incluindo o valor 10
  ;Supondo que msgLendo começasse no endereço DS:0035, iria até DS:0050. Assim, 0051-0035=16
  ;Exemplo : str db 'Teste', que começasse numa posição 15 da memória
  ;                  15 :16 : 17:18 :19 :20
  ;                   |   |   |   |   |  |
  ;                   v   v   v   v   v  v 
  ;Seria assim, str=|'T'|'e'|'s'|'t'|'e'|$|
  ;                                          
  TAM_MSG_LENDO         equ $-msgLendo  
  buffLeitura  times 80 db 0     ;preenche um vetor com 80 zeros
  TAM_BUFF_READ         equ 80            ;declaração de constante (em  C, seria #define TAM_BUFF_READ 80)
  arquivo               db 'teste.txt',0 ; esse zero é algo semelhante ao '\0' da linguagem C
  nl                    db 10,0          ; nova linha
  
  fd                    db 0 
  tamLido               db 0    ;variável para guardar a quantidade de caracteres lida (tamanho lido)
    
  strArquivo  times 30  db 0
  
  ;=========================================================================================================
  ;Valores de serviço syscall
  ;=========================================================================================================
  READ  equ     0 
  WRITE equ     1
  OPEN  equ     2
  CLOSE equ     3
  EXIT  equ    60
  CREAT equ    85
  

  ;=========================================================================================================
  ;Define entrada e saida padrão
  ;========================================================================================================= 

  TECLADO equ 0
  TELA    equ 1

  ;=========================================================================================================
  ;Valores para MODO de acesso. Quando abrimos um arquivo em READ_ONLY outro usuario nao pode alterá-lo
  ;========================================================================================================= 
  
  O_RDONLY              equ 0    ;somente leitura
  O_WRONLY              equ 1    ;somente escrita
  O_RDWR                equ 2    ;leitura e escrita
  O_TRUNC               equ 512  ;abre e limpa o arquivo
  O_APPEND              equ 1024 ;inserir no final
  
  ;**********************************************************************************************************
  ;MODO                  db O_RDWR   ;leitura e escrita, funciona quando se usa tipo .str 
  ;**********************************************************************************************************

  ;=========================================================================================================
  ;VALORES DE MODO DE ACESSO EM DECIMAL E OCTAL (começa com 0 é octal)
  ;=========================================================================================================
  ;ACESSO     	   DECIMAL	          OCTAL 
  ;O_RDONLY     	     0               00
  ;O_WRONLY       	     1               01
  ;O_RDWR      		     2               02
  ;O_CREAT        	    64             0100
  ;O_EXCL              128             0200
  ;O_TRUNC             512            01000
  ;O_APPEND           1024            02000
  ;O_DIRECT          16384           040000
  ;O_NOFOLLOW       131072          0400000
  ;O_FSYNC         1052672         04010000
  ;---------------------------------------------------------------------------------------------------------
  ;=========================================================================================================
  ;VALORES DE PERMISSAO DE ARQUIVO
  ;=========================================================================================================
  ;  USER  | GROUP  | OTHER
  ; R W X  | R W X  | R W X 
  ; A permissao é composta de 9 bits, 3 para USER, 3 para GROUP, e 3 para OTHER
  ; Por exemplo, se somente W e X de USER estivessem setados, o valor de permissao seria 011 000 000.
  ; Isso é equivalente em decimal a 0300, coloca-se um zero antes, por comodidade.
  ; Repare que se somente W fosse setado, teria o valor 2 ou 010, se somente R fosse setado, teria o valor
  ; 4, se somente X fosse setado, teria o valor 1. Assim 011=3, ou seja 2+1=3. Logo associamos os valores 
  ; R=4, W=2, X=1, em ordem decrescente de potência  de 2. Logo, se quero leitura e escrita e execução 
  ; para USER e somente leitura e execução para GROUP teríamos 0750. É assim no linux, com a atribuição 
  ; pelo comando chmod. Para o caso, em nasm, o valor seria 0750o ou 0o0750 ou 0750q ou 0q0750
  ; ======================================================================================================== 
  
;end .data

;************************************************************************************************************
;MAIS INFORMACOES SOBRE ARQUIVOS OU FICHEIROS
;http://web.fe.up.pt/~jmcruz/etc/unix/Unix.pdf
;http://www.gsp.com/cgi-bin/man.cgi?section=2&topic=open
;************************************************************************************************************


section .text
  global _start
 
_start:
     
  push rbp
  
  PRINT "Entre com o nome do arquivo: "
  
  ;----------------------------------------------------------------------
  ;Na entrada de dados teclado a função read inclui o ENTER como um '\n'
  ;Assim, se entrar com "teste", ele guardará "teste\n" e retornará em
  ;retornará em rax o valor 6 e não 5, que seria o tamanho lido.
  ;                 |0|1|2|3|4| 5|, 6 bytes
  ;                 |t|e|s|t|e|\n|
  ;Logo, precisamos colocar um 0 ('\0' em C) na posiçao 5.
  ;                 |t|e|s|t|e|\0|
  ;----------------------------------------------------------------------  
  
  _readFile TECLADO,strArquivo,30
  mov byte [strArquivo+rax-1],0  ; em C strArquivo[rax-1]='\0' ou *(strArquivo+rax-1)='\0'
  

  ;fd=open(arquivo,O_RDONLY) retorna fd em rax
  _open strArquivo, O_RDONLY
      
  mov byte [fd],al    ; salva fd, que tem tamanho no maximo 1 byte 
      
  cmp rax,0
  jb ERRO_ABERTURA ;salta para o label ERRO_ABERTURA se eax < 0 (jump if below, salta se abaixo)
  
  ;tamLido=read(fd,buffLeitura, TAM_BUFF_READ), retorna quantidade lida em rax,
  ;o conteúdo lido fica em buffLeitura
  
  movsx rbx, byte [fd]
  _readFile rbx,buffLeitura,TAM_BUFF_READ 
   
  ;------------------------------------------------------------------------------
  ;SALVANDO O TAMANHO LIDO
  ;------------------------------------------------------------------------------
  mov byte [tamLido], al ; salva o tamanho lido (cabe em um byte)
  cmp rax,0          ; verifica se conseguiu ler algo
  jb ERRO_LEITURA    ; salta para rotina de erro de leitura se algo deu errado
  
  ;----------------------------------------------------------------------------
  ;AGORA VAMOS IMPRIMIR O QUE FOI LIDO NO buffLeitura
  ;----------------------------------------------------------------------------
  movsx rbx, byte [tamLido]
  _printf buffLeitura, rbx
    
  ;IMPRIME UM '\n'
  _printf nl,1  
  
  ;----------------------------------------------------------------------------
  ;FECHA O ARQUIVO
  ;----------------------------------------------------------------------------
  ;ret=close(fd), retorna em rax -1 se deu errado
  movsx rcx, byte [fd]
  _closeFile fd 
  
  ;SAIDA com sucesso
  pop rbp
  _exit 0      ;chama macro _exit, exit(0), saida OK
 
ERRO_ABERTURA:
  ;syscall write(1)
  PRINT "Erro na abertura do arquivo"
  jmp SAI  

ERRO_LEITURA:
  PRINT "Erro na leitura do arquivo"
  
SAI:
  pop rbp
  _exit 1 ;exit(60), deu caca

;end .text  





