Add support for indirect relocations in static binary rewriting
[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->getDiskOffset();
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->getDiskOffset();
107         }else{
108             errMsg = "Failed to locate original .dtors Region -- cannot apply relocation";
109             return false;
110         }
111     } else if (rel.name() == SYMTAB_IREL_START) {
112       // Start of our moved relocation section
113       symbolOffset = globalOffset + lmap.relRegionOffset;
114     }
115     else if (rel.name() == SYMTAB_IREL_END) {
116       // End of our moved relocation section
117       symbolOffset = globalOffset + lmap.relRegionOffset + lmap.relSize;
118     }
119
120     return true;
121 }
122
123 bool emitElfStatic::archSpecificRelocation(Symtab *, Symtab *, char *targetData, relocationEntry &rel,
124        Offset dest, Offset relOffset, Offset globalOffset, LinkMap &lmap,
125        string &errMsg) 
126 {
127   Offset symbolOffset = 0;
128   if (rel.getDynSym()->getType() != Symbol::ST_INDIRECT) {
129     // Easy case, just use the symbol as given
130     symbolOffset = rel.getDynSym()->getOffset();
131   }
132   else {
133     // Indirect; the address is the PLT entry (yes, I said PLT)
134     // associated with this symbol. 
135     auto pltEntry = lmap.pltEntries.find(rel.getDynSym()); 
136     if (pltEntry == lmap.pltEntries.end()) {
137       return false;
138     }
139     symbolOffset = pltEntry->second.first + globalOffset;
140   }
141     
142     if( X86_WIDTH == addressWidth_ ) {
143         /*
144          * Referring to the SYSV 386 supplement:
145          *
146          * All relocations on x86 are one word32 == Elf32_Word
147          *
148          * S = symbolOffset
149          * A = addend
150          * P = relOffset
151          */
152        
153         Elf32_Word addend;
154         if( rel.regionType() == Region::RT_REL ) {
155             memcpy(&addend, &targetData[dest], sizeof(Elf32_Word));
156         }else if( rel.regionType() == Region::RT_RELA ) {
157             addend = rel.addend();
158         }
159
160         if( !computeCtorDtorAddress(rel, globalOffset, lmap, errMsg, symbolOffset) ) {
161             return false;
162         }
163
164         rewrite_printf("relocation for '%s': TYPE = %s(%lu) S = %lx A = %lx P = %lx\n",
165                 rel.name().c_str(), 
166                 relocationEntry::relType2Str(rel.getRelType(), addressWidth_),
167                 rel.getRelType(), symbolOffset, addend, relOffset);
168
169         Offset relocation = 0;
170         map<Symbol *, Offset>::iterator result;
171         stringstream tmp;
172
173         switch(rel.getRelType()) {
174             case R_386_32:
175                 relocation = symbolOffset + addend;
176                 break;
177             case R_386_PLT32: // this works because the address of the symbol is known at link time
178             case R_386_PC32:
179                 relocation = symbolOffset + addend - relOffset;
180                 break;
181             case R_386_TLS_LE: // The necessary value is set during storage allocation
182             case R_386_GLOB_DAT:
183             case R_386_JMP_SLOT:
184                 relocation = symbolOffset;
185                 break;
186             case R_386_TLS_GD: // The address is computed when the GOT is built
187             case R_386_GOT32: 
188             case R_386_TLS_GOTIE:
189                 result = lmap.gotSymbols.find(rel.getDynSym());
190                 if( result == lmap.gotSymbols.end() ) {
191                     errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
192                     return false;
193                 }
194
195                 relocation = result->second;
196                 break;
197             case R_386_GOTOFF:
198                 relocation = symbolOffset + addend - (lmap.gotRegionOffset + globalOffset);
199                 break;
200             case R_386_GOTPC:
201                 relocation = globalOffset + lmap.gotRegionOffset + addend - relOffset;
202                 break;
203             case R_386_TLS_IE:
204                 result = lmap.gotSymbols.find(rel.getDynSym());
205                 if( result == lmap.gotSymbols.end() ) {
206                     errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
207                     return false;
208                 }
209
210                 relocation = result->second + lmap.gotRegionOffset + globalOffset;
211                 break;
212             case R_386_COPY:
213             case R_386_RELATIVE:
214                 tmp << "ERROR: encountered relocation type(" << rel.getRelType() << 
215                        ") that is meant for use during dynamic linking";
216                 errMsg = tmp.str();
217                 return false;
218             default:
219                 tmp << "Relocation type " << rel.getRelType() 
220                     << " currently unimplemented";
221                 errMsg = tmp.str();
222                 return false;
223         }
224
225         rewrite_printf("relocation = 0x%lx @ 0x%lx\n", relocation, relOffset);
226
227         memcpy(&targetData[dest], &relocation, sizeof(Elf32_Word));
228     }else if( X86_64_WIDTH == addressWidth_ ) {
229         /*
230          * Referring to the SYSV supplement:
231          *
232          * There are a few data types used by x86_64 relocations.
233          *
234          * word8 = uint8_t
235          * word16 = uint16_t
236          * word32 = Elf64_Word
237          * word64 = Elf64_Xword
238          *
239          * S = symbolOffset
240          * A = addend
241          * P = relOffset
242          * Z = symbolSize
243          *
244          * x86_64 only uses relocations that contain the addend.
245          */
246         unsigned symbolSize = rel.getDynSym()->getSize();
247
248         Elf64_Xword addend = 0;
249         if( Region::RT_RELA == rel.regionType() ) {
250             addend = rel.addend();
251         }
252
253         if( !computeCtorDtorAddress(rel, globalOffset, lmap, errMsg, symbolOffset) ) {
254             return false;
255         }
256
257         rewrite_printf("relocation for '%s': TYPE = %s(%lu) S = %llx A = %llx P = %llx Z = %lx\n",
258                 rel.name().c_str(), 
259                 relocationEntry::relType2Str(rel.getRelType(), addressWidth_),
260                 rel.getRelType(),
261                 symbolOffset, addend, relOffset, symbolSize);
262
263         Offset relocation = 0;
264         unsigned fieldSize = 0; // This is set depending on the type of relocation
265         map<Symbol *, Offset>::iterator result;
266         stringstream tmp;
267
268         switch(rel.getRelType()) {
269             case R_X86_64_64:
270                 fieldSize = sizeof(Elf64_Xword);
271                 relocation = symbolOffset + addend;
272                 break;
273             case R_X86_64_PLT32:
274             case R_X86_64_PC32:
275                 fieldSize = sizeof(Elf64_Word);
276                 relocation = symbolOffset + addend - relOffset;
277                 break;
278             case R_X86_64_GOT32: // The address is computed when the GOT is built
279                 fieldSize = sizeof(Elf64_Word);
280                 result = lmap.gotSymbols.find(rel.getDynSym());
281                 if( result == lmap.gotSymbols.end() ) {
282                     errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
283                     return false;
284                 }
285
286                 relocation = result->second + addend;
287                 break;
288             case R_X86_64_TPOFF32: // The necessary value is set during storage allocation
289                 fieldSize = sizeof(Elf64_Word);
290                 relocation = symbolOffset;
291                 break;
292             case R_X86_64_GLOB_DAT:
293             case R_X86_64_JUMP_SLOT:
294                 fieldSize = sizeof(Elf64_Xword);
295                 relocation = symbolOffset;
296                 break;
297             case R_X86_64_TLSLD: // Load the symbol offset from the GOT
298             case R_X86_64_TLSGD: 
299             case R_X86_64_GOTTPOFF:
300             case R_X86_64_GOTPCREL:
301                 fieldSize = sizeof(Elf64_Word);
302
303                 result = lmap.gotSymbols.find(rel.getDynSym());
304                 if( result == lmap.gotSymbols.end() ) {
305                     errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
306                     return false;
307                 }
308
309                 relocation = result->second + lmap.gotRegionOffset + 
310                     globalOffset + addend - relOffset;
311                 break;
312             case R_X86_64_DTPOFF32:
313                 fieldSize = sizeof(Elf64_Word);
314                 relocation = addend;
315                 break;
316             case R_X86_64_32:
317             case R_X86_64_32S:
318                 fieldSize = sizeof(Elf64_Word);
319                 relocation = symbolOffset + addend;
320                 break;
321             case R_X86_64_16:
322                 fieldSize = sizeof(uint16_t);
323                 relocation = symbolOffset + addend;
324                 break;
325             case R_X86_64_PC16:
326                 fieldSize = sizeof(uint16_t);
327                 relocation = symbolOffset + addend - relOffset;
328                 break;
329             case R_X86_64_8:
330                 fieldSize = sizeof(uint8_t);
331                 relocation = symbolOffset + addend;
332                 break;
333             case R_X86_64_PC8:
334                 fieldSize = sizeof(uint8_t);
335                 relocation = symbolOffset + addend - relOffset;
336                 break;
337             case R_X86_64_RELATIVE:
338             case R_X86_64_COPY:
339                 tmp << "ERROR: encountered relocation type(" << rel.getRelType() << 
340                        ") that is meant for use during dynamic linking";
341                 errMsg = tmp.str();
342                 return false;
343 #if defined(R_X86_64_IRELATIVE)
344            case R_X86_64_IRELATIVE:
345               // Consistency error; we should never try to process one of these
346               // ourselves.
347               assert(0);
348               return false;
349 #endif
350             case R_X86_64_DTPMOD64:
351             case R_X86_64_DTPOFF64:
352             case R_X86_64_TPOFF64:
353             default:
354                 tmp << "Relocation type " << rel.getRelType() 
355                     << " currently unimplemented";
356                 errMsg = tmp.str();
357                 return false;
358         }
359
360         rewrite_printf("relocation = 0x%llx @ 0x%llx\n", relocation, relOffset);
361
362         memcpy(&targetData[dest], &relocation, fieldSize);
363     }else{
364         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
365     }
366
367     return true;
368 }
369
370 static const string LIBC_ATEXIT_INTERNAL("__cxa_exit");
371 static const string LIBC_ATEXIT("atexit");
372
373 bool emitElfStatic::checkSpecialCaseSymbols(Symtab *member, Symbol *checkSym) {
374     /* 
375      * Special Case 1
376      *
377      * When linking code into stripped binaries, some linked functions will not
378      * work correctly because they rely on some state being initialized or
379      * updated in the original binary.
380      *
381      * For example, the libc function atexit internally keeps a list of
382      * functions to call after the main function returns. When main returns,
383      * this list is processed by libc finalization code. 
384      * 
385      * When the original binary is stripped, there is a disconnect between the
386      * atexit function in the linked code and the original atexit function.
387      * Consequently, any functionality that relies on atexit will not work
388      * (i.e. destructors for global C++ objects).
389      *
390      * The initial release of the binary rewriter for static binaries doesn't
391      * provide a solution to this problem. Therefore, a warning needs to be
392      * generated to alert the user to this outstanding problem.
393      */
394     if( isStripped_ ) {
395         if( LIBC_ATEXIT_INTERNAL == checkSym->getPrettyName() ||
396             LIBC_ATEXIT == checkSym->getPrettyName() )
397         {
398             fprintf(stderr, "WARNING: code in %s(%s) references the libc function %s.\n",
399                     member->getParentArchive()->name().c_str(),
400                     member->memberName().c_str(), checkSym->getPrettyName().c_str());
401             fprintf(stderr, "         Also, the binary to be rewritten is stripped.\n");
402             fprintf(stderr, "         Currently, the combination of these two "
403                             "is unsupported and unexpected behavior may occur.\n");
404         }
405     }
406
407     return true;
408 }
409
410 /* The TLS implementation on x86 is Variant 2 */
411
412 Offset emitElfStatic::layoutTLSImage(Offset globalOffset, Region *dataTLS, Region *bssTLS, LinkMap &lmap) {
413     return tlsLayoutVariant2(globalOffset, dataTLS, bssTLS, lmap);
414 }
415
416 Offset emitElfStatic::adjustTLSOffset(Offset curOffset, Offset tlsSize) {
417     return tlsAdjustVariant2(curOffset, tlsSize);
418 }
419
420 char emitElfStatic::getPaddingValue(Region::RegionType rtype) {
421     const char X86_NOP = 0x90;
422
423     char retChar = 0;
424     if( rtype == Region::RT_TEXT || rtype == Region::RT_TEXTDATA ) {
425         retChar = X86_NOP;
426     }
427
428     return retChar;
429 }
430
431 void emitElfStatic::cleanupTLSRegionOffsets(map<Region *, LinkMap::AllocPair> &regionAllocs,
432         Region *dataTLS, Region *bssTLS) 
433 {
434     tlsCleanupVariant2(regionAllocs, dataTLS, bssTLS);
435 }
436
437 void emitElfStatic::getExcludedSymbolNames(set<string> &symNames) {
438     /*
439      * It appears that some .o's have a reference to _GLOBAL_OFFSET_TABLE_
440      * This symbol is an indication to the linker that a GOT should be 
441      * created, it isn't a symbol that should be resolved. 
442      *
443      * Consequently, a GOT shouldn't always be created when linking 
444      * the .o's into the target. A GOT is built when certain relocations
445      * exist that require a GOT.
446      */
447     symNames.insert("_GLOBAL_OFFSET_TABLE_");
448 }
449
450 bool emitElfStatic::isGOTRelocation(unsigned long relType) {
451     if( X86_WIDTH == addressWidth_ ) {
452         switch(relType) {
453             case R_386_GOT32:
454             case R_386_TLS_IE:
455             case R_386_TLS_GOTIE:
456             case R_386_TLS_LDM:
457             case R_386_TLS_GD:
458                 return true;
459                 break;
460             default:
461                 return false;
462                 break;
463         }
464     }else if( X86_64_WIDTH == addressWidth_ ) {
465         switch(relType) {
466             case R_X86_64_TLSLD:
467             case R_X86_64_TLSGD:
468             case R_X86_64_GOTTPOFF:
469             case R_X86_64_GOT32:
470             case R_X86_64_GOTPCREL:
471                 return true;
472                 break;
473             default:
474                 return false;
475                 break;
476         }
477     }else{
478         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
479     }
480
481     return false;
482 }
483
484 Offset emitElfStatic::getGOTSize(Symtab *, LinkMap &lmap, Offset &layoutStart) {
485     Offset size = 0;
486     layoutStart = 0;
487
488     unsigned slotSize = 0;
489     if( X86_WIDTH == addressWidth_ ) {
490         slotSize = sizeof(Elf32_Addr);
491     }else if( X86_64_WIDTH == addressWidth_ ) {
492         slotSize = sizeof(Elf64_Addr);
493     }else{
494         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
495     }
496
497     // According to the ELF abi, entries 0, 1, 2 are reserved in a GOT on x86
498     if( lmap.gotSymbols.size() > 0 ) {
499       size = (lmap.gotSymbols.size()+GOT_RESERVED_SLOTS)*slotSize;
500     }
501
502     return size;
503 }
504
505 Offset emitElfStatic::getGOTAlign(LinkMap &) {
506     if( X86_WIDTH == addressWidth_ ) {
507         return sizeof(Elf32_Word);
508     }else if( X86_64_WIDTH == addressWidth_ ) {
509         return sizeof(Elf64_Xword);
510     }else{
511         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
512     }
513
514     return 0;
515 }
516
517 void emitElfStatic::buildGOT(Symtab *, LinkMap &lmap) {
518     char *targetData = lmap.allocatedData;
519
520     unsigned slotSize = 0;
521     if( X86_WIDTH == addressWidth_ ) {
522         slotSize = sizeof(Elf32_Addr);
523     }else if( X86_64_WIDTH == addressWidth_ ) {
524         slotSize = sizeof(Elf64_Addr);
525     }else{
526         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
527     }
528
529     // For each GOT symbol, allocate an entry and copy the value of the
530     // symbol into the table, additionally store the offset in the GOT
531     // back into the map
532     Offset curOffset = GOT_RESERVED_SLOTS*slotSize;
533     memset(&targetData[lmap.gotRegionOffset], 0, GOT_RESERVED_SLOTS*slotSize);
534
535     map<Symbol *, Offset>::iterator sym_it;
536     for(sym_it = lmap.gotSymbols.begin(); sym_it != lmap.gotSymbols.end(); ++sym_it) {
537         Offset value = sym_it->first->getOffset();
538         memcpy(&targetData[lmap.gotRegionOffset + curOffset], &value, slotSize);
539
540         sym_it->second = curOffset;
541
542         curOffset += slotSize;
543     }
544 }
545
546 /*
547  * .ctors and .dtors section handling
548  * 
549  * .ctors/.dtors sections are not defined by the ELF standard, LSB defines them.
550  * This is why this implementation is specific to Linux and x86.
551  *
552  * Layout of .ctors and .dtors sections on Linux x86
553  *
554  * Executable .ctors/.dtors format (size in bytes = n)
555  *
556  *  byte 0..3    byte 4..7     byte 8..11        byte n-4..n-1
557  * 0xffffffff <func. ptr 1> <func. ptr 2> ...  0x00000000
558  *
559  * Relocatable file .ctors/.dtors format (size in bytes = n)
560  *
561  *   byte 0..3         byte n-4..n-1
562  * <func. ptr 1> ... <last func. ptr>
563  *
564  * The layout is the same on Linux x86_64 except each entry is 8 bytes
565  * instead of 4. So the header and trailler are the same, but extended to
566  * 8 bytes.
567  */
568 static const Elf64_Word X86_HEADER = 0xffffffff;
569 static const Elf64_Word X86_TRAILER = 0x00000000;
570 static const Elf64_Xword X86_64_HEADER = 0xffffffffffffffffULL;
571 static const Elf64_Xword X86_64_TRAILER = 0x0000000000000000ULL;
572 static const string DTOR_NAME(".dtors");
573 static const string CTOR_NAME(".ctors");
574
575 bool emitElfStatic::isConstructorRegion(Region *reg) {
576     return ( CTOR_NAME.compare(reg->getRegionName()) == 0 );
577 }
578
579 bool emitElfStatic::isGOTRegion(Region *) {
580         return false;
581 }
582
583 Offset emitElfStatic::layoutNewCtorRegion(LinkMap &lmap) {
584     /* 
585      * .ctors sections are processed in reverse order on Linux x86. New .ctors
586      * sections need to be placed before the original .ctors section
587      */
588     Offset retOffset = lmap.ctorRegionOffset; 
589     retOffset += addressWidth_;
590
591     pair<map<Region *, LinkMap::AllocPair>::iterator, bool> result;
592
593     vector<Region *>::iterator reg_it;
594     for(reg_it = lmap.newCtorRegions.begin(); reg_it != lmap.newCtorRegions.end(); ++reg_it) {
595         result = lmap.regionAllocs.insert(make_pair(*reg_it, make_pair(0, retOffset)));
596
597         // If the map already contains this Region, this is a logic error
598         if( !result.second ) {
599             return ~0UL;
600         }
601
602         retOffset += (*reg_it)->getDiskSize();
603     }
604
605     if( lmap.originalCtorRegion != NULL ) {
606         // Account for original .ctors section (minus the header and trailer)
607         retOffset += lmap.originalCtorRegion->getDiskSize() - addressWidth_ - addressWidth_;
608     }
609     retOffset += addressWidth_;
610
611     return retOffset;
612 }
613
614 bool emitElfStatic::createNewCtorRegion(LinkMap &lmap) {
615     char *targetData = lmap.allocatedData;
616
617     if( X86_WIDTH != addressWidth_ && X86_64_WIDTH != addressWidth_ ) {
618         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
619     }
620
621     unsigned trailerSize, headerSize;
622
623     /* Give the new Region a header and trailer */
624     Offset headerOffset = lmap.ctorRegionOffset;
625     Offset trailerOffset;
626     if( X86_WIDTH == addressWidth_ ) {
627         memcpy(&targetData[headerOffset], &X86_HEADER, sizeof(X86_HEADER));
628         trailerOffset = lmap.ctorRegionOffset + lmap.ctorSize - sizeof(X86_TRAILER);
629         memcpy(&targetData[trailerOffset], &X86_TRAILER, sizeof(X86_TRAILER));
630         headerSize = sizeof(X86_HEADER);
631         trailerSize = sizeof(X86_TRAILER);
632     }else{
633         memcpy(&targetData[headerOffset], &X86_64_HEADER, sizeof(X86_64_HEADER));
634         trailerOffset = lmap.ctorRegionOffset + lmap.ctorSize - sizeof(X86_64_TRAILER);
635         memcpy(&targetData[trailerOffset], &X86_64_TRAILER, sizeof(X86_64_TRAILER));
636         headerSize = sizeof(X86_64_HEADER);
637         trailerSize = sizeof(X86_64_TRAILER);
638     }
639
640     if( lmap.originalCtorRegion != NULL ) {
641         /* Determine where the original .ctors section should be placed */
642         Offset originalOffset = lmap.ctorRegionOffset + lmap.ctorSize - 
643             trailerSize - (lmap.originalCtorRegion->getDiskSize() - headerSize - trailerSize);
644
645         /* Copy the original .ctors section w/o the header and trailer */
646         char *rawRegionData = reinterpret_cast<char *>(lmap.originalCtorRegion->getPtrToRawData());
647         memcpy(&targetData[originalOffset], &rawRegionData[headerSize],
648                 lmap.originalCtorRegion->getDiskSize() - headerSize - trailerSize);
649     }
650
651     return true;
652 }
653
654 bool emitElfStatic::isDestructorRegion(Region *reg) {
655     return ( DTOR_NAME.compare(reg->getRegionName()) == 0 );
656 }
657
658 Offset emitElfStatic::layoutNewDtorRegion(LinkMap &lmap) {
659     /*
660      * .dtors sections are processed in forward order on Linux x86. So new
661      * .dtors sections need to be placed after the original .dtors section
662      */
663     Offset retOffset = lmap.dtorRegionOffset;
664     retOffset += addressWidth_;
665
666     pair<map<Region *, LinkMap::AllocPair>::iterator, bool> result;
667     if( lmap.originalDtorRegion != NULL ) {
668         // Account for the original .dtors section (minus the header and trailer)
669         retOffset += lmap.originalDtorRegion->getDiskSize() - addressWidth_ - addressWidth_;
670     }
671
672     vector<Region *>::iterator reg_it;
673     for(reg_it = lmap.newDtorRegions.begin(); reg_it != lmap.newDtorRegions.end(); ++reg_it) {
674         result = lmap.regionAllocs.insert(make_pair(*reg_it, make_pair(0, retOffset)));
675
676         // If the map already contains this Region, this is a logic error
677         if( !result.second ) {
678             return ~0UL;
679         }
680
681         retOffset += (*reg_it)->getDiskSize();
682     }
683
684     retOffset += addressWidth_;
685     return retOffset;
686 }
687
688 bool emitElfStatic::createNewDtorRegion(LinkMap &lmap) {
689     char *targetData = lmap.allocatedData;
690
691     if( X86_WIDTH != addressWidth_ && X86_64_WIDTH != addressWidth_ ) {
692         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
693     }
694
695     unsigned headerSize, trailerSize;
696
697     /* Give the new Region a header and trailer */
698     Offset headerOffset = lmap.dtorRegionOffset;
699     Offset trailerOffset;
700     if( X86_WIDTH == addressWidth_ ) {
701         memcpy(&targetData[headerOffset], &X86_HEADER, sizeof(X86_HEADER));
702         trailerOffset = lmap.dtorRegionOffset + lmap.dtorSize - sizeof(X86_TRAILER);
703         memcpy(&targetData[trailerOffset], &X86_TRAILER, sizeof(X86_TRAILER));
704         headerSize = sizeof(X86_HEADER);
705         trailerSize = sizeof(X86_TRAILER);
706     }else{
707         memcpy(&targetData[headerOffset], &X86_64_HEADER, sizeof(X86_64_HEADER));
708         trailerOffset = lmap.dtorRegionOffset + lmap.dtorSize - sizeof(X86_64_TRAILER);
709         memcpy(&targetData[trailerOffset], &X86_64_TRAILER, sizeof(X86_64_TRAILER));
710         headerSize = sizeof(X86_64_HEADER);
711         trailerSize = sizeof(X86_64_TRAILER);
712     }
713
714     if( lmap.originalDtorRegion != NULL ) {
715         /* Determine where the original .dtors section should be placed */
716         Offset originalOffset = lmap.dtorRegionOffset + headerSize;
717
718         /* Copy the original .dtors section w/o header and trailer */
719         char *rawRegionData = reinterpret_cast<char *>(lmap.originalDtorRegion->getPtrToRawData());
720         memcpy(&targetData[originalOffset], &rawRegionData[headerSize],
721                 lmap.originalDtorRegion->getDiskSize() - headerSize - trailerSize);
722     }
723
724     return true;
725 }
726
727 bool emitElfStatic::updateTOC(Symtab *, LinkMap &, Offset) {
728    return true;
729 }
730
731 Offset emitElfStatic::allocStubRegions(LinkMap &lmap, Offset) {
732    // Size 0
733    return lmap.stubRegionOffset;
734 }