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

为何仅首次读取CNTVCT_EL0寄存器能得到有效值?

问题描述

在Xcode 15.4(运行于macOS 14.5的2020款M1 Mac mini)中创建终端应用,编写如下代码读取ARM64的系统计数器寄存器CNTVCT_EL0:

#include <stdint.h>
#include <stdio.h>
#include <string.h>

uint64_t getfreq(void) {
    uint64_t value=0;
    asm("isb; mrs %0, CNTVCT_EL0" : "=r"(value));
    return value;
}

int main() {
    do {
        printf("CNTVCT_EL0 = 0x%016llX\n", getfreq());
    } while(1);
}

运行后仅首次输出有效,后续输出均为0x0000000000000001,无循环时结果相同。询问原因及解决办法。

解决办法

修改getfreq函数中的汇编语句,添加volatile关键字:

uint64_t getfreq(void) {
    uint64_t value=0;
    asm volatile("isb; mrs %0, CNTVCT_EL0" : "=r"(value));
    return value;
}
原因解释

Xcode使用的Clang编译器会对未标记volatile的汇编语句进行优化:编译器默认认为这类汇编代码没有副作用,多次调用时会尝试复用之前的计算结果,甚至在某些优化级别下会错误地将结果替换为固定常量。

添加volatile关键字后,编译器会明确知晓该汇编语句存在副作用(每次执行都会读取硬件寄存器的新值),因此会确保每次调用getfreq时都执行完整的汇编指令,不会进行不合理的优化。

若开启了-O2及以上的编译优化级别,这种优化行为会更明显,而volatile可以直接规避该问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:51:10