当前位置: 首页 > news >正文

Linux中异常初始化和门设置函数的实现

异常初始化trap_init

void __init trap_init(void)
{
#ifdef CONFIG_EISAif (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) {EISA_bus = 1;}
#endif#ifdef CONFIG_X86_LOCAL_APICinit_apic_mappings();
#endifset_trap_gate(0,&divide_error);set_intr_gate(1,&debug);set_intr_gate(2,&nmi);set_system_intr_gate(3, &int3); /* int3-5 can be called from all */set_system_gate(4,&overflow);set_system_gate(5,&bounds);set_trap_gate(6,&invalid_op);set_trap_gate(7,&device_not_available);set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);set_trap_gate(9,&coprocessor_segment_overrun);set_trap_gate(10,&invalid_TSS);set_trap_gate(11,&segment_not_present);set_trap_gate(12,&stack_segment);set_trap_gate(13,&general_protection);set_intr_gate(14,&page_fault);set_trap_gate(15,&spurious_interrupt_bug);set_trap_gate(16,&coprocessor_error);set_trap_gate(17,&alignment_check);
#ifdef CONFIG_X86_MCEset_trap_gate(18,&machine_check);
#endifset_trap_gate(19,&simd_coprocessor_error);set_system_gate(SYSCALL_VECTOR,&system_call);/** Should be a barrier for any external CPU state.*/cpu_init();trap_init_hook();
}

1. 函数功能

初始化x86架构的异常处理机制,设置中断描述符表(IDT)中的各种异常和陷阱门,为CPU异常处理建立基础框架

2. 代码详细解释

2.1. EISA总线检测

#ifdef CONFIG_EISAif (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) {EISA_bus = 1;}
#endif
  • #ifdef CONFIG_EISA:只有在配置了EISA总线支持时才编译
  • isa_readl(0x0FFFD9):从I/O地址0xFFFD9读取32位值
  • 'E'+('I'<<8)+('S'<<16)+('A'<<24):计算EISA签名"EISA"的数值
    • ‘E’ = 0x45, ‘I’<<8 = 0x4900, ‘S’<<16 = 0x530000, ‘A’<<24 = 0x41000000
    • 总和 = 0x41534945 (小端序为"EISA")
  • 如果匹配,设置EISA_bus = 1标记系统有EISA总线

2.2. APIC初始化

#ifdef CONFIG_X86_LOCAL_APICinit_apic_mappings();
#endif
  • #ifdef CONFIG_X86_LOCAL_APIC:只有在配置了本地APIC支持时才编译
  • init_apic_mappings():初始化APIC(高级可编程中断控制器)的内存映射
  • APIC用于多处理器系统中的中断分发

2.3. 异常0-7设置

        set_trap_gate(0,&divide_error);set_intr_gate(1,&debug);set_intr_gate(2,&nmi);set_system_intr_gate(3, &int3); /* int3-5 can be called from all */set_system_gate(4,&overflow);set_system_gate(5,&bounds);set_trap_gate(6,&invalid_op);set_trap_gate(7,&device_not_available);

异常0:除零错误

  • set_trap_gate(0,&divide_error):设置陷阱门,处理除零异常
  • 当DIV或IDIV指令除数为0时触发

异常1:调试异常

  • set_intr_gate(1,&debug):设置中断门,处理调试异常
  • 用于硬件调试、单步执行等

异常2:NMI(不可屏蔽中断)

  • set_intr_gate(2,&nmi):设置中断门,处理NMI
  • 用于硬件严重错误,无法被屏蔽

异常3:断点指令

  • set_system_intr_gate(3, &int3):设置系统中断门
  • int3-5可以从所有特权级调用
  • INT3指令用于软件断点

异常4:溢出异常

  • set_system_gate(4,&overflow):设置系统门
  • INTO指令在溢出标志设置时触发

异常5:边界检查异常

  • set_system_gate(5,&bounds):设置系统门
  • BOUND指令在数组越界时触发

异常6:无效操作码

  • set_trap_gate(6,&invalid_op):设置陷阱门
  • 执行未定义或无效的指令时触发

异常7:设备不可用

  • set_trap_gate(7,&device_not_available):设置陷阱门

