Back to index

glibc  2.9
dl-machine.c
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation functions.  PowerPC version.
00002    Copyright (C) 1995-2006, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <unistd.h>
00021 #include <string.h>
00022 #include <sys/param.h>
00023 #include <link.h>
00024 #include <ldsodefs.h>
00025 #include <elf/dynamic-link.h>
00026 #include <dl-machine.h>
00027 #include <stdio-common/_itoa.h>
00028 
00029 /* The value __cache_line_size is defined in dl-sysdep.c and is initialised
00030    by _dl_sysdep_start via DL_PLATFORM_INIT.  */
00031 extern int __cache_line_size attribute_hidden;
00032 
00033 /* Because ld.so is now versioned, these functions can be in their own file;
00034    no relocations need to be done to call them.
00035    Of course, if ld.so is not versioned...  */
00036 #if defined SHARED && !(DO_VERSIONING - 0)
00037 #error This will not work with versioning turned off, sorry.
00038 #endif
00039 
00040 
00041 /* Stuff for the PLT.  */
00042 #define PLT_INITIAL_ENTRY_WORDS 18
00043 #define PLT_LONGBRANCH_ENTRY_WORDS 0
00044 #define PLT_TRAMPOLINE_ENTRY_WORDS 6
00045 #define PLT_DOUBLE_SIZE (1<<13)
00046 #define PLT_ENTRY_START_WORDS(entry_number) \
00047   (PLT_INITIAL_ENTRY_WORDS + (entry_number)*2                         \
00048    + ((entry_number) > PLT_DOUBLE_SIZE                                \
00049       ? ((entry_number) - PLT_DOUBLE_SIZE)*2                          \
00050       : 0))
00051 #define PLT_DATA_START_WORDS(num_entries) PLT_ENTRY_START_WORDS(num_entries)
00052 
00053 /* Macros to build PowerPC opcode words.  */
00054 #define OPCODE_ADDI(rd,ra,simm) \
00055   (0x38000000 | (rd) << 21 | (ra) << 16 | ((simm) & 0xffff))
00056 #define OPCODE_ADDIS(rd,ra,simm) \
00057   (0x3c000000 | (rd) << 21 | (ra) << 16 | ((simm) & 0xffff))
00058 #define OPCODE_ADD(rd,ra,rb) \
00059   (0x7c000214 | (rd) << 21 | (ra) << 16 | (rb) << 11)
00060 #define OPCODE_B(target) (0x48000000 | ((target) & 0x03fffffc))
00061 #define OPCODE_BA(target) (0x48000002 | ((target) & 0x03fffffc))
00062 #define OPCODE_BCTR() 0x4e800420
00063 #define OPCODE_LWZ(rd,d,ra) \
00064   (0x80000000 | (rd) << 21 | (ra) << 16 | ((d) & 0xffff))
00065 #define OPCODE_LWZU(rd,d,ra) \
00066   (0x84000000 | (rd) << 21 | (ra) << 16 | ((d) & 0xffff))
00067 #define OPCODE_MTCTR(rd) (0x7C0903A6 | (rd) << 21)
00068 #define OPCODE_RLWINM(ra,rs,sh,mb,me) \
00069   (0x54000000 | (rs) << 21 | (ra) << 16 | (sh) << 11 | (mb) << 6 | (me) << 1)
00070 
00071 #define OPCODE_LI(rd,simm)    OPCODE_ADDI(rd,0,simm)
00072 #define OPCODE_ADDIS_HI(rd,ra,value) \
00073   OPCODE_ADDIS(rd,ra,((value) + 0x8000) >> 16)
00074 #define OPCODE_LIS_HI(rd,value) OPCODE_ADDIS_HI(rd,0,value)
00075 #define OPCODE_SLWI(ra,rs,sh) OPCODE_RLWINM(ra,rs,sh,0,31-sh)
00076 
00077 
00078 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
00079 #define PPC_SYNC asm volatile ("sync" : : : "memory")
00080 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
00081 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
00082 #define PPC_DIE asm volatile ("tweq 0,0")
00083 
00084 /* Use this when you've modified some code, but it won't be in the
00085    instruction fetch queue (or when it doesn't matter if it is). */
00086 #define MODIFIED_CODE_NOQUEUE(where) \
00087      do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
00088 /* Use this when it might be in the instruction queue. */
00089 #define MODIFIED_CODE(where) \
00090      do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
00091 
00092 
00093 /* The idea here is that to conform to the ABI, we are supposed to try
00094    to load dynamic objects between 0x10000 (we actually use 0x40000 as
00095    the lower bound, to increase the chance of a memory reference from
00096    a null pointer giving a segfault) and the program's load address;
00097    this may allow us to use a branch instruction in the PLT rather
00098    than a computed jump.  The address is only used as a preference for
00099    mmap, so if we get it wrong the worst that happens is that it gets
00100    mapped somewhere else.  */
00101 
00102 ElfW(Addr)
00103 __elf_preferred_address (struct link_map *loader, size_t maplength,
00104                       ElfW(Addr) mapstartpref)
00105 {
00106   ElfW(Addr) low, high;
00107   struct link_map *l;
00108   Lmid_t nsid;
00109 
00110   /* If the object has a preference, load it there!  */
00111   if (mapstartpref != 0)
00112     return mapstartpref;
00113 
00114   /* Otherwise, quickly look for a suitable gap between 0x3FFFF and
00115      0x70000000.  0x3FFFF is so that references off NULL pointers will
00116      cause a segfault, 0x70000000 is just paranoia (it should always
00117      be superceded by the program's load address).  */
00118   low =  0x0003FFFF;
00119   high = 0x70000000;
00120   for (nsid = 0; nsid < DL_NNS; ++nsid)
00121     for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
00122       {
00123        ElfW(Addr) mapstart, mapend;
00124        mapstart = l->l_map_start & ~(GLRO(dl_pagesize) - 1);
00125        mapend = l->l_map_end | (GLRO(dl_pagesize) - 1);
00126        assert (mapend > mapstart);
00127 
00128        /* Prefer gaps below the main executable, note that l ==
00129           _dl_loaded does not work for static binaries loading
00130           e.g. libnss_*.so.  */
00131        if ((mapend >= high || l->l_type == lt_executable)
00132            && high >= mapstart)
00133          high = mapstart;
00134        else if (mapend >= low && low >= mapstart)
00135          low = mapend;
00136        else if (high >= mapend && mapstart >= low)
00137          {
00138            if (high - mapend >= mapstart - low)
00139              low = mapend;
00140            else
00141              high = mapstart;
00142          }
00143       }
00144 
00145   high -= 0x10000; /* Allow some room between objects.  */
00146   maplength = (maplength | (GLRO(dl_pagesize) - 1)) + 1;
00147   if (high <= low || high - low < maplength )
00148     return 0;
00149   return high - maplength;  /* Both high and maplength are page-aligned.  */
00150 }
00151 
00152 /* Set up the loaded object described by L so its unrelocated PLT
00153    entries will jump to the on-demand fixup code in dl-runtime.c.
00154    Also install a small trampoline to be used by entries that have
00155    been relocated to an address too far away for a single branch.  */
00156 
00157 /* There are many kinds of PLT entries:
00158 
00159    (1) A direct jump to the actual routine, either a relative or
00160        absolute branch.  These are set up in __elf_machine_fixup_plt.
00161 
00162    (2) Short lazy entries.  These cover the first 8192 slots in
00163         the PLT, and look like (where 'index' goes from 0 to 8191):
00164 
00165        li %r11, index*4
00166        b  &plt[PLT_TRAMPOLINE_ENTRY_WORDS+1]
00167 
00168    (3) Short indirect jumps.  These replace (2) when a direct jump
00169        wouldn't reach.  They look the same except that the branch
00170        is 'b &plt[PLT_LONGBRANCH_ENTRY_WORDS]'.
00171 
00172    (4)  Long lazy entries.  These cover the slots when a short entry
00173        won't fit ('index*4' overflows its field), and look like:
00174 
00175        lis %r11, %hi(index*4 + &plt[PLT_DATA_START_WORDS])
00176        lwzu %r12, %r11, %lo(index*4 + &plt[PLT_DATA_START_WORDS])
00177        b  &plt[PLT_TRAMPOLINE_ENTRY_WORDS]
00178        bctr
00179 
00180    (5) Long indirect jumps.  These replace (4) when a direct jump
00181        wouldn't reach.  They look like:
00182 
00183        lis %r11, %hi(index*4 + &plt[PLT_DATA_START_WORDS])
00184        lwz %r12, %r11, %lo(index*4 + &plt[PLT_DATA_START_WORDS])
00185        mtctr %r12
00186        bctr
00187 
00188    (6) Long direct jumps.  These are used when thread-safety is not
00189        required.  They look like:
00190 
00191        lis %r12, %hi(finaladdr)
00192        addi %r12, %r12, %lo(finaladdr)
00193        mtctr %r12
00194        bctr
00195 
00196 
00197    The lazy entries, (2) and (4), are set up here in
00198    __elf_machine_runtime_setup.  (1), (3), and (5) are set up in
00199    __elf_machine_fixup_plt.  (1), (3), and (6) can also be constructed
00200    in __process_machine_rela.
00201 
00202    The reason for the somewhat strange construction of the long
00203    entries, (4) and (5), is that we need to ensure thread-safety.  For
00204    (1) and (3), this is obvious because only one instruction is
00205    changed and the PPC architecture guarantees that aligned stores are
00206    atomic.  For (5), this is more tricky.  When changing (4) to (5),
00207    the `b' instruction is first changed to to `mtctr'; this is safe
00208    and is why the `lwzu' instruction is not just a simple `addi'.
00209    Once this is done, and is visible to all processors, the `lwzu' can
00210    safely be changed to a `lwz'.  */
00211 int
00212 __elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
00213 {
00214   if (map->l_info[DT_JMPREL])
00215     {
00216       Elf32_Word i;
00217       Elf32_Word *plt = (Elf32_Word *) D_PTR (map, l_info[DT_PLTGOT]);
00218       Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
00219                                 / sizeof (Elf32_Rela));
00220       Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
00221       Elf32_Word data_words = (Elf32_Word) (plt + rel_offset_words);
00222       Elf32_Word size_modified;
00223 
00224       extern void _dl_runtime_resolve (void);
00225       extern void _dl_prof_resolve (void);
00226 
00227       /* Convert the index in r11 into an actual address, and get the
00228         word at that address.  */
00229       plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI (11, 11, data_words);
00230       plt[PLT_LONGBRANCH_ENTRY_WORDS + 1] = OPCODE_LWZ (11, data_words, 11);
00231 
00232       /* Call the procedure at that address.  */
00233       plt[PLT_LONGBRANCH_ENTRY_WORDS + 2] = OPCODE_MTCTR (11);
00234       plt[PLT_LONGBRANCH_ENTRY_WORDS + 3] = OPCODE_BCTR ();
00235 
00236       if (lazy)
00237        {
00238          Elf32_Word *tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
00239          Elf32_Word dlrr = (Elf32_Word)(profile
00240                                     ? _dl_prof_resolve
00241                                     : _dl_runtime_resolve);
00242          Elf32_Word offset;
00243 
00244          if (profile && GLRO(dl_profile) != NULL
00245              && _dl_name_match_p (GLRO(dl_profile), map))
00246            /* This is the object we are looking for.  Say that we really
00247               want profiling and the timers are started.  */
00248            GL(dl_profile_map) = map;
00249 
00250          /* For the long entries, subtract off data_words.  */
00251          tramp[0] = OPCODE_ADDIS_HI (11, 11, -data_words);
00252          tramp[1] = OPCODE_ADDI (11, 11, -data_words);
00253 
00254          /* Multiply index of entry by 3 (in r11).  */
00255          tramp[2] = OPCODE_SLWI (12, 11, 1);
00256          tramp[3] = OPCODE_ADD (11, 12, 11);
00257          if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000)
00258            {
00259              /* Load address of link map in r12.  */
00260              tramp[4] = OPCODE_LI (12, (Elf32_Word) map);
00261              tramp[5] = OPCODE_ADDIS_HI (12, 12, (Elf32_Word) map);
00262 
00263              /* Call _dl_runtime_resolve.  */
00264              tramp[6] = OPCODE_BA (dlrr);
00265            }
00266          else
00267            {
00268              /* Get address of _dl_runtime_resolve in CTR.  */
00269              tramp[4] = OPCODE_LI (12, dlrr);
00270              tramp[5] = OPCODE_ADDIS_HI (12, 12, dlrr);
00271              tramp[6] = OPCODE_MTCTR (12);
00272 
00273              /* Load address of link map in r12.  */
00274              tramp[7] = OPCODE_LI (12, (Elf32_Word) map);
00275              tramp[8] = OPCODE_ADDIS_HI (12, 12, (Elf32_Word) map);
00276 
00277              /* Call _dl_runtime_resolve.  */
00278              tramp[9] = OPCODE_BCTR ();
00279            }
00280 
00281          /* Set up the lazy PLT entries.  */
00282          offset = PLT_INITIAL_ENTRY_WORDS;
00283          i = 0;
00284          while (i < num_plt_entries && i < PLT_DOUBLE_SIZE)
00285            {
00286              plt[offset  ] = OPCODE_LI (11, i * 4);
00287              plt[offset+1] = OPCODE_B ((PLT_TRAMPOLINE_ENTRY_WORDS + 2
00288                                     - (offset+1))
00289                                    * 4);
00290              i++;
00291              offset += 2;
00292            }
00293          while (i < num_plt_entries)
00294            {
00295              plt[offset  ] = OPCODE_LIS_HI (11, i * 4 + data_words);
00296              plt[offset+1] = OPCODE_LWZU (12, i * 4 + data_words, 11);
00297              plt[offset+2] = OPCODE_B ((PLT_TRAMPOLINE_ENTRY_WORDS
00298                                     - (offset+2))
00299                                    * 4);
00300              plt[offset+3] = OPCODE_BCTR ();
00301              i++;
00302              offset += 4;
00303            }
00304        }
00305 
00306       /* Now, we've modified code.  We need to write the changes from
00307         the data cache to a second-level unified cache, then make
00308         sure that stale data in the instruction cache is removed.
00309         (In a multiprocessor system, the effect is more complex.)
00310         Most of the PLT shouldn't be in the instruction cache, but
00311         there may be a little overlap at the start and the end.
00312 
00313         Assumes that dcbst and icbi apply to lines of 16 bytes or
00314         more.  Current known line sizes are 16, 32, and 128 bytes.
00315         The following gets the __cache_line_size, when available.  */
00316 
00317       /* Default minimum 4 words per cache line.  */
00318       int line_size_words = 4;
00319 
00320       if (lazy && __cache_line_size != 0)
00321        /* Convert bytes to words.  */
00322        line_size_words = __cache_line_size / 4;
00323 
00324       size_modified = lazy ? rel_offset_words : 6;
00325       for (i = 0; i < size_modified; i += line_size_words)
00326         PPC_DCBST (plt + i);
00327       PPC_DCBST (plt + size_modified - 1);
00328       PPC_SYNC;
00329 
00330       for (i = 0; i < size_modified; i += line_size_words)
00331         PPC_ICBI (plt + i);
00332       PPC_ICBI (plt + size_modified - 1);
00333       PPC_ISYNC;
00334     }
00335 
00336   return lazy;
00337 }
00338 
00339 Elf32_Addr
00340 __elf_machine_fixup_plt (struct link_map *map, const Elf32_Rela *reloc,
00341                       Elf32_Addr *reloc_addr, Elf32_Addr finaladdr)
00342 {
00343   Elf32_Sword delta = finaladdr - (Elf32_Word) reloc_addr;
00344   if (delta << 6 >> 6 == delta)
00345     *reloc_addr = OPCODE_B (delta);
00346   else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
00347     *reloc_addr = OPCODE_BA (finaladdr);
00348   else
00349     {
00350       Elf32_Word *plt, *data_words;
00351       Elf32_Word index, offset, num_plt_entries;
00352 
00353       num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
00354                       / sizeof(Elf32_Rela));
00355       plt = (Elf32_Word *) D_PTR (map, l_info[DT_PLTGOT]);
00356       offset = reloc_addr - plt;
00357       index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
00358       data_words = plt + PLT_DATA_START_WORDS (num_plt_entries);
00359 
00360       reloc_addr += 1;
00361 
00362       if (index < PLT_DOUBLE_SIZE)
00363        {
00364          data_words[index] = finaladdr;
00365          PPC_SYNC;
00366          *reloc_addr = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1))
00367                               * 4);
00368        }
00369       else
00370        {
00371          index -= (index - PLT_DOUBLE_SIZE)/2;
00372 
00373          data_words[index] = finaladdr;
00374          PPC_SYNC;
00375 
00376          reloc_addr[1] = OPCODE_MTCTR (12);
00377          MODIFIED_CODE_NOQUEUE (reloc_addr + 1);
00378          PPC_SYNC;
00379 
00380          reloc_addr[0] = OPCODE_LWZ (12,
00381                                   (Elf32_Word) (data_words + index), 11);
00382        }
00383     }
00384   MODIFIED_CODE (reloc_addr);
00385   return finaladdr;
00386 }
00387 
00388 void
00389 _dl_reloc_overflow (struct link_map *map,
00390                   const char *name,
00391                   Elf32_Addr *const reloc_addr,
00392                   const Elf32_Sym *refsym)
00393 {
00394   char buffer[128];
00395   char *t;
00396   t = stpcpy (buffer, name);
00397   t = stpcpy (t, " relocation at 0x00000000");
00398   _itoa_word ((unsigned) reloc_addr, t, 16, 0);
00399   if (refsym)
00400     {
00401       const char *strtab;
00402 
00403       strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00404       t = stpcpy (t, " for symbol `");
00405       t = stpcpy (t, strtab + refsym->st_name);
00406       t = stpcpy (t, "'");
00407     }
00408   t = stpcpy (t, " out of range");
00409   _dl_signal_error (0, map->l_name, NULL, buffer);
00410 }
00411 
00412 void
00413 __process_machine_rela (struct link_map *map,
00414                      const Elf32_Rela *reloc,
00415                      struct link_map *sym_map,
00416                      const Elf32_Sym *sym,
00417                      const Elf32_Sym *refsym,
00418                      Elf32_Addr *const reloc_addr,
00419                      Elf32_Addr const finaladdr,
00420                      int rinfo)
00421 {
00422   switch (rinfo)
00423     {
00424     case R_PPC_NONE:
00425       return;
00426 
00427     case R_PPC_ADDR32:
00428     case R_PPC_GLOB_DAT:
00429     case R_PPC_RELATIVE:
00430       *reloc_addr = finaladdr;
00431       return;
00432 
00433     case R_PPC_UADDR32:
00434       ((char *) reloc_addr)[0] = finaladdr >> 24;
00435       ((char *) reloc_addr)[1] = finaladdr >> 16;
00436       ((char *) reloc_addr)[2] = finaladdr >> 8;
00437       ((char *) reloc_addr)[3] = finaladdr;
00438       break;
00439 
00440     case R_PPC_ADDR24:
00441       if (__builtin_expect (finaladdr > 0x01fffffc && finaladdr < 0xfe000000, 0))
00442        _dl_reloc_overflow (map,  "R_PPC_ADDR24", reloc_addr, refsym);
00443       *reloc_addr = (*reloc_addr & 0xfc000003) | (finaladdr & 0x3fffffc);
00444       break;
00445 
00446     case R_PPC_ADDR16:
00447       if (__builtin_expect (finaladdr > 0x7fff && finaladdr < 0xffff8000, 0))
00448        _dl_reloc_overflow (map,  "R_PPC_ADDR16", reloc_addr, refsym);
00449       *(Elf32_Half*) reloc_addr = finaladdr;
00450       break;
00451 
00452     case R_PPC_UADDR16:
00453       if (__builtin_expect (finaladdr > 0x7fff && finaladdr < 0xffff8000, 0))
00454        _dl_reloc_overflow (map,  "R_PPC_UADDR16", reloc_addr, refsym);
00455       ((char *) reloc_addr)[0] = finaladdr >> 8;
00456       ((char *) reloc_addr)[1] = finaladdr;
00457       break;
00458 
00459     case R_PPC_ADDR16_LO:
00460       *(Elf32_Half*) reloc_addr = finaladdr;
00461       break;
00462 
00463     case R_PPC_ADDR16_HI:
00464       *(Elf32_Half*) reloc_addr = finaladdr >> 16;
00465       break;
00466 
00467     case R_PPC_ADDR16_HA:
00468       *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
00469       break;
00470 
00471     case R_PPC_ADDR14:
00472     case R_PPC_ADDR14_BRTAKEN:
00473     case R_PPC_ADDR14_BRNTAKEN:
00474       if (__builtin_expect (finaladdr > 0x7fff && finaladdr < 0xffff8000, 0))
00475        _dl_reloc_overflow (map,  "R_PPC_ADDR14", reloc_addr, refsym);
00476       *reloc_addr = (*reloc_addr & 0xffff0003) | (finaladdr & 0xfffc);
00477       if (rinfo != R_PPC_ADDR14)
00478        *reloc_addr = ((*reloc_addr & 0xffdfffff)
00479                      | ((rinfo == R_PPC_ADDR14_BRTAKEN)
00480                        ^ (finaladdr >> 31)) << 21);
00481       break;
00482 
00483     case R_PPC_REL24:
00484       {
00485        Elf32_Sword delta = finaladdr - (Elf32_Word) reloc_addr;
00486        if (delta << 6 >> 6 != delta)
00487          _dl_reloc_overflow (map,  "R_PPC_REL24", reloc_addr, refsym);
00488        *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
00489       }
00490       break;
00491 
00492     case R_PPC_COPY:
00493       if (sym == NULL)
00494        /* This can happen in trace mode when an object could not be
00495           found.  */
00496        return;
00497       if (sym->st_size > refsym->st_size
00498          || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
00499        {
00500          const char *strtab;
00501 
00502          strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00503          _dl_error_printf ("\
00504 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
00505                          rtld_progname ?: "<program name unknown>",
00506                          strtab + refsym->st_name);
00507        }
00508       memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
00509                                              refsym->st_size));
00510       return;
00511 
00512     case R_PPC_REL32:
00513       *reloc_addr = finaladdr - (Elf32_Word) reloc_addr;
00514       return;
00515 
00516     case R_PPC_JMP_SLOT:
00517       /* It used to be that elf_machine_fixup_plt was used here,
00518         but that doesn't work when ld.so relocates itself
00519         for the second time.  On the bright side, there's
00520          no need to worry about thread-safety here.  */
00521       {
00522        Elf32_Sword delta = finaladdr - (Elf32_Word) reloc_addr;
00523        if (delta << 6 >> 6 == delta)
00524          *reloc_addr = OPCODE_B (delta);
00525        else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
00526          *reloc_addr = OPCODE_BA (finaladdr);
00527        else
00528          {
00529            Elf32_Word *plt, *data_words;
00530            Elf32_Word index, offset, num_plt_entries;
00531 
00532            plt = (Elf32_Word *) D_PTR (map, l_info[DT_PLTGOT]);
00533            offset = reloc_addr - plt;
00534 
00535            if (offset < PLT_DOUBLE_SIZE*2 + PLT_INITIAL_ENTRY_WORDS)
00536              {
00537               index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
00538               num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
00539                                / sizeof(Elf32_Rela));
00540               data_words = plt + PLT_DATA_START_WORDS (num_plt_entries);
00541               data_words[index] = finaladdr;
00542               reloc_addr[0] = OPCODE_LI (11, index * 4);
00543               reloc_addr[1] = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS
00544                                       - (offset+1))
00545                                      * 4);
00546               MODIFIED_CODE_NOQUEUE (reloc_addr + 1);
00547              }
00548            else
00549              {
00550               reloc_addr[0] = OPCODE_LIS_HI (12, finaladdr);
00551               reloc_addr[1] = OPCODE_ADDI (12, 12, finaladdr);
00552               reloc_addr[2] = OPCODE_MTCTR (12);
00553               reloc_addr[3] = OPCODE_BCTR ();
00554               MODIFIED_CODE_NOQUEUE (reloc_addr + 3);
00555              }
00556          }
00557       }
00558       break;
00559 
00560 #define DO_TLS_RELOC(suffix)                                                \
00561     case R_PPC_DTPREL##suffix:                                              \
00562       /* During relocation all TLS symbols are defined and used.            \
00563         Therefore the offset is already correct.  */                        \
00564       if (sym_map != NULL)                                           \
00565        do_reloc##suffix ("R_PPC_DTPREL"#suffix,                      \
00566                        TLS_DTPREL_VALUE (sym, reloc));               \
00567       break;                                                         \
00568     case R_PPC_TPREL##suffix:                                               \
00569       if (sym_map != NULL)                                           \
00570        {                                                             \
00571          CHECK_STATIC_TLS (map, sym_map);                            \
00572          do_reloc##suffix ("R_PPC_TPREL"#suffix,                     \
00573                          TLS_TPREL_VALUE (sym_map, sym, reloc));            \
00574        }                                                             \
00575       break;
00576 
00577     inline void do_reloc16 (const char *r_name, Elf32_Addr value)
00578       {
00579        if (__builtin_expect (value > 0x7fff && value < 0xffff8000, 0))
00580          _dl_reloc_overflow (map, r_name, reloc_addr, refsym);
00581        *(Elf32_Half *) reloc_addr = value;
00582       }
00583     inline void do_reloc16_LO (const char *r_name, Elf32_Addr value)
00584       {
00585        *(Elf32_Half *) reloc_addr = value;
00586       }
00587     inline void do_reloc16_HI (const char *r_name, Elf32_Addr value)
00588       {
00589        *(Elf32_Half *) reloc_addr = value >> 16;
00590       }
00591     inline void do_reloc16_HA (const char *r_name, Elf32_Addr value)
00592       {
00593        *(Elf32_Half *) reloc_addr = (value + 0x8000) >> 16;
00594       }
00595     DO_TLS_RELOC (16)
00596     DO_TLS_RELOC (16_LO)
00597     DO_TLS_RELOC (16_HI)
00598     DO_TLS_RELOC (16_HA)
00599 
00600     default:
00601       _dl_reloc_bad_type (map, rinfo, 0);
00602       return;
00603     }
00604 
00605   MODIFIED_CODE_NOQUEUE (reloc_addr);
00606 }