Remove BPatch_process::setMutationsActive, disable test1_15, and remove associated...
[dyninst.git] / symtabAPI / src / emitElfStatic-x86.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 /* 
32  * holds architecture specific functions for x86 and x86_64 architecture needed for the
33  * static executable rewriter
34  */
35
36 #include <cstdlib>
37 #include <cstdio>
38 #include <cassert>
39 #include <iostream>
40 #include <set>
41 #include <map>
42 #include <sstream>
43
44 #include "emitElfStatic.h"
45 #include "Symtab.h"
46 #include "Symbol.h"
47 #include "Archive.h"
48 #include "Object.h"
49 #include "Region.h"
50 #include "debug.h"
51
52 using namespace Dyninst;
53 using namespace Dyninst::SymtabAPI;
54
55 static const Offset GOT_RESERVED_SLOTS = 3;
56 static const unsigned X86_WIDTH = 4;
57 static const unsigned X86_64_WIDTH = 8;
58
59 #if defined(os_freebsd)
60 #define R_X86_64_JUMP_SLOT R_X86_64_JMP_SLOT
61 #endif
62
63 // Used in an assert so needs to be a macro
64 #define UNKNOWN_ADDRESS_WIDTH_ASSERT "An unknown address width was encountered, can't continue"
65
66 /* NOTE:
67  * As most of these functions are defined per architecture, the description of
68  * each of these functions is in the emitElfStatic header. Comments describing
69  * the function interface are explicitly left out.
70  */
71
72 /**
73  * Specific to x86
74  *
75  * Given a relocation, determines if the relocation corresponds to a .ctors or .dtors
76  * table that requires special consideration. Modifies the passed symbol offset to
77  * point to the right table, if applicable.
78  *
79  * rel          The relocation entry to examine
80  * globalOffset The offset of the linked code (used for symbol offset calculation)
81  * lmap         Holds information about .ctors/.dtors tables
82  * errMsg       Set on error
83  * symbolOffset Modified by this routine to contain the offset of the table
84  *
85  * Returns true, if there are no errors including the case where the relocation 
86  * entry doesn't reference the .ctors/.dtors tables.
87  */
88 static bool computeCtorDtorAddress(relocationEntry &rel, Offset globalOffset,
89         LinkMap &lmap, string &errMsg, Offset &symbolOffset)
90 {
91     if( rel.name() ==  SYMTAB_CTOR_LIST_REL ) {
92         // This needs to be: (the location of the .ctors table)
93         if( lmap.newCtorRegions.size() > 0 ) {
94             symbolOffset = lmap.ctorRegionOffset + globalOffset;
95         }else if( lmap.originalCtorRegion != NULL ) {
96             symbolOffset = lmap.originalCtorRegion->getRegionAddr();
97         }else{
98             errMsg = "Failed to locate original .ctors Region -- cannot apply relocation";
99             return false;
100         }
101     }else if( rel.name() == SYMTAB_DTOR_LIST_REL ) {
102         // This needs to be: (the location of the .dtors table)
103         if( lmap.newDtorRegions.size() > 0 ) {
104             symbolOffset = lmap.dtorRegionOffset + globalOffset;
105         }else if( lmap.originalDtorRegion != NULL ) {
106             symbolOffset = lmap.originalDtorRegion->getRegionAddr();
107         }else{
108             errMsg = "Failed to locate original .dtors Region -- cannot apply relocation";
109             return false;
110         }
111     }
112
113     return true;
114 }
115
116 bool emitElfStatic::archSpecificRelocation(Symtab *, Symtab *, char *targetData, relocationEntry &rel,
117        Offset dest, Offset relOffset, Offset globalOffset, LinkMap &lmap,
118        string &errMsg) 
119 {
120    cerr << "archSpecificRelocation @ " << hex << dest << " /w/ offset " << globalOffset << dec << endl;
121     if( X86_WIDTH == addressWidth_ ) {
122         /*
123          * Referring to the SYSV 386 supplement:
124          *
125          * All relocations on x86 are one word32 == Elf32_Word
126          *
127          * S = symbolOffset
128          * A = addend
129          * P = relOffset
130          */
131        
132         Offset symbolOffset = rel.getDynSym()->getOffset();
133
134         Elf32_Word addend;
135         if( rel.regionType() == Region::RT_REL ) {
136             memcpy(&addend, &targetData[dest], sizeof(Elf32_Word));
137         }else if( rel.regionType() == Region::RT_RELA ) {
138             addend = rel.addend();
139         }
140
141         if( !computeCtorDtorAddress(rel, globalOffset, lmap, errMsg, symbolOffset) ) {
142             return false;
143         }
144
145         rewrite_printf("relocation for '%s': TYPE = %s(%lu) S = %lx A = %lx P = %lx\n",
146                 rel.name().c_str(), 
147                 relocationEntry::relType2Str(rel.getRelType(), addressWidth_),
148                 rel.getRelType(), symbolOffset, addend, relOffset);
149
150         Offset relocation = 0;
151         map<Symbol *, Offset>::iterator result;
152         stringstream tmp;
153
154         switch(rel.getRelType()) {
155             case R_386_32:
156                 relocation = symbolOffset + addend;
157                 break;
158             case R_386_PLT32: // this works because the address of the symbol is known at link time
159             case R_386_PC32:
160                 relocation = symbolOffset + addend - relOffset;
161                 break;
162             case R_386_TLS_LE: // The necessary value is set during storage allocation
163             case R_386_GLOB_DAT:
164             case R_386_JMP_SLOT:
165                 relocation = symbolOffset;
166                 break;
167             case R_386_TLS_GD: // The address is computed when the GOT is built
168             case R_386_GOT32: 
169             case R_386_TLS_GOTIE:
170                 result = lmap.gotSymbols.find(rel.getDynSym());
171                 if( result == lmap.gotSymbols.end() ) {
172                     errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
173                     return false;
174                 }
175
176                 relocation = result->second;
177                 break;
178             case R_386_GOTOFF:
179                 relocation = symbolOffset + addend - (lmap.gotRegionOffset + globalOffset);
180                 break;
181             case R_386_GOTPC:
182                 relocation = globalOffset + lmap.gotRegionOffset + addend - relOffset;
183                 break;
184             case R_386_TLS_IE:
185                 result = lmap.gotSymbols.find(rel.getDynSym());
186                 if( result == lmap.gotSymbols.end() ) {
187                     errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
188                     return false;
189                 }
190
191                 relocation = result->second + lmap.gotRegionOffset + globalOffset;
192                 break;
193             case R_386_COPY:
194             case R_386_RELATIVE:
195                 tmp << "ERROR: encountered relocation type(" << rel.getRelType() << 
196                        ") that is meant for use during dynamic linking";
197                 errMsg = tmp.str();
198                 return false;
199             default:
200                 tmp << "Relocation type " << rel.getRelType() 
201                     << " currently unimplemented";
202                 errMsg = tmp.str();
203                 return false;
204         }
205
206         rewrite_printf("relocation = 0x%lx @ 0x%lx\n", relocation, relOffset);
207
208         memcpy(&targetData[dest], &relocation, sizeof(Elf32_Word));
209     }else if( X86_64_WIDTH == addressWidth_ ) {
210         /*
211          * Referring to the SYSV supplement:
212          *
213          * There are a few data types used by x86_64 relocations.
214          *
215          * word8 = uint8_t
216          * word16 = uint16_t
217          * word32 = Elf64_Word
218          * word64 = Elf64_Xword
219          *
220          * S = symbolOffset
221          * A = addend
222          * P = relOffset
223          * Z = symbolSize
224          *
225          * x86_64 only uses relocations that contain the addend.
226          */
227         Offset symbolOffset = rel.getDynSym()->getOffset();
228         unsigned symbolSize = rel.getDynSym()->getSize();
229
230         Elf64_Xword addend = 0;
231         if( Region::RT_RELA == rel.regionType() ) {
232             addend = rel.addend();
233         }
234
235         if( !computeCtorDtorAddress(rel, globalOffset, lmap, errMsg, symbolOffset) ) {
236             return false;
237         }
238
239         rewrite_printf("relocation for '%s': TYPE = %s(%lu) S = %llx A = %llx P = %llx Z = %lx\n",
240                 rel.name().c_str(), 
241                 relocationEntry::relType2Str(rel.getRelType(), addressWidth_),
242                 rel.getRelType(),
243                 symbolOffset, addend, relOffset, symbolSize);
244
245         Offset relocation = 0;
246         unsigned fieldSize = 0; // This is set depending on the type of relocation
247         map<Symbol *, Offset>::iterator result;
248         stringstream tmp;
249
250         switch(rel.getRelType()) {
251             case R_X86_64_64:
252                 fieldSize = sizeof(Elf64_Xword);
253                 relocation = symbolOffset + addend;
254                 break;
255             case R_X86_64_PLT32:
256             case R_X86_64_PC32:
257                 fieldSize = sizeof(Elf64_Word);
258                 relocation = symbolOffset + addend - relOffset;
259                 break;
260             case R_X86_64_GOT32: // The address is computed when the GOT is built
261                 fieldSize = sizeof(Elf64_Word);
262                 result = lmap.gotSymbols.find(rel.getDynSym());
263                 if( result == lmap.gotSymbols.end() ) {
264                     errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
265                     return false;
266                 }
267
268                 relocation = result->second + addend;
269                 break;
270             case R_X86_64_TPOFF32: // The necessary value is set during storage allocation
271                 fieldSize = sizeof(Elf64_Word);
272                 relocation = symbolOffset;
273                 break;
274             case R_X86_64_GLOB_DAT:
275             case R_X86_64_JUMP_SLOT:
276                 fieldSize = sizeof(Elf64_Xword);
277                 relocation = symbolOffset;
278                 break;
279             case R_X86_64_TLSLD: // Load the symbol offset from the GOT
280             case R_X86_64_TLSGD: 
281             case R_X86_64_GOTTPOFF:
282             case R_X86_64_GOTPCREL:
283                 fieldSize = sizeof(Elf64_Word);
284
285                 result = lmap.gotSymbols.find(rel.getDynSym());
286                 if( result == lmap.gotSymbols.end() ) {
287                     errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
288                     return false;
289                 }
290
291                 relocation = result->second + lmap.gotRegionOffset + 
292                     globalOffset + addend - relOffset;
293                 break;
294             case R_X86_64_DTPOFF32:
295                 fieldSize = sizeof(Elf64_Word);
296                 relocation = addend;
297                 break;
298             case R_X86_64_32:
299             case R_X86_64_32S:
300                 fieldSize = sizeof(Elf64_Word);
301                 relocation = symbolOffset + addend;
302                 break;
303             case R_X86_64_16:
304                 fieldSize = sizeof(uint16_t);
305                 relocation = symbolOffset + addend;
306                 break;
307             case R_X86_64_PC16:
308                 fieldSize = sizeof(uint16_t);
309                 relocation = symbolOffset + addend - relOffset;
310                 break;
311             case R_X86_64_8:
312                 fieldSize = sizeof(uint8_t);
313                 relocation = symbolOffset + addend;
314                 break;
315             case R_X86_64_PC8:
316                 fieldSize = sizeof(uint8_t);
317                 relocation = symbolOffset + addend - relOffset;
318                 break;
319             case R_X86_64_RELATIVE:
320             case R_X86_64_COPY:
321                 tmp << "ERROR: encountered relocation type(" << rel.getRelType() << 
322                        ") that is meant for use during dynamic linking";
323                 errMsg = tmp.str();
324                 return false;
325             case R_X86_64_DTPMOD64:
326             case R_X86_64_DTPOFF64:
327             case R_X86_64_TPOFF64:
328             default:
329                 tmp << "Relocation type " << rel.getRelType() 
330                     << " currently unimplemented";
331                 errMsg = tmp.str();
332                 return false;
333         }
334
335         rewrite_printf("relocation = 0x%llx @ 0x%llx\n", relocation, relOffset);
336
337         memcpy(&targetData[dest], &relocation, fieldSize);
338     }else{
339         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
340     }
341
342     return true;
343 }
344
345 static const string LIBC_ATEXIT_INTERNAL("__cxa_exit");
346 static const string LIBC_ATEXIT("atexit");
347
348 bool emitElfStatic::checkSpecialCaseSymbols(Symtab *member, Symbol *checkSym) {
349     /* 
350      * Special Case 1
351      *
352      * When linking code into stripped binaries, some linked functions will not
353      * work correctly because they rely on some state being initialized or
354      * updated in the original binary.
355      *
356      * For example, the libc function atexit internally keeps a list of
357      * functions to call after the main function returns. When main returns,
358      * this list is processed by libc finalization code. 
359      * 
360      * When the original binary is stripped, there is a disconnect between the
361      * atexit function in the linked code and the original atexit function.
362      * Consequently, any functionality that relies on atexit will not work
363      * (i.e. destructors for global C++ objects).
364      *
365      * The initial release of the binary rewriter for static binaries doesn't
366      * provide a solution to this problem. Therefore, a warning needs to be
367      * generated to alert the user to this outstanding problem.
368      */
369     if( isStripped_ ) {
370         if( LIBC_ATEXIT_INTERNAL == checkSym->getPrettyName() ||
371             LIBC_ATEXIT == checkSym->getPrettyName() )
372         {
373             fprintf(stderr, "WARNING: code in %s(%s) references the libc function %s.\n",
374                     member->getParentArchive()->name().c_str(),
375                     member->memberName().c_str(), checkSym->getPrettyName().c_str());
376             fprintf(stderr, "         Also, the binary to be rewritten is stripped.\n");
377             fprintf(stderr, "         Currently, the combination of these two "
378                             "is unsupported and unexpected behavior may occur.\n");
379         }
380     }
381
382     return true;
383 }
384
385 /* The TLS implementation on x86 is Variant 2 */
386
387 Offset emitElfStatic::layoutTLSImage(Offset globalOffset, Region *dataTLS, Region *bssTLS, LinkMap &lmap) {
388     return tlsLayoutVariant2(globalOffset, dataTLS, bssTLS, lmap);
389 }
390
391 Offset emitElfStatic::adjustTLSOffset(Offset curOffset, Offset tlsSize) {
392     return tlsAdjustVariant2(curOffset, tlsSize);
393 }
394
395 char emitElfStatic::getPaddingValue(Region::RegionType rtype) {
396     const char X86_NOP = 0x90;
397
398     char retChar = 0;
399     if( rtype == Region::RT_TEXT || rtype == Region::RT_TEXTDATA ) {
400         retChar = X86_NOP;
401     }
402
403     return retChar;
404 }
405
406 void emitElfStatic::cleanupTLSRegionOffsets(map<Region *, LinkMap::AllocPair> &regionAllocs,
407         Region *dataTLS, Region *bssTLS) 
408 {
409     tlsCleanupVariant2(regionAllocs, dataTLS, bssTLS);
410 }
411
412 void emitElfStatic::getExcludedSymbolNames(set<string> &symNames) {
413     /*
414      * It appears that some .o's have a reference to _GLOBAL_OFFSET_TABLE_
415      * This symbol is an indication to the linker that a GOT should be 
416      * created, it isn't a symbol that should be resolved. 
417      *
418      * Consequently, a GOT shouldn't always be created when linking 
419      * the .o's into the target. A GOT is built when certain relocations
420      * exist that require a GOT.
421      */
422     symNames.insert("_GLOBAL_OFFSET_TABLE_");
423 }
424
425 bool emitElfStatic::isGOTRelocation(unsigned long relType) {
426     if( X86_WIDTH == addressWidth_ ) {
427         switch(relType) {
428             case R_386_GOT32:
429             case R_386_TLS_IE:
430             case R_386_TLS_GOTIE:
431             case R_386_TLS_LDM:
432             case R_386_TLS_GD:
433                 return true;
434                 break;
435             default:
436                 return false;
437                 break;
438         }
439     }else if( X86_64_WIDTH == addressWidth_ ) {
440         switch(relType) {
441             case R_X86_64_TLSLD:
442             case R_X86_64_TLSGD:
443             case R_X86_64_GOTTPOFF:
444             case R_X86_64_GOT32:
445             case R_X86_64_GOTPCREL:
446                 return true;
447                 break;
448             default:
449                 return false;
450                 break;
451         }
452     }else{
453         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
454     }
455
456     return false;
457 }
458
459 Offset emitElfStatic::getGOTSize(LinkMap &lmap) {
460     Offset size = 0;
461
462     unsigned slotSize = 0;
463     if( X86_WIDTH == addressWidth_ ) {
464         slotSize = sizeof(Elf32_Addr);
465     }else if( X86_64_WIDTH == addressWidth_ ) {
466         slotSize = sizeof(Elf64_Addr);
467     }else{
468         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
469     }
470
471     // According to the ELF abi, entries 0, 1, 2 are reserved in a GOT on x86
472     if( lmap.gotSymbols.size() > 0 ) {
473         size = (lmap.gotSymbols.size()+GOT_RESERVED_SLOTS)*slotSize;
474     }
475
476     return size;
477 }
478
479 Offset emitElfStatic::getGOTAlign(LinkMap &) {
480     if( X86_WIDTH == addressWidth_ ) {
481         return sizeof(Elf32_Word);
482     }else if( X86_64_WIDTH == addressWidth_ ) {
483         return sizeof(Elf64_Xword);
484     }else{
485         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
486     }
487
488     return 0;
489 }
490
491 void emitElfStatic::buildGOT(LinkMap &lmap) {
492     char *targetData = lmap.allocatedData;
493
494     unsigned slotSize = 0;
495     if( X86_WIDTH == addressWidth_ ) {
496         slotSize = sizeof(Elf32_Addr);
497     }else if( X86_64_WIDTH == addressWidth_ ) {
498         slotSize = sizeof(Elf64_Addr);
499     }else{
500         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
501     }
502
503     // For each GOT symbol, allocate an entry and copy the value of the
504     // symbol into the table, additionally store the offset in the GOT
505     // back into the map
506     Offset curOffset = GOT_RESERVED_SLOTS*slotSize;
507     memset(&targetData[lmap.gotRegionOffset], 0, GOT_RESERVED_SLOTS*slotSize);
508
509     map<Symbol *, Offset>::iterator sym_it;
510     for(sym_it = lmap.gotSymbols.begin(); sym_it != lmap.gotSymbols.end(); ++sym_it) {
511         Offset value = sym_it->first->getOffset();
512         memcpy(&targetData[lmap.gotRegionOffset + curOffset], &value, slotSize);
513
514         sym_it->second = curOffset;
515
516         curOffset += slotSize;
517     }
518 }
519
520 /*
521  * .ctors and .dtors section handling
522  * 
523  * .ctors/.dtors sections are not defined by the ELF standard, LSB defines them.
524  * This is why this implementation is specific to Linux and x86.
525  *
526  * Layout of .ctors and .dtors sections on Linux x86
527  *
528  * Executable .ctors/.dtors format (size in bytes = n)
529  *
530  *  byte 0..3    byte 4..7     byte 8..11        byte n-4..n-1
531  * 0xffffffff <func. ptr 1> <func. ptr 2> ...  0x00000000
532  *
533  * Relocatable file .ctors/.dtors format (size in bytes = n)
534  *
535  *   byte 0..3         byte n-4..n-1
536  * <func. ptr 1> ... <last func. ptr>
537  *
538  * The layout is the same on Linux x86_64 except each entry is 8 bytes
539  * instead of 4. So the header and trailler are the same, but extended to
540  * 8 bytes.
541  */
542 static const Elf64_Word X86_HEADER = 0xffffffff;
543 static const Elf64_Word X86_TRAILER = 0x00000000;
544 static const Elf64_Xword X86_64_HEADER = 0xffffffffffffffffULL;
545 static const Elf64_Xword X86_64_TRAILER = 0x0000000000000000ULL;
546 static const string DTOR_NAME(".dtors");
547 static const string CTOR_NAME(".ctors");
548
549 bool emitElfStatic::isConstructorRegion(Region *reg) {
550     return ( CTOR_NAME.compare(reg->getRegionName()) == 0 );
551 }
552
553 bool emitElfStatic::isGOTRegion(Region *) {
554         return false;
555 }
556
557 Offset emitElfStatic::layoutNewCtorRegion(LinkMap &lmap) {
558     /* 
559      * .ctors sections are processed in reverse order on Linux x86. New .ctors
560      * sections need to be placed before the original .ctors section
561      */
562     Offset retOffset = lmap.ctorRegionOffset; 
563     retOffset += addressWidth_;
564
565     pair<map<Region *, LinkMap::AllocPair>::iterator, bool> result;
566
567     vector<Region *>::iterator reg_it;
568     for(reg_it = lmap.newCtorRegions.begin(); reg_it != lmap.newCtorRegions.end(); ++reg_it) {
569         result = lmap.regionAllocs.insert(make_pair(*reg_it, make_pair(0, retOffset)));
570
571         // If the map already contains this Region, this is a logic error
572         if( !result.second ) {
573             return ~0UL;
574         }
575
576         retOffset += (*reg_it)->getDiskSize();
577     }
578
579     if( lmap.originalCtorRegion != NULL ) {
580         // Account for original .ctors section (minus the header and trailer)
581         retOffset += lmap.originalCtorRegion->getDiskSize() - addressWidth_ - addressWidth_;
582     }
583     retOffset += addressWidth_;
584
585     return retOffset;
586 }
587
588 bool emitElfStatic::createNewCtorRegion(LinkMap &lmap) {
589     char *targetData = lmap.allocatedData;
590
591     if( X86_WIDTH != addressWidth_ && X86_64_WIDTH != addressWidth_ ) {
592         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
593     }
594
595     unsigned trailerSize, headerSize;
596
597     /* Give the new Region a header and trailer */
598     Offset headerOffset = lmap.ctorRegionOffset;
599     Offset trailerOffset;
600     if( X86_WIDTH == addressWidth_ ) {
601         memcpy(&targetData[headerOffset], &X86_HEADER, sizeof(X86_HEADER));
602         trailerOffset = lmap.ctorRegionOffset + lmap.ctorSize - sizeof(X86_TRAILER);
603         memcpy(&targetData[trailerOffset], &X86_TRAILER, sizeof(X86_TRAILER));
604         headerSize = sizeof(X86_HEADER);
605         trailerSize = sizeof(X86_TRAILER);
606     }else{
607         memcpy(&targetData[headerOffset], &X86_64_HEADER, sizeof(X86_64_HEADER));
608         trailerOffset = lmap.ctorRegionOffset + lmap.ctorSize - sizeof(X86_64_TRAILER);
609         memcpy(&targetData[trailerOffset], &X86_64_TRAILER, sizeof(X86_64_TRAILER));
610         headerSize = sizeof(X86_64_HEADER);
611         trailerSize = sizeof(X86_64_TRAILER);
612     }
613
614     if( lmap.originalCtorRegion != NULL ) {
615         /* Determine where the original .ctors section should be placed */
616         Offset originalOffset = lmap.ctorRegionOffset + lmap.ctorSize - 
617             trailerSize - (lmap.originalCtorRegion->getDiskSize() - headerSize - trailerSize);
618
619         /* Copy the original .ctors section w/o the header and trailer */
620         char *rawRegionData = reinterpret_cast<char *>(lmap.originalCtorRegion->getPtrToRawData());
621         memcpy(&targetData[originalOffset], &rawRegionData[headerSize],
622                 lmap.originalCtorRegion->getDiskSize() - headerSize - trailerSize);
623     }
624
625     return true;
626 }
627
628 bool emitElfStatic::isDestructorRegion(Region *reg) {
629     return ( DTOR_NAME.compare(reg->getRegionName()) == 0 );
630 }
631
632 Offset emitElfStatic::layoutNewDtorRegion(LinkMap &lmap) {
633     /*
634      * .dtors sections are processed in forward order on Linux x86. So new
635      * .dtors sections need to be placed after the original .dtors section
636      */
637     Offset retOffset = lmap.dtorRegionOffset;
638     retOffset += addressWidth_;
639
640     pair<map<Region *, LinkMap::AllocPair>::iterator, bool> result;
641     if( lmap.originalDtorRegion != NULL ) {
642         // Account for the original .dtors section (minus the header and trailer)
643         retOffset += lmap.originalDtorRegion->getDiskSize() - addressWidth_ - addressWidth_;
644     }
645
646     vector<Region *>::iterator reg_it;
647     for(reg_it = lmap.newDtorRegions.begin(); reg_it != lmap.newDtorRegions.end(); ++reg_it) {
648         result = lmap.regionAllocs.insert(make_pair(*reg_it, make_pair(0, retOffset)));
649
650         // If the map already contains this Region, this is a logic error
651         if( !result.second ) {
652             return ~0UL;
653         }
654
655         retOffset += (*reg_it)->getDiskSize();
656     }
657
658     retOffset += addressWidth_;
659     return retOffset;
660 }
661
662 bool emitElfStatic::createNewDtorRegion(LinkMap &lmap) {
663     char *targetData = lmap.allocatedData;
664
665     if( X86_WIDTH != addressWidth_ && X86_64_WIDTH != addressWidth_ ) {
666         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
667     }
668
669     unsigned headerSize, trailerSize;
670
671     /* Give the new Region a header and trailer */
672     Offset headerOffset = lmap.dtorRegionOffset;
673     Offset trailerOffset;
674     if( X86_WIDTH == addressWidth_ ) {
675         memcpy(&targetData[headerOffset], &X86_HEADER, sizeof(X86_HEADER));
676         trailerOffset = lmap.dtorRegionOffset + lmap.dtorSize - sizeof(X86_TRAILER);
677         memcpy(&targetData[trailerOffset], &X86_TRAILER, sizeof(X86_TRAILER));
678         headerSize = sizeof(X86_HEADER);
679         trailerSize = sizeof(X86_TRAILER);
680     }else{
681         memcpy(&targetData[headerOffset], &X86_64_HEADER, sizeof(X86_64_HEADER));
682         trailerOffset = lmap.dtorRegionOffset + lmap.dtorSize - sizeof(X86_64_TRAILER);
683         memcpy(&targetData[trailerOffset], &X86_64_TRAILER, sizeof(X86_64_TRAILER));
684         headerSize = sizeof(X86_64_HEADER);
685         trailerSize = sizeof(X86_64_TRAILER);
686     }
687
688     if( lmap.originalDtorRegion != NULL ) {
689         /* Determine where the original .dtors section should be placed */
690         Offset originalOffset = lmap.dtorRegionOffset + headerSize;
691
692         /* Copy the original .dtors section w/o header and trailer */
693         char *rawRegionData = reinterpret_cast<char *>(lmap.originalDtorRegion->getPtrToRawData());
694         memcpy(&targetData[originalOffset], &rawRegionData[headerSize],
695                 lmap.originalDtorRegion->getDiskSize() - headerSize - trailerSize);
696     }
697
698     return true;
699 }