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