Eu tenho um programa ac que se parece com isso
main.c
#include <stdio.h>
#define SOME_VAR 10
static int heap[SOME_VAR];
int main(void) {
printf("%p", heap);
return 0;
}
e gera isso quando executo o programa compilado algumas vezes
0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060
Por que sempre termina em 060? E a matriz é armazenada na pilha?
Edit: Estou no Linux e tenho o ASLR ativado. Eu compilei o programa usando o gcc
Respostas:
Os endereços diferem devido ao ASLR (ramdomization do layout do espaço de endereço). Usando isso, o binário pode ser mapeado em diferentes locais no espaço de endereço virtual.
A variável
heap
- ao contrário do nome - não está localizada na pilha, mas nabss
. O deslocamento no espaço de endereço é, portanto, constante.As páginas são mapeadas na granularidade da página, que é 4096 bytes (hex: 0x1000) em várias plataformas. Esta é a razão pela qual os últimos três dígitos hexadecimais do endereço são iguais.
Quando você fez o mesmo com uma variável de pilha , o endereço pode até variar nos últimos dígitos em algumas plataformas (ou seja, linux com kernels recentes), porque a pilha não é apenas mapeada em outro lugar, mas também recebe um deslocamento aleatório na inicialização.
fonte
heap
quando ela não está na pilha?060
.Se você estiver usando o Windows, o motivo é a estrutura do PE .
Sua
heap
variável é armazenada na.data
seção do arquivo e seu endereço é calculado com base no início desta seção. Cada seção é carregada em um endereço independentemente, mas seu endereço inicial é múltiplo do tamanho da página. Como você não possui outras variáveis, o endereço provavelmente é o início da.data
seção, portanto, o endereço terá vários tamanhos de bloco.Por exemplo, esta é a tabela da versão compilada do Windows para o seu código: A
.text
seção é onde seu código compilado é e.data
contém suaheap
variável. Quando o seu PE é carregado na memória, as seções são carregadas em um endereço diferente e retornadoVirtualAlloc()
e será múltiplo do tamanho da página. Mas o endereço de cada variável é relativo ao início da seção que agora é do tamanho de uma página. Então você sempre verá um número fixo nos dígitos inferiores. Como o endereço relativoheap
do início da seção é baseado no compilador, nas opções de compilação, etc., você verá um número diferente do mesmo código, mas diferentes compiladores, mas sempre que o que será impresso for corrigido.Ao compilar o código, notei que ele
heap
é colocado em0x8B0
bytes após o início da.data
seção. Portanto, toda vez que executo esse código, meu endereço termina0x8B0
.fonte
heap
quando ela não está na pilha?Por acaso, o compilador colocou
heap
no deslocamento 0x60 bytes em um segmento de dados, possivelmente porque o compilador possui outras coisas nos primeiros 0x60 bytes, como dados usados pelo código que inicia amain
rotina. É por isso que você vê "060"; é exatamente onde aconteceu, e não há grande significado para isso.A randomização do layout do espaço de endereço altera os endereços base usados para várias partes da memória do programa, mas sempre o faz em unidades de 0x1000 bytes (porque isso evita causar problemas de alinhamento e outros problemas). Portanto, você vê os endereços flutuarem por múltiplos de 0x1000, mas os últimos três dígitos não são alterados.
A definição
static int heap[SOME_VAR];
defineheap
com a duração do armazenamento estático. As implementações típicas de C o armazenam em uma seção de dados geral, não na pilha. O "heap" é um nome impróprio para memória usada para alocação dinâmica. (É um nome impróprio, porque asmalloc
implementações podem usar uma variedade de estruturas e algoritmos de dados, não se limitando a pilhas. Eles podem até usar vários métodos em uma implementação.)fonte