I have recently installed WinARM 20070505. Having compiled some test code and simulated it with Insight, I am certain that things are working correctly. Given the following: - I do not need the RTTI capability. - I do not need dynamic memory (malloc,free,new,delete). - I do not need the stream I/O functionality (fopen,iostream,etc.). - I will need exception handling. - I will need to code in ARM 32 bit mode (no thumb code). My question is: "How can I configure the build/link so that the FLASH/RAM space used is minimal?" Currently, even the smallest test program generates a 40k+ image. With exceptions handling, it jumps 2k+. So it seems to me that a lot of code is being linked in that I do not need and there must be a way to strip it out. Any suggestions/tips/examples would be greatly appreciated. Cheers! Daniel Quinz, P. Eng. Acacetus Inc.
This is what I use: Compiler: -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -fno-exceptions -fno-unwind-tables Linker: -nostartfiles Be careful when using things from newlib (e.g. printf). You need a linker script which takes care of C++ peculiarities, e.g. you need entries *(.text.*) *(.data.*) *(.bss.*) in the respective sections, a .ctors section for *(.ctors.*) and *(.ctors) and a dummy .dtors sections for *(.dtors). Also the startup initialization should call the C++ constructors.
Andreas Kaiser wrote: > This is what I use: > > Compiler: > -ffunction-sections > -fdata-sections > -fno-builtin > -fno-rtti > -fno-exceptions > -fno-unwind-tables Thanks for the tip. I added all of these except "-fno-exceptions" and "-fno-unwind-tables" as I need exception handling. There was no difference in the FLASH memory, but the RAM usage went down only 8 bytes. I have found that if I don't define the variable 'device_table_entry' then I get an unresolved reference error to it during link. The functions that reference it are are: _close_r , _read_r , _write_r , _ioctl_r All of these are in the 'newlib_lpc' library. Given that I make do explicit reference anywhere in my code to any of these functions, nor do I use 'printf', etc., I do not see why these are being linked into the application. I have checked the 'crt0.s' file that I use and there are no references to these functions in there either. There must be a way to avoid linking in these functions if they are not needed. Any thoughts? Dan > Linker: > -nostartfiles Already doing this. > > Be careful when using things from newlib (e.g. printf). I'm not using either (see above text on newlib linking). > You need a linker script which takes care of C++ peculiarities, e.g. you > need entries *(.text.*) *(.data.*) *(.bss.*) in the respective sections, > a .ctors section for *(.ctors.*) and *(.ctors) and a dummy .dtors > sections for *(.dtors). Done. Works fine. > > Also the startup initialization should call the C++ constructors. Done. Works fine.
Dan Quinz wrote: > Andreas Kaiser wrote: >> This is what I use: >> >> Compiler: >> -ffunction-sections >> -fdata-sections >> -fno-builtin >> -fno-rtti >> -fno-exceptions >> -fno-unwind-tables > > Thanks for the tip. I added all of these except "-fno-exceptions" and > "-fno-unwind-tables" as I need exception handling. There was no > difference in the FLASH memory, but the RAM usage went down only 8 > bytes. Make sure to add the linker-option -gc-sections when using -ffunction-sections and -fdata-sections. If you use the compiler frontend (arm-elf-gcc) for linking - recommended - add this option: -Wl,--gc-sections. If you already have some optione passed to the linker (for exampel already -Wl entry in CFLAGS) just add --gc-sections (I usualy use: CFLAGS += -Wl,-Map=$(TARGET).map,--cref,--gc-sections) > I have found that if I don't define the variable 'device_table_entry' > then I get an unresolved reference error to it during link. The > functions that reference it are are: > > _close_r , _read_r , _write_r , _ioctl_r > > All of these are in the 'newlib_lpc' library. The newlib-lpc provides the syscalls for the newlib and so indirectly for the libstdc++.a. newlib-lpc needs the device_table. The use has to provide it. I'm not sure why you get an error about "device_table_entry" since this is basicly just a struct defined in dev_ctrl.h. > Given that I make do explicit reference anywhere in my code to any of > these functions, nor do I use 'printf', etc., I do not see why these are > being linked > into the application. As far as I know the C++ stdlib depends on stdio-functions but I'm not sure if this can be disabled somehow. A map-file should provide more information which functions of the library depend on others. The main reason for the large binary size might be that the C++ stdlib "pulls in" the complete stdio-support including floating-point (IRC this is around 30kBytes for "plain" newlib without C++). > I have checked the 'crt0.s' file that I use and there are no references > to these functions in there either. Maybe the dependencies are "hidden" and from another library like libstdc++.a. > There must be a way to avoid linking in these functions if they are not > needed. Maybe there is some options like the ones for RTTI but I have not found it yet. Maybe the Toolchain (esp. the C++ stdlib) has to be rebuild with special options. Sorry, a lot of "maybes" and no real solution but hopefully some useful hints. Martin Thomas
Check Section "Reducing the Overhead of C++" from http://www.embedded.com/columns/technicalinsights/201001729
> Given that I make do explicit reference anywhere in my code to any of > these functions, nor do I use 'printf', etc., I do not see why these are > being linked into the application. Temporarily remove/rename the newlib. The linker should tell you.
Thanks Martin, I added the options and recompiled. The resulting code reduction was about 4500 bytes. Little to no effect on the RAM usage (10 bytes), but I am happier. I will continue to research a bit more into what the newlib_lpc library is doing as it seems this is the culprit for the external references. Cheers! Dan Martin Thomas wrote: > Dan Quinz wrote: >> Andreas Kaiser wrote: >>> This is what I use: >>> >>> Compiler: >>> -ffunction-sections >>> -fdata-sections >>> -fno-builtin >>> -fno-rtti >>> -fno-exceptions >>> -fno-unwind-tables >> >> Thanks for the tip. I added all of these except "-fno-exceptions" and >> "-fno-unwind-tables" as I need exception handling. There was no >> difference in the FLASH memory, but the RAM usage went down only 8 >> bytes. > > Make sure to add the linker-option -gc-sections when using > -ffunction-sections and -fdata-sections. If you use the compiler > frontend (arm-elf-gcc) for linking - recommended - add this option: > -Wl,--gc-sections. If you already have some optione passed to the linker > (for exampel already -Wl entry in CFLAGS) just add --gc-sections (I > usualy use: CFLAGS += -Wl,-Map=$(TARGET).map,--cref,--gc-sections) > >> I have found that if I don't define the variable 'device_table_entry' >> then I get an unresolved reference error to it during link. The >> functions that reference it are are: >> >> _close_r , _read_r , _write_r , _ioctl_r >> >> All of these are in the 'newlib_lpc' library. > > The newlib-lpc provides the syscalls for the newlib and so indirectly > for the libstdc++.a. newlib-lpc needs the device_table. The use has to > provide it. I'm not sure why you get an error about "device_table_entry" > since this is basicly just a struct defined in dev_ctrl.h. > >> Given that I make do explicit reference anywhere in my code to any of >> these functions, nor do I use 'printf', etc., I do not see why these are >> being linked >> into the application. > > As far as I know the C++ stdlib depends on stdio-functions but I'm not > sure if this can be disabled somehow. A map-file should provide more > information which functions of the library depend on others. The main > reason for the large binary size might be that the C++ stdlib "pulls in" > the complete stdio-support including floating-point (IRC this is around > 30kBytes for "plain" newlib without C++). > >> I have checked the 'crt0.s' file that I use and there are no references >> to these functions in there either. > > Maybe the dependencies are "hidden" and from another library like > libstdc++.a. > >> There must be a way to avoid linking in these functions if they are not >> needed. > > Maybe there is some options like the ones for RTTI but I have not found > it yet. Maybe the Toolchain (esp. the C++ stdlib) has to be rebuild with > special options. > > Sorry, a lot of "maybes" and no real solution but hopefully some useful > hints. > > Martin Thomas
Thanks again Martin. I read this article before and I have added the dummy replacements for malloc/free/new/delete mad the atexit func. The net effect is a code reduction of about 100 bytes, so I'm still not near to removing the "bottom of the iceberg". As stated before, I will continue to dig into the libraries to try to get insight as to what exactly is being linked in and where. Thanks for your help. Cheers! Dan Martin Thomas wrote: > Check Section "Reducing the Overhead of C++" from > http://www.embedded.com/columns/technicalinsights/201001729
Thanks to all for your feedback. I apprecite it! Cheers! Dan
Dan Quinz wrote: > I read this article before and I have added the dummy replacements for > malloc/free/new/delete mad the atexit func. The net effect is a code > reduction of about 100 bytes, so I'm still not near to removing the > "bottom of the iceberg". The article helped me reduce my code a little bit as well, but I'd also like to get some more out of it. Is there anyway to stop it from pulling in an entire library, or at least make it intelligently use my function and not include it from the library? For example From my map file: 0x534 c:/winarm/bin/../lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib/thumb/int erwork\libc.a(lib_a-mallocr.o) 0x000178a0 _malloc_r If I attempt to compile the following to override the library function: extern "C" void *_malloc_r(struct _reent *, size_t) {return (void *)0; } I get this error: 1>c:/winarm/bin/../lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib/thumb/i nterwork\libc.a(lib_a-mallocr.o): In function `_malloc_r': 1>mallocr.c:(.text+0x0): multiple definition of `_malloc_r' 1>.out/Reduced_Newlib.o:../../../../src/HwDrivers/ARM/Reduced_Newlib.cpp :31: first defined here 1>c:/winarm/bin/../lib/gcc/arm-elf/4.1.2/../../../../arm-elf/bin/ld.exe: Warning: size of symbol `_malloc_r' changed from 4 in .out/Reduced_Newlib.o to 1332 in c:/winarm/bin/../lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib/thumb/int erwork\libc.a(lib_a-mallocr.o) I am not using any sort of malloc, or free or anything of that sort in my code, and it would be great if it stopped including these libraries...
Jim Kaz wrote: > If I attempt to compile the following to override the library function: > extern "C" void *_malloc_r(struct _reent *, size_t) {return (void *)0; } Well, I'm not entirely sure what I changed, but while overriding other functions, I decided to try _malloc_r again to see if I could get it working at all. The following works. Looks similar to what I posted before huh? Yea, I dunno? shrug extern "C" void *_malloc_r(struct _reent *, size_t) {return (void *)0; }
Dan Quinz wrote: > I read this article before and I have added the dummy replacements for > malloc/free/new/delete mad the atexit func. The net effect is a code > reduction of about 100 bytes, so I'm still not near to removing the > "bottom of the iceberg". After playing around with my code some more, here are some more things that you can override: extern "C" void *_malloc_r(struct _reent *, size_t) {return (void *)0; } extern "C" void _free_r(struct _reent *, void*) {} extern "C" void *_realloc_r(struct _reent *, void*, size_t) {return (void *)0; }; extern "C" void *realloc(void *, size_t) {return (void *)0; }; extern "C" void *_calloc_r(struct _reent *, size_t, size_t) {return (void *)0; }; These functions should entirely remove malloc.o from your map file and will drop your flash usage by another couple kilobytes, and should drop your RAM by about a kilobyte. Additionally, if you don't use any string manipulation: extern "C" int _vfprintf_r(struct _reent *, FILE*, const char*, void*) {return 0;} That frees up about 14K of flash, maybe 100 bytes of RAM. I'm looking for a way to remove alloc.o, which means I need to override __cxa_free_exception and _cxa_allocate_exception, but I'm having difficulty in finding their declarations. This will free up a few hundred bytes of flash and around a K or 2 of RAM. Thanks for posting that article Martin! Its been a big help. I never knew how to override the functions that got linked in, and this showed me exactly how to do it. Thanks!
Something I came across. The article does __aeabi_atexit, where as I think we want to use __cxa_atexit, since we are using GCC. In addition, we need to use the -fuse-cxa-atexit flag in the compiler. I have yet to actually get this to work though, since I keep getting the following error: 1>.out/HwMemSystem.o: In function `__static_initialization_and_destruction_0': 1>../../../../src/MemSystem/HwMemSystem.cpp:145: undefined reference to `__dso_handle' Additionally, adding the -fno-enforce-eh-specs flag seems like it should disabled the 'eh_' library includes, which would include eh_alloc, thus freeing up about 2K of RAM, but it doesn't seem to do that. The output file is exactly the same size, sigh. Hopefully some of my digging will be useful to you Dan.
Thanks Jim! Your redefinitions for the memory allocation routined helped quite a bit! I dropped the flash down by 4228 bytes and the ram by 1040. There was no effect when I redefined the vprintf function though. I also experimented with removing the global 'device_table_entry' and get the following linker errors: Code: #if 0 const struct device_table_entry * device_table[] = { & com1 , // stdin & com1 , // stdout & com1 , // stderr // 0 } ; #endif c:/winarm.20070505/bin/../lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib\ libnewlib-lpc.a(_close_r.o): In function `_close_r': C:\WinARM\utils\newlib_lpc_rel5a_src/_close_r.c:71: undefined reference to `device_table' c:/winarm.20070505/bin/../lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib\ libnewlib-lpc.a(_read_r.o): In function `_read_r': C:\WinARM\utils\newlib_lpc_rel5a_src/_read_r.c:84: undefined reference to `device_table' c:/winarm.20070505/bin/../lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib\ libnewlib-lpc.a(_write_r.o): In function `_write_r': C:\WinARM\utils\newlib_lpc_rel5a_src/_write_r.c:103: undefined reference to `device_table' c:/winarm.20070505/bin/../lib/gcc/arm-elf/4.1.2/../../../../arm-elf/lib\ libnewlib-lpc.a(_ioctl_r.o): In function `_ioctl_r': C:\WinARM\utils\newlib_lpc_rel5a_src/_ioctl_r.c:75: undefined reference to `device_table' So it eppears there is something in one of the libraries that is causing the stdio stuff to be linked in. I don't use any of it explicitly, so it must be coming from the libraries somewhere. Thanks for sharing your digging. Cheers! Dan Jim Kaz wrote: > Something I came across. The article does __aeabi_atexit, where as I > think we want to use __cxa_atexit, since we are using GCC. In addition, > we need to use the -fuse-cxa-atexit flag in the compiler. I have yet to > actually get this to work though, since I keep getting the following > error: > > 1>.out/HwMemSystem.o: In function > `__static_initialization_and_destruction_0': > 1>../../../../src/MemSystem/HwMemSystem.cpp:145: undefined reference to > `__dso_handle' > > > Additionally, adding the -fno-enforce-eh-specs flag seems like it should > disabled the 'eh_' library includes, which would include eh_alloc, thus > freeing up about 2K of RAM, but it doesn't seem to do that. The output > file is exactly the same size, sigh. > > > Hopefully some of my digging will be useful to you Dan.
Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
Log in with Google account
No account? Register here.