long long int values are incorrectly printed

1

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

  1. The result is upper/lower word swapped.
  2. 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) 
c
embedded
arm
gcc4.7
asked on Stack Overflow Aug 16, 2013 by Girish • edited Aug 20, 2013 by Girish

1 Answer

1

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

  1. 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:

  1. Actual: 5 = 0 (high32) and 5 (low32)

    OABI: R1 = 5, R2 = 0
    EABI: R2 = 5, R3 = 0

  2. 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.

answered on Stack Overflow Aug 16, 2013 by Igor Skochinsky • edited Aug 16, 2013 by Igor Skochinsky

User contributions licensed under CC BY-SA 3.0