2.4. 异常8-13设置

        set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);set_trap_gate(9,&coprocessor_segment_overrun);set_trap_gate(10,&invalid_TSS);set_trap_gate(11,&segment_not_present);set_trap_gate(12,&stack_segment);set_trap_gate(13,&general_protection);

异常8:双重故障

  • set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS):设置任务门
  • 特殊处理:使用任务门切换到专门的TSS(任务状态段)
  • 当处理一个异常时又发生另一个异常时触发

异常9:协处理器段越界

  • set_trap_gate(9,&coprocessor_segment_overrun):设置陷阱门
  • 协处理器操作超出段界限时触发

异常10:无效TSS

  • set_trap_gate(10,&invalid_TSS):设置陷阱门
  • 任务状态段无效时触发

异常11:段不存在

  • set_trap_gate(11,&segment_not_present):设置陷阱门
  • 访问不存在的内存段时触发

异常12:堆栈段异常

  • set_trap_gate(12,&stack_segment):设置陷阱门
  • 堆栈操作违反段规则时触发

异常13:通用保护异常

  • set_trap_gate(13,&general_protection):设置陷阱门
  • 各种保护违规时触发,最常见的异常之一

2.5. 异常14-19设置

        set_intr_gate(14,&page_fault);set_trap_gate(15,&spurious_interrupt_bug);set_trap_gate(16,&coprocessor_error);set_trap_gate(17,&alignment_check);
#ifdef CONFIG_X86_MCEset_trap_gate(18,&machine_check);
#endifset_trap_gate(19,&simd_coprocessor_error);

异常14:页面故障

  • set_intr_gate(14,&page_fault):设置中断门
  • 重要:处理缺页异常,虚拟内存管理的核心

异常15:伪中断bug

  • set_trap_gate(15,&spurious_interrupt_bug):设置陷阱门
  • 处理某些硬件产生的不必要中断

异常16:协处理器错误

  • set_trap_gate(16,&coprocessor_error):设置陷阱门
  • 数学协处理器错误时触发

异常17:对齐检查

  • set_trap_gate(17,&alignment_check):设置陷阱门
  • 未对齐的内存访问时触发(如果启用对齐检查)

异常18:机器检查

  • #ifdef CONFIG_X86_MCE:机器检查异常支持
  • set_trap_gate(18,&machine_check):设置陷阱门
  • 硬件检测到CPU或总线错误时触发

异常19:SIMD协处理器错误

  • set_trap_gate(19,&simd_coprocessor_error):设置陷阱门
  • SSE/SSE2指令执行错误时触发

2.6. 系统调用门设置

        set_system_gate(SYSCALL_VECTOR,&system_call);
  • set_system_gate(SYSCALL_VECTOR,&system_call):设置系统调用门
  • SYSCALL_VECTOR:系统调用中断向量号(通常是0x80)
  • &system_call:系统调用处理函数的地址
  • 允许用户空间程序通过中断进入内核空间

2.7. CPU初始化和钩子函数

        /** Should be a barrier for any external CPU state.*/cpu_init();trap_init_hook();
  • cpu_init():初始化当前CPU的特定状态
    • 设置任务状态段(TSS)
    • 设置本地描述符表(LDT)
    • 初始化其他CPU特定资源
  • trap_init_hook():架构特定的陷阱初始化钩子函数
    • 允许不同x86变体(如x86_64)提供特定实现

3. 门类型区别

门类型特权级检查用途
set_trap_gate严格大多数异常,允许调试
set_intr_gate严格重要异常,禁用中断
set_system_gate宽松用户空间可调用的异常
set_system_intr_gate宽松用户空间可调用的中断
set_task_gate严格任务切换,用于双重故障

4. 异常处理的重要性

这个函数建立的异常处理框架是操作系统稳定性的基石:

  1. 硬件异常到软件处理的桥梁
  2. 内存管理的基础(页面故障)
  3. 调试支持(断点、单步执行)
  4. 系统调用入口
  5. 错误恢复机制

设置陷阱门set_trap_gate

static void __init set_trap_gate(unsigned int n, void *addr)
{_set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
}

1. 函数功能

在中断描述符表(IDT)中设置一个陷阱门,用于处理CPU异常

