INF1018 - Software Básico

Chamadas ao Sistema Operacional em Assembly

Nesse laboratório vamos explorar a interface com o sistema operacional.

  1. Para começar, pegue o programa em C, que copia o arquivo dado na linha de comando para a saída padrão (tela), e salve-o em um arquivo copia.c. Compile e execute esse programa, testando-o com algum arquivos de entrada (pode ser o próprio arquivo copia.c):

    > gcc -Wall -o copia copia.c
    > ./copia copia.c
    
  2. Observe o código de copia.c. A rotina main chama quatro funções definidas neste mesmo arquivo: myopen, myread, mywrite e myclose. Cada uma dessas funções é implementada por uma única linha, que contém uma chamada ao sistema operacional (na verdade, uma chamada a uma função wrapper, provida pela biblioteca padrão de C).

    As chamadas ao sistema operacional são documentadas na seção 2 do manual do Linux. Para ver a documentação de uma delas, basta escrever, por exemplo:

    > man 2 open
    
  3. Agora você deve substituir cada uma das funções (myopen, myread, mywrite e myclose) por funções equivalentes a elas, escritas em assembly.

    Atenção: suas funções assembly não devem chamar as funções da biblioteca de C! Elas devem usar uma interface direta com o SO.

    Crie um arquivo chamadas.s, e comece substituindo a função myopen. Comente a definição dessa função no arquivo copia.c, mantendo o seu protótipo. Implemente myopen em assembly (ver instruções abaixo), e compile tudo agora com:

    > gcc -Wall -o copia chamadas.s copia.c
    
    Para descobrir o código das chamadas ao sistema, consulte esta tabela de chamadas.

    Observe os seguinte pontos:

    • Para ativar o sistema você vai usar a instrução syscall
    • O código da chamada (open, read, etc) deve ser passado em %rax.
    • Os parâmetros da são passados em %rdi, %rsi, %rdx, %r10, %r8 e %r9, nesta ordem.
    • Não se esqueça de observar as convenções de C

  4. Vá comentando, uma a uma, a definição das demais funções no arquivo copia.c e substituindo-as pela implementação em assembly em chamadas.s.

    A implementação em assembly de chamadas a serviços do sistema operacional que você acabou de fazer é semelhante à implementação das funções wrapper disponíveis na biblioteca padrão de C.

  5. Agora escreva em assembly uma função myotherwrite, que receba um descritor de arquivo e uma string, e escreva essa string string no arquivo fornecido, usando uma chamada direta ao sistema operacional:
    int myotherwrite (int fd, char *s);
    
    Dica: você deve calcular o tamanho da string para passar como terceiro parâmetro para a syscall! (não use uma função pronta, esse cálculo é muito simples...)

    Para testar sua função, você pode usar o código abaixo:

    #include <fcntl.h>
    #include <stdio.h>
    #include <unistd.h>
    
    #define MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)
    ssize_t myotherwrite(int fd, const void *buf);
    
    int main (int argc, char** argv) {                                            
      ssize_t tam;
      int arq;                                                                    
      char buf[] = "testando escrita direta\n";
    
      if (argc != 2) {                                                            
        fprintf(stderr,"forma correta: %s \n", argv[0]);       
        return 1;                                                                 
      }                                                                           
    
      arq = open (argv[1], O_CREAT|O_RDWR, MODE);
      if (arq<0) { perror("abertura de arquivo"); return 1;}                      
    
      if ((tam = myotherwrite (arq, buf)) != sizeof(buf)-1) {
        perror("escrita:"); 
        return 1;
      }                                        
      close (arq);                                                              
      return 0;   
    }