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.

Global variables seem to increase code size

Other Parts Discussed in Thread: MSP430G2210, MSP-FET, CCSTUDIO

[The present question is a cleaner version of this recent question. I wrote a minimal code that I can post in its entirety.]

I have noticed that instantiating objects as global variables bloats the code size.  For small low cost microcontrollers, this is an issue.  Here's a test case.

The setup:  CCStudio 6.1.1.00022, MSP-FET via Spy-Bi-Wire, MSP430G2210.

Test code.  The idea behind the test is to create several simple classes, instantiate them in different ways, observe the code size with Optimizer Assistant.

class Foo {
public:
	unsigned int GetDummy();
	void SetDummy(unsigned int iValue);

private:
	unsigned int m_iDummy;
};

unsigned int Foo::GetDummy() {
	return m_iDummy;
}

void Foo::SetDummy(unsigned int iValue) {
	m_iDummy = iValue;
}

class Foo;

class Bar {
public:
	Bar(Foo* pFoo);
	void SetDummy(unsigned int iValue);

private:
	Foo* m_pFoo;
};

Bar::Bar(Foo* pFoo) {
	m_pFoo = pFoo;
}

void Bar::SetDummy(unsigned int iValue) {
	m_pFoo->SetDummy(iValue);
}

These classes are instantiated in the three test cases.

Case 1.  Local variables in main().

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer

    Foo objFoo;
    Bar objBar(&objFoo); //*/

    objFoo.SetDummy(123);
    objBar.SetDummy(234);
	
	return 0;
}

Case 2.  Global variables.

Foo g_objFoo;
Bar g_objBar(&g_objFoo); //*/

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer

    g_objFoo.SetDummy(123);
    g_objBar.SetDummy(234);
	
	return 0;
}

Case 3.  Global pointers.  Objects newed-up in main().

Foo* g_pFoo;
Bar* g_pBar;

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer

    g_pFoo = new Foo;
    g_pBar = new Bar(g_pFoo);

    g_pFoo->SetDummy(123);
    g_pBar->SetDummy(234);
	
	return 0;
}

Results

