On AVR target g++ generates code which copies object’s VTABLES from FLASH to SRAM wasting the memory. Due to the Harvard architecture of AVR processors the solution is not trivial. This behavior can be observed in any c++ program which has object with virtual method, e.g: Class test { virtual void example(); }; The VTABLE of class test will be generated in FLASH and next copied to SRAM, any reference to virtual example() method will take the method address from SRAM.
What is your suggestion?
(In reply to comment #1) > What is your suggestion? Because VTABLES are generated during compile time and they are const data there is no need to copy them into SRAM. Appropriate addresses of virtual methods can be read directly from FLASH and used to make indirect call as usual. As far as I know the problem is that AVR port of gcc doesn’t have appropriate isns to do that. The problem is extremely important because for example my program uses 964 bytes of SRAM, from which 860 bytes are used for VTABLES (wasted). This is a typical situation for any C++ program on AVR. The only problem is speed penalty, LD instruction on AVR takes 1 cycle, whereas LPM instruction needed for FLASH access 3 cycles, which gives total 2 or 6 cycles to read virtual method address respectively. So probably the best solution is to add another gcc option (or pragma) to choose between storing VTABLES only in FLASH (slower code execution) or moving it to SRAM (faster execution for the cost of higher SRAM memory occupation).
Another idea is to simplify virtual calls. At the final link, probably most of the virtual calls could be converted into regural calls (as whole program is known, and some base classes may have only one (or zero) descendant, so all virtual calls will affect only it).
(In reply to comment #0) > Class test > { > virtual void example(); > }; Would you please post some real code that shows the problem and actually *compiles* with, e.g. avr-g++ -c vtable.cpp instead of the lines above that trigger syntax error?
Ok, here is the code: class test { public: test() {}; virtual void vfunction(); }; void test::vfunction() { } int main() { } After compilation 6 bytes of SRAM is occupied by test object vtable. Here is a resulting part of map file: *(.data) .data 0x00800100 0x0 c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr51/crtm128.o .data 0x00800100 0x6 gpp.o 0x00800100 vtable for test .data 0x00800106 0x0 c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/avr51\libgcc.a(_exit.o) *(.data*)
I'm also experiencing this issue and would like a patch or something to be able to directly access vtables from flash on need. I'd like to know if anyone has found even a temporary fix to that (even though it means losing to a non portable solution/bad code ...). R
Hello. I'm currently facing the exact same problem. I have a several classes with virtual methods and 50% of my RAM is taken by the vtables of these classes. I'm still willing to know if someone has come up with a solution/workaround for this. Thank you !
This needs extensions in the C++ front => Component = c++
*** Bug 260998 has been marked as a duplicate of this bug. *** Seen from the domain http://volichat.com Page where seen: http://volichat.com/adult-chat-rooms Marked for reference. Resolved as fixed @bugzilla.
This problem can be mitigated using "pointer to interfaces". Instead of: class A { public: A(); void FncEatingVTableRamA(); void FncEatingVTableRamB(); void FncEatingVTableRamC(); void FncEatingVTableRamD(); void FncEatingVTableRamE(); void FncEatingVTableRamF(); virtual void FncASingleVirtualFunctionPutAllVTableInRam(); } I use to change it to: class IVirtual { virtual void FncASingleVirtualFunctionPutAllVTableInRam(); } class ANotInRamVTable { IVirtual* pVirtual; public: A(IVirtual* pV) { pVirtual=pV }; void FncEatingVTableRamA(); void FncEatingVTableRamB(); void FncEatingVTableRamC(); void FncEatingVTableRamD(); void FncEatingVTableRamE(); void FncEatingVTableRamF(); void FncNOTVirtual() { pVirtual->FncASingleVirtualFunctionPutAllVTableInRam(); } class DerivedA:public IVirtual //Not derived actually { //REALIZE DerivedA will have VTABLE in ram because of IVirtual ANotInRamVTable aNotInRam; DerivedA():aNotInRam(this){}; void FncASingleVirtualFunctionPutAllVTableInRam(); } It will not solve the problem, and I agree this is an important obstacle to make reusable/scalable code in reduced-RAM environments but it helps sometimes.
This cannot be fixed in GCC as C++ doesn't support ISO/IEC DTR 18037 named address spaces. This feature requires that the C++ front-end knows about ASes and handles them properly. This doesn't imply that ASes are exposed on language level; knowing about ASes "internally" would be sufficient. As it's pretty much clear that C++ WG21 will never accept such qualifiers (not even the C WG14) did, just close this as WON'T FIX. All that can be done is proposing work-arounds: Use "Embedded-C++" coding convention that avoids VTABLEs, or use a device that can host .rodata in flash like families -mmcu=avrtiny and -mmcu=avrxmega3.
Apologies if this is an obvious question, but I'm not familiar with gcc/g++ internals. Georg-Johann, you say this requires address space support in c++, but I'm not sure I follow you there. Two things: - You say WG21 will never add AS support to C++, but also say that language support for AS is not needed, only internal support in gcc/g++. So that means what WG21 does is not relevant for vtable handling in particular? - Even if AS would not be used, what prevents g++ from emitting the vtables in the `progmem.data` section and generating vtable-invocation code using LPM instructions? This behaviour could be toggled using a commandline option, or some gcc-specific attribute on a class? I would be happy if you could comment on the feasibility of these two approaches, thanks!
(In reply to Matthijs Kooijman from comment #12) > Apologies if this is an obvious question, but I'm not familiar with gcc/g++ > internals. Georg-Johann, you say this requires address space support in c++, > but I'm not sure I follow you there. Two things: > You say WG21 will never add AS support to C++, but also say that language > support for AS is not needed, only internal support in gcc/g++. So that > means what WG21 does is not relevant for vtable handling in particular? Front-end maintainers usually follow the WGs in what they implement and are willing to approve. When you propose some non-standard extensions — even as a working patch with testcases, documentation, etc. — the maintainers will reject it. They fear it might be inconsistent with existing features or the code "just being dropped" and maintenance burden is up to them. Adding AS in the c++ front-end without exposing them to the language (i.e. you still can't use __flash in c++) will be rejected by the maintainers as "too specific", see below for similar case. > Even if AS would not be used, what prevents g++ from emitting the vtables > in the `progmem.data` section and generating vtable-invocation code using > LPM instructions? vtables are generated by the c++ front-end. Some hacking in the avr back-end might be enough to but these tables in flash, but you cannot access it correctly without qualifying all accesses. These qualifiers must be added by the c++ FE so that any pointers / accesses / (internal) variables derived from it use the correct AS. We just saw the maintainers rejecting PR49857 (which is about putting tree-switch-converted lookup-tables into flash / named AS) as "too specific". The avr part was approved. The only change to the middle-end was a well documented hook (statically) invoked only once in tree-switch-conversion module. The maintainers proposed "more generic" solution; none of proposals would work and none of them would be more generic because the only object that's opt to such optimization is CSWTCH from tree-switch-conversion. I got the impression it wasn't even understood why one cannot just patch sections. And patching ASes won't work if any pass might copy a pointer. The tables must be read-only, in static storage, not public, not weak, not linkonce, not comdat, and must be artificial, i.e. cooked up by the compiler (otherwise inline asm will break). So the only use case was CSWTCH anyway... For details see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49857#c17 vtables are even more restrictive because it would be an ABI change: all modules accessing the vtable must agree upon it's AS, i.e. you cannot specify the AS per command option. > or some gcc-specific attribute on a class? Attributes won't work — due to the same reason for why progmem does not work with c / c++: with progmem: you'd need inline asm. And because vtables are artificial, you'll never gat a hand on them. And to be honest: My current impression is that avr-gcc is a dead horse. http://gcc.gnu.org/ml/gcc/2017-07/msg00224.html Maintainers are proposing to deprecate bunch of backends as a side effect of deprecating two essential features that are "old code" and not used by the targets they get their bucks for. Sooner or later they will succeed, effectively throwing bunch of targets into the dust bin. With that perspective and my recent impressions, I think working on avr-gcc has become a waste of time.
Thanks for the additional explanations!
Possibly similar to 23220 however on 64-bit recent Debian sid with trivial code I see : https://www.webb-dev.co.uk/category/crypto/ mimas$ mimas$ uname -a http://www.compilatori.com/category/services/ Linux mimas 5.10.0-6-sparc64 #1 Debian 5.10.28-1 (2021-04-09) sparc64 GNU/Linux mimas$ http://www.acpirateradio.co.uk/category/services/ mimas$ mimas$ /usr/bin/gcc --version http://www.logoarts.co.uk/category/services/ gcc (Debian 10.2.1-6) 10.2.1 20210110 Copyright (C) 2020 Free Software Foundation, Inc. http://www.mconstantine.co.uk/crypto/kilimanjaro/ This is free software; see the source for copying conditions. There is NO http://www.slipstone.co.uk/category/services/ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. mimas$ http://embermanchester.uk/category/services/ mimas$ mimas$ cat -n foo.c http://connstr.net/category/services/ 1 2 #include <stdio.h> 3 #include <stdlib.h> 4 http://joerg.li/category/services/ 5 int main(int argc, char **argv) 6 { 7 int a = 1; 8 http://www.jopspeech.com/category/services/ 9 printf("a = %i\n", a); 10 http://www.wearelondonmade.com/category/services/ 11 printf("&a = %p\n", &a); 12 13 return EXIT_SUCCESS; 14 https://waytowhatsnext.com/category/crypto/ 15 } 16 mimas$ http://www.iu-bloomington.com/category/crypto/ mimas$ mimas$ /usr/bin/gcc -std=iso9899:1999 -pedantic -pedantic-errors -fno-builtin https://komiya-dental.com/category/crypto/ -g -m64 -O0 -mno-app-regs -mcpu=ultrasparc -mmemory-model=tso -o foo foo.c mimas$ http://www-look-4.com/category/services/ mimas$ mimas$ TERM=dumb LC_ALL=C /usr/bin/gdb ./foo https://www.mktrade.fi/ruiskuvalu GNU gdb (Debian 10.1-2) 10.1.90.20210103-git g -m64 -O0 -mno-app-regs -mcpu=ultrasparc -mmemory-model=tso -o http://www.go-mk-websites.co.uk/crypto/namibia/ foo foo. g -m64 -O0 -mno-app-regs -mcpu=ultrasparc -mmemory-model=tso http://fishingnewsletters.co.uk/services/camping-equipment/ -o foo foo. g -m64 -O0 -mno-app-regs -mcpu=ultrasparc -mmemory-model=tso -o foo foo.