Francesco escreveu:Uma informação importante para processadores de 32 bits é que não é possível fracionar endereços para uma palavra inteira. Explico, suponha a memória abaixo:
(cortei)
Isto depende da ABI (application binary interface), que é a especificação definindo como os dados são alocados e acessados, que é sempre baseada no layout de memória do processador em questão. Alguns processadores de 32 bits só acessam o barramento em 32 bits e só fazem leituras/gravações alinhadas em múltiplos de 32 bits. Neste caso quando é feita a leitura/gravação de dados, há sempre necessidade de mascarar e/ou escorregar dados no processo. Não é exatamente o caso do ARM, pois a micro-arquitetura do lado do processador permite acessar dados com alinhamento natural em 32, 16 e 8 bits, e, mais recentemente (nos cortex-m3 por exemplo), incorporou suporte opcional (configurável em tempo de execução) para leituras totalmente desalinhadas, mantendo os mesmos tamanhos.
É importante ressaltar que embora o barramento suporte isto, as vezes a memória/porta do outro lado do dispositivo não suporta esta seleção de tamanho da i/o, e naquela área é necessário fazer os acessos (especialmente as gravações) conforme suportado. É o caso de alguns periféricos dos LPC 2xxx da NXP, no manual de alguns modelos é pedido que o acesso a alguns registradores seja sempre feito em 32 bits para evitar corromper os bits adjacentes, pois o circuito que trata o acesso para aquela mascara de endereços não possui a lógica adequada para fazer o read-modify-write do tamanho correto sozinha.
Mas voltando a ABI, a maioria dos compiladores modernos para ARM trabalham com a ARM EABI, que é especificada pela própria ARM, de modo a aumentar a interoperabilidade entre código gerado por vários compiladores. Eu desconheço os detalhes internos da EABI, pois trabalho com uma especificação anterior (apcs-gnu se não me engano), e nela, o que ocorre é que a geração de código para acesso a variáveis globais geralmente assume que o linker poderá gerar um layout de memória bastante diferente. Uma coisa que ele pode fazer, por exemplo, é ordenar os símbolos não inicializados conforme o tamanho do alinhamento, do maior para o menor, de modo que os dados que ocupem um byte isoladamente acabam sendo alocados no final da área, independente da ordem de declaração (opção --sort-common). Isto é feito para evitar justamente gaps (áreas sem uso) na memória quando as declarações são feitas inter-mixando dados de tamanho variável, como no teu exemplo.
Não tendo esta opção, prevalece o teu conselho:
Francesco escreveu:Por isso é importante se preocupar na hora de alocar a memória. Colocar primeiramente as variáveis de 32 bits, em seguida as de 16 bits e terminar com as de 8 bits.