When I cross compile an application for target with an Armv7 core, variables with 'long long int' are incorrectly printed.
typedef long long int vmm_int64;
typedef unsigned long long int vmm_uint64;
int main(int argc, char *argv[])
{
vmm_int64 a, b, result;
a = 5;
b = 24;
result = 0;
printf("Initial Values are:\n");
printf("\t a : %lld \n", a);
printf("\t b : %lld \n", b);
printf("\t result : %lld \n", result);
fflush(stdout);
result = a + b;
printf("Final Values are:\n");
printf("\t a : %lld \n", a);
printf("\t b : %lld \n", b);
printf("\t result : %lld \n", result);
fflush(stdout);
return 0;
}
The output is as follows:
Initial Values are:
a : 23639177792
b : 105243556416
result : 2164341312
Final Values are:
a : 23639177792
b : 105243556416
result : 126718392896
Could someone please explain what is going on here? What should I do to make it right?
After some more analysis, I just observed that
a = 0x5 (0x00000005 81013a44 which is hex for 23639177792)
b = 0x18 (0x00000018 81013a40 which is hex for 105243556416)
i. result = 0 (0x00000000 81013a40 which is hex for 2164341312)
ii. result = 0x1D (0x0000001D 81013a40 which is hex for 126718392896)
The upper 32 bits contain the correct values. I just don't understand why
- The result is upper/lower word swapped.
- Even if the words were swapped, why is there junk in the lower word.
Compiler info:
arm-none-eabi-gcc -v
Using built-in specs.
COLLECT_GCC=c:\Program Files\CodeSourcery\Sourcery G++ Lite\bin\arm-none-eabi-gcc.exe
COLLECT_LTO_WRAPPER=c:/program files/codesourcery/sourcery g++ lite/bin/../libexec/gcc/arm-none-eabi/4.5.2/lto-wrapper.exe
Target: arm-none-eabi
Configured with: /scratch/janisjo/arm-eabi-lite/src/gcc-4.5-2011.03/configure --build=i686-pc-linux-gnu --host=i686-mingw32 --target=arm-none-eabi --enable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch --enable-extra-sgxxlite-multilibs --with-gnu-as --with-gnu-ld --with-specs='%{save-temps: -fverbose-asm} -D__CS_SOURCERYGXX_MAJ__=2011 -D__CS_SOURCERYGXX_MIN__=3 -D__CS_SOURCERYGXX_REV__=42 %{O2:%{!fno-remove-local-statics: -fremove-local-statics}} %{O*:%{O|O0|O1|O2|Os:;:%{!fno-remove-local-statics: -fremove-local-statics}}}' --enable-languages=c,c++ --disable-shared --enable-lto --with-newlib --with-pkgversion='Sourcery G++ Lite 2011.03-42' --with-bugurl=https://support.codesourcery.com/GNUToolchain/ --disable-nls --prefix=/opt/codesourcery --with-headers=yes --with-sysroot=/opt/codesourcery/arm-none-eabi --with-build-sysroot=/scratch/janisjo/arm-eabi-lite/install/host-i686-mingw32/arm-none-eabi --with-libiconv-prefix=/scratch/janisjo/arm-eabi-lite/obj/host-libs-2011.03-42-arm-none-eabi-i686-mingw32/usr --with-gmp=/scratch/janisjo/arm-eabi-lite/obj/host-libs-2011.03-42-arm-none-eabi-i686-mingw32/usr --with-mpfr=/scratch/janisjo/arm-eabi-lite/obj/host-libs-2011.03-42-arm-none-eabi-i686-mingw32/usr --with-mpc=/scratch/janisjo/arm-eabi-lite/obj/host-libs-2011.03-42-arm-none-eabi-i686-mingw32/usr --with-ppl=/scratch/janisjo/arm-eabi-lite/obj/host-libs-2011.03-42-arm-none-eabi-i686-mingw32/usr --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' --with-cloog=/scratch/janisjo/arm-eabi-lite/obj/host-libs-2011.03-42-arm-none-eabi-i686-mingw32/usr --with-libelf=/scratch/janisjo/arm-eabi-lite/obj/host-libs-2011.03-42-arm-none-eabi-i686-mingw32/usr --disable-libgomp --enable-poison-system-directories --with-build-time-tools=/scratch/janisjo/arm-eabi-lite/obj/tools-i686-pc-linux-gnu-2011.03-42-arm-none-eabi-i686-mingw32/arm-none-eabi/bin --with-build-time-tools=/scratch/janisjo/arm-eabi-lite/obj/tools-i686-pc-linux-gnu-2011.03-42-arm-none-eabi-i686-mingw32/arm-none-eabi/bin
Thread model: single
gcc version 4.5.2 (Sourcery G++ Lite 2011.03-42)
Looks like you're mixing ABIs. Probably your cross compiler is using APCS (aka Old ABI) while Android runtime expects EABI.
One important difference between the two is how 64-bit values are passed in registers. Old ABI uses the next available pair of registers, e.g.
while EABI uses the next even-aligned register pair:
Let's look how
a
would be passed for both ABIs:1. Actual: 5 = 0 (high32) and 5 (low32)OABI: R1 = 0, R2 = 5
EABI: R2 = 0, R3 = 5
Printed: 23639177792 = 0x581013A40 = 0x5 (high32) and 0x81013A40 (low32)
OABI: R1 = 5, R2 = 0x81013A40
EABI: R2 = 5, R3 = 0x81013A40
So most likely your code loaded 0 into
R1
and 5 intoR2
, butprintf
interpretedR2
as the high part and garbage fromR3
as the low part. You can easily check it by inspecting the generated assembly.The fix should be easy - use a compiler option to generate EABI code, or just use a toolchain which specifically targets Android, e.g. Android NDK.
EDIT: I had the high and low parts swapped. Here's the correct version:
Actual: 5 = 0 (high32) and 5 (low32)
OABI: R1 = 5, R2 = 0
EABI: R2 = 5, R3 = 0
Printed: 23639177792 = 0x581013A40 = 0x5 (high32) and 0x81013A40 (low32)
OABI: R1 = 0x81013A40, R2 = 5
EABI: R2 = 0x81013A40, R3 = 5
So, the evidence actually suggests the opposite: your code is using EABI while
printf
is expecting OABI.