2. 代码详细解释

2.1. 函数定义

static void __init set_trap_gate(unsigned int n, void *addr)
  • static:函数只在当前文件内可见
  • void __init:返回值为void,__init表示该函数只在系统初始化阶段使用,初始化完成后内存可以被释放
  • unsigned int n:中断向量号(0-255)
  • void *addr:中断/异常处理函数的地址

2.2. 函数实现

        _set_gate(idt_table+n,15,0,addr,__KERNEL_CS);

参数1:idt_table+n

  • idt_table:中断描述符表的基地址指针
  • +n:计算第n个中断描述符的地址

参数2:15

  • 这是门描述符的类型和属性字段
  • 二进制:00001111 (15 = 0x0F)
  • 分解:
    • 00:DPL (Descriptor Privilege Level) - 特权级0,只有内核可以调用
    • 1:S (System) 位 - 1表示系统段/门描述符
    • 111:Type字段 - 111表示32位陷阱门(Trap Gate)

参数3:0

  • 设为0表示不使用IST,使用当前堆栈

参数4:addr

  • 中断/异常处理函数的地址
  • 这个地址会被拆分成低16位和高16位填入门描述符

参数5:__KERNEL_CS

  • 代码段选择子
  • 值为0x60(在x86架构中)
  • 表示使用内核代码段

3. 陷阱门的特点

3.1. 执行时行为

// 当通过陷阱门调用时:
1. 保存当前EFLAGS、CS、EIP到堆栈
2. 清除某些EFLAGS位(如NT、TF)
3. 但IF(中断使能)标志保持不变 ← 与中断门的关键区别
4. 切换到目标代码段和偏移地址

3.2. 与中断门的区别

// 中断门 (type=14):
- 进入处理程序时自动禁用中断 (IF=0)
- 用于需要原子性处理的紧急中断// 陷阱门 (type=15): 
- 进入处理程序时保持中断状态不变
- 用于异常处理,允许在异常处理期间响应中断

4. 特权级保护机制

由于DPL=0(最高特权级):

  • 只能从内核模式(Ring 0)调用
  • 如果用户模式(Ring 3)程序尝试通过INT指令触发这些异常,会产生通用保护异常
  • 这保护了关键异常处理程序不被用户程序滥用

设置系统门set_system_gate

static void __init set_system_gate(unsigned int n, void *addr)
{_set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
}

1. 函数功能

在中断描述符表(IDT)中设置一个系统门,允许用户空间程序通过中断调用内核功能

2. 代码详细解释

2.1. 函数定义

static void __init set_system_gate(unsigned int n, void *addr)
  • static:函数只在当前文件内可见
  • void __init:返回值为void,__init表示该函数只在系统初始化阶段使用
  • set_system_gate:函数名,设置系统门
  • unsigned int n:中断向量号
  • void *addr:处理函数的地址

2.2. 函数实现

        _set_gate(idt_table+n,15,3,addr,__KERNEL_CS);

参数1:idt_table+n

  • idt_table:中断描述符表的基地址
  • +n:计算第n个中断描述符的位置
  • 指向要设置的门在IDT中的位置

参数2:15

  • 门描述符的类型字段
  • 二进制:00001111 (15 = 0x0F)
  • 分解:
    • 00:DPL字段的一部分
    • 1:S (System) 位 - 1表示系统段/门描述符
    • 111:Type字段 - 111表示32位陷阱门

参数3:3

  • 关键区别:这是DPL (Descriptor Privilege Level) 字段
  • 二进制:11 = 特权级3
  • 表示用户模式(Ring 3)程序也可以调用这个门

参数4:addr

  • 处理函数的入口地址
  • 当通过这个门调用时,CPU会跳转到这个地址执行

参数5:__KERNEL_CS

  • 代码段选择子,值为0x60
  • 表示处理函数在内核代码段中执行

3. 与set_trap_gate的关键区别

对比分析:

// set_trap_gate - 只能内核调用
_set_gate(idt_table+n, 15, 0, addr, __KERNEL_CS);
//                         ↑ DPL=0 (仅内核)// set_system_gate - 用户也可调用  
_set_gate(idt_table+n, 15, 3, addr, __KERNEL_CS);
//                         ↑ DPL=3 (用户和内核)

