Pages: [1] 2   Go Down
Author Topic: What limitation am I hitting?  (Read 1414 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a situation where I'm hitting some limitation in the GCC tool chain.

I'm using the Uno, so I should have about 30 kB of code flash, and about 2 kB of SRAM (for globals + stack), if I read all the documentation correctly.

Yet, I'm running into problems at code sizes that are way smaller than that. Let me explain the symptoms. I have two global instances of some classes. The classes each have a small vtable, and a handful of bytes of member variables. Those instances, in turn, reference a hundred bytes or so of PROGMEM data and a dozen bytes of other global data.

In the smallest case, these instances are commented out:

Code:
//Menu menu(lcd, &menuExit);
//Page main(&menu, &mainText, &mainAction);

The binary sketch size of this is 8482 bytes (of a 32256 byte maximum). This runs as expected.

Now, I can add one of the variables:
Code:
Menu menu(lcd, &menuExit);
//Page main(&menu, &mainText, &mainAction);

The binary size is 8586 bytes, and it still runs as expected.

Moving on, I can add the second variable, with the first variable still there, and the linker goes bonkers:


Code:
Menu menu(lcd, &menuExit);
Page main(&menu, &mainText, &mainAction);

Compiling this results in a binary size of only 4722 bytes, but no compiler or linker errors. The program does not run as expected. However, I don't think this is "running out of SRAM," by looking at the memory consumed. I think this is a bug in the compiler or linker, where it generates an invalid image, without generating an error to the user, and this concerns me a lot, because I don't know how to diagnose this problem.

But, the plot thickens! If I remove the first variable, only keeping the second, I get an unexplained internal linker error:


Code:
//Menu menu(lcd, &menuExit);
Page main(0, &mainText, &mainAction);

Code:
c:/code/arduino/arduino-0022/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/lib/avr5/crtm328p.o:(.init9+0x0): warning: internal error: out of range error
Binary sketch size: 4610 bytes (of a 32256 byte maximum)

This gives me very little to go on. I'd like to start varying the different inputs to this compilation, and examine the object files (say, with objdump or something similar), but I can't find where the Arduino software stores the intermediate build artifacts. It seems to create temporary directories, compile into there, and then wipe them all out before I can get to them.

Is there some way to avoid that deletion? Is there some way to build my sketch from the command line? Perhaps one step at a time -- gather, compile, link, as separate steps? Is there some way to know how the environment is invoking the compiler/linker so I can reproduce the exact same build under conditions I can examine? And is this documented somewhere? The documentation Wiki just seems to talk about the high-level API of the built-in libraries; perhaps there's some reference documentation that I've simply missed?

Any help on this would be appreciated.

Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26632
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How do you know how much RAM you're consuming?
For that matter, how do we know? (Hint)
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am using indirect measurements. Size of struct/class can be had by adding up the members (include vtable!)
Thus, size delta from changes should be understandable. Some classes may bring in new libraries, which use more sram, which i don't know how to get good grips on.
Printing the address of globals is useful -- globals towards the end of the sketch seem to be towards the end of the data section.
If i could somehow convince the linker to spit out a symbol map, or objdump the .o files or bin/hex file, that would be very helpful. Is there a way to do that?
Note the "binary size" values, though -- the problem I'm seeing is likely in codegen/linking, not runtime.
Logged

Phoenix, Arizona USA
Offline Offline
Faraday Member
**
Karma: 42
Posts: 5612
Where's the beer?
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I am using indirect measurements. Size of struct/class can be had by adding up the members (include vtable!)
Thus, size delta from changes should be understandable. Some classes may bring in new libraries, which use more sram, which i don't know how to get good grips on.
Printing the address of globals is useful -- globals towards the end of the sketch seem to be towards the end of the data section.
If i could somehow convince the linker to spit out a symbol map, or objdump the .o files or bin/hex file, that would be very helpful. Is there a way to do that?
Note the "binary size" values, though -- the problem I'm seeing is likely in codegen/linking, not runtime.

I'm not going to be as polite as AWOL:

POST YOUR CODE.

Seriously - how do you really expect us to help you figure this out, if we can't see exactly what you are doing...?
Logged

I will not respond to Arduino help PM's from random forum users; if you have such a question, start a new topic thread.

0
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12725
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just a thought - using main as an identifier - isn't that going to cause issues?
Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

POST YOUR CODE.

The code is spread across three libraries (each with a .h and a .cpp) and the actual sketchbook project. If I saw someone post all of that on the web and then ask me "hey, debug my code for me," I'd think he was crazy. In fact, I'm not asking for fish (the solution to the problem); I'm asking for a fishing pole (the methods to debug the problem).

Specifically, without any code at all, I can re-phrase my questions much more succinctly:

- How can I capture or re-generate the compiled .o files and run objdump on them?
- How can I capture or re-generate the linked image and obtain a link map for it?


Regarding using the name "main" -- that's a fantastic observation! Gotta go try renaming that. I'd expect a syntax error from the compiler if that were the case, or worst case a linker multiple symbol definition error, but the cases where I do get the error are totally consistent with using "main" as a non-function symbol.
Logged

Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just a thought - using main as an identifier - isn't that going to cause issues?

Alright, MarkT wins the prize! Apparently I posted just enough code to help solve the problem :-D Thanks for the fish, MarkT; I really appreciate it!

My other questions remain, though: Where do I go to get self-help tools, such as .o files, .map files, and the like?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 310
Posts: 26632
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Where do I go to get self-help tools, such as .o files, .map files, and the like?
Hold the shift key down when you click on "verify" or "download". All will be revealed.
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That's good to know! I can now objdump the .elf file it generates, which would hopefully have led me to the solution without MarkT having to force open my eyes :-) Thank you.

Is there a good pointer to where things like these are documented?

Btw: I first tried it with the shortcut keys (Ctrl-shift-R) and menu item (shift-select) which didn't work. Apparently, it only works for the toolbar buttons.
Logged

Global Moderator
Melbourne, Australia
Offline Offline
Brattain Member
*****
Karma: 511
Posts: 19358
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Regarding using the name "main" -- that's a fantastic observation! Gotta go try renaming that. I'd expect a syntax error from the compiler if that were the case, or worst case a linker multiple symbol definition error, but the cases where I do get the error are totally consistent with using "main" as a non-function symbol.

I think he is probably right about main. You can make your own main function - I tried a while back. You don't get a linker error, probably because if it finds your main it doesn't search the libaries for their main.

But if your main function doesn't do what you expect (like call init and loop) you will get odd runtime behaviour. Or it it has the wrong return type, you are likely to get linker errors that aren't immediately obvious.

(Hint: don't make your own init function either).
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

0
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12725
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just a thought - using main as an identifier - isn't that going to cause issues?

Alright, MarkT wins the prize! Apparently I posted just enough code to help solve the problem :-D Thanks for the fish, MarkT; I really appreciate it!

My other questions remain, though: Where do I go to get self-help tools, such as .o files, .map files, and the like?

smiley-wink

If you are interested you can look at the runtime source code for the Arduino in hardware/arduino/cores/arduino/ in your Arduino installation.  You'll find the main() routine there, it calls setup() and when loops calling loop().
Logged

[ I won't respond to messages, use the forum please ]

Global Moderator
Melbourne, Australia
Offline Offline
Brattain Member
*****
Karma: 511
Posts: 19358
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Looks like I was half right. smiley-wink

main calls init and setup, and then loop:

Code:
int main(void)
{
init();

setup();
   
for (;;)
loop();
       
return 0;
}
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You don't get a linker error, probably because if it finds your main it doesn't search the libaries for their main.

This concerns me. A program is only allowed to have one definition of a particular symbol, and you should get a linker error if you define a symbol more than once. Similarly, you should get a compile error if the runtime code simply includes all the data, and you try to define the symbol "main" twice in the same compilation unit.

Thanks for all your help, though!

Regular GCC does this right:

Code:
jwatte@svn:/tmp> cat > foo.cpp

class Foo {
};

Foo main;

int main(int argc, char const *argv[]) {
        return 0;
}
jwatte@svn:/tmp> g++ -c foo.cpp
foo.cpp: In function âint main(int, const char**)â:
foo.cpp:7: error: âint main(int, const char**)â redeclared as different kind of symbol
foo.cpp:5: error: previous declaration of âFoo mainâ
jwatte@svn:/tmp>
Logged

Global Moderator
Melbourne, Australia
Offline Offline
Brattain Member
*****
Karma: 511
Posts: 19358
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This concerns me. A program is only allowed to have one definition of a particular symbol, and you should get a linker error if you define a symbol more than once.

The trigger for the linker searching dozens of library files is the desire to resolve a symbol for which it doesn't yet have code for. It isn't designed to merely search every possibly library for duplicates.
Logged

http://www.gammon.com.au/electronics

Please post technical questions on the forum - not to me by personal message. Thanks a lot.

Offline Offline
God Member
*****
Karma: 4
Posts: 813
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This concerns me. A program is only allowed to have one definition of a particular symbol, and you should get a linker error if you define a symbol more than once.

The trigger for the linker searching dozens of library files is the desire to resolve a symbol for which it doesn't yet have code for. It isn't designed to merely search every possibly library for duplicates.

Actually, the linker searches exactly the libraries you specify, and includes the transitive closure of all symbols that are referenced. In fact, in the UNIX (and thus generally GCC) world, including *any* symbol from a library will include *all* of that particular translation unit, even if the other functions are not used. It seems to me as if the Arduino/AVR version of the compiler fixes that particular mis-feature, though.

And, when a linker searches libraries that have been defined, if it finds multiple definitions of the same name, that is generally a linker error. Here is the error GCC/GLD spits out in that case:

Code:
[jwatte@svn:/tmp]> cat foo.cpp

int main() {
    return 0;
}
[jwatte@svn:/tmp]> cat bar.cpp

int main() {
    return 1;
}
[jwatte@svn:/tmp]> g++ -c foo.cpp
[jwatte@svn:/tmp]> g++ -c bar.cpp
[jwatte@svn:/tmp]> g++ -o foobar foo.o bar.o
bar.o: In function `main':
bar.cpp:(.text+0x0): multiple definition of `main'
foo.o:foo.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status
[jwatte@svn:/tmp]>


And, what I posted was the compile error I would have expected the compiler to generate, assuming that my sketch gets included into some greater file that defines main(). If instead main() lives in a referenced .o file or library, then I would expect a linker error.

Thus, either the Arduino sketch compilation model is separate compilation with linking, in which case I should get a linker error. Or it's a single compilation unit with inclusion, in which case I should get a compiler error. In either case, the AVR toolchain's behavior is mysterious, and hopefully (?) not actually intended. Which reminds me: assuming that the failure to point out my dumb mistake is a toolchain bug, where would I file it? Is there an Arduino or AVR-specific GCC project, or is it just gnu.org?
Logged

Pages: [1] 2   Go Up
Jump to: