Estou depurando uma falha de segmentação em um programa em C++, mas primeiro estou tentando entender melhor como usar o comando gdb
para inspecionar o layout da memória no arquivo principal, produzido quando o processo sofre uma falha de segmentação. Estou usando o seguinte programa de brinquedo, que sofre uma falha de segmentação intencional, para entender gdb
melhor a saída do .
int main() {
int a = 4;
int b = 12;
*(int *)0 =11;
return a + b;
}
Quando abro o arquivo principal (usando gdb my_executable path/to/core.pid
), posso ver os endereços de memória que contêm os valores de a
e b
, o que faz sentido, já que sizeof(int) == 4
:
(gdb) p &a
$5 = (int *) 0x7ffff940e078
(gdb) p &b
$6 = (int *) 0x7ffff940e07c
E quando pergunto pelo conteúdo da memória começando por &a
isso, até que faz sentido, exceto que estou em uma máquina Intel, que deveria ser little endian, e parece que esses inteiros são big endian:
(gdb) x/4x &a
0x7ffff940e078: 0x00000004 0x0000000c 0xf940e120 0x00007fff
# (added by me) ---a==4--- --b==12--- other stuff ->
Então, se eu perguntar o conteúdo da memória começando no próximo endereço, eu esperaria o seguinte (todos os bytes se deslocam um para a esquerda):
(gdb) x/4x 0x7ffff940e079
0x7ffff940e079: 0x00000400 0x00000cf9 0x40e12000 0x007fff..
Mas o que gdb
realmente imprime é isto:
(gdb) x/4x 0x7ffff940e079
0x7ffff940e079: 0x0c000000 0x20000000 0xfff940e1 0xca00007f
# --b==12?-- other stuff ->
Parece que avançamos 7 bytes, ou 4 bytes, e agora b
é little endian. Mas a memória depois desse primeiro 0x0c
byte é diferente do que era no último comando (antes era, 0xf940e...
agora é 0x2000...
). Será que estou lendo a memória acidentalmente com alinhamento diferente? E alguém sabe por que os valores parecem ser big endian?
Estou compilando o código com g++
a versão 13.3.0 no Ubuntu 24.04, caso isso ajude.
Parece que você está interpretando mal a saída de depuração do GDB. Quando você dá a instrução
x/4x
e o gdb mostra0x00000004
, isso não significa que os bytes são00 00 00 04
. Em vez disso, significa que se você interpretar os próximos 4 bytes como um valor hexadecimal, será 0x00000004. Como seu sistema é little-endian, isso significa que os bytes reais sãoVocê pode confirmar isso invocando
x/17bx
o comentário de @ssbssa , que deve mostrar os bytes na ordem correta. Aqui, o prefixob
significa byte.Agora, se você deslocar um byte, os bytes serão reagrupados e reinterpretados, gerando o seguinte resultado:
O que é consistente com a sua observação. Nada de estranho como "pulamos 7 bytes para frente, ou que saltamos 4 bytes para frente e agora
b
é little endian" acontece.Não acho que isso seja exclusivo do GDB e acredito que outros dumpers hexadecimais também
objdump
tenham comportamento semelhante. Veja esta resposta para mais informações. Os dumpers hexadecimais provavelmente são projetados dessa forma para que um usuário casual que não esteja lendo um endereço desalinhado não precise se preocupar com endianismo.