0

My code is written in C++, and compiled with gcc version 4.7.2. It's linked with 3rd party library, which is written in C, and compiled with gcc 4.5.2. My code calls a function initStuff(). During the debug I found out that the value of R15 register before the call to initStuff() is not the same as the value upon return from that function. As a quick hack I did:

asm(" mov %%r15, %0" : "=r" ( saveR15 ) );
initStuff();
asm(" mov %0, %%r15;" : : "r" (saveR15) );

which seems to work for now. Who is to blame here? How can I find if it's a compiler issue, or maybe compatibility issue?

Soumendra Mishra
  • 3,483
  • 1
  • 12
  • 38
Tanya
  • 1
  • I'm [told](https://stackoverflow.com/a/23895527/2189500) that gcc changed some ABI implementation details in 4.7. If so, mixing/matching 4.7.2 with 4.5.2 may not work as expected. – David Wohlferd Sep 15 '20 at 02:06

1 Answers1

1

gcc on x86-64 follows the System V ABI, which defines r15 as a callee-saved register; any function which uses this register is supposed to save and restore it.

So if this third-party function is not doing so, it is failing to conform to the ABI, and unless this is documented, it is to blame. AFAIK this part of the ABI has been stable forever, so if compiler-generated code (with default options) is failing to save and restore r15, that would be a compiler bug. More likely some part of the third-party code uses assembly language and is buggy, or conceivably it was built with non-standard compiler options.

You can either dig into it, or as a workaround, write a wrapper around it that saves and restores r15. Your current workaround is not really safe, since the compiler might reorder your asm statements with respect to surrounding code. You should instead put the call to initStuff inside a single asm block with the save-and-restore (declaring it as clobbering all caller-saved registers), or write a "naked" assembly wrapper which does the save/restore and call, and call it instead. (Make sure to preserve stack alignment.)

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • OP didn't specify so I'll note that x86-64 on Windows using a different [calling convention](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019#callercallee-saved-registers). Although R15 is callee saved there as well. – David Wohlferd Sep 15 '20 at 02:50
  • 1
    "You should instead put the call to initStuff inside a single asm block" - Turns out making `call`s from inline asm is [trickier](https://stackoverflow.com/a/37503773/2189500) than you might think. What's more, if `initstuff` doesn't follow the abi, you have to suspect that other routines in the library could have similar problems, some even more obscure. Without understanding what's going on, trying to wrap this particular call seems risky. – David Wohlferd Sep 15 '20 at 06:38