4. 实际使用场景

trap_init()中的具体使用:

set_system_gate(4,&overflow);      // 溢出异常
set_system_gate(5,&bounds);        // 边界检查异常
set_system_gate(SYSCALL_VECTOR,&system_call);  // 系统调用

5. 安全机制

虽然用户程序可以调用系统门,但有重要限制:

代码段切换

// 即使从用户模式调用:
当前CS = 用户代码段 (特权级3)
目标CS = __KERNEL_CS (特权级0)// 实际执行在内核模式下进行

堆栈切换

// 自动切换到内核堆栈
用户堆栈SS:ESP → 保存到内核堆栈
使用内核堆栈SS0:ESP0执行处理函数

系统调用的特殊角色

SYSCALL_VECTOR(通常是0x80)是最重要的系统门:

// 传统的Linux系统调用机制
set_system_gate(SYSCALL_VECTOR, &system_call);// 用户程序使用:
mov eax, 1      // 系统调用号
mov ebx, 0      // 参数
int 0x80        // 触发系统调用

设置任务门set_task_gate

static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
{_set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
}

1. 函数功能

在中断描述符表(IDT)中设置一个任务门,用于在异常处理时自动进行任务切换

2. 代码详细解释

2.1. 函数定义

static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
  • static:函数只在当前文件内可见
  • void __init:返回值为void,__init表示该函数只在系统初始化阶段使用
  • set_task_gate:函数名,设置任务门
  • unsigned int n:中断向量号
  • unsigned int gdt_entry:GDT(全局描述符表)中的TSS(任务状态段)条目索引

2.2. 函数实现

        _set_gate(idt_table+n,5,0,0,(gdt_entry<<3));

参数1:idt_table+n

  • idt_table:中断描述符表的基地址
  • +n:计算第n个中断描述符的位置
  • 指向要设置的任务门在IDT中的位置

参数2:5

  • 门描述符的类型字段
  • 二进制:00000101 (5 = 0x05)
  • 分解:
    • 00:DPL (Descriptor Privilege Level) - 特权级0
    • 0:S (System) 位 - 0表示这是系统描述符
    • 0101:Type字段 - 0101表示任务门(Task Gate)

参数3:0

  • DPL (Descriptor Privilege Level) 字段

参数4:0

  • 偏移量字段,对于任务门必须为0
  • 因为任务门不直接指定代码地址,而是通过TSS间接指定

参数5:(gdt_entry<<3)

  • 关键参数:TSS段选择子
  • gdt_entry:GDT中的TSS描述符索引
  • <<3:左移3位,将索引转换为段选择子

3. 实际使用场景

trap_init()中的具体使用:

set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);

双重故障异常(8)的特殊处理:

  • 当CPU在处理一个异常时又发生另一个异常
  • 例如:页面故障处理程序中又发生除零错误
  • 使用任务门而不是普通的陷阱门的原因:
    • 需要干净的上下文来处理严重错误
    • 避免在已损坏的堆栈上继续执行
    • 确保系统能够恢复或安全崩溃

4. 任务门与其他门的关键区别

对比分析:

// 陷阱门 - 直接跳转到处理函数
_set_gate(..., 15, 0, addr, __KERNEL_CS);
// 执行流程: 保存上下文 → 跳转到addr// 任务门 - 进行完整的任务切换  
_set_gate(..., 5, 0, 0, (gdt_entry<<3));
// 执行流程: 保存当前TSS → 加载新TSS → 全新开始

任务切换的详细过程:

1. 保存当前任务状态到当前TSS- 所有寄存器值- 段选择子- EFLAGS- EIP2. 加载新任务的TSS- 从GDT中指定的TSS描述符加载- 恢复所有寄存器状态- 切换到新任务的地址空间3. 开始在新任务上下文中执行- 使用全新的堆栈- 独立的地址空间- 隔离的执行环境

5. 双重故障处理的重要性

为什么需要特殊处理?

// 普通异常处理可能失败的场景:
1. 页面故障处理时发生堆栈错误
2. 除零异常处理时发生段错误  
3. 任何异常处理程序中发生严重硬件错误// 后果:
- 当前堆栈可能已损坏
- 关键数据结构可能不一致
- 继续执行可能导致系统完全崩溃

