Pergunta

O que é o alinhamento de pilha? Por que é usado? ele pode ser controlado por configurações do compilador?

Os detalhes desta questão são tomadas a partir de um problema enfrentado ao tentar usar bibliotecas ffmpeg com msvc, no entanto o que eu estou realmente interessado em uma explicação do que é "o alinhamento de pilha".

Os detalhes:

  • Quando runnig meu programa cumpriu msvc que links para avcodec recebo a seguinte erro: "Compiler não variáveis ??de pilha align Libavcodec tem. foi miscompiled", seguido por um acidente em avcodec.dll.
  • avcodec.dll não foi compilado com msvc, assim que eu sou incapaz de ver o que está acontecendo lá dentro.
  • Ao executar ffmpeg.exe e usando o mesmo tudo avcodec.dll funciona bem.
  • ffmpeg.exe não foi compilado com msvc, foi cumprido gcc / mingw (o mesmo que avcodec.dll)

Obrigado,

Dan

Foi útil?

Solução

O alinhamento das variáveis ??na memória (uma história curta).

Nos computadores passados ??tinha um barramento de dados de 8 bits. Isto significa que cada ciclo do relógio de 8 bits de informação pode ser processada. O que era bom, então.

Depois veio computadores de 16 bits. Devido a compatibilidade com versões anteriores e outras questões, o byte de 8 bits foi mantida ea palavra de 16 bits foi introduzido. Cada palavra foi de 2 bytes. E cada ciclo de clock 16 bits de informação poderia ser processado. Mas isso representa um pequeno problema.

Vamos olhar um mapa de memória:

+----+
|0000| 
|0001|
+----+
|0002|
|0003|
+----+
|0004|
|0005|
+----+
| .. |

Em cada endereço há um byte que pode ser acessado individualmente. Mas as palavras só podem ser buscados em endereços mesmo. Então, se nós ler uma palavra em 0000, lemos os bytes em 0000 e 0001. Mas se queremos ler a palavra na posição 0001, precisamos de dois acessos de leitura. Primeiro 0000,0001 e, em seguida, 0002,0003 e nós só manter 0001,0002.

Claro que isso levou algum tempo extra e que não foi apreciado. Então é por isso que eles inventaram alinhamento. Então, nós armazenar variáveis ??palavra em limites de palavra e variáveis ??byte em limites de byte.

Por exemplo, se temos uma estrutura com um campo de byte (B) e um campo de palavra (W) (e um compilador muito ingênuo), obtemos a seguinte:

+----+
|0000| B
|0001| W
+----+
|0002| W
|0003|
+----+

O que não é divertido. Mas ao usar o alinhamento palavra encontramos:

+----+
|0000| B
|0001| -
+----+
|0002| W
|0003| W
+----+

Aqui a memória é sacrificado para a velocidade de acesso.

Você pode imaginar que, ao usar palavra dupla (4 bytes) ou palavra quad (8 bytes) isso é ainda mais importante. É por isso que a maioria dos compiladores modernos que você pode escolher quais o alinhamento que você está usando durante a compilação do programa.

Outras dicas

Algumas arquiteturas de CPU requerem o alinhamento específico de vários tipos de dados, e vai lançar exceções se você não honrar esta regra. No modo padrão, x86 não exige isso para os tipos de dados básicos, mas podem sofrer penalidades de desempenho (confira www.agner.org para dicas de otimização de baixo nível).

No entanto, a SSE conjunto de instruções (muitas vezes usado para alto desempenho ) procesing áudio / vídeo tem requisitos de alinhamento rigoroso, e vai lançar exceções se você tentar usá-lo em dados não alinhados (a menos que você use o, em alguns processadores, tanto versões mais lento não alinhados).

A sua questão é provavelmente que um compilador espera que o chamador para manter a pilha alinhados, enquanto o outro espera callee para alinhar a pilha quando necessário.

Editar : como por que a exceção acontece, uma rotina na DLL provavelmente quer usar instruções SSE em alguns dados pilha temporários, e não porque os dois compiladores diferentes não concordar em chamar convenções .

IIRC, alinhamento pilha é quando as variáveis ??são colocados na pilha "alinhadas" de um determinado número de bytes. Então, se você estiver usando um alinhamento pilha de 16 bits, cada variável na pilha vai começar a partir de um byte que é um múltiplo de 2 bytes do ponteiro de pilha atual dentro de uma função.

Isto significa que se estiver a utilizar uma variável que é <2 bytes, tal como um carvão animal (1 byte), haverá 8 bits de "padding" não utilizado entre ele e o próximo variável. Isso permite que certas otimizações com pressupostos baseados em locais variáveis.

Ao chamar funções, um método de passar argumentos para a próxima função é colocá-los na pilha (em oposição ao colocá-los diretamente em registos). Seja ou não alinhamento está sendo usado aqui é importante, pois a função chamando coloca as variáveis ??na pilha, para ser lido pela função chamar usando deslocamentos. Se a função chamando alinha as variáveis, e a função chamada espera que eles sejam não-alinhados, então a função chamada não será capaz de encontrá-los.

Parece que o código msvc compilado é discordando sobre o alinhamento variável. Tente compilar com todas as otimizações desligado.

Tanto quanto eu sei, compiladores não variáveis ??tipicamente align que estão na pilha. A biblioteca pode ser dependendo de algum conjunto de opções do compilador que não é suportado em seu compilador. A correção normal é a declarar as variáveis ??que precisam ser alinhados como estático, mas se você vai fazer sobre isso no código de outras pessoas, você vai querer ter certeza de que variáveis ??em questão são inicializados, mais tarde, na função em vez de a declaração.

// Some compilers won't align this as it's on the stack...
int __declspec(align(32)) needsToBe32Aligned = 0;
// Change to
static int __declspec(align(32)) needsToBe32Aligned;
needsToBe32Aligned = 0;

Como alternativa, encontrar uma opção de compilador que alinha as variáveis ??na pilha. Obviamente a sintaxe alinhar "__declspec" Eu usei aqui pode não ser o que seus usos do compilador.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top