Поиск по сайту:

 


По базе:  

микроэлектроника, микросхема, микроконтроллер, память, msp430, MSP430, Atmel, Maxim, LCD, hd44780, t6963, sed1335, SED1335, mega128, avr, mega128  
  Главная страница > Статьи > Средства разработки

реклама

 




Мероприятия:




Программа на C

В этом примере рассмотрим компиляцию и линковку программы на C. Выше говорилось, что для запуска программ написанных на языке высокого уровня требуется некоторая предварительная работа по подготовке памяти. Кроме подготовки секции .data , необходимо заполнить секцию .bss нулями. Загрузочный образ будет собираться из 2-х модулей, на ассемблере и на C. На ассемблере написан код инициализации, текст программы, файл ex4.s :

	
@ example 4
    .syntax unified
    .cpu cortex-m3
    .thumb
 .equ  STACKINIT, 0x20002000 
  .section .text
   .type start , %function
   .type _nmi_handler , %function
   .type _hard_fault , %function
   .type _memory_fault , %function
   .type _bus_fault , %function
   .type _usage_fault , %function
     .word STACKINIT        @ stack pointer value 
     .word start            @ reset
     .word _nmi_handler
     .word _hard_fault
     .word _memory_fault
     .word _bus_fault
     .word _usage_fault
start:   ldr r2, =d_size       @ d_size -- size of .data
         cbz r2, fill_0        @ if (r2 == 0) goto fill_0
         ldr r0, =flash_sd
         ldr r1, =s_data
move:    ldrb r4, [r0], #1
         strb r4, [r1], #1
         subs r2, r2, #1
         bne move            @ end copy section 
fill_0:  ldr r2, =b_size     @ b_size --  size of .bss
         cbz r2, go          @ if (b_size == 0) goto 
         ldr r0, =s_bss
         mov r4, #0
fill_1:  strb r4, [r0], #1
         subs r2, r2, #1
         bne fill_1
go:      bl main
_dummy:               @ handlers
  _nmi_handler:
  _hard_fault:
  _memory_fault:
  _bus_fault:
  _usage_fault:   add r0, 1
                  add r1, 1
                  b _dummy
 .end
	 

Cкрипт линкера:

	
MEMORY {
        ROM (RX) : ORIGIN = 0x0 LENGTH = 128K
        RAM (RW) : ORIGIN = 0x020000000 LENGTH = 8K
       }
SECTIONS {
          .text  :        {
            * (.text);    
                          } > ROM
          .rodata :       {
            * (.rodata);
            flash_sd = .; 
                          } > ROM
          .bss : { s_bss = . ;
            * (.bss);
                 } > RAM
          .data  : AT (flash_sd) {
              s_data = . ; 
            * (.data);
                                 } > RAM 
          d_size = SIZEOF(.data) ;
          b_size = SIZEOF(.bss) ;  }
	

В скрипте определено несколько символов. Символ flash_sd хранит адрес конца секции .rodata.

Начиная с этого адреса, будут размещаться данные секции .data в ROM. Именно в ROM! Адрес начала секции .bss в s_bss , а секции .data в s_data . Cимволы d_size и b_size , хранят размеры секций в байтах. В программе на ассемблере эти символы используются для копирования данных и подготовки секции .bss . После инициализации, вызывается подпрограмма main из модуля на C. Текст на C, файл ex4_1.c:

	
 int src[]={1,2,3,4,5,6,7,8,9,10};