任务门的优势:

// 通过任务门处理双重故障:
1. 完全隔离:在新的TSS中执行,与损坏环境隔离
2. 干净状态:全新的寄存器组和堆栈
3. 可靠恢复:有机会保存调试信息并优雅关闭
4. 系统保护:防止错误传播导致整个系统崩溃

设置系统中断门set_system_intr_gate

static inline void set_system_intr_gate(unsigned int n, void *addr)
{_set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS);
}

1. 函数功能

在中断描述符表(IDT)中设置一个系统中断门,允许用户空间程序通过中断调用内核的中断处理程序

2. 代码详细解释

2.1. 函数定义

static inline void set_system_intr_gate(unsigned int n, void *addr)
  • static:函数只在当前文件内可见
  • inline:建议编译器进行内联展开,避免函数调用开销
  • void:函数没有返回值
  • set_system_intr_gate:函数名,设置系统中断门
  • unsigned int n:中断向量号
  • void *addr:中断处理函数的地址

2.2. 函数实现

        _set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS);

参数1:idt_table+n

  • idt_table:中断描述符表的基地址指针
  • +n:计算第n个中断描述符的位置
  • 在x86中,每个中断描述符占8字节,所以这是第n个门的位置

参数2:14

  • 门描述符的类型和属性字段
  • 二进制:00001110 (14 = 0x0E)
  • 分解:
    • 0:P (Present) 位 - 应该为1表示存在
    • 00:DPL字段的一部分
    • 1:S (System) 位 - 1表示系统段/门描述符
    • 1110:Type字段 - 1110表示32位中断门(Interrupt Gate)

参数3:3

  • 关键特性:DPL (Descriptor Privilege Level) 字段
  • 二进制:11 = 特权级3
  • 表示用户模式(Ring 3)程序也可以调用这个中断门

参数4:addr

  • 中断处理函数的入口地址
  • 当通过这个门调用时,CPU会跳转到这个地址执行中断处理

参数5:__KERNEL_CS

  • 代码段选择子,值为0x60
  • 表示中断处理函数在内核代码段中执行

3. 与其他门类型的对比

四种门类型的比较:

// 陷阱门 - 保持中断使能
set_trap_gate:      _set_gate(..., 15, 0, addr, __KERNEL_CS)// 中断门 - 禁用中断  
set_intr_gate:      _set_gate(..., 14, 0, addr, __KERNEL_CS)// 系统门 - 陷阱门 + 用户可访问
set_system_gate:    _set_gate(..., 15, 3, addr, __KERNEL_CS)// 系统中断门 - 中断门 + 用户可访问
set_system_intr_gate: _set_gate(..., 14, 3, addr, __KERNEL_CS)

4. 安全保护机制

可控的用户访问:

// 虽然用户可调用,但是受控的:
1. 只能调用特定的向量(如INT3)
2. 处理函数在内核模式执行
3. 有完整的上下文保存和恢复
4. 内核可以验证和处理请求的合法性

与普通系统调用的区别:

// 系统调用门 (向量0x80):
- 用于正常的系统服务调用
- 保持中断使能(使用陷阱门)
- 有严格的参数验证机制// 系统中断门 (向量3):
- 用于特定的调试异常
- 禁用中断确保原子性(使用中断门)
- 针对调试场景的特殊处理

5. 调试器集成

GDB等调试器的工作原理:

// 调试器设置断点的过程:
1. 保存目标指令字节
2. 写入INT3指令 (0xCC)
3. 程序执行到断点时触发异常3
4. 通过系统中断门进入内核调试处理
5. 内核通知调试器,调试器接管控制// 系统中断门确保:
- 断点触发时立即响应,不被其他中断打断
- 调试状态的一致性
- 可靠的单步执行和断点管理

设置中断门set_intr_gate

void set_intr_gate(unsigned int n, void *addr)
{_set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
}

1. 函数功能

在中断描述符表(IDT)中设置一个中断门,用于处理硬件中断和关键异常,确保处理过程的原子性

2. 代码详细解释

2.1. 函数定义

