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.

Reducing code size of msp430-gcc 3_03_04_00 builds



Hi,

I've developped a few msp430 projects recently using the legacy mspgcc toolchain. Recently, I ran into a compiler error that I thought would be hard to debug, so I took the opportunity to upgrade and try the newer msp430-gcc.

My target memory space is limited (cc430f5137 32KB ROM)

My problem is my builds have ballooned in size. Most don't build at all anymore and error out at "ROM overflowed". I only have one project that still builds, here are some numbers from the project that still builds:

(bin is msp430-gcc, bin.legacy is the legacy mspgcc)

$ msp430-elf-size bin/wizzimote/gateway.elf bin.legacy/wizzimote/gateway.elf
   text	   data	    bss	    dec	    hex	filename
  29532	   1564	   1054	  32150	   7d96	bin/wizzimote/gateway.elf
  10120	     12	   1846	  11978	   2eca	bin.legacy/wizzimote/gateway.elf

that's more than twice the size. Also, somewhat telling:

$ wc -l bin/wizzimote/gateway.map bin.legacy/wizzimote/gateway.map
    4020 bin/wizzimote/gateway.map
    1678 bin.legacy/wizzimote/gateway.map

running msp430-elf-size bin.legacy/wizzimote/*.a (sums to 16,517) and msp430-elf-size bin/wizzimote/*.a (sums to 15,897). This tells me my code is not the culprit.

Casually browsing the generated map files, I get the feeling the culprit is libc? It's hard for me to calculate a sum of the size of all libc elements in the map files, but it looks like there are more functions and more voluminous ones in the msp430-gcc build.

$ grep libc bin/wizzimote/gateway.map | wc -l
     954
$ grep libc bin.legacy/wizzimote/gateway.map | wc -l
     127

You can find a diff of the two map files here, though it's hard to read. At the bottom of the page there are two full map files.

Question: Do you have any ideas or advice to give me to bring these build sizes down, way down?

My msp430-gcc was built as described here

My significant build options are: -g (i need debug builds) -Os

I added the following build options to the msp430-gcc to try to bring down the size, to no avail: -fdata-sections -ffunction-sections -Wl,--gc-sections

I tried -mlarge and -mcode-region=upper -mdata-region=lower (those two down't work with my mcu)

The topic has been discussed before, but I have not found anything useful.

If you can help, Thanks! I'm fairly new to embedded development, so some obvious things my not come to me quickly.

Maybe I should have run these numbers using a simple "hello world" program.

  • I started a discussion with the compiler development team regarding your issue.

    Is there any chance your could produce a test case (smaller is always better) where the compiler links in a RTS function that is not needed?  Or could you point out a specific RTS function that is larger than needed?

    Thanks and regards,

    -George

  • Based on the map diff, I'd say the main culprit is that you're calling printf() without doing anything special to avoid supporting the floating point formats. For example, you could rebuild newlib without %f support. Try adding '#define printf iprintf' in one of your common headers (iprintf is newlib's int-only printf, which saves you a rebuild). The second thing I notice is the inclusion of "__crt0_call_exit" which implies that your main() function returns - gcc will then do all the ISO-required exit handling, including closing all file descriptors, which pulls in a lot of code. Adding 'while(1);' at the end of main() tells gcc to omit all the exit handling, once it knows that main will never exit. Or, provide your own exit() that just calls _exit() (or whatever your exit code is).
  • Thanks George,

    so I wrote a simple program to illustrate this.

    test.c

    #include <stdio.h>
    
    /* not included in mspgcc stdlib */
    #ifndef putchar
    int putchar(int c)
    {
      return 0;
    }
    #endif
    
    int main(void)
    {
      printf("foo %s\n", "bar");
      return 0;
    }
    

    run.sh

    #!/usr/bin/env bash
    set -o xtrace
    
    mkdir -p bin tmp
    rm bin/*
    
    common_opts="\
      -mmcu=cc430f5137 \
      -Wall \
      -g \
      -Os \
      -fdata-sections \
      -ffunction-sections \
      -Wl,--gc-sections"
    
    msp430-gcc $common_opts -o bin/mspgcc.o test.c
    msp430-gcc $common_opts -o bin/mspgcc.o -Wl,-Map,bin/mspgcc.map test.c
    
    msp430-elf-gcc $common_opts -o bin/msp430-gcc.o test.c
    msp430-elf-gcc $common_opts bin/msp430-gcc.o -Wl,-Map,bin/msp430-gcc.map test.c
    
    
    msp430-elf-size bin/mspgcc.o bin/msp430-gcc.o
    echo
    
    msp430-elf-objdump -x bin/mspgcc.o
    msp430-elf-objdump -x bin/msp430-gcc.o
    
    cat bin/mspgcc.map
    cat bin/msp430-gcc.map

    here are results from running this:

    without a reference to printf (printf call commented out):

       text	   data	    bss	    dec	    hex	filename
        204	      0	      2	    206	     ce	bin/mspgcc.o
        530	    148	     16	    694	    2b6	bin/msp430-gcc.o

    full output: http://pastebin.com/kshgA52s

    with call to printf:

       text	   data	    bss	    dec	    hex	filename
       2765	      0	      2	   2767	    acf	bin/mspgcc.o
      26830	   1016	     22	  27868	   6cdc	bin/msp430-gcc.o

    full output: http://pastebin.com/MsC6DK9Q

    with call to printf and "#define printf iprintf" (thanks Delorie)

       text	   data	    bss	    dec	    hex	filename
       2765	      0	      2	   2767	    acf	bin/mspgcc.o
       8628	    422	     22	   9072	   2370	bin/msp430-gcc.o

    full output: http://pastebin.com/WerMpRUu

    Analysis: So, it looks like printf is the bulk of my problem. Using iprintf helps significantly, though I am still orders of magnitude away from my control build (mspgcc).

    George, I guess msp430-gcc is not linking uneeded functions? Just that newlib functions are more voluminous?

    Let me know if you think there are more opportunities to investigate and reduce the size. If not I'll stick to mspgcc when my builds don't fit in ROM.

  • Thanks, I tried you suggestion to use iprintf(), you can see the effect in my reply to George. Glad to learn about iprintf.

    regarding the return of main(), here is the test:

    before

       text	   data	    bss	    dec	    hex	filename
       2785	      0	      2	   2787	    ae3	bin/mspgcc.o
       8628	    422	     22	   9072	   2370	bin/msp430-gcc.o

    with void return type and while(1); at the end of main()

       text	   data	    bss	    dec	    hex	filename
       2785	      0	      2	   2787	    ae3	bin/mspgcc.o
       8620	    422	     22	   9064	   2368	bin/msp430-gcc.o

    Running `./run.sh | grep "crt0_call_exit"` I see that the reference is gone but the impact is minimal.

  • You're still returning from main, try replacing that "return 0;" with "while (1);".

  • no I'm not returning from main, sorry I didn't explicitly say it, this is the main function:

    void main(void)
    {
      printf("foo %s\n", "bar");
      while(1);
    }

  • The only thing I can think of then is that mspgcc replaced libc's printf() with one that didn't go through the stdio functions. To test this, you could try calling sprintf() and write()ing out the buffer. I know *I* have a custom cprintf() that's like printf but only supports the formats I need and calls write() directly, for really tiny projects.

    Another option is that newlib supports a newer version of ISO C that requires more printf format logic...
  • Good thought, using sprintf() instead of printf() frees up over 3KB, Thanks

    program:

    int main(void)
    {
      static char foo[20];
      sprintf(&foo, "foo %s\n", "bar");
      return 0;
    }
    

    with printf():

       text	   data	    bss	    dec	    hex	filename
       2785	      0	      2	   2787	    ae3	bin/mspgcc.o
      26830	   1016	     22	  27868	   6cdc	bin/msp430-gcc.o

     

    with sprintf():

       text	   data	    bss	    dec	    hex	filename
       2871	      0	     26	   2897	    b51	bin/mspgcc.o
      23254	    924	     42	  24220	   5e9c	bin/msp430-gcc.o

    Good idea that I could just provide my own printf functionality, I hadn't thought of that. A web search for "custom printf function" and "newlib printf size embedded" yields quite of bit of info that will be useful should I chose to stick with msp430-gcc and write my own.

     

  • I apparently have a case of the dumb today. Use siprintf() not sprintf() to get rid of the floating point support ;-)

    For fun I put a copy of my cprintf.[ch] (which assumes you provide a tty_putc() function) at:
    www.delorie.com/.../cprintf.h
    www.delorie.com/.../cprintf.c
    Note that the formats are NOT compatible with printf; they're geared towards "debugging via printf".
  • So I gained an about 4KB by using siprintf() instead of iprintf(), thanks. This simple example now compiles down to 5210 bytes using msp430-gcc.

    Thanks for the cprintf examples, they should be useful, I've taken a note of them.

    Cheers