Reputation: 3614
Is there an (automatic) solution to reduce a C++ code size compiled with -Os that's using templates ? Right now, the symbols are mangled and are quite large due to templates & namespaces.
I'm aware of the asm("symbolName")
after each function, but that's a lot to write when you have a lot of symbols.
I'm looking more after a kind of automated tool that'd strip & rename all symbols (or replace them to simple numeric value?)
If the question is not clear, here's an example of 2 codes (one C oriented, the other C++ oriented):
// C like, using virtual table + next pointer
struct Test
{
virtual bool run() = 0;
Test * next;
Test() : next(nullptr) {}
virtual ~Test() { delete next; }
};
Test & head = [...];
bool runTests()
{
Test * t = &head;
while (t) { if (!t->run()) return false; t = t->next; }
return true;
}
For 10 tests, this takes, on an 32 bits systems: 10*virtual table size + 10* next pointer size + head pointer, likely the size of 30 pointers in memory, but the code size (.text) is minimal. On my system, after running strip -Alx a.out
I get a binary size of 9336 bytes
versus:
template <typename Child, typename Next>
struct Test : public Child, public Next
{
bool run()
{
if (!static_cast<Child*>(this)->run()) return false;
return Next::run();
}
};
struct End
{
static bool run() { return true; }
};
// Example follower
volatile bool g = true;
// Example follower
struct Test9 { bool run() { return g; } };
struct Test8 { bool run() { return g; } };
struct Test7 { bool run() { return g; } };
struct Test6 { bool run() { return g; } };
struct Test5 { bool run() { return g; } };
struct Test4 { bool run() { return g; } };
struct Test3 { bool run() { return g; } };
struct Test2 { bool run() { return g; } };
struct Test1 { bool run() { return g; } };
Test<Test1, Test<Test2, Test<Test3, Test<Test4, Test<Test5, Test<Test6, Test<Test7, Test<Test8, Test<Test9, End>>>>>>>>> head;
bool runTests() { return head.run(); }
Shared code:
int main()
{
printf("%s: %s\n", typeid(head).name(), runTests() ? "passed" : "failed");
return 0;
}
Typically, this shouldn't have any pointers, and is minimalist. However, the recursive template code create very large symbols that consume flash space (those symbols are not stripped from the binary, since they must be identified). In my case the latter create a binary size that's 9804 bytes stripped.
Upvotes: 1
Views: 924
Reputation: 93556
C++ is a compiled language - the symbol length does not contribute to the code size in any manner. They are retained in the object code and libraries for the purposes of resolving links and for debugging, but do not occupy space in the binary at runtime.
I'm looking more after a kind of automated tool that'd strip & rename all symbols (or replace them to simple numeric value?)
That is exactly what the linker does; it replaces symbols with addresses. The symbols retained for debugging can be stripped by linker option or by the separate strip
utility.
If your target is a bare-metal non-hosted environment, the binary loaded on the target will not normally include the debug symbol table in any case; so in that case stripping serves no purpose other that to prevent you from using a symbolic debugger. For debugging the symbols are loaded into the debugger running on the development host only and are not present on the target.
If your code has bloated due to the use of templates, that has nothing to do with the length of the symbol names. Every time a template is instantiated with different template parameters, new code will be created, so it is easy for what appears to be a small amount of code to become very large is you are instantiating many different versions of a single template.
Upvotes: 3