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.

Excluding malloc from a link in CCS.

Hello,

I'm trying to stuff a lot of code into one of those dern small "MSP430Gxxx Value Line" processors with only 2K of flash.  In an effort to optimize my footprint, I've been combing through the map files generated by the linker to figure out what I can cut.  Interestingly, the map file always includes malloc from memory.obj in rts430.lib regardless of what my code has in it.  Now why would that be?  I'm not using printf() (nor any of it's friends), my heap is set to 0 bytes, and I'm doing no dynamic memory allocation that I am aware of.  So somewhere, the RTS code is referencing malloc, and it's using up a precious 0xa8 of bytes to do it.  I know that sounds small, and I know the problem would go away by using a chip with 4k or 8k of flash, but I'm still kind of wondering why.  Any ideas?

  • Could you post your linker map file?  (linker option --map_file)

  • File (Flash.map.log) attached.

    Thanks

    Thaddeus.

  • The program uses operator new somewhere, and thus drags in malloc.  It's possible the compiler is generating these calls; you probably have an object being constructed somewhere.  It is my recollection that the compiler always arranges for constructors to call operator new, because the compiler doesn't know that for this program, the constructor will never need to allocate the object.  I recall some discussion about this topic internally, let me see if I can dig up the results.



  • It is a truly scary prospect to think that dynamic memory is getting used when your heap is set to 0!  Nevertheless, I verified that my code does not use malloc or "new" by using a pre-include with the following lines:

    #define malloc foo
    #define new foo

    This would be sure to catch any "new" or malloc commands lurking in pre-processor directives.  But as this caused no compile problems, I feel safe to say that this was not the problem.

    I took a careful look at how some very simple stub code complied.  The code consists of an empty main() function, a class declaration with reference and nothing else.  From this, I was able to discover that the malloc reference was located in the operator "new" function located in the RTS file new_.cpp.  I have constructed a test case "test.c" (actually C++) which captures the problem:



    #if defined TEST_1

    class mytestclass {

    public:
    mytestclass() {
    }
    };

    int main() {

    }

    #elif defined TEST_2

    class mytestclass {

    public:
    mytestclass() {
    }
    };
    static mytestclass ms_oMyTestClass;

    int main() {

    }

    #elif defined TEST_3

    class mytestclass {

    public:
    mytestclass() {
    }
    };

    int main() {
    mytestclass oLocalTestClass;

    }

    #elif defined TEST_4

    class mytestclass {

    public:
    mytestclass() {
    }
    };

    int main() {
    mytestclass* poLocalTestClass =
    new mytestclass;

    }


    #elif defined TEST_5

    class mytestclass {

    public:
    };

    int main() {
    mytestclass oLocalTestClass;

    }


    #endif


    The tests are as follows:
            TEST_1:  Do-nothing main, no references to mytestclass
            TEST_2:  Do-nothing main with static mytestclass.
            TEST_3:  Local mytestclass
            TEST_4:  "new" mytestclass
            TEST_5:  Local mytestclass relying on default constructor.

    First thing I noticed was that the constructors for mytestclass all reference "__nw__FUi" which is the "operator new" that I was mentioning.  This includes TEST_2 and TEST_3 which never use dynamic allocation.  Indeed, the differences between the ASM code for TEST_3 and TEST_4 is illuminating:  TEST_3 passes the stack-allocated pointer to mytestclass to the constructor, whereas TEST_4 passes #0 causing it to dynamically allocate.  Nothing wrong with that, and I applaud the cleverness of the designers here.  Unfortunately for me however, IT CREATES AN UNNECESSARY REFERENCE TO MALLOC IN PROGRAMS THAT NEVER USE DYNAMIC ALLOCATION.

    So what can I do?  Is there any work-around to avoid this?  Or is there a way to cleverly ask the linker to exclude "_malloc" and "__nw__FUi" from the link?  Dangerous option that, but I'm out of space!

    Thaddeus.

     

    tests.tar
  • Thaddeus Niemeyer said:

    So what can I do?  Is there any work-around to avoid this?  Or is there a way to cleverly ask the linker to exclude "_malloc" and "__nw__FUi" from the link?  Dangerous option that, but I'm out of space!

    Here's a brief summary of the situation:

    For COFF modes (which you are using), the constructors contain calls to operator new.  In EABI mode they do not, which would resolve your issue.  MSP430 will have an EABI mode in compiler version 4.0.0 later this year.  It would be a major undertaking to change the way it works in COFF mode.

    If you stick with COFF, you have two possible workarounds:

    1. For every class for which you do not want the constructors to call operator new, add a member function operator new with the following prototype. This will prevent the constructor from calling new at all. You can avoid a little typing by placing this member function in a class that all of your other classes inherit from.

      #include <new>
      
      class object
      {
      public:
          object() { }
          void *operator new(std::size_t, int) { return 0; }
      };
      
      object fn() { return object(); }
      
    2. Redefine the global operator new so that the linker uses that instead of the full-blown library implementation. This has the drawback that your constructors will still have wasted code to call this function, even though it will never be called.

      #include <new>
      #include <stdlib.h>
      
      void *operator new(std::size_t) { abort(); return 0; }
      

  • Yes, both of these are good solutions.  I have already tried #2, and it worked like a charm, saving me 0x9e bytes, which is just what I need at the moment.  Solution #1 however is considerably more elegant, and any serious coding which requires precise control over allocation should inherit from some a base class defining "new".

    Now as long as we are on the topic, I have one other question:

    I have noticed that the .const section of an object file is pulled into the link if ANY of the functions in that object file are referenced, regarless as to whether those functions reference the .const data.  Is this correct?  (I noticed this just now when I tried putting the redefined "new" in a function which had other arrays of const data in them).  I haven't checked closely, but maybe .bss section data is pulled in too?  I can elaborate if this question does not make sense.

    Again, thanks for the excellent help on the prior question.


    Thaddeus.

  • It's more complicated than that.  Is the object file in question one of yours, or is it from the library?  For COFF ABIs, mentioning an object file on the command line usually pulls in everything from that file.  What version of the compiler (not CCS) are you using?

    I think we should start a new topic for this .const question.