GCC: unbenutzte Funktionen entfernen

Wechseln zu: Navigation, Suche

Normalerweise behandelt der Compiler C-Module als kleinste Einheit; das bedeutet es wird immer das komplette Modul (=alle Funktionen einer .c-Datei) gelinkt, auch wenn nur eine Funktion daraus verwendet wird. Dadurch wird oft unnötig viel Speicher verschwendet.

Seit der GCC-Version 4.x kann man nicht benutzte Funktionen aus dem Kompilat entfernen lassen. Dazu muss man dem Compiler die Optionen -ffunction-sections -fdata-sections übergeben, was dafür sorgt dass die Funktionen getrennt behandelt werden, und dem Linker die Option --gc-sections (Enable garbage collection of unused input sections), wodurch nicht benötigte sections entfernt werden. Wird der Linker nicht direkt aufgerufen, sondern über das Compiler-Frontend (avr-gcc/arm-*-gcc) gelinkt, ist die Option per -Wl,--gc-sections zu übergeben.

target-gcc -c [...] -ffunction-sections -fdata-sections main.c -o main.o [...]
target-gcc [...] startup.o main.o --output app.elf -Wl,--gc-sections [...]

Falls das Linkerscript (oft verwendete Dateiendung: .ld) noch nicht dafür vorbereitet sind, die einzelnen function- und data-sections zu verarbeiten, muss man folgende Ersetzungen vornehmen:

*(.text) -> *(.text .text.* .gnu.linkonce.t.*)
*(.data) -> *(.data .data.* .gnu.linkonce.d.*)
*(.bss) -> *(.bss .bss.* .gnu.linkonce.b.*)

Weiterhin ist darauf zu achten, dass der Linker den Startup-Code und die Interrupt-Vektoren nicht verwirft. Für diese gibt es keinen Aufruf im Code, da sie von der Hardware aufgerufen werden, deshalb könnte der Linker den unbedingt erforderlichen Code als nicht genutzt interpretieren und verwerfen. Um dies zu vermeiden, gibt es (zumindest) zwei Möglichkeiten:

  • Zu Beginn des Linkerscript ergänzt man einen ENTRY-Eintrag, als Parameter gibt man den Namen/das Label des startup-codes (z. B. ENTRY(_reset_code)).
  • Man weist den Linker im .text-Bereich des Scripts explizit an, bestimmte sections oder die .text-sections einer aus einer Objekt-Datei immer aufzunehmen (z. B. KEEP(*(.vectors) und/oder KEEP(*(.startup)) bzw. *startup.o (.text .text.*)).

Diese Änderungen sind üblicherweise bei älteren selbst geschriebenen oder von Dritten übernommenen Linkerscripts erforderlich. Die Standard-Linkerscripts aktueller GCC-Distributionen (WinAVR, WinARM) sind bereits entsprechend angepasst. Bei der WinAVR-Standardinstallation vgl. z. B. c:/WinAVR/avr/lib/ldscripts/avr5.x).