void set_intr_gate(unsigned int n, void *addr)
  • void:函数没有返回值
  • set_intr_gate:函数名,设置中断门
  • unsigned int n:中断向量号
  • void *addr:中断处理函数的地址
  • 注意:这个函数没有static__init,意味着它可以在运行时被调用

2.2. 函数实现

        _set_gate(idt_table+n,14,0,addr,__KERNEL_CS);

参数1:idt_table+n

  • idt_table:中断描述符表的基地址指针
  • +n:计算第n个中断描述符的位置
  • 在x86中,每个中断描述符占8字节,所以这是第n个门的位置

参数2:14

  • 门描述符的类型和属性字段
  • 二进制:00001110 (14 = 0x0E)
  • 分解:
    • 00:DPL (Descriptor Privilege Level) - 特权级0
    • 1:S (System) 位 - 1表示系统段/门描述符
    • 1110:Type字段 - 1110表示32位中断门(Interrupt Gate)

参数3:0

  • 关键特性:DPL (Descriptor Privilege Level) 字段
  • 二进制:00 = 特权级0
  • 表示只有内核模式(Ring 0)可以调用这个中断门

参数4:addr

  • 中断处理函数的入口地址
  • 当通过这个门调用时,CPU会跳转到这个地址执行中断处理

参数5:__KERNEL_CS

  • 代码段选择子,值为0x60
  • 表示中断处理函数在内核代码段中执行

3. 中断门的关键特性

自动禁用中断

// 当中断门被调用时:
EFLAGS.IF = 0  // 自动清除中断使能标志// 这意味着:
// - 在中断处理期间不会响应其他中断
// - 确保中断处理的原子性
// - 防止中断嵌套导致堆栈溢出或死锁

严格的特权级保护

// 由于DPL=0:
// - 只有内核代码可以触发这些中断
// - 用户程序尝试访问会产生通用保护异常
// - 保护关键中断处理程序不被滥用

4. 与陷阱门的区别

关键行为差异:

// 中断门 (type=14):
- 进入时自动禁用中断 (IF=0)
- 用于需要原子性处理的紧急情况
- 处理程序必须显式启用中断// 陷阱门 (type=15):
- 进入时保持中断状态不变
- 用于普通的异常处理
- 可以在处理期间响应中断

设置门描述符的内联汇编宏_set_gate

#define _set_gate(gate_addr,type,dpl,addr,seg) \
do { \int __d0, __d1; \__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \"movw %4,%%dx\n\t" \"movl %%eax,%0\n\t" \"movl %%edx,%1" \:"=m" (*((long *) (gate_addr))), \"=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \:"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \"3" ((char *) (addr)),"2" ((seg) << 16)); \
} while (0)

1. 宏功能

在中断描述符表(IDT)或全局描述符表(GDT)中设置一个门描述符,用于定义中断、陷阱或调用门的属性

2. 代码详细解释

2.1. 宏定义开始

#define _set_gate(gate_addr,type,dpl,addr,seg) \
  • 定义宏_set_gate,接受5个参数:
    • gate_addr:门描述符的内存地址
    • type:门类型(陷阱门、中断门等)
    • dpl:描述符特权级
    • addr:处理函数地址
    • seg:代码段选择子

2.2. do-while循环结构

