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

2.6.18内核head.S中.asciz字符串%p格式符解析疑问

Linux 2.6.18 i386内核中int_msg字符串%p的输出逻辑

问题背景

在2.6.18版本的i386内核源码中,arch/i386/kernel/head.S里定义了如下字符串:

int_msg:
  .asciz "Unknown interrupt or fault at EIP %p %p %p\n"

该字符串由ignore_int代码段调用:

ignore_int:
  cld
#ifdef CONFIG_PRINTK
  pushl %eax
  pushl %ecx
  pushl %edx
  pushl %es
  pushl %ds
  movl $(__KERNEL_DS),%eax
  movl %eax,%ds
  movl %eax,%es
  pushl 16(%esp)
  pushl 24(%esp)
  pushl 32(%esp)
  pushl 40(%esp)
  pushl $int_msg
#ifdef CONFIG_EARLY_PRINTK
  call early_printk
#else
  call printk
#endif
  addl $(5*4),%esp
  popl %ds
  popl %es
  popl %edx
  popl %ecx
  popl %eax
#endif
  iret

疑问:无文档说明%p的用法,汇编器或运行时如何确定%p %p %p的输出内容?


解答

1. %p的本质:内核打印函数的格式占位符

%p不是汇编器的语法,它是Linux内核printk(或early_printk)的格式占位符,由运行时的打印函数解析处理,专门用于输出指针/内存地址。在i386架构下,它会把传入的32位整数以十六进制形式输出(早期内核版本可能不带0x前缀,但核心是输出地址值)。

2. 三个%p对应的参数来源

x86架构采用从右往左的栈传参规则,调用printk前的压栈顺序决定了参数的传递:

  • 先压入四个栈偏移参数(16(%esp)、24(%esp)、32(%esp)、40(%esp))
  • 再压入格式字符串int_msg

因此printk的实际调用逻辑等价于:

printk(int_msg, arg1, arg2, arg3, arg4);

由于格式字符串只有三个%p,最后一个参数arg4会被忽略。

结合中断栈帧的结构(中断发生时CPU自动压入EFLAGS、CS、EIP,再加上函数内手动保存的寄存器),三个有效参数对应:

  • 第一个%p:中断触发时的CS寄存器值(代码段选择子)
  • 第二个%p:中断触发时的EIP寄存器值(就是字符串里标注的出错指令地址)
  • 第三个%p:中断触发时的EFLAGS寄存器值(CPU标志寄存器的状态)

3. 偏移量的意义

代码中用16(%esp)这类偏移量,是因为函数开头已经手动压入了%eax、%ecx、%edx、%es、%ds五个寄存器,需要通过偏移跳过这些手动保存的内容,直接访问CPU在中断发生时自动保存的上下文数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 14:13:09