|
Непонятный эффект компилятора (линкера?) |
|
|
|
Jul 30 2015, 05:24
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 17-01-12
Пользователь №: 69 604

|
Имеется IAR 6.50 для ARM. Проект выполнен для STM32F103VCT6 с использованием scmRTOS V4.00. В тексте программы имеется объявление константной структуры с инициализацией: Код typedef struct { char *Name; //Отображаемое имя пункта меню unsigned char Type; //Тип отображения величины пункта меню float *Value; //Ссылка на величину пункта меню unsigned char Precision; //Точность для чисел с плавающей запятой unsigned char Flags; //Флаги пункта меню unsigned char Access; //Уровень доступа к пункту меню float MinValue; //Минимально допустимая величина float MaxValue; //Максимально допустимая величина float DefaultValue; //Величина по умолчанию unsigned short UpMenuItem; //Индекс пункта меню вверх unsigned short DownMenuItem; //Индекс пункта меню вниз unsigned short LeftMenuItem; //Индекс пункта меню влево unsigned short RightMenuItem; //Индекс пункта меню вправо TMenuVariable *MenuVar; //Указатель на переменные величины меню void (*ShowSubroutine)(void *ItemPtr); //Указатель на программу, которая выполняется при отображении величины (передаётся указатель на пункт меню) void (*EditSubroutine)(void *ItemPtr,float NewValue); //Указатель на программу, которая выполняется при изменении величины (передаётся указатель на пункт меню) unsigned char ValueLength; //Количество позиций, отведённое на величину пункта меню unsigned short Index; //Индекс пункта внутри меню } TMenuItem;
const TMenuItem TestMenuItems[] = { /* Name - Type - Value - Precis - Flags - Access - MinValue - MaxValue - DefValuePtr - UpItem - DownItem - LeftItem - RightItem - Var - ShowSubrout - EditSubrout - ValueLength - GroupItem */
{"АЦП",mt_WithoutValue,NULL,0,0,al_Operator,0.0,0.0,0.0,NULL,2,428,66,&MenuTestVariable[0],NULL,NULL,0,1}, //Пункт меню "АЦП" {"АЦП 1",mt_FloatValue,&ADCChannels[0].Value,3,0,al_Operator,0.0,0.0,0.0,1,NULL,65,3,&MenuTestVariable[1],NULL,NULL,6,2}, //Канал АЦП 1 {"АЦП 2",mt_FloatValue,&ADCChannels[1].Value,3,0,al_Operator,0.0,0.0,0.0,1,NULL,2,4,&MenuTestVariable[2],NULL,NULL,6,3}, //Канал АЦП 2
...
{"АЦП 64",mt_FloatValue,&ADCChannels[63].Value,3,0,al_Operator,0.0,0.0,0.0,1,NULL,64,2,&MenuTestVariable[64],NULL,NULL,6,65}, //Канал АЦП 64 }; Оптимизация отключена. Компилируется без ошибок. В файле *.map упоминание об этой структуре отсутствует. Но это только часть таблицы. Добавляю остальное. Опять компилирую. Появляется в файле *.map, но ложится а область ОЗУ (длина таблицы 0x5890 байт). Пытаюсь поставить перед объявлением и инициализацией прагму: #pragma location=0x08000800 Теперь ложится в память согласно прагме, но после загрузки при попытке выполнения "улетает". Что делать и кто виноват?
Сообщение отредактировал Herz - Jul 30 2015, 09:43
|
|
|
|
|
Jul 30 2015, 06:17
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (Вячик13 @ Jul 30 2015, 08:24)  Оптимизация отключена. Никогда, никогда не отключайте опттмизацию, тем более в попытках застаивить работать. Это верный путь в анус. Зато включайте ВСЕ предупреждения компилятора. QUOTE В файле *.map упоминание об этой структуре отсутствует. Значит она никому НЕ нужна, но предупреждения у Вас явно подавлены, посему и представляется чудесным ее отсутствие. QUOTE Но это только часть таблицы. Добавляю остальное. Опять компилирую. Появляется в файле *.map, Значит в "остальном" появилось что-то кому-то нужное. QUOTE но ложится а область ОЗУ (длина таблицы 0x5890 байт). Значит структура не может быть проинициализирована константами на на этапе компиляци QUOTE Теперь ложится в память согласно прагме, но после загрузки при попытке выполнения "улетает". Ну разместили принудительно во Flash, но запись как была так и есть, вот и полетели...
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 30 2015, 06:38
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 17-01-12
Пользователь №: 69 604

|
Ну хорошо, "структура не может быть проинициализирована константами на на этапе компиляции". А как? Каким образом можно сделать так, чтобы на выходе получить то же самое?
Сообщение отредактировал Herz - Jul 30 2015, 09:44
Причина редактирования: Избыточное цитирование
|
|
|
|
|
Jul 30 2015, 06:45
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (Вячик13 @ Jul 30 2015, 09:38)  Каким образом можно сделать... Вы Автор, Вам виднее. Для просветления - оставьте от всего этого ОДНУ строчку и смотрите, что-бы: 1) на нее были ссылки; 2) все, что в структуре было известно на этапе компиляции. Все.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 30 2015, 08:05
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Вячик13 @ Jul 30 2015, 08:24)  Появляется в файле *.map, но ложится а область ОЗУ (длина таблицы 0x5890 байт) Ненаказуемо. Совсем. По стандарту const только заставляет компилятор запрещать запись в такую переменную. Вы просите переменную - она есть. Попробуйте в нее записать - получите по рукам. Все остальные оптимизации вы запретили компилятору лично. На что же вы обижаетесь? Включите оптимизацию и отлаживайте конечный код, zltigo вам совершенно правильно пишет. Он только не прав по поводу причин, заставляющих размещать константы в ОЗУ. По этому поводу вы его не слушайте, вы сюда слушайте, причины я описал выше. Включите оптимизацию - получите ваш массив во флеше.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 30 2015, 09:21
|

