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.
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?