Перейти к содержанию
    

STM32L0 HardFault: заморочки с выравниванием

1 hour ago, jcxz said:

Точку фаулта (PC) знаете?

PC ведь указывает на текущее положение, на ту строку дизассемблера которая сейчас выполняется. Нужно смотреть на LR или проще посмотреть callstack если он не затерт

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, Integro сказал:

PC ведь указывает на текущее положение, на ту строку дизассемблера которая сейчас выполняется. Нужно смотреть на LR или проще посмотреть callstack если он не затерт

Под "точкой фаулта (PC)" я имел в виду адрес PC, на котором произошёл fault.

haker_fox писал, что у него уже анализируются регистры. По-моему под анализом надо понимать выдачу пользователю содержимого всех регистров CPU + кадра активного стека + расшифровки регистров HF. Типа как в синем окне смерти винды. По-крайней мере у меня во всех проектах сделано именно так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 minutes ago, Integro said:

Нужно смотреть на LR или проще посмотреть callstack если он не затерт

В fault'е LR не указывает на точку сбоя, её следует взять из стек-фрейма, который точно не затерт, т.к. записан на входе в исключение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

37 minutes ago, jcxz said:

Под "точкой фаулта (PC)" я имел в виду адрес PC, на котором произошёл fault. 

 

нуда, понял

 

33 minutes ago, aaarrr said:

В fault'е LR не указывает на точку сбоя, её следует взять из стек-фрейма, который точно не затерт, т.к. записан на входе в исключение.

Всмысле точно? Перед входом в исключение я могу совершенно "штатно"(случайно) затереть стек и при этом исключение может сработать только при выходе функции (или еще дальше) а не в момент затирания стека.

void test(void) {

    uint8_t dest[1000];
    uint32_t src[1000] = {0};

    memcpy(dest, src, sizeof(src));
    
    printf("complete");
}

В этом случае в стек фрейме будут нули но в LR будет лежать PC+1, адрес в момент HF.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 minutes ago, Integro said:

В этом случае в стек фрейме будут нули но в LR будет лежать PC+1, адрес в момент HF.

1. Не будет нулей, будет состояние регистров на момент fault'а.

2. В LR не будет лежать PC+1, механизм исключений Cortex'а вообще такого варианта не предусматривает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 hours ago, jcxz said:

Так вроде Вы написали, что анализируете:

Ну да, это я к слову...

Кстати, вы не читали Дж. Ю "Архитектура процессоров Cortex-M3 и Cortex-M4"? У него целая глава посвящена hf. Тоже и в книге для Cortex-M0.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 часов назад, haker_fox сказал:

Кстати, вы не читали Дж. Ю "Архитектура процессоров Cortex-M3 и Cortex-M4"? У него целая глава посвящена hf. Тоже и в книге для Cortex-M0.

Нет. Много лет назад сделал обработку fault-ов. С тех пор просто перетаскиваю её из проекта в проект. Сделал по даташиту на ядро. Там всего ничего регистров. С M0 не работал, только M3/M4.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 2/1/2017 at 8:44 AM, ViKo said:

Допустим, memcpy умеет правильно обращаться по невыровненному адресу. Или тупо байтами копирует. Но как помогает приведение указателя к указателю на выровненную структуру? От этого положение данных не меняется же.

memcpy копирует в общем случае побайтно. Вроде есть реализации, где она копирует сначала в максимальной разрядности процессора, а потом, при нечетном количестве байт, докопирует побайтно. Очевидно, что реализация для M0|M0+ будет побайтная. Приведение к упакованной структуре просто порождает код, который работает побайтно. Потому компилятору и сообщают ключи типа -CortexM0, вроде того.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 часов назад, KnightIgor сказал:

Очевидно, что реализация для M0|M0+ будет побайтная. Приведение к упакованной структуре просто порождает код, который работает побайтно.

Из чего это очевидно?

memcpy в IAR проверяет - выровнены ли на 4 оба адреса и если да, то копирует (size & -16) байт (где size - размер из аргумента функции) инструкциями LDM/STM; если адреса не выровнены или (4 <= size < 16) - копирует пословно (по 4 байта LDR/STR); и только остальное - побайтно. Ну вначале ещё немного копирует побайтно, пытаясь выровнять адреса. То же самое возможно и в M0, имхо.

"Приведение к упакованной структуре" ничего не порождает, так как анализ указателей и размера происходит внутри memcpy() в runtime и memcpy ничего не знает о типе копируемых данных. И вообще не знает - структура это, или её часть или просто произвольная область памяти. Конечно некоторые компиляторы, имея данные о выравнивании или о размере копирования, могут вместо memcpy() общего вида подставлять специализированные memcpy, оптимизированные под данный случай вызова (не нужны проверки и выравнивания внутри в runtime).

Для пользователя (пишущего в коде memcpy()) всё это прозрачно и копирование он может считать побайтным. Если конечно он не сделал глупостей с приведением типа аргументов memcpy() (если такие глупости могут иметь место быть, то компилятор, будучи введён в заблуждение кривым приведением типов, может подставить оптимизированные функции memcpy() вместо memcpy() общего вида - тогда и будут проблемы с выравниванием).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Насчёт упакованной структуры - тут надо более чётко и громко сказать, что она наоборот делает объекты внутри себя невыровненными, выкидывая выравнивающие вставки. И кстати, тут по-моему не упоминался такой приём - объединять в union какой-нибудь void* или что-то вроде и указатель на требующий выравнивания тип. Тогда он будет выровнен и не появятся предупреждения компилятора о потере выравнивания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 2/1/2017 at 1:22 PM, jcxz said:

Вот для типов u16p8 и s16p8 (пакованный до байт беззнаковый и знаковый u16/s16):

Спасибо. После допиливания (я не очень понял, как оно работает изначально, без создания объекта, хотя бы временного) получилось следующее:

struct CASTtoU16 {
	template <typename T>
	CASTtoU16(T *data) :
		bytes((uint8_t *)data)
	{	}
	uint8_t * const bytes;
	operator uint16_t() const {
		return bytes[0] | (bytes[1] << 8);
	}
	CASTtoU16 & operator =(uint32_t val) {
		bytes[0] = val;	bytes[1] = val >> 8;
		return *this;
	}
};


// example
uint8_t arr[32];
CASTtoU16 {&arr[3]} = u16;
uint16_t u16 = CASTtoU16 {&arr[5]};

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...