Pointers to embedded devices

I had a strange problem when creating and modifying pointers on a 32-bit embedded system ( redbee econotag runs contiki OS to be specific).

uint32_t array[2]; array[0] = 0x76543210; array[1] = 0xfedcba98; uint8_t* point = ((uint8_t*)array)+1; printf("%08x \n", *(uint32_t*)point ); 

on my computer:

 98765432 

on the built-in device:

 10765432 

My computer behaves as I expect, the built-in device seems to wrap when it reaches the end of the word. Why is this happening?

+7
source share
5 answers

Your target "redbee econotag" is listed as ARM7 with ARMv4 architecture. ARMv4 does not provide equivalent access to memory, such as ARMv7 or an intelligent machine.

Quote from ARM Documentation :

In the architecture of ARMv4 and ARMv5, as well as in the architecture of ARMv6, depending on how it is configured, care must be taken when accessing unbalanced data in memory so as not to return unexpected results. For example, when a regular pointer is used to read a word in C or C ++ source code, the ARM compiler generates assembly language code that reads the word using the LDR instruction. This works as expected when the address is a multiple of four, for example, if it is on the word boundary. However , if the address is not a multiple of four, LDR returns a rotated result, rather than performing a true unbalanced word load. Typically, this rotation is not what the programmer expects .

+13
source

With this code, you break the strict anti-aliasing rule: the object pointed to by point receives an lvalue expression of type uint32_t .

C11 (n1570), Β§ 6.5. Expressions
The object must have a stored value, accessed only by the lvalue expression, which has one of the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with an effective type of object,
- a type that is a signed or unsigned type corresponding to the effective type of an object,
- a type that is a signed or unsigned type corresponding to a quality version is an effective type of object,
- an aggregate or combined type that includes one of the above types among its members (including, recursively, a member of a sub-aggregate or a united union), or
- type of symbol.

This leads to undefined behavior, so anything can happen.

C11 (n1570), Β§ 4. Compliance
If "or" does not require an external constraint to be violated, then the behavior is undefined.

+13
source
 printf("%08x \n", *(uint32_t*)point ); 

The expression * in this expression causes undefined behavior: it violates the rules of aliases and can perform unattached access.

+6
source

Because of +1 you are performing asymmetric access to a 32-bit value, that is, the address is not a multiple of four.

x86 works regardless of alignment, because its roots completely return to 8-bit machines (maybe performance is a little worse).

ARM requires alignment (as with many other processors), so 32-bit values ​​must be placed at addresses that are multiples of four bytes. Various bad things can happen if it is not (wrong values, errors). For an array, the compiler will take care of this, but when you explicitly specify a pointer, you force it to break alignment.

+6
source

EDIT: note that the body of this answer doesn't matter according to the comments he suggested

The theory of the other answers is fine, but it probably won't help you. The actual problem is what you wrote:

 uint8_t* point = ((uint8_t*)array)+1; 

When you should write something like

 uint8_t* point = (uint8_t*)(array+1); 

because you need to increase the pointer as a pointer to the appropriate type (so the increment operation will add the size of the element) before you draw it on something else.

But one may ask if you really intend to have a byte pointer to a 32-bit value. Perhaps you intend to access it in different ways (beware that the byte order will vary by system!). Or perhaps you intended to point to a pointer to a 32-bit value, which in turn is a pointer to an 8-bit value somewhere else ...

+2
source

All Articles