本文首次發表在 Linux 下如何繞過編譯器優化linux
有同窗在羣裏聊到編譯器優化的事情,不少時候指望編譯器默認作優化,可是有些場景是但願能繞過的,哪些呢?shell
這裏舉兩個實實在在的例子。優化
第一個,在調試的時候,若是默認開啓了優化,要關注的某個變量值,用 gdb 打印時可能會提示被優化掉了,會讓人丈二和尚摸不着頭腦。spa
第二個,就是某些場景,編譯器並不理解背後的實際狀況,好比說,連續往某個地址寫兩個值,編譯器覺得,這不是畫蛇添足了,幫把最後一個寫進去就行了,可是卻不知,這個地址多是個硬件寄存器地址呢,寫第一個,處理器調整一個狀態,再寫一個,再調整一個狀態,兩個都寫完,纔算完整,寫不一樣的位有不一樣的含義。debug
對於第一個,一般不太須要去改整個內核,好比說,把整個 -O2/-Os
都拿掉,這時可能引發的莫名狀況比去 debug 某個問題可能還要棘手。因此,能夠有針對性的,只對某個文件作優化參數調整便可。調試
這個本質上是拿掉 CFLAGS
裏頭的優化參數,其實用替換就行了,可是可選的用法有:rest
文件級:CFLAGS_REMOVE_xxx.o = -O2
code
arch/mips/kernel/Makefile
:cdn
ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_early_printk.o = -pg
CFLAGS_REMOVE_perf_event.o = -pg
CFLAGS_REMOVE_perf_event_mipsxx.o = -pg
endif
複製代碼
原理以下,就是從原始編譯參數中 filter-out
掉特定參數:blog
$ grep CFLAGS_REMOVE -ur linux-stable/scripts/Makefile.lib
_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
複製代碼
目錄級:KBUILD_CFLAGS := $(filter-out -O2, $(KBUILD_CFLAGS))
arch/mips/boot/compressed/Makefile
:
KBUILD_CFLAGS := $(filter-out -pg, $(KBUILD_CFLAGS))
複製代碼
本身主動 filter-out
掉。也能夠直接調用腳本替換:
KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//")
複製代碼
固然,用 Makefile 內置的 filter-out
效率會高,只是方便你們理解邏輯。
怎麼確認這個編譯參數是否真地生效呢,有兩種方法:
一種是直接在相應 Makefile 打印 KBUILD_CFLAGS
,例如:$(error $(KBUILD_CFLAGS))
,另一種是 make /path/to/xxx.o V=1
查看。在 Linux Lab 裏頭能夠用 make k-x /path/to/xxx.o V=1
。
除了直接拿掉,也能夠考慮替換成 -Og
,這個更適合調試須要。
第二個,也來看看實例:
drivers/cpufreq/loongson2_cpufreq.c
:
static void loongson2_cpu_wait(void)
{
unsigned long flags;
u32 cpu_freq;
spin_lock_irqsave(&loongson2_wait_lock, flags);
cpu_freq = LOONGSON_CHIPCFG(0);
LOONGSON_CHIPCFG(0) &= ~0x7; /* Put CPU into wait mode */
LOONGSON_CHIPCFG(0) = cpu_freq; /* Restore CPU state */
spin_unlock_irqrestore(&loongson2_wait_lock, flags);
local_irq_enable();
}
複製代碼
上面中間三句,從 gcc 的角度來看,這不是傻嘛,啥也沒作啊,又讀又寫是什麼鬼,目標變量的值根本「沒變」呢。緣由是什麼,這個背後的 LOONGSON_CHIPCFG(0)
是硬件寄存器地址,有它的時序意義,不一樣的位有不一樣的意義,寫不一樣的值會有不一樣的動做。這個時候就得明確告訴 gcc:
arch/mips/include/asm/mach-loongson64/loongson.h
:
#define LOONGSON_CHIPCFG(id) (*(volatile u32 *)(loongson_chipcfg[id]))
複製代碼
這種狀況怎麼確認呢?make /path/to/xxx.s
,看看代碼還在不在。在 Linux Lab 裏頭能夠用 make k-x /path/to/xxx.s
。
更多 Linux 精彩歡迎透過下方免費體驗卡訪問『Linux 知識星球』: