This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

msp430-elf-gcc: abnormally large compiled binary when using particular string literals and printf

Under the following particular circumstances of a call to printf("a_particular_string_literal"), the compiled binary ends up an overly large binary (overflows MCU code memory):

Good case: printf("zz\n");
Bad case: printf("z\nz");

Specific symptoms: between the good and bad cases, the .text section grows from 0x175a (good) to 0x7f1c (bad); .rodata grows from 0x006c (good) to 0x0348 (bad) and is filled with what looks like garbage.

Just re-arranging the bytes in the string literal causes the problem to appear/disappear. Could not reproduce the problem without a call to printf (tried a simple call to function defined in a different compilation unit). If the literal is defined in static storage, then the behavior is very similar, but for these particular literals, both trigger the problem.

Makefile, compiled binaries, disassembly, and elf header listings for both cases attached.

msp430-elf-gcc --version
msp430-elf-gcc (GCC) 4.9.1 20140707 (prerelease (msp430-14r1-167)) (GNUPro 14r1) (Based on: GCC 4.8 GDB 7.7 Binutils 2.24 Newlib 2.1)

gcc-string-literal.tar.gz

  • Alexei Colin said:
    Good case: printf("zz\n");
    Bad case: printf("z\nz");

    There is an optimization in the GCC compiler which can replace calls to printf() with calls to puts() which the format string allows it - see http://www.ciselant.de/projects/gcc_printf/gcc_printf.html

    This explains the size difference, running nm on good.out shows puts has been linked and running nm on bad.out shows printf has been linked.

    printf increases the code size since it has to handle format strings.

  • Thanks a lot for explaining what's going on.

    Chester Gillon said:
    printf increases the code size since it has to handle format strings.

    By 25Kb.. would never have guessed that much. I need to confirm that this is the expected size of printf plus dependencies from newlib. Right now I'm using tiny printf by oPossum from here. Didn't weigh it, but I bet it's under 25Kb.

    The second mystery is why the resulting binary is not functional. This would need a dedicated diagnosis effort, now that it's clear that the bigger binary is not a symptom of a problem.

  • Alexei Colin said:
    By 25Kb.. would never have guessed that much. I need to confirm that this is the expected size of printf plus dependencies from newlib.

    I am not sure about the expected size, but using GCC MSP430 v4.9.1 with your example programs the program which used printf used almost 32Kb more:

    c:\ti_ccs6_1\ccsv6\tools\compiler\gcc_msp430_4.9.14r1_167\bin\msp430-elf-size.exe MSP430_gccPrintf\Debug\MSP430_gccPrintf.out MSP430_gccPuts\Debug\MSP430_gccPuts.out
       text    data     bss     dec     hex filename
      39350    1310      48   40708    9f04 MSP430_gccPrintf\Debug\MSP430_gccPrintf.out
       7866     454      40    8360    20a8 MSP430_gccPuts\Debug\MSP430_gccPuts.out

    The TI compiler run-time-library has the ability to specify which printf format strings are supported, to be able to reduce code size:

    --printf_support={full|     nofloat|minimal} Enables support for smaller, limited versions of the printf function family (sprintf, fprintf, etc.) and the scanf function family (sscanf, fscanf, etc.) run-time-support functions. The valid values are:
    • full: Supports all format specifiers. This is the default.

    • nofloat: Excludes support for printing and scanning floating-point values. Supports all format specifiers except %a, %A, %f, %F, %g, %G, %e, and %E.

    • minimal: Supports the printing and scanning of integer, char, or string values without width or precision flags. Specifically, only the %%, %d, %o, %c, %s, and %x format specifiers are supported 

    I am not aware of an equivalent option for the GCC MSP430 compiler.

  • Chester Gillon said:

    I am not aware of an equivalent option for the GCC MSP430 compiler.


    The newlib c library which comes with GCC in Code Composer Studio has an option for you, use iprintf() instead of printf.
    See https://sourceware.org/newlib/libc.html#siprintf

    I've used the following define to force the use of diprintf() instead of dprintf():

    #ifdef dprintf
    #undef dprintf
    #endif
    #define dprintf(arg...) diprintf(arg)
    

    Modify the above for printf() and iprintf() and put it into a global include file and you can force the use of the integer only version.

  • friedl said:
    The newlib c library which comes with GCC in Code Composer Studio has an option for you, use iprintf() instead of printf.

    Confirm that changing from printf to iprintf reduces the memory usage (total of 14016 bytes with iprintf compared to 40708 bytes using printf):

    c:\ti_ccs6_1\ccsv6\tools\compiler\gcc_msp430_4.9.14r1_167\bin\msp430-elf-size.exe MSP430_gccPrintf\Debug\MSP430_gccPrintf.out
       text    data     bss     dec     hex filename
      13314     654      48   14016    36c0 MSP430_gccPrintf\Debug\MSP430_gccPrintf.out