do { \
  • 使用do { ... } while (0)是宏定义的常见技巧
  • 确保宏在使用时像单个语句一样工作
  • 允许在宏中使用局部变量而不会与外部代码冲突

2.3. 局部变量声明

  int __d0, __d1; \
  • 声明两个临时整型变量__d0__d1
  • 双下划线前缀避免与用户变量名冲突
  • 这些变量将在内联汇编中使用

2.4. 内联汇编开始

  __asm__ __volatile__ ( \
  • __asm__:GCC内联汇编关键字
  • __volatile__:告诉编译器不要优化这段汇编代码
  • 确保汇编指令按原样执行

2.5. 汇编指令部分

    "movw %%dx,%%ax\n\t" \"movw %4,%%dx\n\t" \"movl %%eax,%0\n\t" \"movl %%edx,%1" \

指令1:"movw %%dx,%%ax\n\t"

  • 将DX寄存器的低16位移动到AX寄存器,DX寄存器保存着处理函数地址
  • 准备构建描述符的低32位

指令2:"movw %4,%%dx\n\t"

  • 将输入操作数%4(属性字)移动到DX寄存器
  • %4对应后面的"i" ((short) (0x8000+(dpl<<13)+(type<<8)))

指令3:"movl %%eax,%0\n\t"

  • 将EAX寄存器的值存储到输出操作数%0,EAX寄存器为段地址 << 16 | addr & 0x0000FFFF
  • %0对应门描述符的低32位内存位置

指令4:"movl %%edx,%1"

  • 将EDX寄存器的值存储到输出操作数%1,EDX寄存器为属性字 | addr & 0xFFFF0000
  • %1对应门描述符的高32位内存位置

2.6. 输出操作数

    :"=m" (*((long *) (gate_addr))), \"=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \

输出操作数0:"=m" (*((long *) (gate_addr)))

  • =m:内存操作数,只写
  • *((long *) (gate_addr)):将gate_addr转换为long指针并解引用
  • 对应门描述符的低32位

输出操作数1:"=m" (*(1+(long *) (gate_addr)))

  • 同样内存操作数,只写
  • *(1+(long *) (gate_addr))gate_addr后4字节的位置
  • 对应门描述符的高32位

输出操作数2:"=&a" (__d0)

  • =&a:早期破坏的EAX寄存器,绑定到__d0
  • &表示在输入操作数使用前就修改

输出操作数3:"=&d" (__d1)

  • =&d:早期破坏的EDX寄存器,绑定到__d1

2.7. 输入操作数

    :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \"3" ((char *) (addr)),"2" ((seg) << 16)); \

输入操作数4:"i" ((short) (0x8000+(dpl<<13)+(type<<8)))

  • "i":立即数
  • 计算属性字:
    • 0x8000:P位(存在位)= 1
    • dpl<<13:DPL字段移到正确位置(位13-14)
    • type<<8:类型字段移到正确位置(位8-11)

输入操作数:"3" ((char *) (addr))

  • "3":匹配第3个操作数(EDX/__d1)
  • 将处理函数地址转换为char指针

输入操作数:"2" ((seg) << 16)

  • "2":匹配第2个操作数(EAX/__d0)
  • 将段选择子左移16位,准备放到描述符的高位
http://www.dtcms.com/a/492187.html

相关文章:

  • tritonserver的docker镜像中运行onnxruntime-gpu,报错segmentationfault
  • 毕业答辩企业网站开发的问题创作平台有哪些
  • 客户推广渠道有哪些seo高端培训
  • AWS Glue中查询一个月的数据条数
  • 自助网站制作系统源码网络热词2022流行语及解释
  • 手机网站跟pc网站有什么不同中国人做的比较好的shopify网站
  • Rust 实战六 | 利用 winres 配置应用程序的图标
  • 通过docker、docker-compose方式安装部署zabbix7.0 LTS监控平台
  • 建设企业网站电话是多少广州市 网站建设 有限公司
  • 外贸网站建设可以吗网站开发流程心得体会
  • 网站内页产品做跳转安徽省建设工程招标网官网
  • 网站开发财务网站建设口号
  • 郑州企业建站系统模板电子商务网站建设属性
  • GroundingDINO安装报错合集解决
  • 具有价值的网站建设平台网站建设的流程分析
  • 国外网站推广平台有哪些?多用户建站平台
  • FastbuildAI新建套餐-前端代码分析
  • 网站建好了还需要什么维护扬中网站推广托管
  • [Sora] 集成 | 封装-调用-推理 | `prepare_api`与`api_fn`
  • 新一代Java应用日志可视化与监控系统开源啦
  • 网站做镜像是什么房产律师网站模板
  • 汕头网站优化系统wordpress格行代码
  • 抓取源ip的包
  • 北京手机版网站制作个人博客主页登录
  • php企业网站程序做网站分层技术
  • 网站建立的链接不安全怎么解决p2p网站制作价格
  • Python 3.14 安装教程:新手友好版
  • SQL 日期处理指南
  • 网站建设备案查询上海建筑网站建设
  • [c++语法学习]Day11:c++面向对象 1