---
title: 替换x86 rdtsc汇编指令
description: "编译报错：error: impossible constraint in ‘asm’__asm__ __volatile__(\"rdtsc\" : \"=a\" (lo), \"=d\" (hi));。"
url: https://www.hikunpeng.com/document/detail/zh/kunpenggrf/codeprtr/kunpengtaishanporting_12_0030.html
sourcePath: /source/zh/kunpenggrf/codeprtr/kunpengtaishanporting_12_0030.html
indexId: a2d1f9ed8d49660694f3650509a1e21709f83937b02d4ed7350c2215150fd0a465
---
# 替换x86 rdtsc汇编指令

#### 现象描述

编译报错：error: impossible constraint in ‘asm’__asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi));。


#### 问题原因

TSC是时间戳计数器的缩写，它是Pentium兼容处理器中的一个计数器，它记录自启动以来处理器消耗的时钟周期数。在每个时钟到来时，该计数器自动加一。因为TSC随着处理器周期速率的变化而变化，所以它提供了非常高的精确度。它经常被用来分析和检测代码。x86平台TSC的值可以通过rdtsc指令来读取，鲲鹏平台需要使用类似算法实现。


#### 处理步骤

x86平台实现样例：

```
static inline uint64_t Rdtsc()
{
uint32_t lo, hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
```

鲲鹏平台实现样例：

- 方法一：使用Linux提供的获取时间函数clock_gettime进行近似替换。

```
#include <time.h>
static inline uint64_t Rdtsc()
{
struct timespec tmp;
clock_gettime(CLOCK_MONOTONIC, &tmp);
return tmp.tv_sec*2400000000+(uint64_t)tmp.tv_nsec*2.4; //2400000000和2.4基于服务器主频而定
}
```


- 方法二：鲲鹏有Performance Monitors Control Register系列寄存器，其中PMCCNTR_EL0就类似于x86的TSC寄存器。但默认情况下用户态是不可读的，需要内核态使能后才能读取。请参见GitHub网站(https://github.com/jerinjacobk/armv8_pmu_cycle_counter_el0)编译内核模块，开启对系统寄存器的访问。

  1. 下载源码。

```
git clone https://github.com/jerinjacobk/armv8_pmu_cycle_counter_el0
```


  2. 执行make命令。
  3. 执行insmod pmu_el0_cycle_counter.ko命令安装内核模块，使能内核态（初次执行即可）。
  4. 代码替换。

```
static inline uint64_t
read_pmccntr(void)
{
uint64_t val;
asm volatile("mrs %0, pmccntr_el0" : "=r"(val));
return val;
}
```