Местный
  
Группа: Свой
Сообщений: 327
Регистрация: 24-06-06
Из: Томск
Пользователь №: 18 328

|
Цитата(AHTOXA @ Jul 30 2015, 14:40)  Я бы в первую очередь заменил char *Name; //Отображаемое имя пункта меню на char const* Name; Не-а. Вот так: char const* const Name; Хотя нет. Можно и без второго const. Сдается мне, что проблема в указателях на функцию. Скорее всего реализации функций в другом файле или ниже по тексту. Соответственно компилятор на момент заполнения структуры не знает их адреса.
|
|
|
|
|
Jul 30 2015, 09:37
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 17-01-12
Пользователь №: 69 604

|
Цитата(Сергей Борщ @ Jul 30 2015, 11:05)  Ненаказуемо. Совсем. По стандарту const только заставляет компилятор запрещать запись в такую переменную. Вы просите переменную - она есть. Попробуйте в нее записать - получите по рукам. Все остальные оптимизации вы запретили компилятору лично. На что же вы обижаетесь? Включите оптимизацию и отлаживайте конечный код, zltigo вам совершенно правильно пишет. Он только не прав по поводу причин, заставляющих размещать константы в ОЗУ. По этому поводу вы его не слушайте, вы сюда слушайте, причины я описал выше. Включите оптимизацию - получите ваш массив во флеше. Включил оптимизацию (пробовал и средний уровень и высокий). Не помогло. Цитата(shreck @ Jul 30 2015, 12:21)  Не-а. Вот так: char const* const Name; Хотя нет. Можно и без второго const.
Сдается мне, что проблема в указателях на функцию. Скорее всего реализации функций в другом файле или ниже по тексту. Соответственно компилятор на момент заполнения структуры не знает их адреса. Так я же объявил их равными NULL.
|
|
|
|
|
Jul 30 2015, 10:23
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 17-01-12
Пользователь №: 69 604

|
Цитата(shreck @ Jul 30 2015, 12:44)  А ADCChannels, MenuTestVariable определены в этом же файле? MenuTestVariable в том же файле прямо перед таблицей, а ADCChannels в main.cpp, но по команде оболочки "Go to Definition" переходит к определению правильно.
|
|
|
|
|
Jul 30 2015, 10:52
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 17-01-12
Пользователь №: 69 604

|
Цитата(shreck @ Jul 30 2015, 13:32)  Ну вот и ответ на вопрос почему не во флешь, а в ОЗУ находится объект. А возможности навигации по коду у редактора здесь вообще не причем. Перенёс и ADCChannels в тот же файл - не помогло.
|
|
|
|
|
Jul 30 2015, 11:19
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 17-01-12
Пользователь №: 69 604

