Incorrect code generation when referencing linker symbols?

Asked by Stuart Juengst

Given this C code:

extern char *__bss_start__;
extern char *__bss_end__;

int main(int argc, char **argv)
{
        unsigned long len = &__bss_end__ - &__bss_start__;
}

why does arm-none-eabi-gcc generate the ASRS instruction following the SUBS?

> arm-none-eabi-gcc test.c --specs=nosys.specs -mthumb

000081bc <main>:
    81bc: b580 push {r7, lr}
    81be: b084 sub sp, #16
    81c0: af00 add r7, sp, #0
    81c2: 6078 str r0, [r7, #4]
    81c4: 6039 str r1, [r7, #0]
    81c6: 4a05 ldr r2, [pc, #20] ; (81dc <main+0x20>)
    81c8: 4b05 ldr r3, [pc, #20] ; (81e0 <main+0x24>)
    81ca: 1ad3 subs r3, r2, r3
    81cc: 109b asrs r3, r3, #2
    81ce: 60fb str r3, [r7, #12]
    81d0: 1c18 adds r0, r3, #0
    81d2: 46bd mov sp, r7
    81d4: b004 add sp, #16
    81d6: bc80 pop {r7}
    81d8: bc02 pop {r1}
    81da: 4708 bx r1
    81dc: 00010998 .word 0x00010998
    81e0: 0001097c .word 0x0001097c

This gives a result 1/4 of the actual size.

Thanks,

Stu

Question information

Language:
English Edit question
Status:
Answered
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
Stuart Juengst (juengst) said :
#1

Adding version info:

$ arm-none-eabi-gcc -v
Using built-in specs.
COLLECT_GCC=C:\Program Files (x86)\GNU Tools ARM Embedded\4.9 2015q3\bin\arm-none-eabi-gcc.exe
COLLECT_LTO_WRAPPER=c:/program\ files\ (x86)/gnu\ tools\ arm\ embedded/4.9\ 2015q3/bin/../lib/gcc/arm-none-eabi/4.9.3/lto-wrapper.exe
Target: arm-none-eabi
Configured with: /home/build/work/GCC-4-9-build/src/gcc/configure --build=i686-linux-gnu --host=i686-w64-mingw32 --target=arm-none-eabi --prefix=/home/build/work/GCC-4-9-build/install-mingw --libexecdir=/home/build/work/GCC-4-9-build/install-mingw/lib --infodir=/home/build/work/GCC-4-9-build/install-mingw/share/doc/gcc-arm-none-eabi/info --mandir=/home/build/work/GCC-4-9-build/install-mingw/share/doc/gcc-arm-none-eabi/man --htmldir=/home/build/work/GCC-4-9-build/install-mingw/share/doc/gcc-arm-none-eabi/html --pdfdir=/home/build/work/GCC-4-9-build/install-mingw/share/doc/gcc-arm-none-eabi/pdf --enable-languages=c,c++ --disable-decimal-float --disable-libffi --disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-libstdcxx-pch --disable-nls --disable-shared --disable-threads --disable-tls --with-gnu-as --with-gnu-ld --with-headers=yes --with-newlib --with-python-dir=share/gcc-arm-none-eabi --with-sysroot=/home/build/work/GCC-4-9-build/install-mingw/arm-none-eabi --with-libiconv-prefix=/home/build/work/GCC-4-9-build/build-mingw/host-libs/usr --with-gmp=/home/build/work/GCC-4-9-build/build-mingw/host-libs/usr --with-mpfr=/home/build/work/GCC-4-9-build/build-mingw/host-libs/usr --with-mpc=/home/build/work/GCC-4-9-build/build-mingw/host-libs/usr --with-isl=/home/build/work/GCC-4-9-build/build-mingw/host-libs/usr --with-cloog=/home/build/work/GCC-4-9-build/build-mingw/host-libs/usr --with-libelf=/home/build/work/GCC-4-9-build/build-mingw/host-libs/usr --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' --with-pkgversion='GNU Tools for ARM Embedded Processors' --with-multilib-list=armv6-m,armv7-m,armv7e-m,cortex-m7,armv7-r
Thread model: single
gcc version 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 227977] (GNU Tools for ARM Embedded Processors)

Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :
#2

Hi Stuart,

GCC is following the C standard here, more precisely its section 6.5.6 paragraph 9 (for C99):

When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. (...) In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t.

You are computing the difference of the *address* of two pointers to char. A pointer has 4 bytes in ARM so it needs to divide the result of the difference by 4, hence a right shift by 2.

Best regards.

Revision history for this message
Andre Vieira (andre-simoesdiasvieira) said :
#3

Hi Stuart,

Just a little tip. I am assuming you are trying to compute the size of bss. You will want to declare __bss_start__ and __bss_end__ as:
extern char __bss_start__;
extern char __bss_end__;

And then you leave your subtraction expression as is, taking their addresses. That way, because the sizeof(char) = 1, you will not need to multiply the result and you will get the size of bss.

Cheers,
Andre

Can you help with this problem?

Provide an answer of your own, or ask Stuart Juengst for more information if necessary.

To post a message you must log in.