【发布时间】:2017-11-05 11:03:26
【问题描述】:
来自Understanding Linux Kernel 3rd edition在描述内核固定映射的章节中,有一个函数使用了以下枚举器-
每个固定映射的线性地址都由一个小整数索引表示 在枚举 fixed_addresses 数据结构中定义:
enum fixed_addresses {
FIX_HOLE,
FIX_VSYSCALL,
FIX_APIC_BASE,
FIX_IO_APIC_BASE_0,
[...]
_ _end_of_fixed_addresses
};
并给出这个枚举器,以下函数将编译 -
固定映射的线性地址放在第四个的末尾 千兆字节的线性地址。 fix_to_virt( ) 函数计算 从索引开始的常量线性地址:
inline unsigned long fix_to_virt(const unsigned int idx)
{
if (idx >= _ _end_of_fixed_addresses)
_ _this_fixmap_does_not_exist( );
return (0xfffff000UL - (idx << PAGE_SHIFT));
}
现在,看看下面关于这个函数是如何最终被翻译成0xfffff000-(3 << PAGE_SHIFT)的解释
假设某个内核函数调用 fix_to_virt(FIX_IOAPIC_BASE_0)。因为函数被声明为 “内联”,C 编译器不生成对 fix_to_virt( ) 的调用, 但在调用函数中插入其代码。此外,检查 索引值永远不会在运行时执行。实际上, FIX_IOAPIC_BASE_0 是一个等于 3 的常数,所以编译器可以剪切 去掉 if 语句,因为它的条件在编译时为假。 相反,如果条件为真或 fix_to_virt( ) 的参数 不是常量,编译器在链接期间发出错误 相位因为符号_ _this_fixmap_does_not_exist 没有在任何地方定义。最终,编译器计算 0xfffff000-(3
因此,代码的编写者似乎依赖于一些假设,即如果我们有一个 if 语句来比较在编译时定义的两个数字(比如说 FIX_IO_APIC_BASE_0 和 _ _end_of_fixed_addresses),因此结果在编译时知道,if 语句肯定会被优化并从代码中删除。
Linux 内核代码如何假设?
另外,编写此类代码的动机是什么?如果作者希望函数被评估为0xfffff000-(3 << PAGE_SHIFT),为什么不直接写0xfffff000-(3 << PAGE_SHIFT) 而不是调用这个函数呢?
【问题讨论】:
标签: c linux compilation linux-kernel