test.c below shows example of a problem seen in a larger code base. happens when access 16bit & 32bit uints inside struct (or byte array) via pointers to struct fields rather than the struct itself expect val to be same in all tests. & for example TESTA is so with gcc-3.4.6 i486-slackwaere-linux little-end: ptr 0xbf81bec0 0xbf81bec1 0xbf81bec3, val 1 302 7060504 ptr 0xbf81bec0 0xbf81bec1 0xbf81bec3, val 1 302 7060504 ptr 0xbf81bec0 0xbf81bec1 0xbf81bec3, val 1 302 7060504 ptr 0xbf81beb0 0xbf81beb1 0xbf81beb3, val 1 302 7060504 & gcc-3.4.2 mips-linux-uclibc big-end (cross compile): ptr 0x7fff7da0 0x7fff7da1 0x7fff7da3, val 1 203 4050607 ptr 0x7fff7da0 0x7fff7da1 0x7fff7da3, val 1 203 4050607 ptr 0x7fff7da0 0x7fff7da1 0x7fff7da3, val 1 203 4050607 ptr 0x7fff7da8 0x7fff7da9 0x7fff7dab, val 1 203 4050607 but have problems with gcc-4.3.3 arm-linux-gnueabi little-end: TESTA: ptr 0xbe93f8db 0xbe93f8dc 0xbe93f8de, val 1 302 7060504 ptr 0xbe93f8db 0xbe93f8dc 0xbe93f8de, val 1 302 7060504 ptr 0xbe93f8db 0xbe93f8dc 0xbe93f8de, val 1 302 3020504 <<< u32 nok ptr 0xbe93f8d4 0xbe93f8d5 0xbe93f8d7, val 1 201 3020104 <<< u16 nok TESTB: ptr 0xbee018dc 0xbee018dd 0xbee018df, val 1 302 7060504 ptr 0xbee018dc 0xbee018dd 0xbee018df, val 1 302 7060504 ptr 0xbee018dc 0xbee018dd 0xbee018df, val 1 201 3020104 <<< u16 nok ptr 0xbee018d5 0xbee018d6 0xbee018d8, val 1 302 7060504 <<< u32 nok - removing packed & 'char c' (TESTC) so us_t.u16 & us_t.u32 both at even address gets around problem. so looks like an alignment issue - but accessing via a pointer to entire struct (us_p) is always ok. so looks like alignment not an issue questions: - is use of pointer to struct fields (@ [1]) non-portable? - is there compiler config &/or options to fix this? (specs attached) - a blue moon case of 'compiler did it wrong' being fact rather than too quick excuse for own buggy code? (gotta be so 1 day) ############################
#include <stdint.h> #include <stdio.h> #define TESTA 1 #define TESTB 0 #define TESTC 0 #if !defined(offsetof) #define offsetof(x, y) __builtin_offsetof(x, y) #endif #if TESTC typedef struct #else typedef struct __attribute__ ((packed)) #endif { uint8_t u8; uint16_t u16; uint32_t u32; } us_t; int main() { #if TESTA char c; // dummy c = 1; #endif // struct us_t us; // byte array uint8_t ua[7]; uint8_t i; uint8_t * j; // fill us & ua 1,2,3.. for (i = 0, j = (uint8_t *)&us; i < sizeof(us); i++, j++) { *j = i + 1; ua[i] = i + 1; } #if 0 printf("%d %d %d\n", offsetof(us_t, u8), offsetof(us_t, u16), offsetof(us_t, u32)); #endif // via struct, all ok printf("ptr %p %p %p, val %x %x %x\n", &us.u8, &us.u16, &us.u32, us.u8, us.u16, us.u32); // via ptr to whole struct, all ok us_t * us_p = &us; printf("ptr %p %p %p, val %x %x %x\n", &us_p->u8, &us_p->u16, &us_p->u32, us_p->u8, us_p->u16, us_p->u32); // [1] via ptr to packed struct fields, armv5tel nok uint8_t * u8_p = &us.u8; uint16_t * u16_p = &us.u16; uint32_t * u32_p = &us.u32; printf("ptr %p %p %p, val %x %x %x\n", u8_p, u16_p, u32_p, *u8_p, *u16_p, *u32_p); #if !TESTC // [2] via ptr to equivalent byte array locations, amv5tel nok u8_p = &ua[0]; u16_p = (uint16_t *)&ua[1]; u32_p = (uint32_t *)&ua[3]; printf("ptr %p %p %p, val %x %x %x\n", u8_p, u16_p, u32_p, *u8_p, *u16_p, *u32_p); #endif return 0; }
############################
$ uname -a Linux xxxx 2.6.26-1-orion5x #1 Sun Jan 11 17:19:11 UTC 2009 armv5tel GNU/Linux ################################# $ gcc -v Using built-in specs. Target: arm-linux-gnueabi Configured with: ../src/configure -v --with-pkgversion='Debian 4.3.3-4' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --disable-libssp --disable-sjlj-exceptions --enable-checking=release --build=arm-linux-gnueabi --host=arm-linux-gnueabi --target=arm-linux-gnueabi Thread model: posix gcc version 4.3.3 (Debian 4.3.3-4) ################################# $ gcc -dumpspecs *asm: %{mbig-endian:-EB} %{mlittle-endian:-EL} %{mcpu=*:-mcpu=%*} %{march=*:-march=%*} %{mapcs-*:-mapcs-%*} %(subtarget_asm_float_spec) %{mthumb-interwork:-mthumb-interwork} %{msoft-float:-mfloat-abi=soft} %{mhard-float:-mfloat-abi=hard} %{mfloat-abi=*} %{mfpu=*} %(subtarget_extra_asm_spec) *asm_debug: %{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}} %{fdebug-prefix-map=*:--debug-prefix-map %*} *asm_final: *asm_options: %{--target-help:%:print-asm-header()} %a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} *invoke_as: %{!S:-o %|.s | as %(asm_options) %m.s %A } *cpp: %(subtarget_cpp_spec) %{msoft-float:%{mhard-float: %e-msoft-float and -mhard_float may not be used together}} %{mbig-endian:%{mlittle-endian: %e-mbig-endian and -mlittle-endian may not be used together}} *cpp_options: %(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w} %{f*} %{g*:%{!g0:%{!fno-working-directory:-fworking-directory}}} %{O*} %{undef} %{save-temps:-fpch-preprocess} *cpp_debug_options: %{d*} *cpp_unique_options: %{C|CC:%{!E:%eGCC does not support -C or -CC without -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}} %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{fmudflap:-D_MUDFLAP -include mf-runtime.h} %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h} %{E|M|MM:%W{o*}} *trad_capable_cpp: cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp} *cc1: %{profile:-p} *cc1_options: %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*} %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{--help=*:--help=%(VALUE)} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants} %{coverage:-fprofile-arcs -ftest-coverage} *cc1plus: *link_gcc_c_sequence: %{static:--start-group} %G %L %{static:--end-group}%{!static:%G} *link_ssp: %{fstack-protector:} *endfile: %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s *link: %{!static:--eh-frame-hdr} %{h*} %{version:-v} %{b} %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker %{muclibc:%{mglibc:%e-mglibc and -muclibc used together}/lib/ld-uClibc.so.0;:/lib/ld-linux.so.3}} -X %{mbig-endian:-EB} %{mlittle-endian:-EL} -m armelf_linux_eabi *lib: %{pthread:-lpthread} %{shared:-lc} %{!shared:%{profile:-lc_p}%{!profile:-lc}} *mfwrap: %{static: %{fmudflap|fmudflapth: --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc --wrap=mmap --wrap=munmap --wrap=alloca} %{fmudflapth: --wrap=pthread_create}} %{fmudflap|fmudflapth: --wrap=main} *mflib: %{fmudflap|fmudflapth: -export-dynamic} *link_gomp: *libgcc: %{static|static-libgcc:-lgcc -lgcc_eh}%{!static:%{!static-libgcc:%{!shared-libgcc:-lgcc --as-needed -lgcc_s --no-as-needed}%{shared-libgcc:-lgcc_s%{!shared: -lgcc}}}} *startfile: %{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}} crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} *switches_need_spaces: *cross_compile: 0 *version: 4.3.3 *multilib: . ; *multilib_defaults: marm mlittle-endian mhard-float mno-thumb-interwork *multilib_extra: *multilib_matches: *multilib_exclusions: *multilib_options: *linker: collect2 *link_libgcc: %D *md_exec_prefix: *md_startfile_prefix: *md_startfile_prefix_1: *startfile_prefix_spec: *sysroot_spec: --sysroot=%R *sysroot_suffix_spec: *sysroot_hdrs_suffix_spec: *subtarget_cpp_spec: %{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT} *subtarget_extra_asm_spec: %{mabi=apcs-gnu|mabi=atpcs:-meabi=gnu;:-meabi=4} *subtarget_asm_float_spec: %{mapcs-float:-mfloat} *link_command: %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S: %(linker) %l %{pie:-pie} %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %(mfwrap) %(link_libgcc) %o %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib) %{fprofile-arcs|fprofile-generate|coverage:-lgcov} %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}} ################################# $ cat /proc/cpuinfo Processor : Feroceon rev 0 (v5l) BogoMIPS : 332.59 Features : swp half thumb fastmult edsp CPU implementer : 0x41 CPU architecture: 5TEJ CPU variant : 0x0 CPU part : 0x926 CPU revision : 0 Cache type : write-back Cache clean : cp15 c7 ops Cache lockdown : format C Cache format : Harvard I size : 32768 I assoc : 1 I line length : 32 I sets : 1024 D size : 32768 D assoc : 1 D line length : 32 D sets : 1024
--