INF1018 - Software Básico

Exercícios de Revisão

  1. Considere o programa C a seguir:
    #include <stdio.h>
    void dump(void *p, int n) {
      unsigned char *p1 = (unsigned char *)p;
      while (n--) {
        printf("%p - %02x\n",p1,*p1);
        p1++;
      }
    }
    
    struct X {
      double d;
      float  f;
      short  s;
    } x = {-4.5, 9.75, -11};
    
    int main(void) {
      dump(&x, sizeof(x));
      return 0;
    }
    
    Considerando que x seja alocado na posição de memória 0x601040, mostre o que esse programa irá imprimir quando executado. Coloque PP nas posições correspondentes a padding. Suponha que a máquina de execução é little-endian e que as convenções de alinhamento são as do Linux em plataforma x86-64.

    Execute o programa e confira suas respostas.

  2. Reescreva a função foo abaixo em assembly e escreva uma função main em C para testá-la. Lembre de testar diferentes valores de entrada!

    double foo (double a, int b) {
      return a * (-b);
    }
    

  3. Reescreva agora em assembly a função pack abaixo, e escreva uma função main em C para testá-la (note que a função foo, chamada por pack, já foi testada no exercício anterior!). Para o teste de pack utilize uma lista de estruturas com pelo menos três elementos.

    struct X {
      int vi;
      double vd;
      struct X *next;
    };
    
    double pack (struct X *px) {
      double acc = 0;
      while (px != NULL) {
        acc += foo(px->vd, px->vi);
        px = px->next;
      }
      return acc;
    }
    

  4. Reescreva em assembly a função pack1 abaixo, e escreva uma função main em C para testá-la. A função foo, chamada por pack1, é a mesma do exercício 1.

    struct X1 {
      int vi;
      float vf;
    };
    
    double pack1 (struct X1 *px, int n) {
      double acc = 0;
      int i;
      for (i=0;i<n;i++)
        acc += foo(px[i].vf, px[i].vi);
      return acc;
    }
    

  5. Considere o módulo arq1.c abaixo:
    #include <string.h>
    #include <stdlib.h>
    
    extern int i;
    char *buff = NULL;
    static int k = 0;
    int f(char *p);
    
    int g(char *s1, char *s2) {
      int a = strlen(s1);
      int b = strlen(s2);
      buff = (char *) malloc(a + b + 1);
      strcat(strcpy(buff,s1), s2);
    
      k += a + b + i;
      return f(buff); 
    }
    
    Liste todos os símbolos exportados e importados pelo módulo objeto arq1.o, ou seja, o que seria listado na saída do programa nm como D ou B (símbolos da área de dados exportados), T (símbolos da área de texto/código exportados) e U (símbolos indefinidos/importados).

    Para conferir sua resposta, gere o arquivo objeto arq1.o compilando arq1.c com o comando

        gcc -c arq1.c
    
    e execute o programa nm para inspecionar a tabela de símbolos de arq1.o. Liste os símbolos exportados (definidos) por este módulo e os símbolos importados por ele (referências externas).

    Considere agora o módulo abaixo:

    #include <stdio.h>
    
    int g(char *s1, char *s2);
    
    int i = 0;
    int k = 0;
    char s1[] = "ola";
    char s2[] = " mundo";
    
    int f(char *p) {
      ...  /* algum código */
    }
    
    int main() {
      int j;
      ...
      j = g(s1, s2);
      printf("%d",k);
      ...
     }
    
    Se esse módulo fosse "ligado" com o módulo anterior para compor um executável, qual seria o resultado da chamada a printf?