As variáveis ​​da pilha estão alinhadas pelo GCC __attribute __ ((alinhado (x)))?

88

eu tenho o seguinte código:

E eu tenho a seguinte saída:

Por que o endereço de a[0]não é um múltiplo de 0x1000?

O que exatamente __attribute__((aligned(x)))faz? Eu entendi mal esta explicação?

Estou usando o gcc 4.1.2.

cojocar
fonte

Respostas:

98

Acredito que o problema é que seu array está na pilha e que seu compilador é muito antigo para suportar variáveis ​​de pilha superalinhadas. O GCC 4.6 e posterior corrigiu esse bug .

C11 / C ++ 11 alignas(64) float a[4];simplesmente funciona para qualquer alinhamento de potência de 2.
O GNU C também__attribute__((aligned(x))) conforme você o estava usando.

(Em C11, #include <stdalign.h>para #define alignas _Alignas: cppref ).


Mas no seu caso de um alinhamento muito grande, para um limite de página de 4k, você pode não querer isso na pilha.

Como o ponteiro da pilha pode ser qualquer coisa quando a função é iniciada, não há como alinhar a matriz sem alocar muito mais do que você precisa e ajustá-lo. (Compiladores irãoand rsp, -4096 ou equivalente e não usarão nenhum dos 0 a 4088 bytes alocados; ramificar se esse espaço é grande o suficiente ou não seria possível, mas não é feito porque grandes alinhamentos muito maiores que o tamanho da matriz ou outros locais não são o caso normal.)

Se você mover o array da função para uma variável global, ele deve funcionar. A outra coisa que você pode fazer é mantê-la como uma variável local (o que é uma coisa muito boa), mas faça-a static. Isso evitará que ele seja armazenado na pilha. Esteja ciente de que ambas as formas não são seguras para threads ou recursivas, pois haverá apenas uma cópia do array.

Com este código:

Eu entendi isso:

que é o que se espera. Com seu código original, recebo apenas valores aleatórios como você fez.

Zifre
fonte
11
+1 resposta correta. Uma solução alternativa é tornar o array local estático. O alinhamento na pilha é sempre um problema e é melhor adquirir o hábito de evitá-lo.
Dan Olson
Ah, sim, não pensei em torná-lo estático. Essa é uma boa ideia, pois evita colisões de nomes. Vou editar minha resposta.
Zifre
3
Observe que torná-lo estático também o torna não reentrante e não seguro para threads.
ArchaeaSoftware
3
O gcc 4.6+ também lida com isso corretamente, mesmo na pilha.
texthell
1
Essa resposta costumava ser correta, mas agora não é. O gcc tão antigo quanto 4.6, talvez mais antigo, sabe como alinhar o ponteiro da pilha para implementar corretamente C11 / C ++ 11 alignas(64)ou qualquer outra coisa em objetos com armazenamento automático. E, é claro, GNU C__attribute((aligned((64)))
Peter Cordes
41

Havia um bug no gcc que fazia com que o atributo alinhado não funcionasse com as variáveis ​​da pilha. Parece estar corrigido com o patch vinculado abaixo. O link a seguir também contém uma boa discussão sobre o problema.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660

Eu tentei seu código acima com duas versões diferentes do gcc: 4.1.2 de uma caixa RedHat 5.7, e ele falhou de forma semelhante ao seu problema (os arrays locais não estavam alinhados em limites de 0x1000 bytes). Então tentei seu código com gcc 4.4.6 no RedHat 6.3, e funcionou perfeitamente (os arrays locais estavam alinhados). O pessoal da Myth TV teve um problema semelhante (que o patch gcc acima parecia corrigir):

http://code.mythtv.org/trac/ticket/6535

De qualquer forma, parece que você encontrou um bug no gcc, que parece ter sido corrigido nas versões posteriores.

rts1
fonte
3
De acordo com o bug vinculado, o gcc 4.6 foi a primeira versão com esse problema totalmente corrigido para todas as arquiteturas.
texthell
Além disso, o código assembly gerado pelo gcc para criar variáveis ​​alinhadas na pilha é horrível e não otimizado. Então, faz sentido alocar variáveis ​​alinhadas na pilha em vez de chamar memalign()?
Jérôme Pouiller,
13

GCC recente (testado com 4.5.2-8ubuntu4) parece funcionar como esperado com o array alinhado corretamente.

Eu recebo:

Caleb Case
fonte
Isso é um pouco surpreendente, considerando que as matrizes estão alocadas na pilha - isso significa que a pilha agora está cheia de buracos?
ysap
Ou sua pilha está alinhada com 16 bytes.
user7116
9

O alinhamento não é eficaz para todos os tipos. Você deve considerar o uso de uma estrutura para ver os atributos em ação:

E então, você lerá:

Que é o que você esperava.

Edit: Empurrado por @yzap e seguindo @Caleb Caso comentário, o problema inicial é devido a versão do GCC única . Eu verifiquei GCC 3.4.6 vs GCC 4.4.1 com o código-fonte do solicitante:

Agora é óbvio que as versões mais antigas do GCC (em algum lugar antes de 4.4.1) mostram patologias de alinhamento.

Nota 1: Meu código proposto não responde à pergunta que entendi como "alinhar cada campo da matriz".

Nota 2: Trazer um não estático [] dentro de main () e compilar com GCC 3.4.6 quebra a diretiva de alinhamento do array de struct, mas mantém a distância de 0x1000 entre structs ... ainda ruim! (veja a resposta @zifre para soluções alternativas)

levif
fonte
2
Conforme respondido por zifre, não é o tipo, mas o fato de que você o tornou estático em sua versão.
ysap
@ysap, foi a versão do GCC e a definição global que o fez funcionar. Obrigado pelo seu comentário! Editei a resposta para consertar. :)
levif