You need to enable JavaScript to run this app. Linux内核宏向自身参数存值含义及rdtsc、DECLARE_ARGS相关疑问
优惠活动
大模型
产品
解决方案
定价
更多

Linux内核宏向自身参数存值含义及rdtsc、DECLARE_ARGS相关疑问

Linux内核rdtsc读取TSC计数器相关疑问

背景说明

rdtsc是x86架构下用于读取CPU 64位时间戳计数器(TSC)的专用指令,执行后会将64位计数值拆分存储在两个32位寄存器中:低32位存于EAX,高32位存于EDX。
开发者在查阅《Linux设备驱动程序(第三版)》时,看到书中描述相关宏会将拆分得到的low32、high32值存储到宏自身的参数中,但对比内核代码时发现当前实现的rdtsc无入参,因此产生疑问,参考的内核代码片段如下:

#define DECLARE_ARGS(val, low, high)    unsigned long low, high

static __always_inline unsigned long long rdtsc(void)
{
    DECLARE_ARGS(val, low, high);

    // 实际汇编指令执行逻辑省略
    return EAX_EDX_VAL(val, low, high);
}

开发者最初按照书中描述,写出了无法正常工作的调用代码:

long long x, y;
rdtsc(x, y); // 误以为可以通过传参直接接收拆分值

疑问对应解答

1. “宏将值存储到自身参数中”的含义、正确取值方式

  • 书中的描述针对的是Linux内核早期的rdtsc宏实现,不是现代内核封装后的无参内联函数。早期实现是直接将rdtsc汇编指令的输出操作数和传入参数做绑定,典型写法为:
    #define rdtsc(low, high) __asm__ __volatile__("rdtsc" : "=a"(low), "=d"(high))
    
    这种宏展开后,会直接把EAX的低32位值写入low对应变量、EDX的高32位值写入high对应变量,也就是书中提到的“将值存储到自身参数中”的实际含义。
  • 现代内核的无参rdtsc是对早期宏的封装优化:它在内部通过汇编拿到low、high两个32位值后,会直接拼接成完整的64位计数值,通过函数返回值输出。正确的取值方式是定义一个unsigned long long类型的变量,直接接收rdtsc的返回值,不需要手动拆分高低位。
  • 之前写的rdtsc(x, y)调用方式,仅适配早期带参数的宏实现,用在现代无参的内联函数上会直接触发编译错误。

2. DECLARE_ARGS宏的作用

  • 从现有宏定义可以看到,这个宏的核心作用是在rdtsc内联函数的栈帧上,声明两个unsigned long类型的局部变量low、high,专门用来承接rdtsc指令执行后从EAX、EDX寄存器读出的两个32位拆分值。
  • 这个宏是跨架构适配的通用抽象层:x86平台下它声明的两个临时变量对应rdtsc指令的两个输出操作数;其他架构下的同类高精度时间戳读取指令,如果同样需要拆分的临时存储变量,也可以复用这套宏逻辑,不需要改动上层rdtsc的对外接口。
  • 宏定义里传入的val参数在x86的宏实现里没有被使用,这是因为跨架构适配时,部分平台的时间戳读取指令会直接输出完整的64位值到单个寄存器,这时候val参数就会承接这个完整值;x86架构下因为需要拆分两个32位寄存器,所以这个参数是冗余设计。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 07:45:05