2

I'm working on an embedded linux project using a Xilinx Zynq (ARM) platform that needs to map some physical FPGA addresses into virtual address space so I can access some 32-bit registers. Is there a way for me to invoke mmap(), then overlay a 32-bit array on at the mapped address for single operation access to these registers?

I'm currently using memcpy() to comply with strict aliasing rules, but this shows up as 4 separate accesses (1 per byte) to the FPGA. Is my only safe option to specify -fno-strict-aliasing when compiling?

KyleL
  • 1,379
  • 2
  • 13
  • 35
  • I'm no expert on memory-mapping or embedded systems, but what's the issue with `int32_t *regs = mmap(...)`? – user2357112 Aug 08 '14 at 01:37
  • Wouldn't that violate the strict aliasing rule since mmap doesn't return a pointer of type int32_t? http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule – KyleL Aug 08 '14 at 01:44
  • 4
    It returns a `void *`. What do you think it's aliasing? I don't think it's violating the rule any more than `int32_t *mem = malloc(4)`. – user2357112 Aug 08 '14 at 01:50

2 Answers2

4

You are misunderstanding the strict aliasing rule.

That rule is not only about types. It's about semantics too. Aliasing through a void * cast to some other pointer type is perfectly fine as long as there is an object of the appropriate type. (Else void * would not be useful.)

E. g.,

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

is OK, because ptr does contain the address of an uint32_t object; it's just that it has a different type.

So, the following piece of code:

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

may or may not violate the strict aliasing rule, depending on whether the register at address 0xf00ba12 is of type uint32_t. Thus, in your case, this is valid.


The strict aliasing rule concerns programmers who try to cheat by working around the type system and accessing an object through an lvalue of a different type. That of course involves casting pointers, but it's not the act of casting and dereferencing pointers that violates strict aliasing, but the fact that there's no object of the given type at the referencing address.

And please do not use -fno-strict-aliasing!

3

Strict aliasing itself is explained here, the relevant standard quotes are C99/C11 6.5 p.7. In short, it says you cannot access an object through an lvalue with a type different from its effective type (with some exceptions, see link).

C99/C11 6.5 p.6

The effective type of an object for an access to its stored value is the declared type of the object, if any.*) If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

*) Allocated objects have no declared type.

In other words, your first write access to that memory determines its effective type until the next write access, e.g.

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

As long as your access your mapped registers only as int32_t, you’re safe (you could do even more).

Community
  • 1
  • 1
mafso
  • 5,433
  • 2
  • 19
  • 40
  • Would `volatile` lvalues be exempt from the Strict Aliasing rule, on the grounds that a compiler is required to perform all accesses of volatile-qualified lvalues in sequence? Given `int p; short *q=(short*)&p, a compiler would have the right to expect that a write to `*q` would not affect p. If, however, both `p` and `*q` were `volatile`-qualified, I would expect that the compiler would never be entitled to assume that anything wouldn't affect p or *q. – supercat Aug 22 '15 at 23:43