It's visible from the chart that globals consume more code space than locals.  But these are the same objects in the same quantities in all cases.  What's going on there?

  • Nick Alexeev said:
    What's going on there?

    Looking at the "SECTION ALLOCATION MAP" part of the linker map file for the different test cases shows the amount of code which is linked in from the compiler run-time-library.

    E.g. using MSP430 compiler v4.4.6 with optimization level zero for the different cases:

    Case 1. Local variables in main()

    SECTION ALLOCATION MAP
    
     output                                  attributes/
    section   page    origin      length       input sections
    --------  ----  ----------  ----------   ----------------
    .stack     0    0000024c    00000032     UNINITIALIZED
                      0000024c    00000002     rts430_eabi.lib : boot.obj (.stack)
                      0000024e    00000030     --HOLE--
    
    .text      0    0000f800    00000062     
                      0000f800    0000002e     main.obj (.text:main)
                      0000f82e    00000012     rts430_eabi.lib : boot_special.obj (.text:_c_int00_noinit_noargs_noexit)
                      0000f840    00000008     main.obj (.text:_ZN3Bar8SetDummyEj)
                      0000f848    00000006     main.obj (.text:_ZN3BarC1EP3Foo)
                      0000f84e    00000006     main.obj (.text:_ZN3Foo8SetDummyEj)
                      0000f854    00000006     rts430_eabi.lib : isr_trap.obj (.text:_isr:__TI_ISR_TRAP)
                      0000f85a    00000004                     : pre_init.obj (.text:_system_pre_init)
                      0000f85e    00000004                     : exit.obj (.text:abort)
    
    .cinit     0    0000f800    00000000     UNINITIALIZED
    
    .init_array 
    *          0    0000f800    00000000     UNINITIALIZED
    

    Case 2. Global variables.

    SECTION ALLOCATION MAP
    
     output                                  attributes/
    section   page    origin      length       input sections
    --------  ----  ----------  ----------   ----------------
    .bss       0    00000200    00000004     UNINITIALIZED
                      00000200    00000002     main.obj (.bss)
                      00000202    00000002     (.common:g_objFoo)
    
    .stack     0    0000024c    00000032     UNINITIALIZED
                      0000024c    00000002     rts430_eabi.lib : boot.obj (.stack)
                      0000024e    00000030     --HOLE--
    
    .text      0    0000f800    000000e8     
                      0000f800    00000058     rts430_eabi.lib : autoinit.obj (.text:_auto_init)
                      0000f858    00000022     main.obj (.text:main)
                      0000f87a    0000001a     rts430_eabi.lib : boot_special.obj (.text:_c_int00_noargs_noexit)
                      0000f894    00000014                     : copy_zero_init.obj (.text:decompress:ZI:__TI_zero_init)
                      0000f8a8    00000010                     : epilog.obj (.text)
                      0000f8b8    0000000e     main.obj (.text:__sti___8_main_cpp_98456f8c)
                      0000f8c6    00000008     main.obj (.text:_ZN3Bar8SetDummyEj)
                      0000f8ce    00000006     main.obj (.text:_ZN3BarC1EP3Foo)
                      0000f8d4    00000006     main.obj (.text:_ZN3Foo8SetDummyEj)
                      0000f8da    00000006     rts430_eabi.lib : isr_trap.obj (.text:_isr:__TI_ISR_TRAP)
                      0000f8e0    00000004                     : pre_init.obj (.text:_system_pre_init)
                      0000f8e4    00000004                     : exit.obj (.text:abort)
    
    .cinit     0    0000f8ea    0000000a     
                      0000f8ea    00000004     (.cinit..bss.load) [load image, compression = zero_init]
                      0000f8ee    00000002     (__TI_handler_table)
                      0000f8f0    00000004     (__TI_cinit_table)
    
    .init_array 
    *          0    0000f8e8    00000002     
                      0000f8e8    00000002     main.obj (.init_array)
    

    Case 3. Global pointers. Objects newed-up in main().

    SECTION ALLOCATION MAP
    
     output                                  attributes/
    section   page    origin      length       input sections
    --------  ----  ----------  ----------   ----------------
    .bss       0    00000200    0000000a     UNINITIALIZED
                      00000200    00000002     (.common:g_pBar)
                      00000202    00000002     (.common:g_pFoo)
                      00000204    00000002     (.common:memsize)
                      00000206    00000002     (.common:sys_base)
                      00000208    00000002     (.common:sys_free)
    
    .data      0    0000020a    00000008     UNINITIALIZED
                      0000020a    00000002     rts430_eabi.lib : _lock.obj (.data:_lock)
                      0000020c    00000002                     : _lock.obj (.data:_unlock)
                      0000020e    00000002                     : memory.obj (.data)
                      00000210    00000002                     : vars.obj (.data)
    
    .sysmem    0    00000214    00000004     UNINITIALIZED
                      00000214    00000004     rts430_eabi.lib : memory.obj (.sysmem)
    
    .stack     0    0000024c    00000032     UNINITIALIZED
                      0000024c    00000002     rts430_eabi.lib : boot.obj (.stack)
                      0000024e    00000030     --HOLE--
    
    .text      0    0000f800    000002ac     
                      0000f800    000000ae     rts430_eabi.lib : memory.obj (.text:malloc)
                      0000f8ae    00000064                     : copy_decompress_rle.obj (.text:__TI_decompress_rle_core)
                      0000f912    00000058                     : autoinit.obj (.text:_auto_init)
                      0000f96a    00000048     main.obj (.text:main)
                      0000f9b2    00000038     rts430_eabi.lib : memory.obj (.text:minit)
                      0000f9ea    00000034                     : new_.obj (.text:_Znwj)
                      0000fa1e    0000001a                     : boot_special.obj (.text:_c_int00_noargs_noexit)
                      0000fa38    00000014                     : copy_zero_init.obj (.text:decompress:ZI:__TI_zero_init)
                      0000fa4c    00000012                     : copy_decompress_none.obj (.text:decompress:none:__TI_decompress_none)
                      0000fa5e    00000012                     : memcpy.obj (.text:memcpy)
                      0000fa70    00000010                     : epilog.obj (.text)
                      0000fa80    00000008     main.obj (.text:_ZN3Bar8SetDummyEj)
                      0000fa88    00000006     main.obj (.text:_ZN3BarC1EP3Foo)
                      0000fa8e    00000006     main.obj (.text:_ZN3Foo8SetDummyEj)
                      0000fa94    00000006     rts430_eabi.lib : isr_trap.obj (.text:_isr:__TI_ISR_TRAP)
                      0000fa9a    00000006                     : copy_decompress_rle.obj (.text:decompress:rle24:__TI_decompress_rle24)
                      0000faa0    00000004                     : pre_init.obj (.text:_system_pre_init)
                      0000faa4    00000004                     : exit.obj (.text:abort)
                      0000faa8    00000002                     : newhandler.obj (.text:_Z21__default_new_handlerv)
                      0000faaa    00000002                     : _lock.obj (.text:_nop)
    
    .cinit     0    0000faac    0000001e     
                      0000faac    0000000c     (.cinit..data.load) [load image]
                      0000fab8    00000006     (__TI_handler_table)
                      0000fabe    00000004     (.cinit..bss.load) [load image, compression = zero_init]
                      0000fac2    00000008     (__TI_cinit_table)
    
    .init_array 
    *          0    0000f800    00000000     UNINITIALIZED
    
    .TI.persistent 
    *          0    0000020a    00000000     UNINITIALIZED
    

    In case 2 the code size increase is driven by the run-time-library code to perform auto-initialization, which in needed to call the constructors for the global variables before main is called.

    In case 3 the code size increase is driven by the run-time-library code to support the dynamic memory allocation for the new function.

    What this shows is that for a device such as a MSP430G2210 with only 2K of flash, the user code needs to be written in a way which reduces how much run-time-library code is required.