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

Linux内核中连续stmfd sp!, {lr}与ldmfd sp!, {lr}指令的疑问

ARM Linux内核中stmfd sp!, {lr}+ldmfd sp!, {lr}指令对的作用分析

我在分析Linux内核的ARM汇编代码时,发现多个函数(比如vfs_write)里都有一组重复出现的指令对:

stmfd sp!, {lr}
ldmfd sp!, {lr}

以vfs_write的汇编片段为例:

0xc03741d4 <vfs_write>: push    {r4, r5, r6, r7, r8, r9, r11, lr}
0xc03741d8 <vfs_write+4>:       add     r11, sp, #24
0xc03741dc <vfs_write+8>:       sub     sp, sp, #96     ; 0x60
0xc03741e0 <vfs_write+12>:      mov     r4, r0
0xc03741e4 <vfs_write+16>:      movw    r0, #25800      ; 0x64c8
0xc03741e8 <vfs_write+20>:      movt    r0, #49472      ; 0xc140
0xc03741ec <vfs_write+24>:      mov     r8, r3
0xc03741f0 <vfs_write+28>:      ldr     r0, [r0]
0xc03741f4 <vfs_write+32>:      mov     r5, r2
0xc03741f8 <vfs_write+36>:      mov     r7, r1
0xc03741fc <vfs_write+40>:      str     r0, [r11, #-28] ; 0xffffffe4
0xc0374200 <vfs_write+44>:      stmfd   sp!, {lr}
0xc0374204 <vfs_write+48>:      ldmfd   sp!, {lr}
0xc0374208 <vfs_write+52>:      ldr     r0, [r4, #40]   ; 0x28
0xc037420c <vfs_write+56>:      mvn     r6, #8
0xc0374210 <vfs_write+60>:      tst     r0, #2

这组指令看似把lr压栈后立即弹出,完全没改变寄存器或栈的状态,看起来像冗余代码,但在多个内核函数中重复出现,想知道这是有特定设计原因还是纯粹的冗余?


这组指令不是冗余,是内核调试/追踪机制的产物

这对指令是Linux内核中函数graph tracer(函数调用图追踪器)的占位代码,具体原因如下:

  • 函数graph tracer需要在函数入口附近插入追踪代码,记录函数调用关系和执行时间。对于ARM架构,开启该功能时,这组指令会被替换成bl指令,跳转到追踪处理函数;关闭追踪功能时,内核会保留这对stmfd+ldmfd指令——它们的行为等价于空操作,但长度和bl指令一致(都是4字节),这样能保证内核代码的地址偏移不变,避免关闭追踪后需要重新调整所有函数的地址引用。
  • 虽然这组指令会短暂修改栈指针sp,但随即恢复,对程序逻辑没有任何影响。这种设计的核心是为了在开启/关闭追踪功能时,无需重新编译整个内核,仅替换这组占位指令即可实现功能切换,同时保持代码结构的兼容性。

补充验证

你可以检查内核配置选项,查看是否开启过CONFIG_FUNCTION_GRAPH_TRACER相关调试选项。即便当前关闭了该选项,内核构建时仍会保留这组占位指令,后续开启追踪时可直接patch代码,无需重新编译所有模块。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 12:17:35