1

I'm trying to count, using rdtsc, how many cycles it takes write something using sys_write. I was able to test the printf and scanf functions. They worked correctly, and now I have a problem with system calls.

In my opinion, the problem is with %eax and %edx registers, because rdtsc saves the result in these registers.

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;
}

When I run the program I get a Segmentation fault (core dumped) error.

delvian
  • 15
  • 3
  • 1
    Is a `long long` actually supposed to be returned in `edx:eax` according to your (unknown) ABI? - also, CPUID is not needed here, nor the save of `ebx`, nor the stack frame. (well, the save of `ebx` is needed if you insist on `cpuid`). – 500 - Internal Server Error Jun 12 '19 at 12:50
  • @500-InternalServerError `cpuid` is needed as a synchronising instruction. – fuz Jun 12 '19 at 12:57
  • @500-InternalServerError You're right about stack frame, updated. – delvian Jun 12 '19 at 13:03
  • 1
    Use `lfence` instead of `cpuid` so you don't have to push/pop `ebx` in RDTSC. But yes, in 32-bit calling conventions `long long` does return in `EDX:EAX`. – Peter Cordes Jun 12 '19 at 13:05
  • 2
    Why not use [the `__rdtsc` intrinsic](https://stackoverflow.com/questions/13772567/get-cpu-cycle-count)? But the real problem is in your `print` function, which does not follow SysV ABI. (In general, when you say "I get a segmentation fault" you need to provide details, because those details often tell you where you messed up.) – Raymond Chen Jun 12 '19 at 13:08

1 Answers1

3

Your problem has nothing to do with RDTSC, and everything to do with your print() function. Reducing your problem to a MCVE would have narrowed that down.

movl $STDOUT, %ebx

You clobber EBX in your print function. You save/restore it correctly in your rdtsc function, but not print. EBX is a call-preserved register that the compiler will assume keeps its value across function calls.

If you compiled a 32-bit PIE executable, it probably used EBX for a GOT pointer, and thus faults when trying to get the address of the string literal for printf or at some point earlier.


Ironically, you don't need to save/restore EBX in your rdtsc function if you use lfence to serialize it instead of cpuid.

Or better, use _mm_lfence() + __rdtsc() intrinsics instead of asm. See Get CPU cycle count?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847