02 - Representação de dados em RAM¶
Experimentos¶
Vamos trabalhar com os arquivos experimento0-4.c
. Compile e execute cada um deles, execute e analise suas saídas. Comente os resultados comparando os valores das constantes no código em C e a saída dos programas. Tente entender o que está acontecendo.
Para compilar cada .c
, utilize:
$ gcc -Wall -pedantic experimento0.c -o e0
Exercise
Examine o código C do arquivo experimento0.c e compare com o resultado de sua execução. Há algo estranho? Se sim, escreva abaixo algumas hipóteses para o comportamento do programa.
Exercise
Examine o código C do arquivo experimento1.c e compare com o resultado de sua execução. Há algo estranho? Se sim, escreva abaixo algumas hipóteses para o comportamento do programa.
Exercise
Examine o código C do arquivo experimento2.c e compare com o resultado de sua execução. Há algo estranho? Se sim, escreva abaixo algumas hipóteses para o comportamento do programa.
Exercise
Examine o código C do arquivo experimento3.c e compare com o resultado de sua execução. Há algo estranho? Se sim, escreva abaixo algumas hipóteses para o comportamento do programa.
Exercise
Examine o código C do arquivo experimento4.c e compare com o resultado de sua execução. Há algo estranho? Se sim, escreva abaixo algumas hipóteses para o comportamento do programa.
Representação de struct
em RAM¶
A utilização de struct
junta tudo que já vimos sobre representação de todos os tipos de dados na memória. Não se esqueça de levar em conta as questões de alinhamento mostradas na parte expositiva da aula.
Atenção!
Você não deverá abrir o código de parte1.c
. Ele está no repositório para você poder conferir suas respostas.
Vamos compilar?!
Compile e execute parte1.c.
Exercise
Os endereços mostrados na saída de parte1
pertencem a um só struct declarado como struct player one
. Quais são os tamanhos de cada campo?
Dica: pode não ser possível identificar exatamente o tamanho de cada campo, mas é esperado que você identifique ao menos o tamanho máximo de cada um.
Exercise
A segunda parte da saída de parte1
mostra os endereços de cada campo do struct. Note que &one
e &one.icon
são iguais. Você consegue explicar por que? Se não, volte na aula expositiva e reveja a parte sobre struct
e alinhamento de memória.
Exercise
Baseado nas respostas acima, declare abaixo o struct
. Escreva-o da mesma maneira que usaria em um programa em C.
Hora de conferir!
Agora confira suas respostas no arquivo parte1.c.
Examinando a execução de programas usando gdb
¶
Podemos examinar um programa durante sua execução usando o gdb. Podemos parar em qualquer instrução do programa, examinar conteúdo de registradores e da memória e listar todos os símbolos disponíveis (que podem ser funções ou variáveis globais).
Dica!
Para compilar um programa com suporte a debugging usamos a flag -g
do gcc
$ gcc -g -Wall -pedantic parte2.c -o parte2
Siga os passos para para carregar um programa usando o gdb:
-
Lance o
gdb
e passe para ele seu programa:$ gdb ./parte2
-
Para sair, utilize:
(gdb) quit
Tip
O gdb é uma ferramenta poderosa que possui muitas opções. Sua documentação está online e pode ser vista em https://sourceware.org/gdb/onlinedocs/gdb/index.html#Top.
Nesta primeira parte iremos abrir o arquivo parte2.c e olhar seu conteúdo. Também executaremos o programa compilado parte2.
Exercise
Abra o código parte2.c e liste os nomes das variáveis globais declaradas e seus tamanhos. Anote também as funções declaradas.
Atenção, tarefa dupla!
Para os próximos exercícios, compile o arquivo parte2.c
com e sem debugging e repita cada exercício com ambas as versões do executável. Exemplo de compilação:
$ gcc -g -Wall -pedantic parte2.c -o parte2_debug
$ gcc -Wall -pedantic parte2.c -o parte2_semdebug
Exercise
O comando info mostra informações que podem ser obtidas a partir de um executável. Execute-o e veja o que acontece.
Exercise
Use info
para mostrar as funções e variáveis globais que existem em parte2
. Lembre de fazer tanto na versão com quanto na sem debugging!
Muita informação!
Muitos nomes são estranhos. Eles fazem parte do padrão de arquivos executáveis ELF, que contém informações específicas do sistema operacional usado. Você não precisa se preocupar com estes nomes.
Exercise
Qual é o significado da primeira coluna do comando info variables?
Dica: o valor está em hexadecimal, que usamos na expositiva para mostrar ponteiros.
Exercise
Podemos usar o comando print para mostrar o valor inicial das variáveis globais identificadas. Mostre o valor inicial de global_var
usando este comando e compare com o visto no arquivo parte2.c.
Dicas:
- Pode não funcionar de primeira. O quê a mensagem de erro diz?
- A sintaxe de conversão de tipos de C (casting) pode ser útil aqui.
Exercise
Podemos usar o gdb também para examinar a memória de um executável. Acesse esta página da documentação, entenda como usar o comando x
e escreva abaixo qual o comando usado para mostrar o conteúdo do segundo item do vetor global_array
. Em seguida, teste-o e garanta que funcionou corretamente.
Link: https://sourceware.org/gdb/onlinedocs/gdb/Memory.html
Dicas:
- volte nos exercícios anteriores e encontre o endereço do início do vetor
- calcule o endereço do segundo elemento manualmente e passe para o comando
x
- não se esqueça de buscar na memória o tamanho correto do elemento
Exercise
global_array
tem tipo short
. Ou seja, é formado por dois bytes. Mostre agora o conteúdo de cada um deles. Ou seja, você deverá dar dois comandos para examinar a memória. Explique como converter esses dois bytes para o valor mostrado no exercício anterior.
Exercise
Use agora o comando x
para exibir global_str
como uma string. Escreva o comando abaixo.