Skip to content

Commit

Permalink
toolchain: gcc: Add compiler barrier at the end of UNALIGNED_PUT()
Browse files Browse the repository at this point in the history
compiler_barrier() is itself defined down in this file. Without
adding it, newer versions of GCC (7+) for ARM Cortex-M may mistakenly
coalesce multiple strb/strh/str (store byte/half-word/word)
instructions, which support unaligned access on some
sub-architectures (Cortex-M3 and higher, but not on Cortex-M0),
into strd (store double), which doesn't support unaligned access.

Fixes: zephyrproject-rtos#6307

Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
  • Loading branch information
pfalcon committed Jun 8, 2018
1 parent 8b9042c commit 35fc5f0
Showing 1 changed file with 25 additions and 0 deletions.
25 changes: 25 additions & 0 deletions include/toolchain/gcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,29 @@ __extension__ ({ \
__p->__v; \
})


#if __GNUC__ >= 7 && defined(CONFIG_ARM)

/* Version of UNALIGNED_PUT() which issues a compiler_barrier() after
* the store. It is required to workaround an apparent optimization
* bug in GCC for ARM Cortex-M3 and higher targets, when multiple
* byte, half-word and word stores (strb, strh, str instructions),
* which support unaligned access, can be coalesced into store double
* (strd) instruction, which doesn't support unaligned access (the
* compilers in question do this optimization ignoring __packed__
* attribute).
*/
#define UNALIGNED_PUT(v, p) \
do { \
struct __attribute__((__packed__)) { \
__typeof__(*p) __v; \
} *__p = (__typeof__(__p)) (p); \
__p->__v = (v); \
compiler_barrier(); \
} while (0)

#else

#define UNALIGNED_PUT(v, p) \
do { \
struct __attribute__((__packed__)) { \
Expand All @@ -74,6 +97,8 @@ do { \
__p->__v = (v); \
} while (0)

#endif

/* Double indirection to ensure section names are expanded before
* stringification
*/
Expand Down

0 comments on commit 35fc5f0

Please sign in to comment.