RDTSC和系统调用sys_read和sys_write

时间:2019-06-12 12:45:29

标签: c assembly x86 att rdtsc

我试图使用rdtsc来计算使用sys_write写东西需要多少个周期。我能够测试printf和scanf函数。他们工作正常,现在我在系统调用方面遇到了问题。

在我看来,问题出在%eax和%edx寄存器上,因为rdtsc将结果保存在这些寄存器中。

write.s

.data
SYS_EXIT = 1
SYS_WRITE = 4
STDOUT = 1
EXIT_SUCCES = 0
text: .ascii  "Hello from assembler\n"
textLength: .long   . - text

.section .text
.globl print
.type print, @function             
print:


  movl $SYS_WRITE, %eax
  movl $STDOUT, %ebx
  movl $text, %ecx
  movl textLength, %edx
  int $0x80

  ret

rdtsc.s

.data
.text

.globl rdtsc

rdtsc:
   push %ebx
   xor %eax, %eax
   cpuid
   rdtsc
   pop %ebx
ret

main.c


#include <stdio.h>

unsigned long long rdtsc();
extern void print();
unsigned long long startTime, stopTime, workingTime;

int main (void)
{
            startTime = rdtsc();
        print();
        stopTime = rdtsc();
        workingTime = stopTime - startTime;
        printf("Cycles %llu\n", workingTime);
return 0;
}

当我运行程序时,出现分段错误(核心转储)错误。

1 个答案:

答案 0 :(得分:3)

您的问题与RDTSC无关,与您的print()函数无关。将您的问题减少到MCVE可以缩小范围。

movl $STDOUT, %ebx

您可以在print函数中破坏EBX 。您可以正确地将其保存/恢复到rdtsc函数中,而不是print中。 EBX是一个调用保留的寄存器,编译器将假定它在函数调用之间保持其值。

如果编译了32位PIE可执行文件,则它可能使用EBX作为GOT指针,因此在尝试获取printf或更早的字符串文字的地址时出错。


具有讽刺意味的是,如果您使用rdtsc而不是lfence对其进行序列化,则无需在cpuid函数中保存/恢复EBX。

或者更好,使用_mm_lfence() + __rdtsc()内在函数而不是asm。参见Get CPU cycle count?