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