Notes: 1. the same issue occurs on x86 and x86_64 linux hosts, with a GCC cross-compiler of the same version is built with the same options 2. the same issue occurs with GCC cross compiler 4.4.3 (same build options, without the MPC host library)
I'm afraid I failed to understand something obvious, as this "bug" seems so weird that I can't really believe it is an actual compiler bug. Please let me know if/where I'm wrong. I first encountered this "bug" while compiling the eCos 3.0+ kernel for an ARM926 target. The issue appends within the fopen.cxx source file (fopen() implementation): the 'mode' parameter is converted from a char string - such as "r" - into a fcntl enumerated value - O_RDONLY in this case, through two switch/case statements When built with -O0 or-01, the compiler does not emit a jump table for the switch/case and the produced 'mode' integer value is the expected one. When build with -O2 or -O3, the compiler does emit a jump table, but the jump table is invalid: the net result is that for the '0' case value, the jump table index points to an address that is outside the jump table, and the value returned from the jump table is random. When the -Wtype-limits option switch is used, the compiler does emit a warning, but I failed to understand the reason for this warning. I shrinked down the 'fopen.cxx' code to a single, simple function and the assembly code contains the same invalid statement as it is in the original file, the type-limits warning is also the same. The source code does not rely on any other file (no header file). //------------- C source ---------------------------------------------- #define O_RDONLY (1<<0) #define O_WRONLY (1<<1) #define O_RDWR (O_RDONLY|O_WRONLY) #define O_CREAT (1<<3) #define O_TRUNC (1<<6) typedef enum { OM_READ = 0, OM_WRITE, OM_READWRITE_NOCREATE, OM_READWRITE_CREATE } OpenMode; extern "C" int open(const char *name, int mode); void open_file(const char *filename, const OpenMode rw) { int mode = 0; switch( rw ) { case OM_WRITE: mode = O_WRONLY|O_CREAT|O_TRUNC; break; case OM_READ: mode = O_RDONLY; break; case OM_READWRITE_NOCREATE: mode = O_RDWR; break; case OM_READWRITE_CREATE: mode = O_RDWR|O_CREAT|O_TRUNC; break; } open( filename, mode ); } // ----------------- end of C code ------------------------------------ The above C code is built with the following command: arm-eabi-gcc -c -O2 -mcpu=arm926ej-s -fno-rtti -fno-exceptions -Wtype-limits \ -o fopen.o fopen.cxx The compiler emits the following warning: fopen.cxx: In function void open_file(const char*, OpenMode): fopen.cxx:16:6: warning: comparison always true due to limited range of data type The disassemble code looks like the following: //------------- ASM --------------------------------------------------- fopen.o: file format elf32-littlearm Disassembly of section .text: 00000000 <_Z9open_filePKc8OpenMode>: 0: e59f300c ldr r3, [pc, #12] ; 14 <_Z9open_filePKc8OpenMode+0x14> 4: e2411001 sub r1, r1, #1 8: e20110ff and r1, r1, #255 ; 0xff c: e7931101 ldr r1, [r3, r1, lsl #2] 10: eafffffe b 0 <open> 14: 00000000 andeq r0, r0, r0 Disassembly of section .rodata: 00000000 <CSWTCH.1>: 0: 0000004a andeq r0, r0, r10, asr #32 4: 00000003 andeq r0, r0, r3 8: 0000004b andeq r0, r0, r11, asr #32 //------------- end of ASM -------------------------------------------- The jump table should contain 4 entries. It is only 3 entry wide. There's no entry for 'case OM_READ'. Nevertheless, the compiler shifts the index (sub r1, r1, #1), as if the switch() value were starting from 1, rather than from 0. When switch (OM_READ) is executed, r1 is decremented from 0 to 0xffffffff, then masked to a single byte 0xff, following the ARM AAPCS variable-width enumerated types. This new index is used to access the jump table, but index 0xff is out of the jump table. Notes: * If OpenMode enum is forced to start from 1 -rather than 0-, the emitted code is valid (4-entry jump table): OM_READ = 1 * If OpenMode enum is simply added another entry, the emitted code changes and becomes valid (4-entry jump table): OM_READWRITE_CREATE, OM_DUMMY, * If mode is not initialized to a default value, but mode is assigned the same value (0) within a 'default', emitted code is valid: int mode; // default: mode = 0; break; The compiler has been built with the following options: $> arm-eabi-gcc -c -O2 -mcpu=arm926ej-s -fno-rtti -fno-exceptions -o fopen.o fopen.cxx -Wtype-limits -v Using built-in specs. COLLECT_GCC=arm-eabi-gcc COLLECT_LTO_WRAPPER=/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/libexec/gcc/arm-eabi/4.5.0/lto-wrapper Target: arm-eabi Configured with: ../configure --prefix=/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0 --target=arm-eabi --disable-shared --with-gnu-as --with-gnu-ld --with-newlib --enable-softfloat --disable-bigendian --disable-fpu --disable-underscore --enable-multilibs --with-float=soft --enable-interwork --enable-lto --with-multilib-list=interwork --with-abi=aapcs --enable-languages=c,c++ --disable-__cxa_atexit --with-gmp=/usr/local/homebrew/Cellar/gmp/5.0.1 --with-mpfr=/usr/local/homebrew/Cellar/mpfr/2.4.2 --with-mpc=/usr/local/homebrew/Cellar/libmpc/0.8.1 --with-ppl=/usr/local/homebrew/Cellar/ppl/0.10.2 --with-cloog=/usr/local/homebrew/Cellar/cloog-ppl/0.15.7 --with-libelf=/usr/local/homebrew/Cellar/libelf/0.8.13 --with-gxx-include-dir=/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/arm-eabi/include --disable-debug Thread model: single gcc version 4.5.0 COLLECT_GCC_OPTIONS='-c' '-O2' '-mcpu=arm926ej-s' '-fno-rtti' '-fno-exceptions' '-o' 'fopen.o' '-Wextra' '-save-temps' '-v' '-mfloat-abi=soft' '-mabi=aapcs' /usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/libexec/gcc/arm-eabi/4.5.0/cc1plus -E -quiet -v -D__USES_INITFINI__ fopen.cxx -mcpu=arm926ej-s -mfloat-abi=soft -mabi=aapcs -Wextra -fno-rtti -fno-exceptions -O2 -fpch-preprocess -o fopen.ii ignoring nonexistent directory "/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/../../../../arm-eabi/sys-include" ignoring duplicate directory "/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/../../../../arm-eabi/include" #include "..." search starts here: #include <...> search starts here: /usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/arm-eabi/include /usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/arm-eabi/include/arm-eabi /usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/arm-eabi/include/backward /usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/include /usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/include-fixed End of search list. COLLECT_GCC_OPTIONS='-c' '-O2' '-mcpu=arm926ej-s' '-fno-rtti' '-fno-exceptions' '-o' 'fopen.o' '-Wextra' '-save-temps' '-v' '-mfloat-abi=soft' '-mabi=aapcs' /usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/libexec/gcc/arm-eabi/4.5.0/cc1plus -fpreprocessed fopen.ii -quiet -dumpbase fopen.cxx -mcpu=arm926ej-s -mfloat-abi=soft -mabi=aapcs -auxbase-strip fopen.o -O2 -Wextra -version -fno-rtti -fno-exceptions -o fopen.s GNU C++ version 4.5.0 (arm-eabi) compiled by GNU C version 4.2.1 (Apple Inc. build 5659), GMP version 5.0.1, MPFR version 2.4.2, MPC version 0.8.1 GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 GNU C++ version 4.5.0 (arm-eabi) compiled by GNU C version 4.2.1 (Apple Inc. build 5659), GMP version 5.0.1, MPFR version 2.4.2, MPC version 0.8.1 GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: dc4afb9bd29f2a2942808dba7d87c9cb fopen.cxx: In function void open_file(const char*, OpenMode): fopen.cxx:17:6: warning: comparison always true due to limited range of data type COLLECT_GCC_OPTIONS='-c' '-O2' '-mcpu=arm926ej-s' '-fno-rtti' '-fno-exceptions' '-o' 'fopen.o' '-Wextra' '-save-temps' '-v' '-mfloat-abi=soft' '-mabi=aapcs' /usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/../../../../arm-eabi/bin/as -v -mcpu=arm926ej-s -mfloat-abi=soft -meabi=5 -o fopen.o fopen.s GNU assembler version 2.20.1 (arm-eabi) using BFD version (GNU Binutils) 2.20.1.20100303 COMPILER_PATH=/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/libexec/gcc/arm-eabi/4.5.0/:/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/libexec/gcc/arm-eabi/4.5.0/:/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/libexec/gcc/arm-eabi/:/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/:/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/:/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/../../../../arm-eabi/bin/ LIBRARY_PATH=/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/:/usr/local/homebrew/Cellar/gcc-arm-ecos/4.5.0/lib/gcc/arm-eabi/4.5.0/../../../../arm-eabi/lib/ COLLECT_GCC_OPTIONS='-c' '-O2' '-mcpu=arm926ej-s' '-fno-rtti' '-fno-exceptions' '-o' 'fopen.o' '-Wextra' '-save-temps' '-v' '-mfloat-abi=soft' '-mabi=aapcs' -- Summary: switch/case optimization produces an invalid jump table index Product: gcc Version: 4.5.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: eblot dot ml at gmail dot com GCC build triplet: x86_64-apple-darwin10 GCC host triplet: x86_64-apple-darwin10 GCC target triplet: arm-eabi http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44328