EmbeddedRelated.com
Forums
Memfault State of IoT Report

And -- pow! My memory was gone.

Started by Tim Wescott February 21, 2011
David Brown <david@westcontrol.removethisbit.com> writes:

> On 23/02/2011 16:47, Tim Wescott wrote: >> On 02/23/2011 12:20 AM, Andreas Huennebeck wrote: >>> Tim Wescott wrote: >>> >>>> If I could figure out how to keep C++ without using the heap, I'd be a >>>> happy camper. >>> >>> Don't use 'new'. Put your objects on the stack and let subroutines use >>> them through references as function arguments, e.g.: >>> >>> static int foo(MyClass& c) >>> { >>> c.do_something(); >>> } >>> >>> int main() >>> { >>> int some_data; >>> ... some code ... >>> MyClass my_object(some_data); >>> ... some code ... >>> foo(my_object); >>> ... some code ... >>> } >>> >>>> I'm not even sure if malloc&c. are getting _called_, or >>>> just pulled in because C++ uses "new", which uses -- well, you get the >>>> idea. >>> >>> If your classes don't call new and your functions never call new and >>> if you >>> don't use classes from other libraries then malloc() should not be >>> linked in. >>> That's theory though :-( >>> >>>> For embedded I pretty much avoid dynamic deallocation like the >>>> plague*; while this is against the C++ desktop paradigm, it lets you use >>>> a very useful subset of the language without a whole 'heap' of trouble. >>>> >>>> * Meaning I'll "new" things at system startup but only if they're going >>>> to live until power-down. This gives one great flexibility in making >>>> portable libraries while still not fragmenting the heap through >>>> new-delete-new-delete-new sequences. >>> >>> For this approach (and placement new, see >>> http://en.wikipedia.org/wiki/Placement_syntax) >>> malloc is linked in. >>> >>> bye >>> Andreas >> >> void * malloc(size_t n) >> { >> assert(false); >> return 0; >> } >> >> is pretty small -- maybe I'll use that. >> > > void * malloc(size_t n) { > return 0; > } > > is smaller. "assert" can bring in all sorts of junk, depending on how > it is defined, and what flags you have enabled - if it tries to print > out a message on stderr, then this may be the cause of some of your > problems.
I sometimes use a trivial malloc and no free(), Just a few lines of code that allocates from a configurable static array. That allows me to allocate at run-time, without worrying about heap fragmentation or non-deterministic behaviour. -- John Devereux
On 02/23/2011 08:04 AM, David Brown wrote:
> On 23/02/2011 16:47, Tim Wescott wrote: >> On 02/23/2011 12:20 AM, Andreas Huennebeck wrote: >>> Tim Wescott wrote: >>> >>>> If I could figure out how to keep C++ without using the heap, I'd be a >>>> happy camper. >>> >>> Don't use 'new'. Put your objects on the stack and let subroutines use >>> them through references as function arguments, e.g.: >>> >>> static int foo(MyClass& c) >>> { >>> c.do_something(); >>> } >>> >>> int main() >>> { >>> int some_data; >>> ... some code ... >>> MyClass my_object(some_data); >>> ... some code ... >>> foo(my_object); >>> ... some code ... >>> } >>> >>>> I'm not even sure if malloc&c. are getting _called_, or >>>> just pulled in because C++ uses "new", which uses -- well, you get the >>>> idea. >>> >>> If your classes don't call new and your functions never call new and >>> if you >>> don't use classes from other libraries then malloc() should not be >>> linked in. >>> That's theory though :-( >>> >>>> For embedded I pretty much avoid dynamic deallocation like the >>>> plague*; while this is against the C++ desktop paradigm, it lets you >>>> use >>>> a very useful subset of the language without a whole 'heap' of trouble. >>>> >>>> * Meaning I'll "new" things at system startup but only if they're going >>>> to live until power-down. This gives one great flexibility in making >>>> portable libraries while still not fragmenting the heap through >>>> new-delete-new-delete-new sequences. >>> >>> For this approach (and placement new, see >>> http://en.wikipedia.org/wiki/Placement_syntax) >>> malloc is linked in. >>> >>> bye >>> Andreas >> >> void * malloc(size_t n) >> { >> assert(false); >> return 0; >> } >> >> is pretty small -- maybe I'll use that. >> > > void * malloc(size_t n) { > return 0; > } > > is smaller. "assert" can bring in all sorts of junk, depending on how it > is defined, and what flags you have enabled - if it tries to print out a > message on stderr, then this may be the cause of some of your problems.
Let me rephrase that for you: "assert" can bring in all sorts of junk, if you're dumb enough not to write your own. Honest libraries that are really intended for deep embedded use don't even _have_ an assert written, because they know that each development team is going to want its own (or is going to be too slow to use it). The rest need their assert function redefined. So you spelunk through the headers and find out what the 'assert()' macro points to, and you write your own. This one's teeny, and if your debugger lets you set a variable you can break out and see what code was running in the previous function*. Sometimes you can even break out of the assert and correct the problem in the calling function that once, check to see that it's doing the right thing, then go back and find out why the assert was popping off: static volatile int break_out = 0; void __assert_func(const char * this, int that, const char * the, const char * other) { while (break_out == 0) { } } I really do know what I'm doing, even if I'm not as familiar with gnu tools and newlib as I'd like to be (and am becoming). * Which doesn't seem to be necessary with gdb, as it seems to do a good to superlative job of navigating the call stack, but it is a boon with other debuggers. -- Tim Wescott Wescott Design Services http://www.wescottdesign.com Do you need to implement control loops in software? "Applied Control Theory for Embedded Systems" was written for you. See details at http://www.wescottdesign.com/actfes/actfes.html
On 02/23/2011 09:33 AM, John Devereux wrote:
> David Brown<david@westcontrol.removethisbit.com> writes: > >> On 23/02/2011 16:47, Tim Wescott wrote: >>> On 02/23/2011 12:20 AM, Andreas Huennebeck wrote: >>>> Tim Wescott wrote: >>>> >>>>> If I could figure out how to keep C++ without using the heap, I'd be a >>>>> happy camper. >>>> >>>> Don't use 'new'. Put your objects on the stack and let subroutines use >>>> them through references as function arguments, e.g.: >>>> >>>> static int foo(MyClass& c) >>>> { >>>> c.do_something(); >>>> } >>>> >>>> int main() >>>> { >>>> int some_data; >>>> ... some code ... >>>> MyClass my_object(some_data); >>>> ... some code ... >>>> foo(my_object); >>>> ... some code ... >>>> } >>>> >>>>> I'm not even sure if malloc&c. are getting _called_, or >>>>> just pulled in because C++ uses "new", which uses -- well, you get the >>>>> idea. >>>> >>>> If your classes don't call new and your functions never call new and >>>> if you >>>> don't use classes from other libraries then malloc() should not be >>>> linked in. >>>> That's theory though :-( >>>> >>>>> For embedded I pretty much avoid dynamic deallocation like the >>>>> plague*; while this is against the C++ desktop paradigm, it lets you use >>>>> a very useful subset of the language without a whole 'heap' of trouble. >>>>> >>>>> * Meaning I'll "new" things at system startup but only if they're going >>>>> to live until power-down. This gives one great flexibility in making >>>>> portable libraries while still not fragmenting the heap through >>>>> new-delete-new-delete-new sequences. >>>> >>>> For this approach (and placement new, see >>>> http://en.wikipedia.org/wiki/Placement_syntax) >>>> malloc is linked in. >>>> >>>> bye >>>> Andreas >>> >>> void * malloc(size_t n) >>> { >>> assert(false); >>> return 0; >>> } >>> >>> is pretty small -- maybe I'll use that. >>> >> >> void * malloc(size_t n) { >> return 0; >> } >> >> is smaller. "assert" can bring in all sorts of junk, depending on how >> it is defined, and what flags you have enabled - if it tries to print >> out a message on stderr, then this may be the cause of some of your >> problems. > > I sometimes use a trivial malloc and no free(), Just a few lines of code > that allocates from a configurable static array. That allows me to > allocate at run-time, without worrying about heap fragmentation or > non-deterministic behaviour.
Me too. Or if I can't link because of the presence of free I'll put the assert there*, as a gentle hint to future developers that it's the wrong damn thing to do, and as a tool to figure out if it's actually being called in active code, or if it's buried somewhere in C++'s exit code (which should also never get called). -- Tim Wescott Wescott Design Services http://www.wescottdesign.com Do you need to implement control loops in software? "Applied Control Theory for Embedded Systems" was written for you. See details at http://www.wescottdesign.com/actfes/actfes.html
Tim Wescott wrote:
> On 02/22/2011 12:12 PM, 42Bastian Schick wrote: >> 2nd: Check the map-file who pulls in malloc. If you use sprintf, there >> you are. > > I should know this -- how do I do that? I can see it in the symbol > table, but I don't know how, from the object file, I can see what ended > up pulling in malloc.
I'd start with "objdump --disassemble --reloc" or "nm". Stefan
On 23/02/11 18:43, Tim Wescott wrote:
> On 02/23/2011 08:04 AM, David Brown wrote: >> On 23/02/2011 16:47, Tim Wescott wrote: >>> On 02/23/2011 12:20 AM, Andreas Huennebeck wrote: >>>> Tim Wescott wrote: >>>> >>>>> If I could figure out how to keep C++ without using the heap, I'd be a >>>>> happy camper. >>>> >>>> Don't use 'new'. Put your objects on the stack and let subroutines use >>>> them through references as function arguments, e.g.: >>>> >>>> static int foo(MyClass& c) >>>> { >>>> c.do_something(); >>>> } >>>> >>>> int main() >>>> { >>>> int some_data; >>>> ... some code ... >>>> MyClass my_object(some_data); >>>> ... some code ... >>>> foo(my_object); >>>> ... some code ... >>>> } >>>> >>>>> I'm not even sure if malloc&c. are getting _called_, or >>>>> just pulled in because C++ uses "new", which uses -- well, you get the >>>>> idea. >>>> >>>> If your classes don't call new and your functions never call new and >>>> if you >>>> don't use classes from other libraries then malloc() should not be >>>> linked in. >>>> That's theory though :-( >>>> >>>>> For embedded I pretty much avoid dynamic deallocation like the >>>>> plague*; while this is against the C++ desktop paradigm, it lets you >>>>> use >>>>> a very useful subset of the language without a whole 'heap' of >>>>> trouble. >>>>> >>>>> * Meaning I'll "new" things at system startup but only if they're >>>>> going >>>>> to live until power-down. This gives one great flexibility in making >>>>> portable libraries while still not fragmenting the heap through >>>>> new-delete-new-delete-new sequences. >>>> >>>> For this approach (and placement new, see >>>> http://en.wikipedia.org/wiki/Placement_syntax) >>>> malloc is linked in. >>>> >>>> bye >>>> Andreas >>> >>> void * malloc(size_t n) >>> { >>> assert(false); >>> return 0; >>> } >>> >>> is pretty small -- maybe I'll use that. >>> >> >> void * malloc(size_t n) { >> return 0; >> } >> >> is smaller. "assert" can bring in all sorts of junk, depending on how it >> is defined, and what flags you have enabled - if it tries to print out a >> message on stderr, then this may be the cause of some of your problems. > > Let me rephrase that for you: "assert" can bring in all sorts of junk, > if you're dumb enough not to write your own. Honest libraries that are > really intended for deep embedded use don't even _have_ an assert > written, because they know that each development team is going to want > its own (or is going to be too slow to use it). The rest need their > assert function redefined. > > So you spelunk through the headers and find out what the 'assert()' > macro points to, and you write your own. This one's teeny, and if your > debugger lets you set a variable you can break out and see what code was > running in the previous function*. Sometimes you can even break out of > the assert and correct the problem in the calling function that once, > check to see that it's doing the right thing, then go back and find out > why the assert was popping off: > > static volatile int break_out = 0; > void __assert_func(const char * this, int that, const char * the, const > char * other) > { > while (break_out == 0) > { > } > } > > I really do know what I'm doing, even if I'm not as familiar with gnu > tools and newlib as I'd like to be (and am becoming). >
I have your book, though I haven't had time to read it yet, so I know you know your stuff. But even experts make mistakes on unfamiliar territory. And since you have been having issues with the libraries already, it's possible that you've been unintentionally been getting extra library code sneaking in here.
> * Which doesn't seem to be necessary with gdb, as it seems to do a good > to superlative job of navigating the call stack, but it is a boon with > other debuggers. >
On 22.2.11 11:11 , Tim Wescott wrote:
> On 02/22/2011 12:12 PM, 42Bastian Schick wrote: > >> 2nd: Check the map-file who pulls in malloc. If you use sprintf, there >> you are. > > I should know this -- how do I do that? I can see it in the symbol > table, but I don't know how, from the object file, I can see what ended > up pulling in malloc.
I had some private correspondence with Tim, and I promised to post here the part about GNU toolkit switches for diagnostic output: --- clip clip --- The GNU tools are very flexible, but it needs some tuning to the make files to get the desired results. Here are my switches for GCC plain C compilation: CFLAGS = $(INCDIR) -g -Wall -Wstrict-prototypes CFLAGS += -Wa,-adhlms=$(@:.o=.lst) CFLAGS += -ffreestanding -fno-guess-branch-probability CFLAGS += -W -Wpointer-arith The flags for GNU as via the gcc driver and pre-processor (.S files): ASFLAGS = $(INCDIR) -g -Wa,-ahlms=$(@:.o=.lst) The flags for linking via the gcc driver: LDFLAGS = -g -nostartfiles -L.. -L../../lib -lm LDFLAGS += -Wl,-Map=$(TGT).map,--cref,-T,myscript.ld Please note that there must be no whitespace inside the -Wa and -Wl arguments. The flags create assembly listings into .lst files so you can see what the compiler did. The linker flags create a cross-reference into the map. I recall that you asked for it in the news. The library paths in the linker scripts have to be tailored to match your set-up. --- clip clip --- -- Tauno Voipio tauno voipio (at) iki fi
On 02/23/2011 12:51 PM, Tauno Voipio wrote:
> On 22.2.11 11:11 , Tim Wescott wrote: >> On 02/22/2011 12:12 PM, 42Bastian Schick wrote: >> >>> 2nd: Check the map-file who pulls in malloc. If you use sprintf, there >>> you are. >> >> I should know this -- how do I do that? I can see it in the symbol >> table, but I don't know how, from the object file, I can see what ended >> up pulling in malloc. > > I had some private correspondence with Tim, and I promised to > post here the part about GNU toolkit switches for diagnostic > output: > > --- clip clip --- > > The GNU tools are very flexible, but it needs some tuning to > the make files to get the desired results. Here are my switches > for GCC plain C compilation: > > CFLAGS = $(INCDIR) -g -Wall -Wstrict-prototypes > CFLAGS += -Wa,-adhlms=$(@:.o=.lst) > CFLAGS += -ffreestanding -fno-guess-branch-probability > CFLAGS += -W -Wpointer-arith > > The flags for GNU as via the gcc driver and pre-processor (.S files): > > ASFLAGS = $(INCDIR) -g -Wa,-ahlms=$(@:.o=.lst) > > The flags for linking via the gcc driver: > > LDFLAGS = -g -nostartfiles -L.. -L../../lib -lm > LDFLAGS += -Wl,-Map=$(TGT).map,--cref,-T,myscript.ld > > Please note that there must be no whitespace inside the -Wa and > -Wl arguments. > > The flags create assembly listings into .lst files so you > can see what the compiler did. The linker flags create a > cross-reference into the map. I recall that you asked for it > in the news. The library paths in the linker scripts have > to be tailored to match your set-up. > > --- clip clip --- >
And the -Wl,-Map= stuff was very useful. I don't need to address this at the moment, but should I care to do so, I have some good tools for shaking the box. -- Tim Wescott Wescott Design Services http://www.wescottdesign.com Do you need to implement control loops in software? "Applied Control Theory for Embedded Systems" was written for you. See details at http://www.wescottdesign.com/actfes/actfes.html
On 02/23/2011 12:06 PM, David Brown wrote:
> On 23/02/11 18:43, Tim Wescott wrote: >> On 02/23/2011 08:04 AM, David Brown wrote: >>> On 23/02/2011 16:47, Tim Wescott wrote: >>>> On 02/23/2011 12:20 AM, Andreas Huennebeck wrote: >>>>> Tim Wescott wrote: >>>>> >>>>>> If I could figure out how to keep C++ without using the heap, I'd >>>>>> be a >>>>>> happy camper. >>>>> >>>>> Don't use 'new'. Put your objects on the stack and let subroutines use >>>>> them through references as function arguments, e.g.: >>>>> >>>>> static int foo(MyClass& c) >>>>> { >>>>> c.do_something(); >>>>> } >>>>> >>>>> int main() >>>>> { >>>>> int some_data; >>>>> ... some code ... >>>>> MyClass my_object(some_data); >>>>> ... some code ... >>>>> foo(my_object); >>>>> ... some code ... >>>>> } >>>>> >>>>>> I'm not even sure if malloc&c. are getting _called_, or >>>>>> just pulled in because C++ uses "new", which uses -- well, you get >>>>>> the >>>>>> idea. >>>>> >>>>> If your classes don't call new and your functions never call new and >>>>> if you >>>>> don't use classes from other libraries then malloc() should not be >>>>> linked in. >>>>> That's theory though :-( >>>>> >>>>>> For embedded I pretty much avoid dynamic deallocation like the >>>>>> plague*; while this is against the C++ desktop paradigm, it lets you >>>>>> use >>>>>> a very useful subset of the language without a whole 'heap' of >>>>>> trouble. >>>>>> >>>>>> * Meaning I'll "new" things at system startup but only if they're >>>>>> going >>>>>> to live until power-down. This gives one great flexibility in making >>>>>> portable libraries while still not fragmenting the heap through >>>>>> new-delete-new-delete-new sequences. >>>>> >>>>> For this approach (and placement new, see >>>>> http://en.wikipedia.org/wiki/Placement_syntax) >>>>> malloc is linked in. >>>>> >>>>> bye >>>>> Andreas >>>> >>>> void * malloc(size_t n) >>>> { >>>> assert(false); >>>> return 0; >>>> } >>>> >>>> is pretty small -- maybe I'll use that. >>>> >>> >>> void * malloc(size_t n) { >>> return 0; >>> } >>> >>> is smaller. "assert" can bring in all sorts of junk, depending on how it >>> is defined, and what flags you have enabled - if it tries to print out a >>> message on stderr, then this may be the cause of some of your problems. >> >> Let me rephrase that for you: "assert" can bring in all sorts of junk, >> if you're dumb enough not to write your own. Honest libraries that are >> really intended for deep embedded use don't even _have_ an assert >> written, because they know that each development team is going to want >> its own (or is going to be too slow to use it). The rest need their >> assert function redefined. >> >> So you spelunk through the headers and find out what the 'assert()' >> macro points to, and you write your own. This one's teeny, and if your >> debugger lets you set a variable you can break out and see what code was >> running in the previous function*. Sometimes you can even break out of >> the assert and correct the problem in the calling function that once, >> check to see that it's doing the right thing, then go back and find out >> why the assert was popping off: >> >> static volatile int break_out = 0; >> void __assert_func(const char * this, int that, const char * the, const >> char * other) >> { >> while (break_out == 0) >> { >> } >> } >> >> I really do know what I'm doing, even if I'm not as familiar with gnu >> tools and newlib as I'd like to be (and am becoming). >> > > I have your book, though I haven't had time to read it yet, so I know > you know your stuff. But even experts make mistakes on unfamiliar > territory. And since you have been having issues with the libraries > already, it's possible that you've been unintentionally been getting > extra library code sneaking in here.
I mostly chose gnu tools because I'm a cheap bastard, but I also chose them to force me to learn more about them. Half of the tool chains out there seem to be based on gnu tools, and with the ARM seemingly taking over the world, and being such a good fit for the tool chain, I see a lot of value in becoming the go-to guy for that tool chain. -- Tim Wescott Wescott Design Services http://www.wescottdesign.com Do you need to implement control loops in software? "Applied Control Theory for Embedded Systems" was written for you. See details at http://www.wescottdesign.com/actfes/actfes.html
Tauno Voipio wrote:

[...]

> The GNU tools are very flexible, but it needs some tuning to > the make files to get the desired results. Here are my switches > for GCC plain C compilation: > > CFLAGS = $(INCDIR) -g -Wall -Wstrict-prototypes > CFLAGS += -Wa,-adhlms=$(@:.o=.lst)
what is the "m" flag? Do you also experience a clobbered listing when the C sources contain asm instructions?
> CFLAGS += -ffreestanding -fno-guess-branch-probability
-ffreestanding kills also builtins. Do you re-enable them? Do you have any experience with -fno-guess-branch-probability ? Oliver -- Oliver Betz, Munich despammed.com is broken, use Reply-To:
On 24/02/2011 00:21, Tim Wescott wrote:
> On 02/23/2011 12:06 PM, David Brown wrote: >> On 23/02/11 18:43, Tim Wescott wrote: >>> On 02/23/2011 08:04 AM, David Brown wrote: >>>> On 23/02/2011 16:47, Tim Wescott wrote: >>>>> On 02/23/2011 12:20 AM, Andreas Huennebeck wrote: >>>>>> Tim Wescott wrote: >>>>>> >>>>>>> If I could figure out how to keep C++ without using the heap, I'd >>>>>>> be a >>>>>>> happy camper. >>>>>> >>>>>> Don't use 'new'. Put your objects on the stack and let subroutines >>>>>> use >>>>>> them through references as function arguments, e.g.: >>>>>> >>>>>> static int foo(MyClass& c) >>>>>> { >>>>>> c.do_something(); >>>>>> } >>>>>> >>>>>> int main() >>>>>> { >>>>>> int some_data; >>>>>> ... some code ... >>>>>> MyClass my_object(some_data); >>>>>> ... some code ... >>>>>> foo(my_object); >>>>>> ... some code ... >>>>>> } >>>>>> >>>>>>> I'm not even sure if malloc&c. are getting _called_, or >>>>>>> just pulled in because C++ uses "new", which uses -- well, you get >>>>>>> the >>>>>>> idea. >>>>>> >>>>>> If your classes don't call new and your functions never call new and >>>>>> if you >>>>>> don't use classes from other libraries then malloc() should not be >>>>>> linked in. >>>>>> That's theory though :-( >>>>>> >>>>>>> For embedded I pretty much avoid dynamic deallocation like the >>>>>>> plague*; while this is against the C++ desktop paradigm, it lets you >>>>>>> use >>>>>>> a very useful subset of the language without a whole 'heap' of >>>>>>> trouble. >>>>>>> >>>>>>> * Meaning I'll "new" things at system startup but only if they're >>>>>>> going >>>>>>> to live until power-down. This gives one great flexibility in making >>>>>>> portable libraries while still not fragmenting the heap through >>>>>>> new-delete-new-delete-new sequences. >>>>>> >>>>>> For this approach (and placement new, see >>>>>> http://en.wikipedia.org/wiki/Placement_syntax) >>>>>> malloc is linked in. >>>>>> >>>>>> bye >>>>>> Andreas >>>>> >>>>> void * malloc(size_t n) >>>>> { >>>>> assert(false); >>>>> return 0; >>>>> } >>>>> >>>>> is pretty small -- maybe I'll use that. >>>>> >>>> >>>> void * malloc(size_t n) { >>>> return 0; >>>> } >>>> >>>> is smaller. "assert" can bring in all sorts of junk, depending on >>>> how it >>>> is defined, and what flags you have enabled - if it tries to print >>>> out a >>>> message on stderr, then this may be the cause of some of your problems. >>> >>> Let me rephrase that for you: "assert" can bring in all sorts of junk, >>> if you're dumb enough not to write your own. Honest libraries that are >>> really intended for deep embedded use don't even _have_ an assert >>> written, because they know that each development team is going to want >>> its own (or is going to be too slow to use it). The rest need their >>> assert function redefined. >>> >>> So you spelunk through the headers and find out what the 'assert()' >>> macro points to, and you write your own. This one's teeny, and if your >>> debugger lets you set a variable you can break out and see what code was >>> running in the previous function*. Sometimes you can even break out of >>> the assert and correct the problem in the calling function that once, >>> check to see that it's doing the right thing, then go back and find out >>> why the assert was popping off: >>> >>> static volatile int break_out = 0; >>> void __assert_func(const char * this, int that, const char * the, const >>> char * other) >>> { >>> while (break_out == 0) >>> { >>> } >>> } >>> >>> I really do know what I'm doing, even if I'm not as familiar with gnu >>> tools and newlib as I'd like to be (and am becoming). >>> >> >> I have your book, though I haven't had time to read it yet, so I know >> you know your stuff. But even experts make mistakes on unfamiliar >> territory. And since you have been having issues with the libraries >> already, it's possible that you've been unintentionally been getting >> extra library code sneaking in here. > > I mostly chose gnu tools because I'm a cheap bastard, but I also chose > them to force me to learn more about them. Half of the tool chains out > there seem to be based on gnu tools, and with the ARM seemingly taking > over the world, and being such a good fit for the tool chain, I see a > lot of value in becoming the go-to guy for that tool chain. >
I mostly choose gnu tools because I like them better, and I find they do a better job than many commercial tools. The price is of course nice - especially if I am doing stuff at home. Free tools means it is easy to install them on my work PC, and my home PC, and a laptop, etc., without ever having to think about whether it is cost-effective. It also means there is no administrative overhead involved in "purchasing" the tools - you don't need to fit them into budgets, arrange purchasing orders, etc. I use a wide range of processors in my work - having gcc for almost all of them makes life easier for me. I can use the same editors, and the same procedures (and to a fair extent, the same makefile) for all the projects. I have used (and still use) a fair number of commercial tools over the years. Details vary wildly, but gcc generates roughly as good code for most 32-bit targets (and it's not too bad even for the 8-bit avr). I also find some gcc enhancements and newer standard C features let me write clearer source code and smaller or faster target code. It's always annoying when I have to back to a commercial compiler that doesn't support things like intermixing variable declarations and executable code.

Memfault State of IoT Report