emitElfStatic-ppc64.C

Go to the documentation of this file.
00001 /*
00002  * See the dyninst/COPYRIGHT file for copyright information.
00003  * 
00004  * We provide the Paradyn Tools (below described as "Paradyn")
00005  * on an AS IS basis, and do not warrant its validity or performance.
00006  * We reserve the right to update, modify, or discontinue this
00007  * software at any time.  We shall have no obligation to supply such
00008  * updates or modifications or any other form of support to you.
00009  * 
00010  * By your use of Paradyn, you understand and agree that we (or any
00011  * other person or entity with proprietary rights in Paradyn) are
00012  * under no obligation to provide either maintenance services,
00013  * update services, notices of latent defects, or correction of
00014  * defects for Paradyn.
00015  * 
00016  * This library is free software; you can redistribute it and/or
00017  * modify it under the terms of the GNU Lesser General Public
00018  * License as published by the Free Software Foundation; either
00019  * version 2.1 of the License, or (at your option) any later version.
00020  * 
00021  * This library is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00024  * Lesser General Public License for more details.
00025  * 
00026  * You should have received a copy of the GNU Lesser General Public
00027  * License along with this library; if not, write to the Free Software
00028  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00029  */
00030 
00031 /* 
00032  * holds architecture specific functions for x86 and x86_64 architecture needed for the
00033  * static executable rewriter
00034  */
00035 
00036 #include <cstdlib>
00037 #include <cstdio>
00038 #include <cassert>
00039 #include <iostream>
00040 #include <set>
00041 #include <map>
00042 #include <sstream>
00043 
00044 #include "emitElfStatic.h"
00045 #include "Symtab.h"
00046 #include "Symbol.h"
00047 #include "Archive.h"
00048 #include "Object.h"
00049 #include "Region.h"
00050 #include "debug.h"
00051 #include "common/h/arch-power.h"
00052 
00053 using namespace Dyninst;
00054 using namespace Dyninst::SymtabAPI;
00055 using namespace NS_power;
00056 
00057 static const unsigned PPC32_WIDTH = 4;
00058 static const unsigned PPC64_WIDTH = 8;
00059 
00060 static const Elf64_Word X86_HEADER = 0xffffffff;
00061 static const Elf64_Word X86_TRAILER = 0x00000000;
00062 static const Elf64_Xword X86_64_HEADER = 0xffffffffffffffffULL;
00063 static const Elf64_Xword X86_64_TRAILER = 0x0000000000000000ULL;
00064 
00065 static const Offset GOT_RESERVED_SLOTS = 0;
00066 
00067 unsigned int setBits(unsigned int target, unsigned int pos, unsigned int len, unsigned int value) {
00068   rewrite_printf("setBits target 0x%lx value 0x%lx pos %d len %d \n", target, value, pos, len);
00069 // There are three parts of the target - 0:pos, pos:len, len:32 
00070 // We want to create a mask with 0:pos and len:32 set to 1
00071     unsigned int mask, mask1, mask2;
00072     mask1 = ~(~0 << pos);
00073     mask1 = (mask1 << (32-pos));
00074     mask2 = ~(~0 << (32-(pos+len)));
00075     mask = mask1 | mask2;
00076     target = target & mask;
00077     rewrite_printf(" mask1 0x%lx mask2 0x%lx mask 0x%lx target 0x%lx \n", mask1, mask2, mask, target);
00078 
00079     if(len != 32)
00080         mask = ~mask;
00081 
00082     value = value & mask;
00083     rewrite_printf(" mask 0x%lx value 0x%lx \n", mask, value);
00084     target = target | value;
00085     rewrite_printf( "setBits target 0x%lx value 0x%lx pos %d len %d \n", target, value, pos, len);
00086 
00087     return target;
00088 }
00089 
00090 unsigned long setBits64(unsigned long target, unsigned int pos, unsigned int len, unsigned long value) {
00091     unsigned  long mask;
00092     mask = ~(~0 << len);
00093     mask = (mask << pos);
00094     target = target & mask;
00095         if(len != 32)
00096     mask = ~mask;
00097     value = value & mask;
00098 
00099     target = target | value;
00100     return target;
00101 }
00102 
00103 
00104 #if defined(os_freebsd)
00105 #define R_X86_64_JUMP_SLOT R_X86_64_JMP_SLOT
00106 #endif
00107 
00108 // Used in an assert so needs to be a macro
00109 #define UNKNOWN_ADDRESS_WIDTH_ASSERT "An unknown address width was encountered, can't continue"
00110 
00111 /* NOTE:
00112  * As most of these functions are defined per architecture, the description of
00113  * each of these functions is in the emitElfStatic header. Comments describing
00114  * the function interface are explicitly left out.
00115  */
00116 
00117 /** 
00118  *
00119  * Given a relocation, determines if the relocation corresponds to a .ctors or .dtors
00120  * table that requires special consideration. Modifies the passed symbol offset to
00121  * point to the right table, if applicable.
00122  *
00123  * rel          The relocation entry to examine
00124  * globalOffset The offset of the linked code (used for symbol offset calculation)
00125  * lmap         Holds information about .ctors/.dtors tables
00126  * errMsg       Set on error
00127  * symbolOffset Modified by this routine to contain the offset of the table
00128  *
00129  * Returns true, if there are no errors including the case where the relocation 
00130  * entry doesn't reference the .ctors/.dtors tables.
00131  */
00132 
00133 static bool computeCtorDtorAddress(relocationEntry &rel, Offset globalOffset,
00134         LinkMap &lmap, string &errMsg, Offset &symbolOffset)
00135 {
00136     if( rel.name() ==  SYMTAB_CTOR_LIST_REL ) {
00137         // This needs to be: (the location of the .ctors table)
00138         if( lmap.newCtorRegions.size() > 0 ) {
00139             symbolOffset = lmap.ctorRegionOffset + globalOffset;
00140         rewrite_printf("new CTOR computeCtorDtorAddress symbolOffset 0x%lx \n", symbolOffset);
00141         }else if( lmap.originalCtorRegion != NULL ) {
00142             symbolOffset = lmap.originalCtorRegion->getMemOffset();
00143         rewrite_printf("original CTOR computeCtorDtorAddress symbolOffset 0x%lx \n", symbolOffset);
00144         }else{
00145             errMsg = "Failed to locate original .ctors Region -- cannot apply relocation";
00146             rewrite_printf("Failed to locate original .ctors Region -- cannot apply relocation\n");
00147             return false;
00148         }
00149     }else if( rel.name() == SYMTAB_DTOR_LIST_REL ) {
00150         // This needs to be: (the location of the .dtors table)
00151         if( lmap.newDtorRegions.size() > 0 ) {
00152             symbolOffset = lmap.dtorRegionOffset + globalOffset;
00153         }else if( lmap.originalDtorRegion != NULL ) {
00154             symbolOffset = lmap.originalDtorRegion->getMemOffset();
00155         }else{
00156             errMsg = "Failed to locate original .dtors Region -- cannot apply relocation";
00157             rewrite_printf("Failed to locate original .dtors Region -- cannot apply relocation\n");
00158             return false;
00159         }
00160     }
00161     return true;
00162 }
00163 
00164 
00165 bool emitElfStatic::archSpecificRelocation(Symtab* targetSymtab, Symtab* srcSymtab,
00166                        char *targetData, relocationEntry &rel,
00167                        Offset dest, Offset relOffset, Offset globalOffset, LinkMap &lmap,
00168                        string &errMsg) 
00169 {
00170     if( PPC64_WIDTH == addressWidth_ ) {
00171     Symbol *dynsym = rel.getDynSym();
00172     //  Offset TOCoffset = srcSymtab->getTOCoffset();
00173     
00174     Offset newTOCoffset = 0;
00175     if (dynsym->getModule()) {
00176       newTOCoffset = dynsym->getSymtab()->getTOCoffset(dynsym->getOffset());
00177     }
00178 
00179     // This is an added file, thus there's only one TOC value, so look up @0. 
00180     Offset curTOCoffset = srcSymtab->getTOCoffset((Offset) 0);
00181 
00182     rewrite_printf(" archSpecificRelocation %s\ndynsym %s, reloc offset 0x%lx\n new TOC 0x%lx, cur TOC 0x%x\n dest 0x%lx \n", 
00183                rel.name().c_str(), 
00184                dynsym->getMangledName().c_str(), relOffset,
00185                newTOCoffset, curTOCoffset, dest);
00186 
00187        if (rel.getRelType() == R_PPC64_JMP_SLOT) {
00188           // This is a 24-byte structure with the following form:
00189           // bytes 0..8: pointer to a function
00190           // bytes 9..15: TOC
00191           // bytes 16..23: unused (by us)
00192           // Instead of hard-coding it, we treat it as a pair of relocations:
00193           // R_PPC64_GLOB_DAT (for the pointer)
00194           // R_PPC64_TOC (for the TOC)
00195           relocationEntry func = rel;
00196           func.setRelType(R_PPC64_GLOB_DAT);
00197           if (!archSpecificRelocation(targetSymtab, srcSymtab, targetData, func,
00198                                       dest, relOffset, globalOffset, lmap, errMsg)) {
00199              return false;
00200           }
00201           relocationEntry toc = rel;
00202           toc.setRelType(R_PPC64_TOC);
00203           // Also shift its target address by 8 so it overwrites the second slot
00204           toc.setTargetAddr(toc.target_addr() + 8);
00205           if (!archSpecificRelocation(targetSymtab, srcSymtab, targetData, toc,
00206                                       dest + 8, relOffset + 8, globalOffset, lmap, errMsg)) {
00207              return false;
00208           }
00209           return true;
00210        }
00211 
00212     int relocation_length = sizeof(Elf64_Word)*8; // in bits
00213     int relocation_pos = 0; // in bits
00214     int branch_pred = -1;
00215         /*
00216          * Referring to the SYSV 386 supplement:
00217          *
00218          * All relocations on x86 are one word32 == Elf32_Word
00219          *
00220          * S = symbolOffset
00221          * A = addend
00222          * P = relOffset
00223          */
00224        
00225         Offset symbolOffset = rel.getDynSym()->getOffset();
00226 
00227         Elf64_Word addend;
00228         if( rel.regionType() == Region::RT_REL ) {
00229             memcpy(&addend, &targetData[dest], sizeof(Elf64_Word));
00230         }else if( rel.regionType() == Region::RT_RELA ) {
00231             addend = rel.addend();
00232         }
00233         
00234     if(!computeCtorDtorAddress(rel, globalOffset, lmap, errMsg, symbolOffset)) {
00235         return false;
00236     }
00237 
00238     // Handle TOC-changing inter-module calls
00239     // handleInterModule returns false if it's not its problem. 
00240     if (rel.getRelType() == R_PPC64_REL24 &&
00241         newTOCoffset != curTOCoffset && 
00242         handleInterModuleSpecialCase(targetSymtab, srcSymtab, lmap,
00243                      targetData, rel,
00244                      newTOCoffset, curTOCoffset, dest, 
00245                      relOffset, globalOffset)) {
00246       return true;
00247     }
00248 
00249     // If symbol is .toc, we must return the got offset
00250         if(rel.getRelType() == R_PPC64_TOC16_DS || rel.getRelType() == R_PPC64_TOC16) {
00251       vector<Region *> allRegions;
00252       srcSymtab->getAllRegions(allRegions);
00253       vector<Region *>::iterator region_it;
00254       for(region_it = allRegions.begin(); region_it != allRegions.end(); ++region_it) {
00255         if((*region_it)->getRegionName().compare(".toc") == 0) {
00256           map<Region *, LinkMap::AllocPair>::iterator result = lmap.regionAllocs.find(*region_it);
00257           if( result != lmap.regionAllocs.end() ) {
00258         Offset regionOffset = result->second.second;
00259         symbolOffset = globalOffset + regionOffset;
00260         rewrite_printf("\tregionOffset 0x%lx symbolOffset 0x%lx \n", regionOffset, symbolOffset);
00261         break;
00262           }
00263         }
00264       }
00265         }
00266 
00267         rewrite_printf("\trelocation for '%s': TYPE = %s(%lu) S = %lx A = %lx P = %lx Total 0x%lx \n",
00268                 rel.name().c_str(), 
00269                 relocationEntry::relType2Str(rel.getRelType(), addressWidth_),
00270                 rel.getRelType(), symbolOffset, addend, relOffset, symbolOffset+addend);
00271 
00272 
00273         Offset relocation = 0;
00274         map<Symbol *, Offset>::iterator result;
00275         stringstream tmp;
00276 
00277         switch(rel.getRelType()) {
00278       /* PowerPC64 relocations defined by the ABIs */
00279     case R_PPC64_ADDR64:
00280     case R_PPC64_GLOB_DAT:  
00281       //      rewrite_printf("ADDR64 or GLOB_DAT\n");
00282       relocation_length = 64;
00283       relocation = symbolOffset + addend;
00284       break;
00285     case R_PPC64_REL24:
00286     case R_PPC64_GOT_TPREL16_DS:
00287       //rewrite_printf("GOT_TPREL16_DS or REL24\n");
00288       relocation_length = 24;
00289       relocation_pos = 6;
00290       //relocation = (symbolOffset + addend - relOffset)>> 2;
00291       relocation = symbolOffset + addend - relOffset;
00292       //rewrite_printf(" R_PPC64_REL24 S = 0x%lx A = %d relOffset = 0x%lx relocation without shift 0x%lx %ld \n", 
00293       //symbolOffset, addend, relOffset, symbolOffset + addend - relOffset, symbolOffset + addend - relOffset);
00294       break;
00295     case R_PPC64_REL32:
00296       //rewrite_printf("REL32\n");
00297       relocation_length = 24;
00298       relocation_pos = 6;
00299       relocation = symbolOffset + addend - relOffset;
00300       break;
00301     case R_PPC64_REL64:
00302       //rewrite_printf("REL64\n");
00303       relocation = symbolOffset + addend - relOffset;
00304       break;
00305     case R_PPC64_TLS:
00306       rewrite_printf("TLS - UNIMPLEMENTED\n");
00307       break;
00308     case R_PPC64_TOC16:
00309       //rewrite_printf("TOC16\n");
00310       relocation_length = 16;
00311       relocation_pos = 0;
00312       relocation = symbolOffset + addend - newTOCoffset;
00313       break;
00314     case R_PPC64_TOC16_DS:
00315       //rewrite_printf("TOC16_DS\n");
00316       relocation_length = 16;
00317       relocation_pos = 16;
00318       relocation = (symbolOffset + addend - newTOCoffset) >> 2 ;
00319       relocation = relocation << 2;
00320       break;
00321     case R_PPC64_TOC:
00322       // I don't know how we never had to deal with these before...
00323       relocation_length = 64;
00324       relocation = newTOCoffset;
00325       break;
00326     default:
00327       assert(0);
00328     }
00329         rewrite_printf("\tbefore: relocation = 0x%lx @ 0x%lx target data %lx %lx %lx %lx %lx %lx \n", 
00330     relocation, relOffset,targetData[dest-2],  targetData[dest-1], targetData[dest], targetData[dest+1],  targetData[dest+2],  targetData[dest+3]);
00331 
00332     if (relocation_length == 64) {
00333         char *td = (targetData + dest - (dest%8));
00334             unsigned long target = *((unsigned long *) td);
00335             target = setBits64(target, relocation_pos, relocation_length, relocation);
00336             memcpy(td, &target, 2*sizeof(Elf64_Word));
00337     } else {
00338         char *td = (targetData + dest - (dest%4));
00339             unsigned int target = *((unsigned int *) td);
00340             target = setBits(target, relocation_pos, relocation_length, relocation);
00341             memcpy(td, &target, sizeof(Elf64_Word));
00342     }
00343 
00344         rewrite_printf("\tafter: relocation = 0x%lx @ 0x%lx target data %lx %lx %lx %lx %lx %lx \n", relocation, relOffset,targetData[dest-2],  targetData[dest-1], targetData[dest], targetData[dest+1],  targetData[dest+2],  targetData[dest+3]);
00345 
00346 /*
00347     if (branch_pred >= 0) {
00348     unsigned int *td = (unsigned int *) targetData;
00349     unsigned int target;
00350     target = td[dest/4];
00351     target = setBits(target, 10, 1, branch_pred);
00352         memcpy(&td[dest/4], &target, sizeof(Elf64_Word));
00353     } 
00354 */
00355 
00356 #if 0
00357 switch(0){
00358 case R_PPC64_NONE           :/* R_PPC_NONE */
00359 case R_PPC64_ADDR32         :/* R_PPC_ADDR32  32bit absolute address */
00360 case R_PPC64_ADDR24         :/* R_PPC_ADDR24  26bit address, word aligned */
00361 case R_PPC64_ADDR16         :/* R_PPC_ADDR16  16bit absolute address */
00362 case R_PPC64_ADDR16_LO      :/* R_PPC_ADDR16_LO  lower 16bits of address */
00363 case R_PPC64_ADDR16_HI      :/* R_PPC_ADDR16_HI  high 16bits of address. */
00364 case R_PPC64_ADDR16_HA      :/* R_PPC_ADDR16_HA  adjusted high 16bits.  */
00365 case R_PPC64_ADDR14         :/* R_PPC_ADDR14  16bit address, word aligned */
00366 case R_PPC64_ADDR14_BRTAKEN :/* R_PPC_ADDR14_BRTAKEN */
00367 case R_PPC64_ADDR14_BRNTAKEN:/* R_PPC_ADDR14_BRNTAKEN */
00368 case R_PPC64_REL24          :/* R_PPC_REL24 PC-rel. 26 bit, word aligned */
00369 case R_PPC64_REL14          :/* R_PPC_REL14  PC relative 16 bit */
00370 case R_PPC64_REL14_BRTAKEN  :/* R_PPC_REL14_BRTAKEN */
00371 case R_PPC64_REL14_BRNTAKEN :/* R_PPC_REL14_BRNTAKEN */
00372 case R_PPC64_GOT16          :/* R_PPC_GOT16 */
00373 case R_PPC64_GOT16_LO       :/* R_PPC_GOT16_LO */
00374 case R_PPC64_GOT16_HI       :/* R_PPC_GOT16_HI */
00375 case R_PPC64_GOT16_HA       :/* R_PPC_GOT16_HA*/
00376 case R_PPC64_COPY           :/* R_PPC_COPY*/
00377 case R_PPC64_GLOB_DAT       :/* R_PPC_GLOB_DAT*/
00378 case R_PPC64_JMP_SLOT       :/* R_PPC_JMP_SLOT*/
00379 case R_PPC64_RELATIVE       :/* R_PPC_RELATIVE*/
00380 case R_PPC64_UADDR32        :/* R_PPC_UADDR32*/
00381 case R_PPC64_UADDR16        :/* R_PPC_UADDR16*/
00382 case R_PPC64_REL32          :/* R_PPC_REL32*/
00383 case R_PPC64_PLT32          :/* R_PPC_PLT32*/
00384 case R_PPC64_PLTREL32       :/* R_PPC_PLTREL32*/
00385 case R_PPC64_PLT16_LO       :/* R_PPC_PLT16_LO*/
00386 case R_PPC64_PLT16_HI       :/* R_PPC_PLT16_HI*/
00387 case R_PPC64_PLT16_HA       :/* R_PPC_PLT16_HA*/
00388 case R_PPC64_SECTOFF        :/* R_PPC_SECTOFF*/
00389 case R_PPC64_SECTOFF_LO     :/* R_PPC_SECTOFF_LO*/
00390 case R_PPC64_SECTOFF_HI     :/* R_PPC_SECTOFF_HI*/
00391 case R_PPC64_SECTOFF_HA     :/* R_PPC_SECTOFF_HA*/
00392 case R_PPC64_ADDR30         : /* 37  word30 (S + A - P) >> 2 */
00393 case R_PPC64_ADDR64         : /* 38 doubleword64 S + A */
00394 case R_PPC64_ADDR16_HIGHER  : /* 39 half16 #higher(S + A) */
00395 case R_PPC64_ADDR16_HIGHERA :/* 40 half16 #highera(S + A) */
00396 case R_PPC64_ADDR16_HIGHEST :/*41 half16 #highest(S + A) */
00397 case R_PPC64_ADDR16_HIGHESTA:/*42  half16 #highesta(S + A) */
00398 case R_PPC64_UADDR64        :/*43  doubleword64 S + A */
00399 case R_PPC64_REL64          :/*44  doubleword64 S + A - P */
00400 case R_PPC64_PLT64          :/*45  doubleword64 L + A */
00401 case R_PPC64_PLTREL64       :/*46  doubleword64 L + A - P */
00402 case R_PPC64_TOC16          :/*47  half16* S + A - .TOC */
00403 case R_PPC64_TOC16_LO       :/*48  half16 #lo(S + A - .TOC.) */
00404 case R_PPC64_TOC16_HI       :/*49  half16 #hi(S + A - .TOC.) */
00405 case R_PPC64_TOC16_HA       :/*50  half16 #ha(S + A - .TOC.) */
00406 case R_PPC64_TOC            :/*51  doubleword64 .TOC */
00407 case R_PPC64_PLTGOT16       :/*52  half16* M + A */
00408 case R_PPC64_PLTGOT16_LO    :/*53  half16 #lo(M + A) */
00409 case R_PPC64_PLTGOT16_HI    :/*54  half16 #hi(M + A) */
00410 case R_PPC64_PLTGOT16_HA    :/*55  half16 #ha(M + A) */
00411 
00412 case R_PPC64_ADDR16_DS      :/*56  half16ds* (S + A) >> 2 */
00413 case R_PPC64_ADDR16_LO_DS   :/*57  half16ds  #lo(S + A) >> 2 */
00414 case R_PPC64_GOT16_DS       :/*58  half16ds* (G + A) >> 2 */
00415 case R_PPC64_GOT16_LO_DS    :/*59  half16ds  #lo(G + A) >> 2 */
00416 case R_PPC64_PLT16_LO_DS    :/*60  half16ds  #lo(L + A) >> 2 */
00417 case R_PPC64_SECTOFF_DS     :/*61  half16ds* (R + A) >> 2 */
00418 case R_PPC64_SECTOFF_LO_DS  :/*62  half16ds  #lo(R + A) >> 2 */
00419 case R_PPC64_TOC16_DS       :/*63  half16ds* (S + A - .TOC.) >> 2 */
00420 case R_PPC64_TOC16_LO_DS    :/*64  half16ds  #lo(S + A - .TOC.) >> 2 */
00421 case R_PPC64_PLTGOT16_DS    :/*65  half16ds* (M + A) >> 2 */
00422 case R_PPC64_PLTGOT16_LO_DS :/*66  half16ds  #lo(M + A) >> 2 */
00423 
00424 /* PowerPC64 relocations defined for the TLS access ABI.  */
00425 case R_PPC64_TLS            :/*67  none      (sym+add)@tls */
00426 case R_PPC64_DTPMOD64       :/*68  doubleword64 (sym+add)@dtpmod */
00427 case R_PPC64_TPREL16        :/*69  half16*   (sym+add)@tprel */
00428 case R_PPC64_TPREL16_LO     :/*70  half16    (sym+add)@tprel@l */
00429 case R_PPC64_TPREL16_HI     :/*71  half16    (sym+add)@tprel@h */
00430 case R_PPC64_TPREL16_HA     :/*72  half16    (sym+add)@tprel@ha */
00431 case R_PPC64_TPREL64        :/*73  doubleword64 (sym+add)@tprel */
00432 case R_PPC64_DTPREL16       :/*74  half16*   (sym+add)@dtprel */
00433 case R_PPC64_DTPREL16_LO    :/*75  half16    (sym+add)@dtprel@l */
00434 case R_PPC64_DTPREL16_HI    :/*76  half16    (sym+add)@dtprel@h */
00435 case R_PPC64_DTPREL16_HA    :/*77  half16    (sym+add)@dtprel@ha */
00436 case R_PPC64_DTPREL64       :/*78  doubleword64 (sym+add)@dtprel */
00437 case R_PPC64_GOT_TLSGD16    :/*79  half16*   (sym+add)@got@tlsgd */
00438 case R_PPC64_GOT_TLSGD16_LO :/*80  half16    (sym+add)@got@tlsgd@l */
00439 case R_PPC64_GOT_TLSGD16_HI :/*81  half16    (sym+add)@got@tlsgd@h */
00440 case R_PPC64_GOT_TLSGD16_HA :/*82  half16    (sym+add)@got@tlsgd@ha */
00441 case R_PPC64_GOT_TLSLD16    :/*83  half16*   (sym+add)@got@tlsld */
00442 case R_PPC64_GOT_TLSLD16_LO :/*84  half16    (sym+add)@got@tlsld@l */
00443 case R_PPC64_GOT_TLSLD16_HI :/*85  half16    (sym+add)@got@tlsld@h */
00444 case R_PPC64_GOT_TLSLD16_HA :/*86  half16    (sym+add)@got@tlsld@ha */
00445 case R_PPC64_GOT_TPREL16_DS :/*87  half16ds* (sym+add)@got@tprel */
00446 case R_PPC64_GOT_TPREL16_LO_DS:/*88  half16ds (sym+add)@got@tprel@l */
00447 case R_PPC64_GOT_TPREL16_HI :/*89  half16    (sym+add)@got@tprel@h */
00448 case R_PPC64_GOT_TPREL16_HA :/*90  half16    (sym+add)@got@tprel@ha */
00449 case R_PPC64_GOT_DTPREL16_DS:/*91  half16ds* (sym+add)@got@dtprel */
00450 case R_PPC64_GOT_DTPREL16_LO_DS:/*92  half16ds (sym+add)@got@dtprel@l */
00451 case R_PPC64_GOT_DTPREL16_HI:/*93  half16    (sym+add)@got@dtprel@h */
00452 case R_PPC64_GOT_DTPREL16_HA:/*94  half16    (sym+add)@got@dtprel@ha */
00453 case R_PPC64_TPREL16_DS     :/*95  half16ds* (sym+add)@tprel */
00454 case R_PPC64_TPREL16_LO_DS  :/*96  half16ds  (sym+add)@tprel@l */
00455 case R_PPC64_TPREL16_HIGHER :/*97  half16    (sym+add)@tprel@higher */
00456 case R_PPC64_TPREL16_HIGHERA:/*98  half16    (sym+add)@tprel@highera */
00457 case R_PPC64_TPREL16_HIGHEST:/*99  half16    (sym+add)@tprel@highest */
00458 case R_PPC64_TPREL16_HIGHESTA:/*100  half16  (sym+add)@tprel@highesta */
00459 case R_PPC64_DTPREL16_DS    :/*101  half16ds* (sym+add)@dtprel */
00460 case R_PPC64_DTPREL16_LO_DS :/*102  half16ds (sym+add)@dtprel@l */
00461 case R_PPC64_DTPREL16_HIGHER:/*103  half16   (sym+add)@dtprel@higher */
00462 case R_PPC64_DTPREL16_HIGHERA:/*104  half16  (sym+add)@dtprel@highera */
00463 case R_PPC64_DTPREL16_HIGHEST:/*105  half16  (sym+add)@dtprel@highest */
00464 case R_PPC64_DTPREL16_HIGHESTA:/*106  half16 (sym+add)@dtprel@highesta */
00465 
00466 /* Keep this the last entry.  */
00467 case R_PPC64_NUM            :/*107 */
00468 
00469         default:
00470             break;
00471     }
00472 #endif
00473     } else if (PPC32_WIDTH == addressWidth_ ){
00474     int relocation_length = sizeof(Elf32_Word)*8; // in bits
00475     int relocation_pos = 0; // in bits
00476     int branch_pred = -1;
00477         /*
00478          * Referring to the SYSV 386 supplement:
00479          *
00480          * All relocations on x86 are one word32 == Elf32_Word
00481          *
00482          * S = symbolOffset
00483          * A = addend
00484          * P = relOffset
00485          */
00486        
00487         Offset symbolOffset = rel.getDynSym()->getOffset();
00488 
00489         Elf32_Word addend;
00490         if( rel.regionType() == Region::RT_REL ) {
00491             memcpy(&addend, &targetData[dest], sizeof(Elf32_Word));
00492         }else if( rel.regionType() == Region::RT_RELA ) {
00493             addend = rel.addend();
00494         }
00495         
00496     if(!computeCtorDtorAddress(rel, globalOffset, lmap, errMsg, symbolOffset)) {
00497         return false;
00498     }
00499 
00500         rewrite_printf("relocation for '%s': TYPE = %s(%lu) S = %lx A = %lx P = %lx\n",
00501                 rel.name().c_str(), 
00502                 relocationEntry::relType2Str(rel.getRelType(), addressWidth_),
00503                 rel.getRelType(), symbolOffset, addend, relOffset);
00504 
00505         Offset relocation = 0;
00506     map<Symbol *, Offset>::iterator result;
00507 
00508         stringstream tmp;
00509 
00510         switch(rel.getRelType()) {
00511 
00512 /* PowerPC relocations defined by the ABIs */
00513 case R_PPC_NONE:/*            0 */
00514     break;
00515 case R_PPC_ADDR32:/*          1        32bit absolute address */
00516     relocation = symbolOffset + addend;
00517     break;
00518 case R_PPC_ADDR24:/*          2        26bit address, 2 bits ignored.  */
00519         relocation_length = 26;
00520         relocation_pos = 2;
00521     relocation = (symbolOffset + addend) >> 2;
00522     break;
00523 case R_PPC_ADDR16:/*          3        16bit absolute address */
00524         relocation_length = 16;
00525         relocation_pos = 16;
00526     relocation = symbolOffset + addend;
00527     break;
00528 case R_PPC_ADDR16_LO:/*       4        lower 16bit of absolute address */
00529         relocation_length = 16;
00530         relocation_pos = 0;
00531         relocation = symbolOffset + addend;
00532     relocation = (relocation & 0xffff);
00533     break;
00534 case R_PPC_ADDR16_HI:/*       5        high 16bit of absolute address */
00535     relocation_length = 16;
00536         relocation_pos = 0;
00537         relocation = symbolOffset + addend;
00538     relocation = ((relocation >> 16) & 0xffff);
00539     break;
00540 case R_PPC_ADDR16_HA:/*       6        adjusted high 16bit */
00541     relocation_length = 16;
00542         relocation_pos = 0;
00543         relocation = symbolOffset + addend;
00544         relocation = (((relocation >> 16) + ((relocation & 0x8000)? 1:0)) & 0xffff);
00545         break;
00546 case R_PPC_ADDR14:/*          7        16bit address, 2 bits ignored */
00547     relocation_length = 14;
00548         relocation_pos = 16;
00549     relocation = (symbolOffset + addend) >> 2;
00550     break;
00551 case R_PPC_ADDR14_BRTAKEN:/*  8 */
00552     relocation_length = 14;
00553         relocation_pos = 16;
00554     relocation = (symbolOffset + addend) >> 2;
00555     // bit 10 is set
00556     branch_pred = 1;
00557     break;
00558 case R_PPC_ADDR14_BRNTAKEN:/* 9 */
00559     relocation_length = 14;
00560         relocation_pos = 16;
00561     relocation = (symbolOffset + addend) >> 2;
00562     // bit 10 is set
00563     branch_pred = 0;
00564     break;
00565 case R_PPC_REL24:/*           10       PC relative 26 bit */
00566     relocation_length = 24;
00567         relocation_pos = 2;
00568         relocation = (symbolOffset + addend - relOffset) >> 2;
00569         break;
00570 case R_PPC_REL14:/*           11       PC relative 16 bit */
00571     relocation_length = 14;
00572         relocation_pos = 16;
00573         relocation = (symbolOffset + addend - relOffset) >> 2;
00574         break;
00575 case R_PPC_REL14_BRTAKEN:/*   12*/
00576     relocation_length = 14;
00577         relocation_pos = 16;
00578         relocation = (symbolOffset + addend - relOffset) >> 2;
00579     branch_pred = 1;
00580         break;
00581 case R_PPC_REL14_BRNTAKEN:/*  13*/
00582     relocation_length = 14;
00583         relocation_pos = 16;
00584         relocation = (symbolOffset + addend - relOffset) >> 2;
00585     branch_pred = 0;
00586         break;
00587 case R_PPC_GOT16:/*           14*/
00588         result = lmap.gotSymbols.find(rel.getDynSym());
00589         if( result == lmap.gotSymbols.end() ) {
00590             errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
00591             return false;
00592         }
00593         relocation = result->second;
00594     relocation = (relocation) >> 16;
00595         relocation_length = 16;
00596         relocation_pos = 16;
00597         break;
00598 case R_PPC_GOT16_LO:/*        15*/
00599         result = lmap.gotSymbols.find(rel.getDynSym());
00600         if( result == lmap.gotSymbols.end() ) {
00601             errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
00602             return false;
00603         }
00604         relocation = result->second;
00605     relocation = (relocation & 0xffff);
00606         relocation_length = 16;
00607         relocation_pos = 0;
00608         break;
00609 case R_PPC_GOT16_HI:/*        16*/
00610         result = lmap.gotSymbols.find(rel.getDynSym());
00611         if( result == lmap.gotSymbols.end() ) {
00612             errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
00613             return false;
00614         }
00615         relocation = result->second;
00616     relocation = ((relocation >> 16) & 0xffff);
00617         relocation_length = 16;
00618         relocation_pos = 0;
00619         break;
00620 case R_PPC_GOT16_HA:/*        17*/
00621         result = lmap.gotSymbols.find(rel.getDynSym());
00622         if( result == lmap.gotSymbols.end() ) {
00623             errMsg = "Expected GOT symbol does not exist in GOT symbol mapping";
00624             return false;
00625         }
00626         relocation = result->second;
00627         relocation = (((relocation >> 16) + ((relocation & 0x8000)? 1:0)) & 0xffff);
00628         relocation_length = 16;
00629         relocation_pos = 0;
00630         break;
00631 case R_PPC_PLTREL24:/*        18*/
00632     relocation_length = 24;
00633         relocation_pos = 2;
00634     relocation = (symbolOffset + addend - relOffset) >> 2;
00635     break;
00636 case R_PPC_COPY:/*            19*/
00637     break;
00638 case R_PPC_GLOB_DAT:/*        20*/
00639     relocation = symbolOffset + addend;
00640     break;
00641 case R_PPC_JMP_SLOT:/*        21*/
00642     break;
00643 case R_PPC_RELATIVE:/*        22*/
00644         tmp << "ERROR: encountered relocation type(" << rel.getRelType() << 
00645                 ") that is meant for use during dynamic linking";
00646         errMsg = tmp.str();
00647         return false;
00648 case R_PPC_LOCAL24PC:/*       23*/
00649     relocation_length = 24;
00650         relocation_pos = 2;
00651     relocation = (symbolOffset + addend - relOffset) >> 2;
00652     break;
00653 case R_PPC_UADDR32:/*         24*/
00654     relocation = symbolOffset + addend ;
00655     break;
00656 case R_PPC_UADDR16:/*         25*/
00657         relocation_length = 16;
00658         relocation_pos = 16;
00659     relocation = symbolOffset + addend;
00660     break;
00661 case R_PPC_REL32:/*           26*/
00662     relocation = symbolOffset + addend - relOffset;
00663         break;
00664 case R_PPC_PLT32:/*           27*/
00665     relocation = symbolOffset + addend;
00666         break;
00667 case R_PPC_PLTREL32:/*        28*/
00668     relocation = symbolOffset + addend - relOffset;
00669         break;
00670 case R_PPC_PLT16_LO:/*        29*/
00671     relocation = symbolOffset + addend;
00672     relocation = (relocation & 0xffff);
00673         break;
00674 case R_PPC_PLT16_HI:/*        30*/
00675     relocation = symbolOffset + addend;
00676     relocation = ((relocation >> 16) & 0xffff);
00677         break;
00678 case R_PPC_PLT16_HA:/*        31*/
00679     relocation = symbolOffset + addend;
00680         relocation = (((relocation >> 16) + ((relocation & 0x8000)? 1:0)) & 0xffff);
00681         break;
00682 case R_PPC_SDAREL16:/*        32*/
00683 case R_PPC_SECTOFF:/*         33*/
00684 case R_PPC_SECTOFF_LO:/*      34*/
00685 case R_PPC_SECTOFF_HI:/*      35*/
00686 case R_PPC_SECTOFF_HA:/*      36*/
00687         tmp << "Relocation type " << rel.getRelType() 
00688             << " currently unimplemented";
00689         errMsg = tmp.str();
00690       rewrite_printf(" Relocation type %s  currently unimplemented \n", relocationEntry::relType2Str(rel.getRelType(), addressWidth_));
00691         return false;
00692 
00693 /* PowerPC relocations defined for the TLS access ABI.  */
00694 case R_PPC_TLS:/*             67  none      (sym+add)@tls */
00695 case R_PPC_DTPMOD32:/*        68  word32    (sym+add)@dtpmod */
00696 case R_PPC_TPREL16:/*         69  half16*   (sym+add)@tprel */
00697 case R_PPC_TPREL16_LO:/*      70  half16    (sym+add)@tprel@l */
00698 case R_PPC_TPREL16_HI:/*      71  half16    (sym+add)@tprel@h */
00699 case R_PPC_TPREL16_HA:/*      72  half16    (sym+add)@tprel@ha */
00700 case R_PPC_TPREL32:/*         73  word32    (sym+add)@tprel */
00701 case R_PPC_DTPREL16:/*        74  half16*   (sym+add)@dtprel */
00702 case R_PPC_DTPREL16_LO:/*     75  half16    (sym+add)@dtprel@l */
00703 case R_PPC_DTPREL16_HI:/*     76  half16    (sym+add)@dtprel@h */
00704 case R_PPC_DTPREL16_HA:/*     77  half16    (sym+add)@dtprel@ha */
00705 case R_PPC_DTPREL32:/*        78  word32    (sym+add)@dtprel */
00706 case R_PPC_GOT_TLSGD16:/*     79  half16*   (sym+add)@got@tlsgd */
00707 case R_PPC_GOT_TLSGD16_LO:/*  80  half16    (sym+add)@got@tlsgd@l */
00708 case R_PPC_GOT_TLSGD16_HI:/*  81  half16    (sym+add)@got@tlsgd@h */
00709 case R_PPC_GOT_TLSGD16_HA:/*  82  half16    (sym+add)@got@tlsgd@ha */
00710 case R_PPC_GOT_TLSLD16:/*     83  half16*   (sym+add)@got@tlsld */
00711 case R_PPC_GOT_TLSLD16_LO:/*  84  half16    (sym+add)@got@tlsld@l */
00712 case R_PPC_GOT_TLSLD16_HI:/*  85  half16    (sym+add)@got@tlsld@h */
00713 case R_PPC_GOT_TLSLD16_HA:/*  86  half16    (sym+add)@got@tlsld@ha */
00714 case R_PPC_GOT_TPREL16:/*     87  half16*   (sym+add)@got@tprel */
00715 case R_PPC_GOT_TPREL16_LO:/*  88  half16    (sym+add)@got@tprel@l */
00716 case R_PPC_GOT_TPREL16_HI:/*  89  half16    (sym+add)@got@tprel@h */
00717 case R_PPC_GOT_TPREL16_HA:/*  90  half16    (sym+add)@got@tprel@ha */
00718 case R_PPC_GOT_DTPREL16:/*    91  half16*   (sym+add)@got@dtprel */
00719 case R_PPC_GOT_DTPREL16_LO:/* 92  half16*   (sym+add)@got@dtprel@l */
00720 case R_PPC_GOT_DTPREL16_HI:/* 93  half16*   (sym+add)@got@dtprel@h */
00721 case R_PPC_GOT_DTPREL16_HA:/* 94  half16*   (sym+add)@got@dtprel@ha */
00722       relocation_length = 16;
00723       relocation_pos = 16;
00724       relocation = symbolOffset + addend;
00725       rewrite_printf(" Relocation type %s  currently unimplemented \n", relocationEntry::relType2Str(rel.getRelType(), addressWidth_));
00726       break;
00727 
00728 /* GNU relocs used in PIC code sequences.  */
00729 /* NOTE: The following relocations are not defined in some elf.h
00730    Hence, using numbers instead of name */
00731 case 249: /*R_PPC_REL16:           249      word32   (sym-.) */
00732     relocation_length = 16;
00733         relocation_pos = 16;
00734         relocation = symbolOffset + addend - relOffset ;
00735         break;
00736 case 250: /*R_PPC_REL16_LO:        250      half16   (sym-.)@l */
00737     relocation_length = 16;
00738         relocation_pos = 16;
00739         relocation = symbolOffset + addend - relOffset ;
00740     relocation = (relocation & 0xffff);
00741         break;
00742 case 251: /*R_PPC_REL16_HI:        251      half16   (sym-.)@h */
00743     relocation_length = 16;
00744         relocation_pos = 16;
00745         relocation = symbolOffset + addend - relOffset ;
00746     relocation = ((relocation >> 16) & 0xffff);
00747         break;
00748 case 252: /*R_PPC_REL16_HA:        252      half16   (sym-.)@ha */
00749     relocation_length = 16;
00750         relocation_pos = 16;
00751         relocation = symbolOffset + addend - relOffset ;
00752         relocation = (((relocation >> 16) + ((relocation & 0x8000)? 1:0)) & 0xffff);
00753         break;
00754 /* This is a phony reloc to handle any old fashioned TOC16 references
00755    that may still be in object files.  */
00756 case 255: /*R_PPC_TOC16:              255*/
00757         break;
00758 
00759 default:
00760      tmp << "Relocation type " << rel.getRelType() 
00761          << " currently unimplemented";
00762      rewrite_printf(" Relocation type %s  currently unimplemented \n", relocationEntry::relType2Str(rel.getRelType(), addressWidth_));
00763      errMsg = tmp.str();
00764      return false;
00765         }
00766 
00767         rewrite_printf(" relocation = 0x%lx @ 0x%lx target data 0x%lx %lx %lx %lx \n", relocation, relOffset, targetData[dest], targetData[dest+1],  targetData[dest+2],  targetData[dest+3]);
00768     if (rel.getRelType() == R_PPC_REL24) {
00769     unsigned int *td = (unsigned int *) targetData;
00770     unsigned int target;
00771     target = td[dest/4];
00772     target = setBits(target, relocation_pos, relocation_length, relocation);
00773         memcpy(&targetData[dest], &target, sizeof(Elf32_Word));
00774     } else {
00775     unsigned int *td = (unsigned int *) targetData;
00776     unsigned int target;
00777     target = td[dest/4];
00778     target = setBits(target, relocation_pos, relocation_length, relocation);
00779         memcpy(&td[dest/4], &target, sizeof(Elf32_Word));
00780 //        memcpy(&targetData[dest], r+2, relocation_size);
00781         rewrite_printf(" relocation = 0x%lx @ 0x%lx target data 0x%lx %lx %lx %lx \n", relocation, relOffset, targetData[dest], targetData[dest+1],  targetData[dest+2],  targetData[dest+3]);
00782     }
00783     if (branch_pred >= 0) {
00784     unsigned int *td = (unsigned int *) targetData;
00785     unsigned int target;
00786     target = td[dest/4];
00787     target = setBits(target, 10, 1, branch_pred);
00788         memcpy(&td[dest/4], &target, sizeof(Elf32_Word));
00789     } 
00790 
00791     } else{
00792         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
00793     }
00794     return true;
00795 }
00796 
00797 bool emitElfStatic::checkSpecialCaseSymbols(Symtab *, Symbol *) {
00798     return true;
00799 }
00800 
00801 /* The TLS implementation on ppc is Variant 1 */
00802 
00803 Offset emitElfStatic::layoutTLSImage(Offset globalOffset, Region *dataTLS, Region *bssTLS, LinkMap &lmap) {
00804     return tlsLayoutVariant1(globalOffset, dataTLS, bssTLS, lmap);
00805 }
00806 
00807 Offset emitElfStatic::adjustTLSOffset(Offset curOffset, Offset tlsSize) {
00808     return curOffset;
00809 }
00810 
00811 char emitElfStatic::getPaddingValue(Region::RegionType rtype) {
00812    // Can't noop-pad because this returns a char, not an unsigned
00813    return 0x0;
00814 }
00815 
00816 void emitElfStatic::cleanupTLSRegionOffsets(map<Region *, LinkMap::AllocPair> &regionAllocs,
00817                                             Region *dataTLS, Region *bssTLS) 
00818 {
00819     tlsCleanupVariant2(regionAllocs, dataTLS, bssTLS);
00820 }
00821 
00822 Offset emitElfStatic::getGOTSize(Symtab *target, LinkMap &lmap, Offset &layoutStart) {
00823     Offset size = 0;
00824 
00825     unsigned slotSize = 0;
00826     if( PPC32_WIDTH == addressWidth_ ) {
00827         slotSize = sizeof(Elf32_Addr);
00828     }else if( PPC64_WIDTH == addressWidth_ ) {
00829         slotSize = sizeof(Elf64_Addr);
00830     }else{
00831         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
00832     }
00833 
00834     // According to the ELF abi, entries 0, 1, 2 are reserved in a GOT on x86
00835     if( lmap.gotSymbolTable.size() > 0 ) {
00836        rewrite_printf("Determining new GOT size: %d symtab entries, %d reserved slots, %d slot size\n",
00837                       lmap.gotSymbolTable.size(), GOT_RESERVED_SLOTS, slotSize);
00838         size = (lmap.gotSymbolTable.size()+GOT_RESERVED_SLOTS)*slotSize;
00839     }
00840 
00841     // DISABLED
00842 #if 0
00843     // On PPC64 we move the original GOT as well, as we can't guarantee that we can reach
00844     // the new GOT from the old. 
00845     if (PPC64_WIDTH == addressWidth_) {
00846        rewrite_printf("New GOT size is 0x%lx, adding original GOT size 0x%lx\n", size, target->getObject()->gotSize());
00847        layoutStart = target->getObject()->gotSize();
00848        size += layoutStart;
00849     }
00850 #endif
00851 
00852     return size;
00853 }
00854 
00855 Offset emitElfStatic::getGOTAlign(LinkMap &) {
00856 
00857     if( PPC32_WIDTH == addressWidth_ ) {
00858     return 0;
00859     }
00860     if( PPC32_WIDTH == addressWidth_ ) {
00861         return sizeof(Elf32_Word);
00862     }else if( PPC64_WIDTH == addressWidth_ ) {
00863         return sizeof(Elf64_Xword);
00864     }else{
00865         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
00866     }
00867 
00868     return 0;
00869 }
00870 
00871 void emitElfStatic::buildGOT(Symtab *target, LinkMap &lmap) {
00872 
00873     if( PPC32_WIDTH == addressWidth_ ) {
00874     return;
00875     }
00876     char *targetData = lmap.allocatedData;
00877 
00878     unsigned slotSize = 0;
00879     if( PPC32_WIDTH == addressWidth_ ) {
00880         slotSize = sizeof(Elf32_Addr);
00881     }else if( PPC64_WIDTH == addressWidth_ ) {
00882         slotSize = sizeof(Elf64_Addr);
00883     }else{
00884         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
00885     }
00886 
00887     Offset curOffset = 0;
00888 #if 0
00889     // DISABLED
00890     // Copy over the original GOT
00891     // Inefficient lookup, but it's easy to debug :)
00892     Region *origGOT = NULL; 
00893     if (target->findRegion(origGOT, ".got")) {
00894        memcpy(&targetData[lmap.gotRegionOffset + curOffset], origGOT->getPtrToRawData(), origGOT->getDiskSize());
00895        curOffset += origGOT->getDiskSize();
00896        rewrite_printf("Copying 0x%lx bytes of original GOT to new, curOffset is 0x%lx\n",
00897               origGOT->getDiskSize(), curOffset);
00898     }
00899 #endif
00900 
00901     // For each GOT symbol, allocate an entry and copy the value of the
00902     // symbol into the table, additionally store the offset in the GOT
00903     // back into the map
00904     memset(&targetData[lmap.gotRegionOffset], 0, GOT_RESERVED_SLOTS*slotSize);
00905     curOffset += GOT_RESERVED_SLOTS*slotSize;
00906 
00907     rewrite_printf("Copied GOT_RESERVED_SLOTS %d, curOffset 0x%lx\n",
00908            GOT_RESERVED_SLOTS, curOffset);
00909 
00910     vector<pair<Symbol *, Offset> >::iterator sym_it;
00911     rewrite_printf("Copying in %d symbol table entries\n", lmap.gotSymbolTable.size());
00912 
00913     for(sym_it = lmap.gotSymbolTable.begin(); sym_it != lmap.gotSymbolTable.end(); ++sym_it) {
00914         Offset value = sym_it->first->getOffset()+sym_it->second;
00915         memcpy(&targetData[lmap.gotRegionOffset + curOffset], &value, slotSize);
00916 
00917         sym_it->second = curOffset;
00918     rewrite_printf(" Building GOT at 0x%lx is 0x%lx name %s Offset 0x%lx addend 0x%lx addr 0x%lx \n", 
00919                curOffset, value,  
00920                sym_it->first->getPrettyName().c_str(),  sym_it->first->getOffset(), 
00921                sym_it->second, lmap.gotRegionOffset + curOffset);
00922         curOffset += slotSize;
00923     }
00924     rewrite_printf("curOffset is 0x%lx, calculated GOT size is 0x%lx\n", curOffset, lmap.gotSize);
00925     assert(curOffset == lmap.gotSize);
00926 }
00927 
00928 /*
00929  * .ctors and .dtors section handling
00930  * 
00931  * .ctors/.dtors sections are not defined by the ELF standard, LSB defines them.
00932  * This is why this implementation is specific to Linux and x86.
00933  *
00934  * Layout of .ctors and .dtors sections on Linux x86
00935  *
00936  * Executable .ctors/.dtors format (size in bytes = n)
00937  *
00938  *  byte 0..3    byte 4..7     byte 8..11        byte n-4..n-1
00939  * 0xffffffff <func. ptr 1> <func. ptr 2> ...  0x00000000
00940  *
00941  * Relocatable file .ctors/.dtors format (size in bytes = n)
00942  *
00943  *   byte 0..3         byte n-4..n-1
00944  * <func. ptr 1> ... <last func. ptr>
00945  *
00946  * The layout is the same on Linux x86_64 except each entry is 8 bytes
00947  * instead of 4. So the header and trailler are the same, but extended to
00948  * 8 bytes.
00949  */
00950 static const string DTOR_NAME(".dtors");
00951 static const string CTOR_NAME(".ctors");
00952 static const string TOC_NAME(".toc");
00953 
00954 Offset emitElfStatic::layoutNewCtorRegion(LinkMap &lmap) {
00955     /* 
00956      * .ctors sections are processed in reverse order on Linux x86. New .ctors
00957      * sections need to be placed before the original .ctors section
00958      */
00959 
00960     Offset retOffset = lmap.ctorRegionOffset;
00961     retOffset += addressWidth_;
00962 
00963     pair<map<Region *, LinkMap::AllocPair>::iterator, bool> result;
00964 
00965     vector<Region *>::iterator reg_it;
00966     for(reg_it = lmap.newCtorRegions.begin(); reg_it != lmap.newCtorRegions.end(); ++reg_it) {
00967         result = lmap.regionAllocs.insert(make_pair(*reg_it, make_pair(0, retOffset)));
00968 
00969         // If the map already contains this Region, this is a logic error
00970         if( !result.second ) {
00971             return ~0UL;
00972         }
00973 
00974         retOffset += (*reg_it)->getDiskSize();
00975     }
00976 
00977     if( lmap.originalCtorRegion != NULL ) {
00978         // Account for original .ctors section (minus the header and trailer)
00979         retOffset += lmap.originalCtorRegion->getDiskSize() - addressWidth_ - addressWidth_;
00980     }
00981     retOffset += addressWidth_;
00982 
00983     return retOffset;
00984 
00985     return 0;
00986 }
00987 
00988 bool emitElfStatic::createNewCtorRegion(LinkMap &lmap) {
00989     char *targetData = lmap.allocatedData;
00990 
00991     if( PPC32_WIDTH != addressWidth_ && PPC64_WIDTH != addressWidth_ ) {
00992         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
00993     }
00994 
00995     unsigned trailerSize, headerSize;
00996 
00997     /* Give the new Region a header and trailer */
00998     Offset headerOffset = lmap.ctorRegionOffset;
00999     Offset trailerOffset;
01000     if( PPC32_WIDTH == addressWidth_ ) {
01001         memcpy(&targetData[headerOffset], &X86_HEADER, sizeof(X86_HEADER));
01002         trailerOffset = lmap.ctorRegionOffset + lmap.ctorSize - sizeof(X86_TRAILER);
01003         memcpy(&targetData[trailerOffset], &X86_TRAILER, sizeof(X86_TRAILER));
01004         headerSize = sizeof(X86_HEADER);
01005         trailerSize = sizeof(X86_TRAILER);
01006     }else{
01007         memcpy(&targetData[headerOffset], &X86_64_HEADER, sizeof(X86_64_HEADER));
01008         trailerOffset = lmap.ctorRegionOffset + lmap.ctorSize - sizeof(X86_64_TRAILER);
01009         memcpy(&targetData[trailerOffset], &X86_64_TRAILER, sizeof(X86_64_TRAILER));
01010         headerSize = sizeof(X86_64_HEADER);
01011         trailerSize = sizeof(X86_64_TRAILER);
01012     }
01013 
01014     if( lmap.originalCtorRegion != NULL ) {
01015         /* Determine where the original .ctors section should be placed */
01016         Offset originalOffset = lmap.ctorRegionOffset + lmap.ctorSize -
01017             trailerSize - (lmap.originalCtorRegion->getDiskSize() - headerSize - trailerSize);
01018 
01019         /* Copy the original .ctors section w/o the header and trailer */
01020         char *rawRegionData = reinterpret_cast<char *>(lmap.originalCtorRegion->getPtrToRawData());
01021         memcpy(&targetData[originalOffset], &rawRegionData[headerSize],
01022                 lmap.originalCtorRegion->getDiskSize() - headerSize - trailerSize);
01023     }
01024 
01025     return true;
01026 }
01027 
01028 
01029 Offset emitElfStatic::layoutNewDtorRegion(LinkMap &lmap) {
01030     /*
01031      * .dtors sections are processed in forward order on Linux x86. So new
01032      * .dtors sections need to be placed after the original .dtors section
01033      */
01034 
01035     Offset retOffset = lmap.dtorRegionOffset;
01036     retOffset += addressWidth_;
01037 
01038     pair<map<Region *, LinkMap::AllocPair>::iterator, bool> result;
01039     if( lmap.originalDtorRegion != NULL ) {
01040         // Account for the original .dtors section (minus the header and trailer)
01041         retOffset += lmap.originalDtorRegion->getDiskSize() - addressWidth_ - addressWidth_;
01042     }
01043 
01044     vector<Region *>::iterator reg_it;
01045     for(reg_it = lmap.newDtorRegions.begin(); reg_it != lmap.newDtorRegions.end(); ++reg_it) {
01046         result = lmap.regionAllocs.insert(make_pair(*reg_it, make_pair(0, retOffset)));
01047 
01048         // If the map already contains this Region, this is a logic error
01049         if( !result.second ) {
01050             return ~0UL;
01051         }
01052 
01053         retOffset += (*reg_it)->getDiskSize();
01054     }
01055 
01056     retOffset += addressWidth_;
01057     return retOffset;
01058 
01059     return 0;
01060 }
01061 
01062 bool emitElfStatic::createNewDtorRegion(LinkMap &lmap) {
01063     char *targetData = lmap.allocatedData;
01064 
01065     if( PPC32_WIDTH != addressWidth_ && PPC64_WIDTH != addressWidth_ ) {
01066         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
01067     }
01068 
01069     unsigned headerSize, trailerSize;
01070 
01071     /* Give the new Region a header and trailer */
01072     Offset headerOffset = lmap.dtorRegionOffset;
01073     Offset trailerOffset;
01074     if( PPC32_WIDTH == addressWidth_ ) {
01075         memcpy(&targetData[headerOffset], &X86_HEADER, sizeof(X86_HEADER));
01076         trailerOffset = lmap.dtorRegionOffset + lmap.dtorSize - sizeof(X86_TRAILER);
01077         memcpy(&targetData[trailerOffset], &X86_TRAILER, sizeof(X86_TRAILER));
01078         headerSize = sizeof(X86_HEADER);
01079         trailerSize = sizeof(X86_TRAILER);
01080     }else{
01081         memcpy(&targetData[headerOffset], &X86_64_HEADER, sizeof(X86_64_HEADER));
01082         trailerOffset = lmap.dtorRegionOffset + lmap.dtorSize - sizeof(X86_64_TRAILER);
01083         memcpy(&targetData[trailerOffset], &X86_64_TRAILER, sizeof(X86_64_TRAILER));
01084         headerSize = sizeof(X86_64_HEADER);
01085         trailerSize = sizeof(X86_64_TRAILER);
01086     }
01087 
01088     if( lmap.originalDtorRegion != NULL ) {
01089         /* Determine where the original .dtors section should be placed */
01090         Offset originalOffset = lmap.dtorRegionOffset + headerSize;
01091 
01092         /* Copy the original .dtors section w/o header and trailer */
01093         char *rawRegionData = reinterpret_cast<char *>(lmap.originalDtorRegion->getPtrToRawData());
01094         memcpy(&targetData[originalOffset], &rawRegionData[headerSize],
01095                 lmap.originalDtorRegion->getDiskSize() - headerSize - trailerSize);
01096     }
01097 
01098     return true;
01099 
01100 }
01101 
01102 bool emitElfStatic::isConstructorRegion(Region *reg) {
01103     return ( CTOR_NAME.compare(reg->getRegionName()) == 0 );
01104 
01105 }
01106 
01107 bool emitElfStatic::isDestructorRegion(Region *reg) {
01108     return ( DTOR_NAME.compare(reg->getRegionName()) == 0 );
01109 }
01110 
01111 bool emitElfStatic::isGOTRegion(Region *reg) {
01112 
01113     if( PPC32_WIDTH == addressWidth_ ) {
01114     return false;
01115     }
01116     return ( TOC_NAME.compare(reg->getRegionName()) == 0 );
01117 }
01118 bool emitElfStatic::isGOTRelocation(unsigned long relType) {
01119     if( PPC32_WIDTH == addressWidth_ ) {
01120         switch(relType) {
01121             case R_PPC_GOT16:
01122             case R_PPC_GOT16_LO:
01123             case R_PPC_GOT16_HI:
01124             case R_PPC_GOT16_HA:
01125             case R_PPC_GOT_TPREL16:
01126             case R_PPC_TLS:
01127                 return true;
01128                 break;
01129             default:
01130                 return false;
01131                 break;
01132         }
01133     } else if( PPC64_WIDTH == addressWidth_) {
01134         switch(relType) {
01135             case R_PPC64_GOT16:
01136             case R_PPC64_GOT16_LO:
01137             case R_PPC64_GOT16_HI:
01138             case R_PPC64_GOT16_HA:
01139             case R_PPC64_TLS:
01140         case R_PPC64_TOC16_DS:
01141             case R_PPC64_TOC16:
01142                 return true;
01143                 break;
01144             default:
01145                 return false;
01146                 break;
01147         }
01148     } else{
01149         assert(!UNKNOWN_ADDRESS_WIDTH_ASSERT);
01150     }
01151 
01152     return false;
01153 }
01154 
01155 void emitElfStatic::getExcludedSymbolNames(set<string> &) {
01156 }
01157 
01158 bool emitElfStatic::updateTOC(Symtab *file, LinkMap &lmap, Offset globalOffset) {
01159   // I don't think we need this now that we're using multiple TOCs. Instead we'll
01160   // split the GOTs. 
01161   // DISABLED
01162   return true;
01163 
01164 
01165   rewrite_printf("Updating TOC in %s\n", file->name().c_str());
01166 
01167   Address GOTbase = lmap.gotRegionOffset;
01168 
01169   Address oldTOC = file->getTOCoffset((Offset) 0);
01170   Address newTOC = GOTbase + 0x8000 + globalOffset; // Convention is to use +8k to split the 
01171   // reachable distance. TODO: calculate this from the original GOT and TOC value.
01172   Address deltaTOC = newTOC - oldTOC;
01173 
01174   rewrite_printf("Set TOC to 0x%lx = 0x%lx + 0x%lx + 0x%lx; old 0x%lx\n", newTOC, GOTbase, 0x8000, globalOffset, oldTOC);
01175 
01176   // We're doing this _before_ the emitElf64::driver call, so we can make changes
01177   // to original sections. That's good, because we need to update the OPD section
01178   // to match our new TOC value. 
01179 
01180   Region *OPD = NULL;
01181   if (!file->findRegion(OPD, ".opd")) return true;
01182   
01183   unsigned long *oldData = (unsigned long *) OPD->getPtrToRawData();
01184   unsigned long *newData = (unsigned long *) malloc(OPD->getDiskSize());
01185   memcpy(newData, oldData, OPD->getDiskSize());
01186   OPD->setPtrToRawData(newData, OPD->getDiskSize());
01187 
01188   // Let's do the thing. 
01189   // The OPD data structures are 3-tuples of <func ptr, TOC, misc>. We want
01190   // to update the TOC part of that. So... cleverness.
01191   for (unsigned i = 1; i < (OPD->getDiskSize() / sizeof(unsigned long)); i += 3) {
01192     unsigned long oldVal = newData[i];
01193     newData[i] = oldVal + deltaTOC;
01194   }
01195 
01196   return true;
01197 }
01198 
01199 Offset emitElfStatic::allocStubRegions(LinkMap &lmap, Offset globalOffset) {
01200   // Count the number of external calls in each Region and alloc
01201   // 16 (4*insnsize) bytes for each. 
01202   //
01203   // 16: stub code pattern is:
01204   //   std   r2, 40(r1)
01205   //   addis r2, r2, <hi(new TOC - old TOC)>
01206   //   addi  r2, r2, <lo(new TOC - old TOC)>
01207   //   b     <destination>
01208 
01209   // We can get external calls by looking for unique relocation destinations; 
01210   // any intra-module call would not have a relocation. 
01211   
01212   // So. Relocation time. 
01213   // We can't just count relocations because there are TOC setting relocs and we'll massively overapproximate. 
01214   // Instead, count of type R_PPC64_REL24. Also, unique. 
01215 
01216   Offset relStubOffset = lmap.stubRegionOffset;
01217   rewrite_printf("Allocating stub regions for inter-module calls\n");
01218 
01219   for (deque<Region *>::iterator reg_iter = lmap.codeRegions.begin(); reg_iter != lmap.codeRegions.end(); ++reg_iter) {
01220     vector<relocationEntry> region_rels = (*reg_iter)->getRelocations();
01221     rewrite_printf("\t For region %s in %s, %d relocations, %d unique symbols so far\n",
01222            (*reg_iter)->getRegionName().c_str(), 
01223            (*reg_iter)->symtab()->name().c_str(),
01224            region_rels.size(), 
01225            lmap.stubMap.size());
01226     for (vector<relocationEntry>::iterator rel_iter = region_rels.begin(); rel_iter != region_rels.end(); ++rel_iter) {
01227       relocationEntry &rel = *rel_iter;
01228       if (rel.getRelType() != R_PPC64_REL24) continue;
01229       
01230       if (lmap.stubMap.find(rel.getDynSym()) == lmap.stubMap.end()) {
01231     rewrite_printf("\t\tSetting stub offset for %s to 0x%lx\n", rel.getDynSym()->getMangledName().c_str(), relStubOffset);
01232     lmap.stubMap[rel.getDynSym()] = relStubOffset + globalOffset;
01233     relStubOffset += 4*sizeof(unsigned);
01234       }
01235     }
01236   }
01237   rewrite_printf("\t After regions, returning offset 0x%lx = current 0x%lx + stub area 0x%lx\n",
01238          lmap.stubRegionOffset + (16 * lmap.stubMap.size()), lmap.stubRegionOffset, 16*lmap.stubMap.size());
01239   return relStubOffset;
01240 }
01241 
01242 
01243 bool emitElfStatic::handleInterModuleSpecialCase(Symtab *target,
01244                          Symtab *src,
01245                          LinkMap &lmap,
01246                          char *data,
01247                          relocationEntry rel,
01248                          Offset newTOC,
01249                          Offset oldTOC,
01250                          Offset dest,
01251                          Offset relOffset,
01252                          Offset globalOffset) {
01253   // This isn't that bad :)
01254   //
01255   // We have code of the following type:
01256   //
01257   // call <target>
01258   // nop
01259   //
01260   // where <target> is encoded in the relocation rel. We also have
01261   // varying TOC values. 
01262   //
01263   // We want:
01264   //
01265   // call <stub>
01266   // ld r2, 40(r1)
01267   //
01268   // stub code:
01269   // 
01270   // std    r2, 40(r1)
01271   // addis  r2, r2(hi(newTOC - oldTOC))
01272   // addi   r2, r2(lo(newTOC - oldTOC))
01273   // b <target>
01274   //
01275   // So this needs to either look up existing stub code and reuse it 
01276   // or create it. 
01277   //
01278 
01279   unsigned int *td = (unsigned int *)(data + dest - (dest % 4));
01280   unsigned int &call = td[0];
01281   unsigned int &post = td[1];
01282 
01283   instruction callInsn(call);
01284   if (!callInsn.isCall()) {
01285     // A branch or other non-call/noop
01286     return false;
01287   }
01288   if (!post != 0x60000000) {
01289     // No noop for us to restore the TOC
01290     return false;
01291   }
01292 
01293   Offset stubOffset = findOrCreateStub(rel.getDynSym(), lmap, newTOC, oldTOC, data, globalOffset);
01294   Offset branchOffset = stubOffset - relOffset;
01295   rewrite_printf("Handling TOC set stub, using stub offset 0x%lx, curr addr 0x%lx so branch is 0x%lx \n", 
01296          stubOffset, relOffset, branchOffset);
01297   rewrite_printf("\t Raw original call is 0x%lx...", call);
01298   // 6 bits in, 24 bits long
01299   call = setBits(call, 6, 24, (unsigned) (branchOffset));
01300   rewrite_printf("and patched 0x%lx\n", call);
01301   
01302   // And set the TOC restore
01303   // Post better be a noop. Assert for now, return false after devel is done. 
01304   assert(post == 0x60000000);   
01305   // And ld r2, 40(r1). Always the same instruction. 
01306   post = 0xe8410028; 
01307 
01308   return true;
01309 }
01310 
01311 Offset emitElfStatic::findOrCreateStub(Symbol *sym, LinkMap &lmap, Offset newTOC, Offset oldTOC, char *data, Offset globalOffset) {
01312   // Easy case
01313   std::map<Symbol *, TOCstub>::iterator iter = stubMap.find(sym);
01314   if (iter != stubMap.end() &&
01315       getNewTOC(iter->second) == newTOC &&
01316       getOldTOC(iter->second) == oldTOC) {
01317     return getStubOffset(iter->second);
01318   }
01319 
01320   // Otherwise create one
01321   Offset stubOffset = lmap.stubMap[sym];
01322   assert(stubOffset);
01323 
01324   unsigned stub[4];
01325   createStub(stub, stubOffset, newTOC, oldTOC, sym->getOffset());
01326   
01327   char *td = data + stubOffset - globalOffset;
01328   rewrite_printf("Creating stub at 0x%lx (0x%lx in buffer)\n",
01329          stubOffset, stubOffset - globalOffset);
01330   memcpy(td, stub, 4*sizeof(unsigned));
01331   
01332   stubMap[sym] = TOCstub(stubOffset, newTOC, oldTOC);
01333   return stubOffset;
01334 } 
01335 
01336 void emitElfStatic::createStub(unsigned *stub, Offset stubOffset, Offset newTOC, Offset oldTOC, Offset dest) {
01337 
01338   unsigned deltaTOChi = HA((newTOC - oldTOC));
01339   unsigned deltaTOClo = LOW((newTOC - oldTOC));
01340   unsigned deltaAddr = dest - (stubOffset + 3*sizeof(unsigned));
01341 
01342   rewrite_printf("Calculating stub:\n\thigh TOC bits 0x%x (from 0x%lx - 0x%lx),\n\tlow TOC bits 0x%x (from 0x%lx - 0x%lx),\n\tbranch offset 0x%x (from 0x%lx - 0x%lx)\n",
01343          deltaTOChi, newTOC, oldTOC,
01344          deltaTOClo, newTOC, oldTOC,
01345          deltaAddr, dest, stubOffset);
01346 
01347   stub[0] = 0xf8410028; // std
01348   stub[1] = 0x3c420000 | (deltaTOChi & 0xffff);
01349   stub[2] = 0x38420000 | (deltaTOClo & 0xffff);
01350 
01351   instruction branch;
01352   IFORM_OP_SET(branch, Bop);
01353   IFORM_LI_SET(branch, deltaAddr >> 2);
01354   IFORM_AA_SET(branch, 0);
01355   IFORM_LK_SET(branch, 0);
01356 
01357   stub[3] = branch.asInt();
01358   
01359 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 12 Jul 2013 for SymtabAPI by  doxygen 1.6.1