GCC believes int pointers are not bound to ARM

I have the following test program:

#include <string.h> int q(int *p) { int x; memcpy(&x,p,sizeof(int)); x+=12; memcpy(p,&x,sizeof(int)); return p[0]; } 

When I compile this with GCC 4.7.2 for arm-linux-gnueabihf, the compiler suspects that the pointer calls may be jagged, annotating the loads and storage at the output of the assembly, for example:

  ldr r0, [r0, #0] @ unaligned 

If I compile with -mno-unaligned-access , the compiler does not generate direct loads and saves files, but calls the memcpy library. But in fact, pointers in this case should never be unbalanced. Is this a pass in gcc, or am I mistaken?

+4
source share
4 answers

I think gcc really gets confused when pressing int* on void* in a memcpy call and accepts the worst for such a pointer. Perhaps he tried to check the alignment of the pointer. Have you tried to increase the level of optimization? Maybe at higher levels gcc getting smarter.

It is also possible that gcc does not guarantee alignment of int pointers in all of its code, but that would be unreasonable and unlikely.

The compiler allows proper alignment of int*p due to clause 6.2.3.2 ad 7:

A pointer to an object type can be converted to a pointer to another object type. If the resulting pointer is not correctly aligned 68) for the reference type, the behavior is undefined.

Note 68) relates to the transitivity of proper alignment.

+2
source

There are several improvements in C compilers that are better optimized than the loads and stores of int values, which by design have a natural size for the machine.

Write the function as

 int q(int *p) { return *p += 12; } 

which allows you to avoid two calls to the library procedure, which you otherwise would rely on for the optimizer for the built-in one and come down to simple loading and storage, and expresses the intention to change the parameter of the integer value in place and return the result.

Using memcpy to assign integers will mask the intent.

If this question is the result of reducing a larger problem to an example of a misunderstanding, then my implementation may not help directly. But even if the type p is equal to some_complex_struct * rather than int * , the tip will still apply. The assignment operator works. Use it instead of memcpy where it makes sense.

+2
source

If your version of the Linux kernel is up to version 2.6.28. GCC throws this Warning . -munaligned-access supports memory access on unmanaged addresses. This requires that the core of these systems include such calls. Alternatively, unaudited calls are not supported, all code must be compiled with -mno-unaligned-access. Upstream Linux kernel versions automatically and unconditionally support nonaligned calls issued by GCC because this option has been active since version 2.6.28.

+1
source

This is the solution I came across when implementing a couple of alternatives for accessing data fields:

 // #define USE_MEMCPY // #define USE_PACKED #ifdef __cplusplus template <typename T> void SET(T *__attribute__((may_alias)) p, T val) { *p=val; } template <typename T> T GET(T *__attribute__((may_alias)) p) { return *p; } #else #ifdef USE_MEMCPY #include <string.h> #define _SET(p,val,line) \ ({ typeof(val) _temp_##line = (val); \ memcpy((void*)(p),(void*)&_temp_##line,sizeof(_temp_##line)); }) #define _GET(p,line) \ ({ typeof(*(p)) _temp_##line; \ memcpy((void*)&_temp_##line,(void*)(p),sizeof(_temp_##line)); \ _temp_##line; }) #define SET(p,val) _SET(p,val,__LINE__) #define GET(p) _GET(p,__LINE__) #else /* no memcpy */ #ifdef USE_PACKED #define SET(p,val) (((struct { typeof(val) x __attribute__((packed)); } __attribute__((may_alias))*)p)->x=(val)) #define GET(p) (((struct { typeof(*p) x __attribute__((packed)); } __attribute__((may_alias))*)p)->x) #else #define SET(p,val) (*((typeof(val) __attribute__((may_alias))*)p)=(val)) #define GET(p) (*((typeof(*p) __attribute__((may_alias))*)p)) #endif #endif #endif 

Then I can write a function like this:

 int q(int *p) { SET(p,GET(p)+12); return p[0]; } 
+1
source

All Articles