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
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.
; printf("\t a : %lld \n", a);
load format string into R0
load 'a' into R1 and R2
call printf
while EABI uses the next even-aligned register pair:
; printf("\t a : %lld \n", a);
load format string into R0
load 'a' into R2 and R3
call printf
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 into R2
, but printf
interpreted R2
as the high part and garbage from R3
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.
User contributions licensed under CC BY-SA 3.0