I'm implementing a function which is going to perform some time-consuming task, and I'd like to hack the benchmarking part a bit by changing the variable indicating the CPU time my function has started executing. Here is the code:

#if defined(_MSC_VER)
#pragma intrinsic(__rdtsc)
static __inline__ uint64_t __rdtsc() {
    uint32_t hi, lo;
    __asm__ volatile
        : "=a"(lo), "=d"(hi)
    return (((uint64_t) hi) << 32) | ((uint64_t) lo);

int arg = 42;

uint64_t start_tSC, end_tSC;

// Get total clock cycles for func
start_tSC = __rdtsc();
end_tSC = __rdtsc();
double func_tSC = end_tSC - start_tSC;  // <---- let's minimize this

Basically, I want to set start_tSC to the current clock time-stamp right before all tasks have been completed within func.

void func(int arg) {
    /* black magic that resets start_tSC in the CALLER */

Since local variables and function parameters tend to be stored on the stack, can I somehow deduce where start_tSC resides by looking at the address of arg?

System information

~ $ uname -a
Linux hive30 4.15.0-36-generic #39~16.04.1-Ubuntu SMP Tue Sep 25 08:59:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Also note that I have access to the target system as a normal user, which means I can build the executable as well as view the resulting assembly code via gcc -S. Here is some hardware information, if relevant.

  • please do not cross post your questions Oct 29 '18 at 3:21
  • Not very related to reverse engineering.
    – user202729
    Oct 29 '18 at 16:06

To make the offset irrelevent to your stack frame size, i'd start by reading the address of the caller's stack frame pointer (the caller's ebp, located right before your return address, at DWORD PTR [ebp]).

You cannot assume the offset of start_tSC doesn't change as your code can be run with different versions of benchmarks.

Before explaining the idea, it operates under the assumption that the call for [GetSystemTimeAsFileTime, __rdtsc, GetTickCount or any other function ] is performed right before the call for your function. The justification for this assumption is that when preforming benchmarks, precision is essential and timing tend to wrap the tested code as close as possible.

The basic idea is to find the variable that contains the value that returns from the timing function.
You can read the return address from the memory (at DWORD PTR [ebp + 4]) and try to disassemble the code prior to your function until you find a call instruction (skip the call to your own function as the return address points right after this call). the instruction after the call should look something like:

MOV [ebp - offset], eax

and you can deduce the offset of start_tSC from here.

Do note that disassemble code backwards is not straightforward as x86 code doesn't have constant length opcodes.
Also note that this solution requires more code, expanding the function size by (probably) a lot.

  • You seem to have missed the point of the question with this proposal to modify the code of the caller. The point is to modify the behavior of the existing calling code, without actually changing that code. Dec 28 '18 at 16:12
  • 1
    oh, yea, i see it now. my bad. i really misunderstood the question here
    – Frowner
    Dec 28 '18 at 16:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.