Gremlins in Legacy Object Files
Why you shouldn’t fear linking object files from different compiler versions ('cross linking') with the newest TriCore 6.1 compiler and two older versions.
When the daughter of a friend of mine was still a little girl, she could not sleep at night because she was afraid of the monsters under her bed. Her parents could talk all they wanted, it did not help; she had nightmares about those monsters. In the end my friend came up with a beautiful solution: he glued a cardboard star to a wooden stick, painted it in bright colors, added some glitter, and explained to his daughter that this magic wand would scare away the monsters. And it worked: clutching her magic wand she slept peacefully every night from then on.
With today's focus on Quality Assurance (QA), it is perfectly fine to be scared of gremlins lurking in the shadows of our software. In fact - it is recommended - because they are out to get us, and this time there's no magic wand to still our fears. The gremlins that this post deals with lurk in the deep waters of legacy object files, and how to safely link those against your v6.1r1 toolset of TriCore-VX.
The time that compilation times were significant is now so long gone, that only myths have survived. Normally, we just re-compile our source code without a second thought. Still, there are circumstances where old object files are precious enough to keep them. For example, these object files have undergone a costly certification procedure, or perhaps the source code is not available for re-compilation.
Whatever the reason, if these legacy object files have been compiled with an older version of the compiler, you have a nasty dilemma: do you also use this version for the rest of your software, or do you move on to a newer compiler? Moving on is of course tempting, but this is where the gremlins lurk; how do you know that it is safe to cross-link object files from two different compilers? After all, calling conventions may have changed, data layouts may be different, and who knows what other surprises there are?
The simplest way to find out is to just try, and if you trust your test suites that may even be an acceptable solution. However, for many people this is not good enough. They are too paranoid (read: have too strict QA requirements), and they want formal reassurances. The only one who can give these reassurances is the compiler vendor. In fact, one of our customers has asked us to give such formal reassurances: Is it safe to cross-link object files from the current TASKING TriCore compiler to object files from two older versions of the compiler?
How can we prove that linking with code from these older versions is safe? Again, there is a simple answer: trust the TriCore Embedded Applications Binary Interface (EABI)! With this EABI, Infineon, the TriCore vendor, defines the calling conventions that should be used, and since all versions of the TASKING compiler adhere to that EABI, nothing can go wrong, right? As an excercise, let's try to dig a little deeper. How do we know for sure that there is no `wiggle room' in the EABI that can cause problems? What about those options in the TASKING compilers that deviate from the EABI? Did we miss anything?
To properly address this question, we used a two-pronged approach. First, we asked our engineers to draw up a list of potential suspects. They came up with some restrictions, including obvious ones: some compiler flags enable or disable specific deviations from the standard EABI, and of course all object files should be compiled with the same settings for these flags. Just as obvious: you should use the same size for the double type everywhere, and alignment options should also match. But apart from their list of mild restrictions, they did not expect problems. We also had to add the restrictions that you shouldn't do anything undefined, such as violating array bounds, and that you should not trigger any known bugs in one of the compilers.
The second part of our answer was to methodically compare the relevant aspects of the two compilers, such as data sizes and alignments, and test the compatibility of the calling conventions. We had to make a few weak assumptions to keep testing times manageable, but assuming these assumptions were met (certainly the case for our compilers), we generated a set of tests to cover all possible cases, and passing this set of tests means two compilers are compatible.
So what's the takeaway from all this? In the introduction we already mentioned there's no magic wand that can safe you from your trepidations of cross-linking. Some restrictions must be imposed to avoid known incompatibilities, we also have to add some other disclaimers. However, given these restrictions, we can assure you that you can safely mix object files from two old versions and our current TriCore compiler. So with some added glitter from TASKING your gremlin will remain what it was supposed to be in the first place; a cuddly little pet.
Following v6.1r1, these assurances will hold for future versions of the compiler. Although currently we only support cross-linking of v4.2r2 and v5.0r2 object code, extending them to other old versions of the compiler is probably simple, but rest assured, our commitment for your application's safety, prevents us from making these promises without going through the same testing process.
To learn more about safely linking legacy object files, watch the recorded webinar “Mixing Compiler Output: How to Safely Integrate Legacy Code”