- /* Definindo as areas de memoria
- */
- MEMORY
- {
- FLASH : ORIGIN = 0x08000000, LENGTH = 64K
- RAM : ORIGIN = 0x20000000, LENGTH = 8K
- }
- /* Definindo o endereco do inicio
- * da pilha de sistema
- */
- _stack_init = ORIGIN(RAM)+LENGTH(RAM);
- /* Definindo as sessoes
- * por enquanto temos apenas uma
- * sessao de interesse: a de código
- */
- SECTIONS
- {
- .text : { *(.text) } > FLASH
- .data : { *(.data) } > RAM
- }
O linker script é um arquivo texto onde definimos as particularidades que desejamos para o processo do linker. Primeiramente faremos um arquivo chamado stm32f0discovery.ld que, como o nome diz, será particular para o processador STM32F05xx da placa STM32F0Discovery. Começamos pelo comando MEMORY. Esse comando dá ao linker as características dos tipos de memória que o nosso processador tem. No nosso caso, o processador STM32F05xx possui 64k KBytes de memória flash iniciando no endereço 0x08000000 e 8 KBytes de memória ram iniciando no endereço 0x20000000. Pronto: já definimos o tipo, tamanho e endereço de nossa memória física. Com isso, na linha 14, criamos um símbolo que possui, automaticamente, o endereço da pilha de sistema.
O próximo comando faz o mapeamento entre as sessões internas (definidas no programas) com as sessões externas nas áreas e endereços físicos da(s) memória(s) do processador. Temos, como padrão, as seguintes sessões:
- .text : contém as instruções do programa a serem executadas;
- .data : contém as áreas de memórias pré-inicializadas com valores;
- .bss : contém as áreas de memórias não inicializadas com valores.
Por enquanto, nos preocuparemos com a sessão .text. A sessão .data está presente por ser obrigatória no processo do linker mas nós a utilizaremos efetivamente mais adiante. No nosso arquivo, começamos esse mapeamento através do comando SECTIONS. De forma simples, mapeamos a sessão .text externa para a memória flash e a sessão externa .data para a memória ram. Como o processo do linker pode unir muitos programas em um único módulo objeto (aliás essa é sua função principal), determinamos que todas as sessões .text internas (dos programas) serão alocadas na memória flash e todas as sessões .data internas para a memória ram. Isso se dá pelo caractere coringa '*' presente no comando. Em suma:
.text : { *(.text) } > FLASH
.text : a sessão .text do módulo objeto de saída
{ ... } engloba
*(.text) todas as sessões .text dos arquivos objetos dos programas individuais
> FLASH e residirá na memória flash
Raciocínio semelhante é usado para a sessão .data.
Completando o processo, faremos as alterações necessárias no nosso programa e no makefile.
- // Segundo programa para ARM Cortex-M0 configurado para linker script
- .thumb // Define código como THUMB
- .globl _start // Necessario para o linker
- .globl _reset_handler // visto externamente
- .text // Inicio da área de código
- _start:
- // Inicio do Vector Table
- .word _stack_init // Inicio da pilha
- .word _reset_handler // Endereco do Reset Handler
- // define o label como função para que o linker
- // resolva como código THUMB
- .weak _reset_handler // pode ser redefinido em outro modulo
- .type _reset_handler, function
- // tabela de bytes para somar 1
- tbl:
- .byte 3,7,9,0
- .align
- _reset_handler: // inicio do tratamento do reset
- ldr r0,=tbl // carrega r0 com o endereco da tabela
- mov r1,#1 // move o valor 1 para r1
- segue:
- ldrb r2,[r0] // carrega em r2 o byte enderecado por r0
- cmp r2,#0 // se r2 for zero,
- beq _stop // encerra
- add r3, r2, r1 // soma r1 e r2 guardando em r3
- add r0,#1 // avanca na tabela
- b segue // continua
- _stop:
- b . // loop infinito
Primeiramente, rebatizamos nosso função de tratamento de reset como _reset_handler (linha 25) e o definimos como global (linha 5) e, com a diretiva .weak (linha 18), é possível que outro módulo externo ao nosso redefina essa função. O inicio da pilha do sistema (_stack_init) agora é uma referência resolvida externamente no linker script e não mais inicializada dentro do programa.
Quanto ao makefile, retiramos os passos de geração do arquivo binário que não usaremos por agora. Além disso, retiramos o parâmetro -Ttext=0x00000000 do passo do linker substituindo-o pelo parâmetro informando nosso arquivo de linker script: -T stm32f0discovery.ld.
- rst_0.elf: rst_0.o
- @echo&echo&echo&echo&echo&echo ///////////// Executando o linker
- @echo
- arm-none-eabi-ld -o rst_0.elf rst_0.o -T stm32f0discovery.ld
- @echo&echo&echo&echo&echo&echo ///////////// Mostrando os simbolos apos o linker
- @echo
- arm-none-eabi-nm rst_0.elf
- @echo&echo&echo&echo&echo&echo ///////////// Dump das sessoes do programa
- @echo
- arm-none-eabi-objdump -h rst_0.elf
- rst_0.o: rst_0.s
- @echo&echo&echo&echo&echo&echo ///////////// Montando o programa assembly
- @echo
- arm-none-eabi-as -mcpu=cortex-m0 -g -o rst_0.o rst_0.s
- clean:
- @echo&echo&echo&echo&echo&echo ///////////// Eliminando os arquivos de saida
- @echo
- rm *.o
- rm *.elf
Pronto. Nosso processo de geração do módulo objeto pode ser executado:
- T:\arm_03>make
- ///////////// Montando o programa assembly
- arm-none-eabi-as -mcpu=cortex-m0 -g -o rst_0.o rst_0.s
- ///////////// Executando o linker
- arm-none-eabi-ld -o rst_0.elf rst_0.o -T stm32f0discovery.ld
- ///////////// Mostrando os simbolos apos o linker
- arm-none-eabi-nm rst_0.elf
- 0800000c W _reset_handler
- 20002000 A _stack_init
- 08000000 T _start
- 0800001c t _stop
- 08000010 t segue
- 08000008 t tbl
- ///////////// Dump das sessoes do programa
- arm-none-eabi-objdump -h rst_0.elf
- rst_0.elf: file format elf32-littlearm
- Sections:
- Idx Name Size VMA LMA File off Algn
- 0 .text 00000024 08000000 08000000 00008000 2**2
- CONTENTS, ALLOC, LOAD, READONLY, CODE
- 1 .ARM.attributes 00000021 00000000 00000000 00008024 2**0
- CONTENTS, READONLY
- 2 .debug_line 00000042 00000000 00000000 00008045 2**0
- CONTENTS, READONLY, DEBUGGING
- 3 .debug_info 0000003a 00000000 00000000 00008087 2**0
- CONTENTS, READONLY, DEBUGGING
- 4 .debug_abbrev 00000014 00000000 00000000 000080c1 2**0
- CONTENTS, READONLY, DEBUGGING
- 5 .debug_aranges 00000020 00000000 00000000 000080d8 2**3
- CONTENTS, READONLY, DEBUGGING
- T:\arm_03>
Vemos duas informações importantes: na linha 27 o símbolo _stack_init foi gerado pelo linker e com conteúdo correto: 0x20002000. Nas linhas 44 e 45 temos as informações por ora relevantes da nossa sessão .text do nosso módulo objeto: ela possui um tamanho de 0x24 bytes, e possui os endereços de memória VMA e LMA iguais a 0x08000000 que é o nosso endereço da memória flash. Por enquanto é o suficiente. No próximo post quando falarmos da utilização da memória ram, descreveremos as diferenças e usos dos endereços VMA e LMA.
Agora é só depurarmos da mesma forma como feito no post anterior. Boa sorte.
REFERÊNCIAS
The GNU linker - http://www.eecs.umich.edu/courses/eecs373/readings/Linker.pdf
Using AS - http://www.eecs.umich.edu/courses/eecs373/readings/Assembler.pdf
Nenhum comentário:
Postar um comentário