You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解析Linux内核入口点x86汇编代码相关疑问

Linux内核启动汇编代码疑问解答

首先贴出对应的AT&T语法汇编代码:

00:     leal    (BP_scratch+4)(%esi), %esp
01:     call    1f
02: 1:  popl    %edx
03:     addl    $_GLOBAL_OFFSET_TABLE_+(.-1b), %edx
04:
05:     /* Load new GDT */
06:     leal    gdt@GOTOFF(%edx), %eax
07:     movl    %eax, 2(%eax)
08:     lgdt    (%eax)
09:
0A:     /* Load segment registers with our descriptors */
0B:     movl    $__BOOT_DS, %eax
0C:     movl    %eax, %ds
0D:     movl    %eax, %es
0E:     movl    %eax, %fs
0F:     movl    %eax, %gs
10:     movl    %eax, %ss

问题解答

  1. 第一行指令中%esi寄存器存储的内容是什么?
    %esi存储的是boot_params结构体的物理地址。BP_scratch是该结构体中的字段,这段代码用它来设置栈指针%esp,将栈起始位置设为BP_scratch+4相对于boot_params的偏移处。

  2. 被弹出并存储到%edx中的栈内容是什么?
    call 1f指令会把标签1:对应指令的物理地址压入栈中,随后popl %edx将这个地址弹出到%edx。这是x86汇编里获取当前指令地址的经典技巧,用于计算全局偏移表(GOT)的地址。

  3. 第7行movl指令的操作逻辑是什么?是否是将%eax的值设为%eax+2?
    完全不是。AT&T语法遵循源, 目的的顺序,这条指令的意思是:把%eax中的值,写入到内存地址为%eax+2的位置。
    这里%eax指向GDT描述符的起始地址,GDT描述符是6字节结构:前2字节是GDT大小,后4字节是GDT基地址。这条指令是把GDT的实际物理地址(存在%eax中)写入描述符的基地址字段(从偏移2字节开始的位置),让lgdt指令能正确加载GDT的基地址和大小。

  4. 为何所有段寄存器都要加载__BOOT_DS常量?
    __BOOT_DS是GDT中定义的平坦数据段选择子,对应的段描述符基地址为0、限长4GB。在保护模式下,段寄存器存储段选择子,加载这个值后:

  • 所有数据段(ds、es、fs、gs)和栈段(ss)共用同一个平坦段,内存访问无需计算段偏移,直接使用线性地址(此时分页未开启,线性地址等于物理地址)。
  • 统一段寻址规则,避免因段配置不一致导致内存访问错误,为后续内核初始化流程铺路。

内容的提问来源于stack exchange,提问作者Jeremy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 10:09:55