reducing code size with Gnude GCC compiler | developer.brewmp.com reducing code size with Gnude GCC compiler | developer.brewmp.com

Developer

reducing code size with Gnude GCC compiler

I'm trying to reduce the size of the code that is generated by the Gnude GCC 3.3 compiler. Here's what I've done so far to my makefile (based on the one included with the BREW GCC support .zip). These changes reduced my binary from 68K down to 33K. (Which compiles at 27K with the ARM 1.1 ADS compiler in ARM mode, and 18K in Thumb mode)

a) Set the compiler options to remove exceptions, unwind tables, rtti. The function-sections switch makes it easier to see how big each function is in the map file.

OUT = -fno-exceptions -fno-unwind-tables -fno-rtti -ffunction-sections -c

b) Set the libs to only include gcc. I don't want it bringing in exceptions, rtti, and other stuff with out me knowing about it as a linker error:

LIBS = -lgcc

c) Set the optimization option to optimize for space

OPT = -Os

d) define your own __cxa_pure_virtual that doesn't use exceptions like the default version does. I put this in the same .cpp file as my operator new, etc. This is a very important step as the builtin version brings in exceptions, rtti, etc.

extern "C" void __cxa_pure_virtual (void) {}

e) Optional, no code size reduction: change your linker options to output a map file, cross references, and to not warn about those interworking incompatibilities.

LINK_CMD = -Ttext 0 --no-warn-mismatch -Map $(TARGET).map --cref --emit-relocs -entry AEEMod_Load --gc-sections -o

Now, if you look at your map file, you'll see that its defining each constructor twice and each destructor three times. Yuk. This is a known issue with the 3.x toolchain and there are some patches to get around it (see http://gcc.gnu.org/ml/gcc-patches/2002-08/msg00354.html). I've been having trouble compiling the toolchain from scratch, so I haven't invested the time and effort to apply the patch.

Does anyone have any other suggestions on how to reduce code size when using the GCC tools?

How do you define your new/delete operators?
I originally tried compiling and got an error from BREWelf2mod saying:
Unknown section name ".gcc_except_table]:"
So I figure it's somewhere trying to use exceptions and I work out since I'm not using them anywhere it must be the built in functions new/delete etc. So after reading your mail I too try only linking -lgcc to prevent from using them but of course now it can't find operator new etc.
Could you please explain how should these be defined?
Also what is the purpose of the extern "C" void __cxa_pure_virtual (void) {} function you define?
Thanks,
JayA

How do you define your new/delete operators?
I originally tried compiling and got an error from BREWelf2mod saying:
Unknown section name ".gcc_except_table]:"
So I figure it's somewhere trying to use exceptions and I work out since I'm not using them anywhere it must be the built in functions new/delete etc. So after reading your mail I too try only linking -lgcc to prevent from using them but of course now it can't find operator new etc.
Could you please explain how should these be defined?
Also what is the purpose of the extern "C" void __cxa_pure_virtual (void) {} function you define?
Thanks,
JayA

