To illustrate my problem, I just implemented demonstration code:
#include <stdint.h> uint64_t read(const uint32_t *wordStream) { uint32_t low = *wordStream++; uint64_t high = *wordStream++; high <<= 32; return high | low; }
This code reads (according to C) two unsigned 32 bit words. It assumes a little endian notation. Then it assembles these two words into a 64 bit value and returns it.
Unfortunately, the compiler assumes, that the first word is 64 bit aligned (by using the LDRD instruction which is only allowed on aligned 64 bit values):
; generated by Component: ARM Compiler 5.06 update 1 (build 61) Tool: armcc [4d35ad] ; commandline armcc [--thumb -c --asm -otestCode.o --cpu=SC300 testCode.c] THUMB REQUIRE8 PRESERVE8 AREA ||.text||, CODE, READONLY, ALIGN=1 read PROC LDRD r2,r1,[r0,#0] MOV r0,r2 BX lr ENDP ...
Where did I tell the compiler that the first word is aligned?
#include <stdint.h> #include <string.h> uint64_t read(const void *wordStream) { // alignment agnostic uint64_t u64; memcpy(&u64, wordStream, sizeof(uint64_t)); return u64; }
#include <stdint.h> uint64_t read(const void *wordStream) { // alignment agnostic return (*(__packed uint64_t *)wordStream); }
Thank you for this suggestion.
It definitely works. It also produces a lot of unnecessary (performance) overhead. I just didn't see the need to call a function if (in C) there is a fine way to express the access.
Of course, my real field of application is a lot more complex. Instead of calling memcpy, I will implement or embed the read function in assembly language.
Thanks again, Werner
/** \brief Read 32-bit variable from network byte-order. \param[in] u32 pointer to a variable. \return 32-bit result in host byte-order. */ uint32_t net_rd_u32 (const uint8_t *u32) { uint32_t retv; #ifndef __USE_UNALIGNED_ACCESS retv = u32[0] << 24; retv |= u32[1] << 16; retv |= u32[2] << 8; retv |= u32[3]; #else retv = ntohl(*(uint32_t *)u32); #endif return (retv); }