INF1018 - Software Básico

Compilação e Ligação

  1. Considere o programa formado pelos arquivos abaixo:

    • arquivo temp1.c:

      #include <stdio.h>
      #include "temp1.h"
      #include "temp2.h"
      
      int a = 1024;
      
      int main (void) {
        foo();
        printf("%d\n", a);
        return 0;
      }
      
    • arquivo temp2.c:

      #include "temp1.h"
      #include "temp2.h"
      
      int b = 10;
      
      void foo (void) {
        a = -3;
      }
      
    • arquivo temp1.h:

      extern int a;
      
    • arquivo temp2.h:

      extern int b;
      void foo(void);
      

    Note que os arquivos temp1.h e temp2.h contém declarações dos simbolos globais exportados, respectivamente, por temp1.c e temp2.c A inclusão desses arquivos garante a consistência dessas declarações entre os módulos, tanto para os arquivos que definem os símbolos quanto para os que os importam.

    Compile, ligue e execute esse programa, seguindo os passos abaixo:
    > gcc -m32 -c -Wall temp1.c
    > gcc -m32 -c -Wall temp2.c
    > gcc -m32 -o prog  temp1.o temp2.o
    
    (Você poderia fazer tudo de uma só vez chamando gcc -m32 -Wall temp1.c temp2.c, mas aí o gcc não gera os arquivos .o.)
  2. Use o programa nm para inspecionar os símbolos usados por cada módulo (chame nm temp1.o e nm temp2.o). Você consegue inferir o significado das letras que aparecem na saída deste programa (U, T, etc.)? (Dica: "man nm".)

  3. Troque no 1o arquivo (temp1.c) a linha int a = 1024; por char a = 1; e recompile esse módulo. O que acontece?

    Você percebe como a inclusão dos arquivos de header inclusive pelos módulos que definem os símbolos garante a consistência das declarações?

  4. Restabeleça no arquivo temp1.c declaração int a = 1024;

    • Troque no 2o arquivo (temp2.c) a linha #include "temp1.h" por extern char a; Recompile e execute o programa. O que aconteceu? Você consegue explicar?
    • Agora troque a declaração extern char a; por char a = 0; e recompile o programa. O que acontece?
    • E se a troca for por static char a = 0;, o que acontece? Certifique-se que você entendeu o que aconteceu! (Dê uma olhada nos símbolos de cada módulo usando o nm).

  5. Restaure a inclusão de "temp1.h" no 2o arquivo (temp2.c), e remova a declaração "local" static char a = 0;.

    Agora remova no primeiro arquivo (temp1.c) a linha #include "temp2.h" (isto é, a declaração dos símbolos exportados por temp2).

    Troque em temp1.c a linha foo(); por b(); Recompile e execute o programa. (Atenção: Gere o executável com gcc -m32 -o prog -Wa,--execstack temp1.c temp2.c) . O que acontece?

    Repita com o valor inicial de b sendo 0xC3. O que acontece agora?

    Certifique-se que você entendeu o que aconteceu nos dois casos!