Dead Code Elimination là gì trong embedded C?

Ghi chú về cách GCC và linker loại bỏ function/data không dùng bằng function sections, data sections và gc-sections.

2 phút đọc
Build System cover

Ghi chú nhanh

Dead Code Elimination là quá trình compiler/linker loại bỏ code hoặc data không còn được dùng trong binary cuối cùng.

Với GCC embedded, combo thường gặp là:

Compiler:
-ffunction-sections
-fdata-sections

Linker:
-Wl,--gc-sections

Ý tưởng là: mỗi function/data được đặt vào section riêng, rồi linker có thể “quét rác” những section không còn ai tham chiếu.

Vì sao embedded engineer nên quan tâm?

Trên PC, thừa vài KB code có thể không ai để ý. Trên MCU 64 KB flash, vài KB đó đôi khi là cả một buổi chiều đau đầu.

Trong project debug logger, khi tắt log ở production build, ta muốn những thứ này biến mất khỏi binary:

  • hàm logger;
  • buffer log;
  • chuỗi format debug;
  • code phụ trợ chỉ dùng cho debug.

Không phải chỉ “không chạy tới” là đủ. Với firmware production, càng ít thứ thừa càng tốt.

Ví dụ thực tế

Giả sử bạn có macro:

#ifdef ENABLE_DEBUG_LOG
#define DBG_LOG(...) Debug_Printf(__VA_ARGS__)
#else
#define DBG_LOG(...) ((void)0)
#endif

Khi ENABLE_DEBUG_LOG bị tắt, các lời gọi DBG_LOG() biến thành câu lệnh rỗng.

Nếu không còn code nào gọi Debug_Printf(), linker có cơ hội loại bỏ luôn function đó và những data chỉ phục vụ cho nó.

Cách kiểm tra có bị loại thật không?

Đừng đoán. Hãy mở file .map.

Tìm các symbol như:

Debug_Printf
Debug_UART_StartDmaIfNeeded
s_log_buffer

Nếu production build vẫn còn những symbol này, có thể:

  • vẫn còn nơi nào đó gọi logger;
  • function/data không được đặt vào section riêng;
  • linker chưa bật --gc-sections;
  • biến global bị giữ lại vì có tham chiếu gián tiếp.

Bẫy dễ gặp

Có người nghĩ chỉ cần if (debug_enabled) là đủ:

if (debug_enabled) {
    Debug_Printf("value=%d
", value);
}

Cách này có thể vẫn giữ lại chuỗi log và function logger trong binary, tùy compiler tối ưu thế nào và biến debug_enabled có phải compile-time constant hay không.

Nếu muốn production build sạch, nên để điều kiện bật/tắt log xảy ra ở compile time bằng macro.

Cách nhớ

Macro tắt log ở compile time.
Linker GC dọn phần code không còn được gọi.
File .map là nơi kiểm chứng, không phải cảm giác.

Bài liên quan nên đọc tiếp

Thấy nội dung này hữu ích?

Lưu lại hoặc chia sẻ cho người cũng đang học firmware, BIOS/UEFI và embedded systems.

Nội dung liên quan

Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.

Biến note thành bài viết hoàn chỉnh

Notes là nơi ghi nhanh khái niệm.