x64 link-editor is painfully literal-minded about TLS
The x64 link-editor makes erroneous assumptions about Initial Executable TLS (GOTTPOFF relocations).
The assumption is that the instruction sequences outlined in the manuals are precisely what must be used, rather than exemplars and that both register choice and precise instruction sequence are set in stone.
Neither of these assumptions is true.
The Linker & Libraries Guide actually documents one Initial Executable sequence which we will currently corrupt.
The current code is (machrel.amd.c):
626 /* 627 * Adjust 'offset' to beginning of instruction sequence. 628 */ 629 offset -= 12; 630 631 /* 632 * Same code sequence used in the GD -> LE transition. 633 */ 634 (void) memcpy(offset, tlsinstr_gd_le, sizeof (tlsinstr_gd_le)); 635 return (FIX_RELOC);
In the simple case -- GOTTPOFF code that uses the correct instruction sequence but different registers -- we will subtly corrupt the code, and provide the wrong answers to applications (as we'll stomp %rax where they want %rdi for eg., since we copy in the fixed sequence tlsinstr_gd_le (actually reusing the Global Dynamic translation)
In the more complicated case -- GOTTPOFF code where we differ from the documented instruction sequence slightly (or, because we use the 2nd sequence which we don't handle at all...) -- we will corrupt the code utterly. This happens because we blindly copy an instruction pattern the instructions prior to the relocation (see line 629), actually copying in precisely the same instruction that we believe must always be there. Because of this, if there is a surprising instruction before the relocation, we will blindly replace part of it with the text of a movq, absolutely destroying the function text.
The link-editor must be adjusted so that:
- We continue to use the intended registers after any IE->LE transition
- We only update the instruction containing the GOTTPOFF relocation, rather than blindly changing adjacent instructions.
- We fatally error if we encounter text we do not explicitly understand (to prevent recurrences of this bug in the form of silent corruption).
Updated by Rich Lowe about 8 years ago
- % Done changed from 30 to 70
It's going to prove fairly challenging to test this, but I have code that very likely works maybe 90% of the time-ish.
I'll write up an evaluation, etc, once I can restate that first sentence without all the hedging.
The basic premise is that our code for handling Initial Executable transitions is wrong in almost every respect. Unfortunately, fooling around with the corner cases of this has found that there is at least one case that everyone else screws up too, so we can't just compare ourselves to known correct output.