Я работаю над встроенным проектом Linux, использующим платформу Xilinx Zynq (ARM), которая должна отображать некоторые физические адреса FPGA в виртуальное адресное пространство, чтобы я мог получить доступ к некоторым 32-битным регистрам. Есть ли способ для меня вызвать mmap (), а затем наложить 32-битный массив на сопоставленный адрес для доступа одной операции к этим регистрам?
В настоящее время я использую memcpy () для соответствия строгим правилам алиасинга, но это проявляется как 4 отдельных доступа (1 на байт) к FPGA. Является ли мой единственный безопасный способ указать -fno-strict-aliasing при компиляции?
Сам строгий псевдоним объясняется Вот, соответствующие стандартные цитаты — 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
Вы в безопасности (вы могли бы сделать еще больше).
Вы неправильно понимаете строгое правило псевдонимов.
Это правило не только о типах. Это касается и семантики тоже. Псевдоним через 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
!