同学们,告诉大家一个好消息,近日,泰晓科技与阅码场强强联合,首度推出码农自我修养之 「360° 剖析 Linux ELF」在线视频课程。由 吴章金 老师亲自授课,由浅入深地讲解程序加载、上下文传递、系统调用、内存布局、进程调度、代码调试以及程序退出全过程。如果您想进一步了解详情,请点击 “课程介绍”。
![4789fda8f770fa87bd33cecce7bee501.png](https://i-blog.csdnimg.cn/blog_migrate/788f63f616eeb4112e2569cb545334d9.jpeg)
以下为正文:
有同学在群里聊到编译器优化的事情,很多时候期望编译器默认做优化,但是有些场景是希望能绕过的,哪些呢?
这里举两个实实在在的例子。
第一个,在调试的时候,如果默认开启了优化,要关注的某个变量值,用 gdb 打印时可能会提示被优化掉了,会让人丈二和尚摸不着头脑。
第二个,就是某些场景,编译器并不理解背后的实际情况,比如说,连续往某个地址写两个值,编译器以为,这不是多此一举了,帮把最后一个写进去就好了,但是殊不知,这个地址可能是个硬件寄存器地址呢,写第一个,处理器调整一个状态,再写一个,再调整一个状态,两个都写完,才算完整,写不同的位有不同的含义。
1. 怎么去掉显式优化参数
对于第一个,通常不太需要去改整个内核,比如说,把整个 -O2/-Os
都拿掉,这时可能引起的莫名情况比去 debug 某个问题可能还要棘手。所以,可以有针对性的,只对某个文件做优化参数调整即可。
这个本质上是拿掉 CFLAGS
里头的优化参数,其实用替换就好了,但是可选的用法有:
文件级:CFLAGS_REMOVE_xxx.o = -O2
arch/mips/kernel/Makefile
:
1ifdef CONFIG_FUNCTION_TRACER
2CFLAGS_REMOVE_ftrace.o = -pg
3CFLAGS_REMOVE_early_printk.o = -pg
4CFLAGS_REMOVE_perf_event.o = -pg
5CFLAGS_REMOVE_perf_event_mipsxx.o = -pg
6endif
原理如下,就是从原始编译参数中 filter-out
掉特定参数:
1$ grep CFLAGS_REMOVE -ur linux-stable/scripts/Makefile.lib
2_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
目录级:KBUILD_CFLAGS := $(filter-out -O2, $(KBUILD_CFLAGS))
arch/mips/boot/compressed/Makefile
:
1KBUILD_CFLAGS := $(filter-out -pg, $(KBUILD_CFLAGS))
自己主动 filter-out
掉。也可以直接调用脚本替换:
1KBUILD_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
,这个更适合调试需要。
2. 怎么去掉隐式优化
第二个,也来看看实例:
drivers/cpufreq/loongson2_cpufreq.c
:
1static void loongson2_cpu_wait(void) 2{
3 unsigned long flags;
4 u32 cpu_freq;
5
6 spin_lock_irqsave(&loongson2_wait_lock, flags);
7
8 cpu_freq = LOONGSON_CHIPCFG(0);
9 LOONGSON_CHIPCFG(0) &= ~0x7; /* Put CPU into wait mode */
10 LOONGSON_CHIPCFG(0) = cpu_freq; /* Restore CPU state */
11
12 spin_unlock_irqrestore(&loongson2_wait_lock, flags);
13 local_irq_enable();
14}
上面中间三句,从 gcc 的角度来看,这不是傻嘛,啥也没做啊,又读又写是什么鬼,目标变量的值根本“没变”呢。原因是什么,这个背后的 LOONGSON_CHIPCFG(0)
是硬件寄存器地址,有它的时序意义,不同的位有不同的意义,写不同的值会有不同的动作。这个时候就得明确告诉 gcc:
arch/mips/include/asm/mach-loongson64/loongson.h
:
1#define LOONGSON_CHIPCFG(id) (*(volatile u32 *)(loongson_chipcfg[id]))
这种情况怎么确认呢?make /path/to/xxx.s
,看看代码还在不在。在 “Linux Lab” 里头可以用 make k-x /path/to/xxx.s
。
点击文末左下角 “”
“泰晓科技”开通“Linux 知识星球”啦! 为答谢读者的关心,星主奉上免费体验卡一张,可以多人使用,也欢迎转赠给周边的朋友。
关注“泰晓科技”!点“在看”