|
Цитата(shreck @ Jul 30 2015, 13:58)  Значит есть что-то еще, о чем не знает компилятор на момент построения таблицы. Собственно первые ответы поясняют все что нужно. А без нормально представленного кода указать конкретное место затруднительно. Понял, спасибо. Вполне возможно. Сейчас начну перелопачивать таблицу построчно, постепенно добавляя данные.
|
|
|
|
|
Jul 31 2015, 02:23
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Вячик13 @ Jul 30 2015, 11:24)  В файле *.map упоминание об этой структуре отсутствует. Значит нигде в коде она у Вас не используется. Цитата(Вячик13 @ Jul 30 2015, 11:24)  Но это только часть таблицы. Добавляю остальное. Опять компилирую. Появляется в файле *.map, но ложится а область ОЗУ (длина таблицы 0x5890 байт). Открывайте icf-файл компоновщика и смотрите куда у Вас компонуются какие секции. Пример моего icf-файла для какого-то STM32F100: CODE define memory mem with size = 4G; define region FLASH_regionA = mem:[from 0x08000000 to 0x080000FF]; define region FLASH_regionB = mem:[from 0x08000100 to 0x0800FFFF]; define region RAM_regionA = mem:[from 0x20000000 size 0x5000];
define block CSTACK with alignment = 8, size = 0x000 {}; define block HEAP with alignment = 8, size = 0x000 {};
//.dma: для DMA-транзакций //.BITBAND_RAM: для bitband-переменных
initialize by copy {rw}; do not initialize {section .noinit}; do not initialize {section .dma}; do not initialize {section .bssStk}; do not initialize {section .bssStkMain}; do not initialize {section .bssMemNoFill}; do not initialize {section .imonSave};
define block IMAGE_HEAD with fixed order {section .intvec, section .checksum, section .codehead, section .intvecTail}; place in FLASH_regionA {block IMAGE_HEAD}; place in FLASH_regionB {ro, first section .codebegin, last section .codetail}; place in RAM_regionA {rw, first block CSTACK, section .BITBAND_RAM, section .dma, section .bssMemNoFill, block HEAP};
include "io.icf"; Строка place in FLASH_regionB задаёт компоновщику линковать все readonly-секции, для которых целевые регионы не указанные явно, во FLASH_regionB. Цитата(Вячик13 @ Jul 30 2015, 11:24)  Пытаюсь поставить перед объявлением и инициализацией прагму: #pragma location=0x08000800 Теперь ложится в память согласно прагме, но после загрузки при попытке выполнения "улетает". Ну да, а по этим адресам у Вас случайно не код находится? И получается каша. Понятно что "улетает"... Цитата(Вячик13 @ Jul 30 2015, 11:24)  Что делать и кто виноват? Виноваты понятно - Вы. А что делать - написано выше. Цитата(AHTOXA @ Jul 30 2015, 14:40)  Я бы в первую очередь заменил char *Name; //Отображаемое имя пункта меню на char const* Name; И почему? Почему Вы думаете, что это у автора указатель на константные данные? Ничто не запрещает указателю на данные в ОЗУ быть константным. Он просто становится char * const Name;Цитата(Вячик13 @ Jul 30 2015, 17:19)  Понял, спасибо. Вполне возможно. Сейчас начну перелопачивать таблицу построчно, постепенно добавляя данные. Нет в Вашем объявлении ничего, что мешает экземпляру структуры быть константным. Разве что убедитесь что в этом экземпляре (и подобных ему остальных): {"АЦП",mt_WithoutValue,NULL,0,0,al_Operator,0.0,0.0,0.0,NULL,2,428,66,&MenuTestVariable[0],NULL,NULL,0,1}что: mt_WithoutValue и al_Operator - константы (enum или #define), а не переменные. PS: И возможно ещё что Вы что-то намутили с ключами проекта IAR.
|
|
|
|
|
Jul 31 2015, 02:44
|

Местный
  
Группа: Свой
Сообщений: 327
Регистрация: 24-06-06
Из: Томск
Пользователь №: 18 328

|
Цитата(zltigo @ Jul 30 2015, 17:44)  По барабану в каком файле они находятся - компилятор по любому НЕ знает абсолютные адреса обьектов, где-бы они не описывались. Абсолютными адресами будет по любому потом линкер заниматься. Проверил на IAR 7.40.1 и на GCC 4.9 IAR не справился с задачей. Он действительно кладет подобную структуру в ОЗУ. А вот GCC справился. А поскольку у ТС IAR, то вопрос исчерпан. Хотя у меня в голове сидят смутные воспоминания, что когда-то давно у меня получилось проделать этот трюк с IAR'ом. Только не помню каким и для какого проца.
|
|
|
|
|
Jul 31 2015, 05:12
|
Участник

Группа: Участник
Сообщений: 71
Регистрация: 17-01-12
Пользователь №: 69 604

|
Ура! Нашёл причину.
В структуре должны быть только ссылки на переменные в ОЗУ. Тогда она ложится во флэш. А у меня в середине массива структур были не ссылки , а сами переменные.
{"После фильтра",mt_FloatValue,&WeightShowFilter.OutputValue,0,0,al_Operator,0.0,0.0,0.0,260,NULL,261,263,&MenuTestVariable[261],NULL,NULL,6,262}, //Вес на выходе после фильтра индикации весового канала 1 {"Смещение нуля",mt_FloatValue,WeightChannel[0].Offset,0,0,al_Operator,0.0,0.0,0.0,260,NULL ,262,261,&MenuTestVariable[262],NULL,NULL,6,263}, //Смещение нуля в Вольтах весового канала 1
Вот здесь. Первая строка всё нормально. А появление второй сразу закидывает таблицу в ОЗУ, поскольку объект "WeightChannel[0]" находится в ОЗУ.
Всем спасибо за помощь. Тема закрыта.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|