2016-06-21 14 views
7

Ecco la storia: Sto sviluppando software C++ per processore ARM Cortex-M0 in Linux con AC6 Toolpack. Prima di usare Keil (in Windows) (che ha una propria toolchain) e sono migrato alla GNU-toolchain ((GNU Tools per ARM Embedded Processors) 5.2.1). La prima cosa che ho capito è; la dimensione del file binario è aumentata notevolmente. Ho testato tutte le ottimizzazioni del compilatore (tranne l'ottimizzazione del tempo di collegamento, fornisce un errore nell'assemblaggio in linea, non fa parte della domanda ma può essere correlato alla risposta). Quindi ha iniziato a ispezionare gli eseguibili (file elf non bin, gnu produce entrambi) con qualsiasi strumento disponibile: objdump, readelf, nm. Ho trovato alcuni simboli che causano un aumento delle dimensioni, quelli significativi sono: 'd_print_comp_inner', 'd_exprlist', 'd_template_args'. Ma non ho idea di cosa stia causando queste funzioni in binario. (Ho usato librerie minime: nano newlib). Per farla breve ho iniziato ad eliminare i codici uno per uno per trovare colpevole. Finalmente era la dichiarazione del metodo astratto!Dichiarare la classe astratta (metodo virtuale puro) aumentare sostanzialmente la dimensione binaria

funzione Definire come

virtual Return_type function_name(...)=0; 

anziché

virtual Return_type function_name(...); 

aggiungendo 45 KB ei simboli che ho menzionato. E questo è l'unico cambiamento nel codice sorgente. È presente una definizione vuota nella classe base. Si noti che: il metodo è ancora virtuale e sovrascritto in classi figlie

uscita Dimensioni senza astratta Classe: uscita

text data  bss  dec  hex filename 
    15316  24 4764 20104 4e88 temc_discovery.elf 

Size con classe astratta:

text data  bss  dec  hex filename 
    61484  128 4796 66408 10368 temc_discovery.elf 

Qui i simboli e la loro dimensione che si presenta quando il metodo è astratto, eliminati quelli che appaiono in entrambe le versioni. (nm strumento viene utilizzato. Non elenco completo, quelli con dimensioni> = 0x60)

00002de4 t d_print_comp_inner 
00001a34 t d_exprlist 
00000ca4 t d_template_args 
00000678 t d_type 
00000574 t d_print_mod 
000003f8 t d_encoding 
000003e0 r cplus_demangle_operators 
000003c8 t d_expression_1 
000003a8 t d_name 
00000354 t d_demangle_callback.constprop.15 
000002e0 t d_print_mod_list 
00000294 r cplus_demangle_builtin_types 
00000268 t d_unqualified_name 
00000244 T _printf_i 
00000238 t d_print_function_type.isra.11 
000001fc T _svfprintf_r 
000001fc T _svfiprintf_r 
000001f4 t d_print_array_type.isra.10 
000001ce t d_print_cast.isra.12 
0000018c t d_substitution 
00000110 t d_operator_name 
0000010c T __sflush_r 
000000e8 T __swsetup_r 
000000e6 t d_cv_qualifiers 
000000e0 t d_print_subexpr 
000000e0 t d_expr_primary 
000000dc T _printf_common 
000000cc T __cxa_demangle 
000000c8 t d_source_name 
000000c4 r standard_subs 
000000c4 T __ssputs_r 
000000b0 T __swbuf_r 
000000ac T _malloc_r 
000000a8 T _fputs_r 
000000a4 T __smakebuf_r 
000000a0 T __gnu_cxx::__verbose_terminate_handler() 
00000096 t d_print_expr_op 
0000008c T _free_r 
0000008c t d_parmlist 
0000008a t d_growable_string_callback_adapter 
0000007c T __sfp 
00000072 t d_append_buffer 
00000068 T __sinit 
00000060 d impure_data 

Alcuni nomi familiari a me (come printf, a filo, malloc, fputs ecc) non sono nemmeno menzionato nella fonte codice.

Chiunque abbia idea di cosa stia causando questo comportamento?

Aggiornamento: ero già disabilitando eccezioni con la bandierina --noexception, quindi non ho dato alcuna però ad esso. A quanto pare, è correlato a rispondere così bene a dirlo qui.

Aggiornamento 2: This is the most comprehensive website spiegare tutto, se si traccia i collegamenti in risposte.

+0

Potrebbe essere meglio per fornire il comando di compilazione e di collegamento, ad esempio, L'opzione '-g' produrrà un binario più grande per i simboli di debug, ecc. E si può controllare la dimensione del binario stripped. – Mine

+0

Purtroppo, ho provato tutte le ottimizzazioni del compilatore. Stesso risultato (con aumento maggiore di 40 KB). – ifyalciner

+2

Soluzione. probabilmente, già fornito qui: https://stackoverflow.com/questions/14689639/can-i-disable-exceptions-for-when-a-pure-virtual-function-is-called – deniss

risposta

6

È quasi certamente a causa dell'inaspettata inclusione della gestione delle eccezioni, che è stata integrata da libC++, indipendentemente dal fatto che si compili o meno il codice con --noexception o qualunque sia il corretto gnu-ism.

L'eccezione in questione è probabilmente 'pura chiamata di funzione virtuale' o qualcosa del genere (un errore di runtime abbastanza oscuro da ottenere, ma possibile se si chiamano funzioni virtuali nel costruttore della classe base).

La risposta è fornire la propria implementazione vuota di this, atexit() e qualsiasi callout casuale di cui non si ha realmente bisogno. Una volta fatto ciò, il linker non trascinerà nell'altra roba (che trascina altre cose, che trascinano altre cose, ecc.).

void __cxa_pure_virtual(void) 
{ 
    BKPT(); 
} 

è quello che ho sul nostro progetto, anche se le cose potrebbero essere cambiate nella versione di libC++

+0

Grazie per la risposta. Ha funzionato. – ifyalciner

5

Per quanto ho capito, quando si effettua la funzione virtuale nella classe base pura si crea il potenziale per effettuare una chiamata virtuale pura. Quindi il compilatore genera il codice dove stampa il messaggio sul puro fatto di chiamata virtuale, i nomi demarcati per la funzione e la classe e potrebbe essere qualcos'altro. Aggiunge un sacco di funzioni al tuo binario per questo, quindi le dimensioni aumentano.

Suggerisco di aggiungere un'implementazione vuota alla tua pura funzione virtuale - potrebbe impedire al compilatore di fare quella roba.

+0

Solo la modifica del codice è '= 0'. Quindi per non avere 'errore funzione non definito' ho già una definizione vuota di funzione. – ifyalciner

+0

Vedere http://stackoverflow.com/questions/99552/where-do-pure-virtual-function-call-crashes-come-da –

+0

@ifyalciner, è possibile avere entrambi = 0 per la funzione e la sua implementazione è vuota, ad es. distruttore virtuale. – user2807083

Problemi correlati