Reputation: 3930
From Understanding Linux Kernel 3rd edition In the chapter that describes kernel fixed mapping, there is a function which uses the following enumorator-
Each fix-mapped linear address is represented by a small integer index defined in the enum fixed_addresses data structure:
enum fixed_addresses {
FIX_HOLE,
FIX_VSYSCALL,
FIX_APIC_BASE,
FIX_IO_APIC_BASE_0,
[...]
_ _end_of_fixed_addresses
};
and giving this enumerator, the following function will compile-
Fix-mapped linear addresses are placed at the end of the fourth gigabyte of linear addresses. The fix_to_virt( ) function computes the constant linear address starting from the index:
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));
}
Now, take a look at the following explanation regarding how this function is finally translated to only 0xfffff000-(3 << PAGE_SHIFT)
Let's assume that some kernel function invokes fix_to_virt(FIX_IOAPIC_BASE_0). Because the function is declared as "inline," the C compiler does not generate a call to fix_to_virt( ), but inserts its code in the calling function. Moreover, the check on the index value is never performed at runtime. In fact, FIX_IOAPIC_BASE_0 is a constant equal to 3, so the compiler can cut away the if statement because its condition is false at compile time. Conversely, if the condition is true or the argument of fix_to_virt( ) is not a constant, the compiler issues an error during the linking phase because the symbol _ _this_fixmap_does_not_exist is not defined anywhere. Eventually, the compiler computes 0xfffff000-(3 << PAGE_SHIFT) and replaces the fix_to_virt( ) function call with the constant linear address 0xffffc000.
So, it seems that the writer of the code relies on some assumption that if we have an if statement with comparison between two numbers that are defined in compilation time (lets say FIX_IO_APIC_BASE_0
and _ _end_of_fixed_addresses
) and thus the results is knows in compilation time, than the if
statement is sure to be optimized and removed from code.
How can the Linux kernel code assume that?
Also, what is the motivation for such code? if the writer want the function to be evaluated to 0xfffff000-(3 << PAGE_SHIFT)
why not just write 0xfffff000-(3 << PAGE_SHIFT)
instead of a call to this function?
Upvotes: 3
Views: 765
Reputation: 347
_ _end_of_fixed_addresses is known at unit compilation time, but not idx: there's the possibility that that function beign called with invalid idx from an external source code. As this_fixmap_does_not_exists symbol doesnt exists, like told in explanation, if a developer attempts to use fix_to_virt with an invalid idx will go to a compiling error. But if he uses a correct one, 'if' statement will be removed by compiler. So, this is in fact not a runtime protection, but a development protection, a technique for translating a possible runtime error to just a compiling one. About the fix result, note that is just by the example. idx could be different of 3, and so result of that function.
Upvotes: 1
Reputation: 17424
There are actually two questions here:
Upvotes: 1