Understanding the Linux Kernel Exception Table __ex_table and Its Role in Exception Handling
This article provides a comprehensive overview of the Linux kernel's exception handling mechanism, focusing on the __ex_table data structure, its creation via macros, how the kernel locates and executes fix‑up code, and the supporting APIs and sorting process that ensure reliable recovery from faults.
The Linux kernel uses an exception handling mechanism to keep the system stable when unexpected faults occur, and the __ex_table exception table is the core data structure that maps faulting instruction addresses to corresponding fix‑up code.
Each entry in __ex_table stores a pair of relative addresses: the instruction that may fault ( insn ) and the address of the fix‑up code ( fixup ). When an exception is raised, the kernel searches the table for the matching insn , retrieves the fixup address, and redirects execution to the repair code.
The table is generated by the _ASM_EXTABLE macro, which emits entries into the special __ex_table section. The macro differs for assembly and C contexts, but both store the relative offsets of the faulting and fix‑up addresses.
Linker scripts combine all per‑object __ex_table sections into a single kernel section, exposing the symbols __start___ex_table and __stop___ex_table that delimit the table. The kernel declares these symbols as arrays of struct exception_table_entry :
extern struct exception_table_entry __start___ex_table[];
extern struct exception_table_entry __stop___ex_table[];During boot, sort_main_extable() sorts the table using a binary‑search‑compatible heap sort, ensuring that look‑ups can be performed efficiently.
// file: init/main.c
asmlinkage void __init start_kernel(void)
{
...
sort_main_extable();
...
}The primary API functions include:
ex_insn_addr() – computes the absolute faulting address.
ex_fixup_addr() – computes the absolute fix‑up address.
search_exception_tables() – searches the global and module exception tables.
fixup_exception() – invoked by the low‑level exception handler to apply the fix‑up and adjust the instruction pointer.
// file: arch/x86/mm/extable.c
int fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
unsigned long new_ip;
fixup = search_exception_tables(regs->ip);
if (fixup) {
new_ip = ex_fixup_addr(fixup);
if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
current_thread_info()->uaccess_err = 1;
new_ip -= 0x7ffffff0;
}
regs->ip = new_ip;
return 1;
}
return 0;
}Special handling exists for user‑space faults via the _ASM_EXTABLE_EX macro, which adds a magic constant (0x7ffffff0) to the fix‑up offset, allowing the kernel to distinguish user‑space access errors.
// file: arch/x86/include/asm/asm.h
#define _ASM_EXTABLE_EX(from,to) \
" .pushsection \"__ex_table\",\"a\"\n" \
" .balign 8\n" \
" .long (" #from ") - .\n" \
" .long (" #to ") - . + 0x7ffffff0\n" \
" .popsection\n"Through this mechanism, the kernel can recover from page‑faults, invalid memory accesses, and other critical errors without crashing, ensuring continuous operation of services ranging from system calls to device drivers.
Deepin Linux
Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.