Как получить доступ к многобайтовым регистрам с отображением в памяти, не нарушая правила строгого алиасинга?

Я работаю над встроенным проектом Linux, использующим платформу Xilinx Zynq (ARM), которая должна отображать некоторые физические адреса FPGA в виртуальное адресное пространство, чтобы я мог получить доступ к некоторым 32-битным регистрам. Есть ли способ для меня вызвать mmap (), а затем наложить 32-битный массив на сопоставленный адрес для доступа одной операции к этим регистрам?

В настоящее время я использую memcpy () для соответствия строгим правилам алиасинга, но это проявляется как 4 отдельных доступа (1 на байт) к FPGA. Является ли мой единственный безопасный способ указать -fno-strict-aliasing при компиляции?

2

Решение

Сам строгий псевдоним объясняется Вот, соответствующие стандартные цитаты — C99 / C11 6.5 с.7. Короче говоря, он говорит, что вы не можете получить доступ к объекту через lvalue с типом, отличным от его эффективный тип (с некоторыми исключениями, см. ссылку).

C99 / C11 6,5 с.6

Эффективным типом объекта для доступа к его сохраненному значению является объявленный тип объекта, если таковой имеется.*) Если значение сохраняется в объекте, у которого нет объявленного типа, через lvalue, имеющий тип, который не является символьным типом, то тип lvalue становится эффективным типом объекта для этого доступа и для последующих доступов, которые не изменяют сохраненное значение. Если значение копируется в объект, не имеющий объявленного типа, с использованием memcpy или memmove, или копируется как массив символьного типа, то эффективный тип измененного объекта для этого доступа и для последующих обращений, которые не изменяют значение, является действующий тип объекта, из которого копируется значение, если оно есть. Для всех других обращений к объекту, у которого нет объявленного типа, эффективный тип объекта — это просто тип lvalue, используемого для доступа.

*) Выделенные объекты не имеют объявленного типа.

Другими словами, ваш первый доступ к записи в эту память определяет ее эффективный тип до следующего доступа к записи, например,

void *foo = mmap(...);
*(int32_t *)foo = 1; // legal, the type of the mmaped object is now int32_t
*(float *)foo = 1.0; // legal, now the effective type is float
int32_t tmp = *(int32_t *)foo; // illegal, not compatible with the effective type

Пока ваш доступ к вашим картам регистрируется только как int32_tВы в безопасности (вы могли бы сделать еще больше).

3

Другие решения

Вы неправильно понимаете строгое правило псевдонимов.

Это правило не только о типах. Это касается и семантики тоже. Псевдоним через void * приведение к какому-либо другому типу указателя прекрасно, пока есть является объект соответствующего типа. (Else void * не было бы полезно.)

Например,

uint32_t reg = 1337;
void *ptr = ®
*(uint32_t *)ptr = 42;

все в порядке, потому что ptr содержит адрес uint32_t объект; просто у него другой тип.

Итак, следующий кусок кода:

uint32_t *regs = mmap(0xf00ba12, ...);
regs[0] = 0xffffffff;

может или не может нарушать строгое правило псевдонимов, в зависимости от того, регистр по адресу 0xf00ba12 имеет тип uint32_t, Таким образом, в вашем случае это действительно.


Строгое правило псевдонимов касается программистов, которые пытаются обманывать, работая с системой типов и получая доступ к объекту через lvalue другого типа. Это, конечно, включает в себя указатели, но это не акт приведения и разыменования указателей это нарушает строгий псевдоним, но тот факт, что по адресу ссылки нет объекта данного типа.

И пожалуйста сделай не использование -fno-strict-aliasing!

4

По вопросам рекламы [email protected]