выравнивание памяти mmap в ARM

Я работаю над проектом, который переносится на ARM7 (изначально был на x86). Он работает на QNX. У нас было несколько проблем с выравниванием памяти (ошибка SIGBUS) из-за чтения/записи со смещенными указателями. Я исправил большинство проблем с выравниванием, просто заменив приведение и назначение указателя на memcpy, но эту проблему я не могу решить таким образом.

Существует общий пул памяти между процессами, который инициализируется следующим образом:

int m_nSharedMemory = shm_open(EVENT_LIST_NAME, O_RDWR | O_CREAT, 0777);
ftruncate(m_nSharedMemory, nSize)
unsigned char* m_pMemory = (unsigned char*) mmap(0, nSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_nSharedMemory, 0); 

Предполагается, что память используется следующим образом: в начале адресного пространства есть Header, а затем массив Event. Таким образом, nSize = sizeof(Header) + MAX_EVENTS * sizeof(Event).

m_pHeader = (Header*)m_pMemory;
m_pEvents = (Event*)(m_pMemory + sizeof(Header));

И Header, и Event являются структурами с примитивными типами. Насколько мне известно, эта память не выровнена, поэтому выполнение m_pEvents[0].m_SomeField == 3 или m_pHeader->m_SomeField = 1 потенциально может вызвать ошибку SIGBUS. Такого рода инструкции повсюду, поэтому замена каждой из них на memcpy будет настоящей проблемой, я надеюсь, что смогу обойтись чем-то другим.

Я нашел posix_memalign, который, по моему мнению, может заменить либо shm_open, либо mmap, еще не уверен, что именно, но это тоже не решает проблему. Во-первых, я все еще получаю предупреждение. Даже игнорируя предупреждение, я мог бы убедиться, что память выровнена по sizeof(Header), но m_pEvents не будет выровнена.

Есть ли способ предотвратить ошибку SIGBUS без внесения серьезных изменений в эту схему? Сейчас компилятор ругается из-за "cast from 'unsigned char*' to 'Header*' increases required alignment of target type" (такое же предупреждение есть для Event), но программа не падает, чего я действительно не могу объяснить.

Итак, два вопроса: 1) Почему не вылетает? 2) Как мне убедиться, что этого никогда не произойдет, в идеале, обеспечив выравнивание памяти и подавление предупреждения


person freejuices    schedule 29.05.2017    source источник
comment
вы имели в виду armv7 или arm7? Вы указываете на ram, в основном пересекая домен компиляции, нет никакого способа гарантировать, что он никогда не выйдет из строя (ну, вы можете отключить проверку выравнивания, и результат варьируется между armv7 и arm7) этот стиль программирования всегда будет иметь эту проблему, поэтому вам всегда придется поддерживать этот код, если/когда вы его перекомпилируете.   -  person old_timer    schedule 29.05.2017
comment
элементарная математика указателя поставит вас на правильное начальное выравнивание, если вам нужно выровнять границу 8 байтов (64 бита), тогда вы выделяете 7 или 8 дополнительных байтов и настраиваете указатель, который возвращается из распределения. кроме того, если вы используете структуры, то это проблема обслуживания на всю жизнь.   -  person old_timer    schedule 29.05.2017
comment
Измените Header на 32/64 бита или добавьте дополнение к nSize и выровняйте m_pEvents. (m_pMemory + sizeof(Header) + 7) & ~7 Вы должны прочитать FSR (регистр статуса ошибки), чтобы посмотрите, не является ли это проблемой выравнивания или разрешения.   -  person artless noise    schedule 29.05.2017
comment
вы можете предотвратить сбой, но не можете гарантировать работу.   -  person old_timer    schedule 29.05.2017
comment
@artlessnoise, круто, мы спрашиваем кандидатов на собеседовании о согласованности, и почти никто, ну на самом деле никто, включая большинство сотрудников, не предлагает этого простого решения. большинство делают по модулю с if и add, другие делают маску с if и add, приятно это видеть...   -  person old_timer    schedule 29.05.2017
comment
@old_timer Моя цель в gcc — PLT_ARM7LE, не уверен, что это отвечает на вопрос. Что я хочу сделать, так это предотвратить сбои SIGBUS, работает ли код или нет, это проблема для другого дня.   -  person freejuices    schedule 29.05.2017
comment
@artlessnoise Я нашел решение для m_pEvents. Все еще не получил тот для Header. Что вы имеете в виду, чтобы изменить его, чтобы выровнять его до 32/64? Header запустится везде, где mmap решит выровнять m_pMemroy. Может быть, я должен добавить, что nSize = sizeof(Header) + MAX_EVENTS * sizeof(Event)   -  person freejuices    schedule 29.05.2017
comment
нет не помогает. бесхитростный шум просто дал вам рыбу на этом, а не научил вас ловить рыбу. вам нужно начать с правильного начального выравнивания, тогда в зависимости от структур, а не только от массива некоторой степени двойного размера (байты, полуслова, слова, двойные слова), у вас может быть больше работы. структуры могут приземлиться где-то между предотвращением сбоя или нет или всегда работать в зависимости от того, как вы объявляете их и их содержимое и упаковываете их. если он хорошо упакован, вы можете проверить sizeof во время выполнения перед использованием и выручить, если он неправильный.   -  person old_timer    schedule 29.05.2017
comment
нет причин, по которым вам нужно использовать указатель, который возвращается из mmap, поскольку вы можете начать с нескольких байтов, в этом суть.   -  person old_timer    schedule 29.05.2017
comment
если вы указываете на что-то в памяти, используемое чем-то другим, тогда, конечно, вы должны использовать начальный адрес указателя как есть, но тогда вам придется иметь дело с попыткой перевыравнивания вещей, если они не попадают на красивую границу, тогда вы нужно разделить их на байты и построить то, что вам нужно...   -  person old_timer    schedule 29.05.2017