int dst[10];
const int n = 10;
void main()
{ int i;
    for (i=0;i

Стандарт C поддерживает 4 спецификатора класса памяти: extern, static, register, auto. Если класс не определён явно, то по умолчанию принимается класс extern для объектов, описанных вне функций, и класс auto в пределах описания функций. Автоматические объекты (auto) существуют только во время выполнения данного блока и при выходе из блока теряют свои значения и освобождают занимаемую память. Классы static и extern касаются объектов, существующих в течение всего времени выполнения программы. Разница между ними в том, что объекты класса extern доступны из всех модулей, в то время как объекты класса static , доступны только в пределах того модуля, где они описаны. Это краткое напоминание об основах C.

Компилируем программу на С, командой:

	
arm-none-eabi-gcc  -mcpu=cortex-m3  -mthumb  -O0 -g  -c ./ex4_1.c -o ./ex4_1.o
		 

Флаг -O0 указывает компилятору, что не нужно выполнять оптимизацию программы, так как возможны трудности с отладкой. Смотрим символы полученного объектного файла:

	
arm-none-eabi-nm -t  x -n ./ex4_1.o
       00000000 T main
       00000000 R n
       00000000 D src
       00000028 C dst
		 

Все символы глобальные. Тип C - общедоступные символы (common). Тип D - глобальные символы в секции .data . Если программа состоит из нескольких модулей компилируемых раздельно, и в этих модулях имеются символы типа C с одинаковыми именами, то эти символы будут ссылаться на один и тот же участок памяти. А если эти символы разного размера, то под символ будет выбран участок памяти максимального размера, из имеющихся участков. И что важно, линковщик не сообщит, о том, что в разных модулях определены символы с одинаковыми именами.

Проведём эксперимент, создадим 2-ой модуль на C, в котором объявим не инициализированную переменную dst, с классом памяти extern , и меньшего размера. Текст 2-го модуля на C, из файла ex4_2.c совсем короткий, из одной строки.

	
int  dst ; //common symbol
		 

Скомпилируем командой:

	
arm-none-eabi-gcc  -mcpu=cortex-m3  -mthumb  -O0 -g  -c ./ex4_2.c -o ./ex4_2.o
		 

Скомпонуем командой:

	
arm-none-eabi-ld -v -Tl.ld ex4.o ex4_1.o ex4_2.o -o ex4.elf
		 

Посмотрим символ dst в ELF файле:

	
   arm-none-eabi-nm -t x -n ./ex4.elf|grep dst
       20000000 B dst
		 

Как видим, в исполнимом файле создан символ типа B - не инициализированные данные в секции .bss. Символы типа C не создаются в исполнимых файлах ELF. Никаких предупреждающих сообщений не последовало об определении нескольких символов с одним именем в разных модулях. Нужно различать определение, от описания переменной. Описание переменной - это ссылка на участок памяти. Определение переменной - это выделение ей участка памяти.

Можно запретить компилятору создавать символы типа C (common). В параметрах компилятора задаётся опция -fno-common. В этом случае для глобальных, не инициализированных переменных, будут создаваться символы типа B. А при компоновке, линковщик сообщит об ошибке, о наличии нескольких символов с одним именем в разных модулях.

Переменная int i , по умолчанию имеет класс памяти auto. Для этой переменной компилятор не создаёт символ (именованный участок памяти в RAM), её значение хранится в регистре процессора. Кто интересуется, может получить ассемблерный текст, сгенерированный компилятором C:

	
arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -S ./ex4_1.c
		 

Проведём ещё один эксперимент, изменим класс памяти переменных и функции на static:

	
static int src[]={1,2,3,4,5,6,7,8,9,10};
 static int dst[10];
 const int n = 10;
 static void main(void)
  { int i;
     for (i=0;i

Компилируем командой:

	
arm-none-eabi-gcc -fno-common -mcpu=cortex-m3 -mthumb -O0 -c ./ex4_1.c -o ./ex4_1.o
		 

Таблица символов:

	
00000000 b dst
00000000 t main
00000000 R n
00000000 d src
		 

Переменные dst и src перестали быть доступными из других модулей, а функция main стала недоступной для вызова из модуля на ассемблере. Символ dst - типа b , не общедоступный (common), как в предыдущем примере. Это результат действия -fno-common . При попытке компоновки, будет выдано сообщение, о невозможности разрешить символ main. Для функции main, класс памяти static излишний, нужно изменить класc памяти функции main.

<-- Предыдущая страница Оглавление Следующая страница -->





 
Впервые? | Реклама на сайте | О проекте | Карта портала
тел. редакции: +7 (995) 900 6254. e-mail:info@eust.ru
©1998-2023 Рынок Микроэлектроники