Mês: junho 2015

.text .data .bss entendendo essas seções

Estes três nomes costumam aparecer muito quando compilamos e ‘linkamos’ algum programa utilizando o gcc e tanto faz se for x86, avr ou arm estas seções estarão lá e muitos não sabem o que significam. Para entende-los um utilitário útil para compreender estas seções e  ver o tamanho de um programa é o ‘size‘ cuja saída é tipicamente como segue

 $ arm-none-eabi-size bin/Release/out.a
 text       data      bss       dec     hex     filename
 10920   4         5564     16488 4068   bin/Release/out.a
 

No exemplo foi utilizado o size do toolchain arm e cada número indica o tamanho da seção em bytes. Há uma versão especifica para cada plataforma como visto na lista:

  • x86:  size
  • arm-baremetal: arm-none-eabi-size
  • avr: avr-size

O único argumento é o arquivo ELF.

Vamos entender de vez o que cada seção nos diz.

.text

Esta seção é o que será gravado na flash do microcontrolador, ou seja, o executável e dados constantes. O programa estará armazenado nesta seção assim como variáveis declaradas const.

Assim o seguinte código será todo ele incluído na seção .text:

const int seno[] = {0,1,0,-1};
void func (void) {
//... faz algo
}
int main (void) {
return 1;
}

Esse programa compilado para x86/Linux terá um tamanho de:

$ gcc c.c
$ size a.out
   text	   data	    bss	    dec	    hex	filename
   1199	    552	      8	   1759	    6df	a.out

As outras seções estão cheias devido a inicialização imposta pelo compilador.

.data

Nesta seção as variáveis que precisam ser inicializadas com algum valor serão alocadas. No código exemplo:

float PI = 3.14f;
int Mil = 1000;

As variáveis precisarão ser alocadas na RAM (ou SRAM) e inicializadas com um valor que será copiado da Flash para a RAM. Dessa forma PI é um posição da memória RAM que antes da execução de ‘main’ será preenchida com o valor copiado da Flash de ‘3.14f’.

Isso já indica um desperdício de espaço visto que a flash será ocupada pelos valores de inicialização.

.bss

A mais incompreendida das seções é somente a seção onde as variáveis globais não inicializadas são alocadas. Neste caso no C/C++ estas variáveis serão inicializadas com o valor 0. Lembra-se? Nada mais é que um memzero em uma região da RAM delimitada pelas variáveis declaradas globais. Não confunda com variáveis declaradas localmente que podem estar no stack ou nos registradores (e se não forem inicializadas terão valores indefinidos).

Antes de main

Quem faz todas estas inicializações é algum código startup.s a ser compilado ou linkado junto ao código que nada mais faz que zerar uma região da memória na seção .bss  neste caso e copiar da Flash para a RAM no caso da seção .data.

Algumas vezes queremos (e eu já precisei) não inicializar uma variável global com 0 então para isto use o atributo

int valoraleatorio __attribute__ ((section ( .noinit ))) ;

Que instrui o compilador a deixar de fora a variável da inicialização com zeros.

Raspberry PI barato

Raspberry PI 2