My new, new[], delete, delete[], and __assert are defined as follows. These are the standard BREW way to do it that has been mentioned in a few other threads.
void* operator new(size_t sz)
{
return MALLOC(sz);

void operator delete(void *p)
{
FREE(p);

void* operator new[](size_t sz)
{
return MALLOC(sz);

void operator delete[](void *p)
{
FREE(p);

extern "C" void __assert(const char * , const char * , int ) {
}
-Aaron

My new, new[], delete, delete[], and __assert are defined as follows. These are the standard BREW way to do it that has been mentioned in a few other threads.
void* operator new(size_t sz)
{
return MALLOC(sz);

void operator delete(void *p)
{
FREE(p);

void* operator new[](size_t sz)
{
return MALLOC(sz);

void operator delete[](void *p)
{
FREE(p);

extern "C" void __assert(const char * , const char * , int ) {
}
-Aaron

The purpose of __cxa_pure_virtual is to provide run-time support if someone calls a pure virtual function. Hopefully, the Win32 debugging you do should find any times you call a pure virtual function (its probably possible if you do some funky pointers to member function stuff, but its never happened to me before).
-Aaron

The purpose of __cxa_pure_virtual is to provide run-time support if someone calls a pure virtual function. Hopefully, the Win32 debugging you do should find any times you call a pure virtual function (its probably possible if you do some funky pointers to member function stuff, but its never happened to me before).
-Aaron

Anybody had linking problems using Gnude and C++?
My source files seem to compile just fine,
however arm-elf-ld.exe fails in numerous places (mostly constructors and destructors) with
'undefined reference to __gxx_personality_sj0'

Anybody had linking problems using Gnude and C++?
My source files seem to compile just fine,
however arm-elf-ld.exe fails in numerous places (mostly constructors and destructors) with
'undefined reference to __gxx_personality_sj0'

I think that is something to do with Exception handling.. in order to reduce bloat in your .mod file I suggest you don't use any exception handling code at all.. use the compiler flags and the implementation of new/delete, etc. that aisaksen posted earlier in this thread and make sure you only link the gcc library and no others.. (Just -lgcc) This way you will get linker errors if you accidentally use anythign that depends on anything else.
Also make sure you're using the GCCResolver.c and the gnu headers provided with the BREW GNU tools (Put the GNU headers first on your search path with the -I option, before your other BREW headers if you want to retain the original headers intact for MS compiler). The GCCResolver is badly written as it assumes the C language.. so you'll need to put something like
#ifdef __cplusplus__
extern "C"
{
#endif
at the top with the matching close brace at the bottom, or simply put extern "C" before the functions.
Hope this helps.
J

I think that is something to do with Exception handling.. in order to reduce bloat in your .mod file I suggest you don't use any exception handling code at all.. use the compiler flags and the implementation of new/delete, etc. that aisaksen posted earlier in this thread and make sure you only link the gcc library and no others.. (Just -lgcc) This way you will get linker errors if you accidentally use anythign that depends on anything else.
Also make sure you're using the GCCResolver.c and the gnu headers provided with the BREW GNU tools (Put the GNU headers first on your search path with the -I option, before your other BREW headers if you want to retain the original headers intact for MS compiler). The GCCResolver is badly written as it assumes the C language.. so you'll need to put something like
#ifdef __cplusplus__
extern "C"
{
#endif
at the top with the matching close brace at the bottom, or simply put extern "C" before the functions.
Hope this helps.
J

Thanks for the good suggestions for the makefile.
From the link map I notice that the compiler is including many floating point conversion functions from the gcc library:
__adddf3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
__ashldi3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_ashldi3.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_pack_df.o)
__div0 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_dvmd_tls.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_divsi3.o)
__divsi3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_divsi3.o)
__fixdfsi D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_df_to_si.o)
__floatsidf D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_si_to_df.o)
__lshrdi3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_lshrdi3.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_pack_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_df_to_si.o)
__pack_d D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_pack_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_si_to_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
__subdf3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
__thenan_df D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_thenan_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
__unpack_d D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_unpack_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_df_to_si.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
I do not believe I am doing any floating point at all, so is there a good easy way to see where these are being invoked in the code. For example, can I get an assembler file with line numbers so that I can search for the offending lines?

Thanks for the good suggestions for the makefile.
From the link map I notice that the compiler is including many floating point conversion functions from the gcc library:
__adddf3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
__ashldi3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_ashldi3.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_pack_df.o)
__div0 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_dvmd_tls.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_divsi3.o)
__divsi3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_divsi3.o)
__fixdfsi D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_df_to_si.o)
__floatsidf D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_si_to_df.o)
__lshrdi3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_lshrdi3.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_pack_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_df_to_si.o)
__pack_d D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_pack_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_si_to_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
__subdf3 D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
__thenan_df D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_thenan_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
__unpack_d D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_unpack_df.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_df_to_si.o)
D:\CellGames\BREWGnuArm\gnude/lib/gcc-lib/arm-elf/3.3/libgcc.a(_addsub_df.o)
I do not believe I am doing any floating point at all, so is there a good easy way to see where these are being invoked in the code. For example, can I get an assembler file with line numbers so that I can search for the offending lines?

Use -S -g and look at the .o file. It will have the assembly code and line numbers.
As for example, above it was pilot error (DOH!).

Use -S -g and look at the .o file. It will have the assembly code and line numbers.
As for example, above it was pilot error (DOH!).