pe32: tls refactoring

This commit is contained in:
László Molnár
2014-02-18 00:23:42 +01:00
parent 9cb639b505
commit 07cba6c774
4 changed files with 114 additions and 175 deletions
-137
View File
@@ -162,143 +162,6 @@ int PackW32Pe::readFileHeader()
return super::readFileHeader();
}
//new: processTLS moved to p_w32pe.cpp for TLS callback support
/*************************************************************************
// TLS handling
**************************************************************************/
// thanks for theowl for providing me some docs, so that now I understand
// what I'm doing here :)
// 1999-10-17: this was tricky to find:
// when the fixup records and the tls area are on the same page, then
// the tls area is not relocated, because the relocation is done by
// the virtual memory manager only for pages which are not yet loaded.
// of course it was impossible to debug this ;-)
#define TLS_CB_ALIGNMENT 4u // alignment of tls callbacks
__packed_struct(tls)
LE32 datastart; // VA tls init data start
LE32 dataend; // VA tls init data end
LE32 tlsindex; // VA tls index
LE32 callbacks; // VA tls callbacks
char _[8]; // zero init, characteristics
__packed_struct_end()
void PackW32Pe::processTls(Interval *iv) // pass 1
{
COMPILE_TIME_ASSERT(sizeof(tls) == 24)
COMPILE_TIME_ASSERT_ALIGNED1(tls)
if ((sotls = ALIGN_UP(IDSIZE(PEDIR_TLS),4)) == 0)
return;
const tls * const tlsp = (const tls*) (ibuf + IDADDR(PEDIR_TLS));
// note: TLS callbacks are not implemented in Windows 95/98/ME
if (tlsp->callbacks)
{
if (tlsp->callbacks < ih.imagebase)
throwCantPack("invalid TLS callback");
else if (tlsp->callbacks - ih.imagebase + 4 >= ih.imagesize)
throwCantPack("invalid TLS callback");
unsigned v = get_le32(ibuf + tlsp->callbacks - ih.imagebase);
//NEW: TLS callback support - Stefan Widmann
if(v != 0)
{
//count number of callbacks, just for information string - Stefan Widmann
unsigned num_callbacks = 0;
unsigned callback_offset = 0;
while(get_le32(ibuf + tlsp->callbacks - ih.imagebase + callback_offset))
{
//increment number of callbacks
num_callbacks++;
//increment pointer by 4
callback_offset += 4;
}
info("TLS: %u callback(s) found, adding TLS callback handler", num_callbacks);
//set flag to include necessary sections in loader
use_tls_callbacks = true;
//define linker symbols
tlscb_ptr = tlsp->callbacks;
}
}
const unsigned tlsdatastart = tlsp->datastart - ih.imagebase;
const unsigned tlsdataend = tlsp->dataend - ih.imagebase;
// now some ugly stuff: find the relocation entries in the tls data area
unsigned pos,type;
Reloc rel(ibuf + IDADDR(PEDIR_RELOC),IDSIZE(PEDIR_RELOC));
while (rel.next(pos,type))
if (pos >= tlsdatastart && pos < tlsdataend)
iv->add(pos,type);
sotls = sizeof(tls) + tlsdataend - tlsdatastart;
// if TLS callbacks are used, we need two more DWORDS at the end of the TLS
// ... and those dwords should be correctly aligned
if (use_tls_callbacks)
sotls = ALIGN_UP(sotls, TLS_CB_ALIGNMENT) + 8;
// the PE loader wants this stuff uncompressed
otls = new upx_byte[sotls];
memset(otls,0,sotls);
memcpy(otls,ibuf + IDADDR(PEDIR_TLS),sizeof(tls));
// WARNING: this can acces data in BSS
memcpy(otls + sizeof(tls),ibuf + tlsdatastart,sotls - sizeof(tls));
tlsindex = tlsp->tlsindex - ih.imagebase;
//NEW: subtract two dwords if TLS callbacks are used - Stefan Widmann
info("TLS: %u bytes tls data and %u relocations added",sotls - (unsigned) sizeof(tls) - (use_tls_callbacks ? 8 : 0),iv->ivnum);
// makes sure tls index is zero after decompression
if (tlsindex && tlsindex < ih.imagesize)
set_le32(ibuf + tlsindex, 0);
}
void PackW32Pe::processTls(Reloc *rel,const Interval *iv,unsigned newaddr) // pass 2
{
if (sotls == 0)
return;
// add new relocation entries
unsigned ic;
//NEW: if TLS callbacks are used, relocate the VA of the callback chain, too - Stefan Widmann
for (ic = 0; ic < (use_tls_callbacks ? 16u : 12u); ic += 4)
rel->add(newaddr + ic,3);
tls * const tlsp = (tls*) otls;
// now the relocation entries in the tls data area
for (ic = 0; ic < iv->ivnum; ic += 4)
{
void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - ih.imagebase) + sizeof(tls);
unsigned kc = get_le32(p);
if (kc < tlsp->dataend && kc >= tlsp->datastart)
{
kc += newaddr + sizeof(tls) - tlsp->datastart;
set_le32(p,kc + ih.imagebase);
rel->add(kc,iv->ivarr[ic].len);
}
else
rel->add(kc - ih.imagebase,iv->ivarr[ic].len);
}
const unsigned tls_data_size = tlsp->dataend - tlsp->datastart;
tlsp->datastart = newaddr + sizeof(tls) + ih.imagebase;
tlsp->dataend = tlsp->datastart + tls_data_size;
//NEW: if we have TLS callbacks to handle, we create a pointer to the new callback chain - Stefan Widmann
tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + ih.imagebase - 8 : 0);
if(use_tls_callbacks)
{
//set handler offset
set_le32(otls + sotls - 8, tls_handler_offset + ih.imagebase);
//add relocation for TLS handler offset
rel->add(newaddr + sotls - 8, 3);
}
}
/*************************************************************************
// Load Configuration handling
**************************************************************************/