Domanda

Quando si scrive codice C/C++, per eseguire il debug dell'eseguibile binario è necessario abilitare l'opzione debug sul compilatore/linker.Nel caso di GCC, l'opzione è -g.Quando l'opzione di debug è abilitata, in che modo influisce sull'eseguibile binario?Quali dati aggiuntivi sono memorizzati nel file che consente la funzione del debugger come fa?

È stato utile?

Soluzione

-g dice al compilatore di memorizzare le informazioni sulla tabella dei simboli nell'eseguibile.Tra le altre cose, questo include:

  • nomi di simboli
  • digitare informazioni per i simboli
  • file e numeri di riga da cui provengono i simboli

I debugger utilizzano queste informazioni per generare nomi significativi per i simboli e per associare istruzioni a righe particolari nell'origine.

Per alcuni compilatori, fornire -g disabiliterà alcune ottimizzazioni.Ad esempio, icc imposta il livello di ottimizzazione predefinito su -O0 con -g a meno che tu non indichi esplicitamente -O[123].Inoltre, anche se fornisci -O[123], le ottimizzazioni che impediscono l'analisi dello stack saranno comunque disabilitate (ad es.rimozione dei puntatori ai frame dagli stack frame.Ciò ha solo un effetto minore sulle prestazioni).

Con alcuni compilatori, -g disabiliterà le ottimizzazioni che possono confondere la provenienza dei simboli (riordino delle istruzioni, srotolamento del loop, incorporamento, ecc.).Se vuoi eseguire il debug con l'ottimizzazione, puoi usare -g3 con gcc per aggirare alcuni di questi problemi.Verranno incluse informazioni di debug aggiuntive su macro, espansioni e funzioni che potrebbero essere state integrate.Ciò può consentire ai debugger e agli strumenti per le prestazioni di mappare il codice ottimizzato all'origine originale, ma è il massimo sforzo.Alcune ottimizzazioni alterano davvero il codice.

Per maggiori informazioni, dai un'occhiata a NANO, il formato di debug originariamente progettato per essere utilizzato con ELF (il formato binario per Linux e altri sistemi operativi).

Altri suggerimenti

All'eseguibile viene aggiunta una tabella di simboli che associa i nomi di funzioni/variabili alle posizioni dei dati, in modo che i debugger possano restituire informazioni significative, anziché solo puntatori.Ciò non influisce sulla velocità del tuo programma e puoi rimuovere la tabella dei simboli con il comando 'strip'.

Oltre alle informazioni sul debug e sui simboli
Google DWARF (uno scherzo degli sviluppatori su ELF)

Per impostazione predefinita, la maggior parte delle ottimizzazioni del compilatore sono disattivate quando il debug è abilitato.
Quindi il codice è la pura traduzione del sorgente in codice macchina piuttosto che il risultato di molte trasformazioni altamente specializzate applicate ai file binari di rilascio.

Ma la differenza più importante (secondo me)
La memoria nelle build di debug viene in genere inizializzata su alcuni valori specifici del compilatore per facilitare il debug.Nelle build di rilascio la memoria non viene inizializzata a meno che non venga esplicitamente fatto dal codice dell'applicazione.

Controlla la documentazione del compilatore per ulteriori informazioni:
Ma un esempio per DevStudio è:

  • 0xCDCDCDCD Allocato nell'heap, ma non inizializzato
  • 0xDDDDDDDD Memoria heap rilasciata.
  • 0xFDFDFDFD Recinti "NoMansLand" posizionati automaticamente al confine della memoria heap.Non dovrebbe mai essere sovrascritto.Se ne sovrascrivi uno, probabilmente stai uscendo dalla fine di un array.
  • 0xCCCCCCCC Allocato sullo stack, ma non inizializzato

-g aggiunge informazioni di debug nell'eseguibile, come i nomi delle variabili, i nomi delle funzioni e i numeri di riga.Ciò consente a un debugger, come gdb, di scorrere il codice riga per riga, impostare punti di interruzione e controllare i valori delle variabili.A causa di queste informazioni aggiuntive l'utilizzo di -g aumenta la dimensione dell'eseguibile.

Inoltre, gcc consente di utilizzare -g insieme ai flag -O, che attivano l'ottimizzazione.Il debug di un eseguibile ottimizzato può essere molto complicato, perché le variabili potrebbero essere ottimizzate o le istruzioni potrebbero essere eseguite in un ordine diverso.In generale, è una buona idea disattivare l'ottimizzazione quando si utilizza -g, anche se risulta in un codice molto più lento.

C'è qualche sovrapposizione con questo domanda che copre la questione dall'altro lato.

Per tua curiosità, puoi aprire un hexeditor e dare un'occhiata all'eseguibile prodotto con -g e uno senza.Puoi vedere i simboli e le cose che vengono aggiunte.Potrebbe modificare l'assemblaggio (-S) anch'io, ma non ne sono sicuro.

Alcuni sistemi operativi (es z/OS) producono un "file laterale" che contiene i simboli di debug.Ciò aiuta a evitare di gonfiare l'eseguibile con informazioni aggiuntive.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top