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.
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?
File (Flash.map.log) attached.
Thanks
Thaddeus.
****************************************************************************** MSP430 Evaluation Linker PC v3.3.3 ****************************************************************************** >> Linked Thu May 19 18:14:54 2011 OUTPUT FILE NAME: <Flash.out> ENTRY POINT SYMBOL: "_c_int00" address: 0000fe26 MEMORY CONFIGURATION name origin length used unused attr fill ---------------------- -------- --------- -------- -------- ---- -------- SFR 00000000 00000010 00000000 00000010 RWIX PERIPHERALS_8BIT 00000010 000000f0 00000000 000000f0 RWIX PERIPHERALS_16BIT 00000100 00000100 00000000 00000100 RWIX RAM 00000200 00000080 00000060 00000020 RWIX INFOD 00001000 00000040 00000000 00000040 RWIX INFOC 00001040 00000040 00000000 00000040 RWIX INFOB 00001080 00000040 00000000 00000040 RWIX INFOA 000010c0 00000040 00000000 00000040 RWIX FLASH 0000f800 000007e0 0000076e 00000072 RWIX INT00 0000ffe0 00000002 00000000 00000002 RWIX INT01 0000ffe2 00000002 00000000 00000002 RWIX INT02 0000ffe4 00000002 00000000 00000002 RWIX INT03 0000ffe6 00000002 00000000 00000002 RWIX INT04 0000ffe8 00000002 00000002 00000000 RWIX INT05 0000ffea 00000002 00000000 00000002 RWIX INT06 0000ffec 00000002 00000000 00000002 RWIX INT07 0000ffee 00000002 00000000 00000002 RWIX INT08 0000fff0 00000002 00000000 00000002 RWIX INT09 0000fff2 00000002 00000000 00000002 RWIX INT10 0000fff4 00000002 00000000 00000002 RWIX INT11 0000fff6 00000002 00000000 00000002 RWIX INT12 0000fff8 00000002 00000000 00000002 RWIX INT13 0000fffa 00000002 00000000 00000002 RWIX INT14 0000fffc 00000002 00000000 00000002 RWIX RESET 0000fffe 00000002 00000002 00000000 RWIX SECTION ALLOCATION MAP output attributes/ section page origin length input sections -------- ---- ---------- ---------- ---------------- .pinit 0 0000f800 00000000 UNINITIALIZED .bss 0 00000200 00000020 UNINITIALIZED 00000200 0000000c util.obj (.bss) 0000020c 00000008 rts430.lib : memory.obj (.bss) 00000214 00000004 : _lock.obj (.bss) 00000218 00000004 : boot.obj (.bss) 0000021c 00000002 EmbeddedLib.lib : hal_spi2.obj (.bss) 0000021e 00000002 rts430.lib : vars.obj (.bss) .sysmem 0 00000220 00000004 UNINITIALIZED 00000220 00000004 rts430.lib : memory.obj (.sysmem) .stack 0 00000244 0000003c UNINITIALIZED 00000244 00000002 rts430.lib : boot.obj (.stack) 00000246 0000003a --HOLE-- .text 0 0000f800 000006d6 0000f800 000000f4 EmbeddedLib.lib : hal_spi2.obj (.text:vSlaveService__14masterslavespiFPPCcPCiPcb) 0000f8f4 000000b0 : hal_spi2.obj (.text:vInit__14masterslavespiFi) 0000f9a4 000000a8 rts430.lib : memory.obj (.text:malloc) 0000fa4c 00000066 EmbeddedLib.lib : hal_spi2.obj (.text:bServiceInterrupt__14masterslavespiFv) 0000fab2 00000062 Test_SlaveMasterSPI_Slave.obj (.text:main) 0000fb14 00000060 Test_SlaveMasterSPI_Slave.obj (.text:__ct__14masterslavespiF8eSPIPORTib) 0000fb74 00000058 rts430.lib : div32u.obj (.text) 0000fbcc 0000004e EmbeddedLib.lib : hal_spi2.obj (.text:vTransmit__14masterslavespiFPUcib) 0000fc1a 00000046 rts430.lib : autoinit.obj (.text:_auto_init) 0000fc60 00000046 EmbeddedLib.lib : hal_spi2.obj (.text:vTransmitLP__14masterslavespiFPUci) 0000fca6 00000042 : hal_spi2.obj (.text:puReceive__14masterslavespiFPUcib) 0000fce8 00000040 rts430.lib : div32s.obj (.text) 0000fd28 0000003c EmbeddedLib.lib : hal_spi2.obj (.text:puReceiveLP__14masterslavespiFPUci) 0000fd64 0000003a rts430.lib : memory.obj (.text:minit) 0000fd9e 00000034 : new_.obj (.text:__nw__FUi) 0000fdd2 0000002c : lsl16.obj (.text) 0000fdfe 00000028 EmbeddedLib.lib : hal_spi2.obj (.text:universal_serial_interface__Fv) 0000fe26 00000026 rts430.lib : boot.obj (.text:_c_int00_noexit) 0000fe4c 00000018 EmbeddedLib.lib : hal_spi2.obj (.text:nSlaveService__14masterslavespiFiPc) 0000fe64 00000016 rts430.lib : div16u.obj (.text) 0000fe7a 00000014 : mult16.obj (.text) 0000fe8e 00000012 : memcpy.obj (.text:memcpy) 0000fea0 00000010 : epilog.obj (.text) 0000feb0 00000010 EmbeddedLib.lib : hal_spi2.obj (.text:vWait__14masterslavespiFv) 0000fec0 0000000a : hal_assert.obj (.text:halAssertHandler) 0000feca 00000004 rts430.lib : pre_init.obj (.text:_system_pre_init) 0000fece 00000004 : exit.obj (.text:abort) 0000fed2 00000002 : newhandler.obj (.text:__default_new_handler__Fv) 0000fed4 00000002 : _lock.obj (.text:_nop) .const 0 0000fed6 0000008a 0000fed6 00000042 util.obj (.const:.string) 0000ff18 00000020 Test_SlaveMasterSPI_Slave.obj (.const:.string) 0000ff38 00000014 EmbeddedLib.lib : hal_spi2.obj (.const:.string) 0000ff4c 00000008 : hal_spi2.obj (.const:__vtbl__14masterslavespi) 0000ff54 00000006 Test_SlaveMasterSPI_Slave.obj (.const:$P$T0$1) 0000ff5a 00000006 Test_SlaveMasterSPI_Slave.obj (.const:$P$T1$2) .cinit 0 0000ff60 0000000e 0000ff60 00000006 rts430.lib : memory.obj (.cinit) 0000ff66 00000006 : vars.obj (.cinit) 0000ff6c 00000002 --HOLE-- [fill = 0] .int04 0 0000ffe8 00000002 0000ffe8 00000002 EmbeddedLib.lib : hal_spi2.obj (.int04) .reset 0 0000fffe 00000002 0000fffe 00000002 rts430.lib : boot.obj (.reset) GLOBAL SYMBOLS: SORTED ALPHABETICALLY BY Name address name -------- ---- 00000200 .bss 0000f800 .text 0000004a ADC10AE0 000001b0 ADC10CTL0 000001b2 ADC10CTL1 00000048 ADC10DTC0 00000049 ADC10DTC1 000001b4 ADC10MEM 000001bc ADC10SA 00000057 BCSCTL1 00000058 BCSCTL2 00000053 BCSCTL3 0000fece C$$EXIT 000010ff CALBC1_1MHZ 000010fe CALDCO_1MHZ 00000056 DCOCTL 00000128 FCTL1 0000012a FCTL2 0000012c FCTL3 00000000 IE1 00000002 IFG1 0000fdd2 I_LSL 0000fdfa I_LSL_1 0000fde8 I_LSL_10 0000fde6 I_LSL_11 0000fde4 I_LSL_12 0000fde2 I_LSL_13 0000fde0 I_LSL_14 0000fdde I_LSL_15 0000fdf8 I_LSL_2 0000fdf6 I_LSL_3 0000fdf4 I_LSL_4 0000fdf2 I_LSL_5 0000fdf0 I_LSL_6 0000fdee I_LSL_7 0000fdec I_LSL_8 0000fdea I_LSL_9 00000022 P1DIR 00000025 P1IE 00000024 P1IES 00000023 P1IFG 00000020 P1IN 00000021 P1OUT 00000027 P1REN 00000026 P1SEL 0000002a P2DIR 0000002d P2IE 0000002c P2IES 0000002b P2IFG 00000028 P2IN 00000029 P2OUT 0000002f P2REN 0000002e P2SEL 00000172 TACCR0 00000174 TACCR1 00000162 TACCTL0 00000164 TACCTL1 00000160 TACTL 0000012e TAIV 00000170 TAR 0000007a USICCTL 0000007a USICKCTL 0000007b USICNT 00000078 USICTL 00000078 USICTL0 00000079 USICTL1 0000007c USISR 0000007d USISRH 0000007c USISRL 00000120 WDTCTL 00000280 __STACK_END 0000003c __STACK_SIZE 00000004 __SYSMEM_SIZE 00000001 __TI_args_main 00000001 __TI_auto_init 00000001 __TI_exit ffffffff __binit__ 00000200 __bss__ ffffffff __c_args__ 0000ff60 __cinit__ 0000fed2 __default_new_handler__Fv 0000fce8 __divli 0000fe64 __divu 0000fb74 __divul 00000220 __end__ 0000fed6 __etext__ 0000fe7a __mpyi 0000fd9e __nw__FUi ffffffff __pinit__ 0000fce8 __remli 0000fe64 __remu 0000fb74 __remul 0000f800 __text__ 0000ff4c __vtbl__14masterslavespi 0000fc1a _auto_init 0000fe26 _c_int00 0000fe26 _c_int00_noexit 00000218 _cleanup_ptr 0000021a _dtors_ptr 00000214 _lock 0000021e _new_handler 0000fed4 _nop 0000fffe _reset_vector 00000244 _stack 00000220 _sys_memory 0000feca _system_pre_init 00000216 _unlock 0000fece abort 0000fa4c bServiceInterrupt__14masterslavespiFv ffffffff binit 0000ff60 cinit 00000220 end 0000fed6 etext 0000feac func_epilog_1 0000feaa func_epilog_2 0000fea8 func_epilog_3 0000fea6 func_epilog_4 0000fea4 func_epilog_5 0000fea2 func_epilog_6 0000fea0 func_epilog_7 0000fec0 halAssertHandler 0000fab2 main 0000f9a4 malloc 0000fe8e memcpy 0000fd64 minit 0000fe4c nSlaveService__14masterslavespiFiPc ffffffff pinit 0000fdfe universal_serial_interface__Fv 0000f8f4 vInit__14masterslavespiFi 0000f800 vSlaveService__14masterslavespiFPPCcPCiPcb GLOBAL SYMBOLS: SORTED BY Symbol Address address name -------- ---- 00000000 IE1 00000001 __TI_args_main 00000001 __TI_auto_init 00000001 __TI_exit 00000002 IFG1 00000004 __SYSMEM_SIZE 00000020 P1IN 00000021 P1OUT 00000022 P1DIR 00000023 P1IFG 00000024 P1IES 00000025 P1IE 00000026 P1SEL 00000027 P1REN 00000028 P2IN 00000029 P2OUT 0000002a P2DIR 0000002b P2IFG 0000002c P2IES 0000002d P2IE 0000002e P2SEL 0000002f P2REN 0000003c __STACK_SIZE 00000048 ADC10DTC0 00000049 ADC10DTC1 0000004a ADC10AE0 00000053 BCSCTL3 00000056 DCOCTL 00000057 BCSCTL1 00000058 BCSCTL2 00000078 USICTL 00000078 USICTL0 00000079 USICTL1 0000007a USICCTL 0000007a USICKCTL 0000007b USICNT 0000007c USISR 0000007c USISRL 0000007d USISRH 00000120 WDTCTL 00000128 FCTL1 0000012a FCTL2 0000012c FCTL3 0000012e TAIV 00000160 TACTL 00000162 TACCTL0 00000164 TACCTL1 00000170 TAR 00000172 TACCR0 00000174 TACCR1 000001b0 ADC10CTL0 000001b2 ADC10CTL1 000001b4 ADC10MEM 000001bc ADC10SA 00000200 .bss 00000200 __bss__ 00000214 _lock 00000216 _unlock 00000218 _cleanup_ptr 0000021a _dtors_ptr 0000021e _new_handler 00000220 __end__ 00000220 _sys_memory 00000220 end 00000244 _stack 00000280 __STACK_END 000010fe CALDCO_1MHZ 000010ff CALBC1_1MHZ 0000f800 .text 0000f800 __text__ 0000f800 vSlaveService__14masterslavespiFPPCcPCiPcb 0000f8f4 vInit__14masterslavespiFi 0000f9a4 malloc 0000fa4c bServiceInterrupt__14masterslavespiFv 0000fab2 main 0000fb74 __divul 0000fb74 __remul 0000fc1a _auto_init 0000fce8 __divli 0000fce8 __remli 0000fd64 minit 0000fd9e __nw__FUi 0000fdd2 I_LSL 0000fdde I_LSL_15 0000fde0 I_LSL_14 0000fde2 I_LSL_13 0000fde4 I_LSL_12 0000fde6 I_LSL_11 0000fde8 I_LSL_10 0000fdea I_LSL_9 0000fdec I_LSL_8 0000fdee I_LSL_7 0000fdf0 I_LSL_6 0000fdf2 I_LSL_5 0000fdf4 I_LSL_4 0000fdf6 I_LSL_3 0000fdf8 I_LSL_2 0000fdfa I_LSL_1 0000fdfe universal_serial_interface__Fv 0000fe26 _c_int00 0000fe26 _c_int00_noexit 0000fe4c nSlaveService__14masterslavespiFiPc 0000fe64 __divu 0000fe64 __remu 0000fe7a __mpyi 0000fe8e memcpy 0000fea0 func_epilog_7 0000fea2 func_epilog_6 0000fea4 func_epilog_5 0000fea6 func_epilog_4 0000fea8 func_epilog_3 0000feaa func_epilog_2 0000feac func_epilog_1 0000fec0 halAssertHandler 0000feca _system_pre_init 0000fece C$$EXIT 0000fece abort 0000fed2 __default_new_handler__Fv 0000fed4 _nop 0000fed6 __etext__ 0000fed6 etext 0000ff4c __vtbl__14masterslavespi 0000ff60 __cinit__ 0000ff60 cinit 0000fffe _reset_vector ffffffff __binit__ ffffffff __c_args__ ffffffff __pinit__ ffffffff binit ffffffff pinit [130 symbols]
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.
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:
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(); }
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.