Back to index

glibc  2.9
dl-machine.h
Go to the documentation of this file.
00001 /* Machine-dependent ELF dynamic relocation inline functions.
00002    PowerPC64 version.
00003    Copyright 1995-2005, 2006, 2008 Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public License as
00008    published by the Free Software Foundation; either version 2 of the
00009    License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public
00017    License along with the GNU C Library; see the file COPYING.LIB.  If not,
00018    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.  */
00020 
00021 #ifndef dl_machine_h
00022 #define dl_machine_h
00023 
00024 #define ELF_MACHINE_NAME "powerpc64"
00025 
00026 #include <assert.h>
00027 #include <sys/param.h>
00028 #include <dl-tls.h>
00029 #include <sysdep.h>
00030 
00031 /* Translate a processor specific dynamic tag to the index
00032    in l_info array.  */
00033 #define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
00034 
00035 /* A PowerPC64 function descriptor.  The .plt (procedure linkage
00036    table) and .opd (official procedure descriptor) sections are
00037    arrays of these.  */
00038 typedef struct
00039 {
00040   Elf64_Addr fd_func;
00041   Elf64_Addr fd_toc;
00042   Elf64_Addr fd_aux;
00043 } Elf64_FuncDesc;
00044 
00045 #define ELF_MULT_MACHINES_SUPPORTED
00046 
00047 /* Return nonzero iff ELF header is compatible with the running host.  */
00048 static inline int
00049 elf_machine_matches_host (const Elf64_Ehdr *ehdr)
00050 {
00051   return ehdr->e_machine == EM_PPC64;
00052 }
00053 
00054 /* Return nonzero iff ELF header is compatible with the running host,
00055    but not this loader.  */
00056 static inline int
00057 elf_host_tolerates_machine (const Elf64_Ehdr *ehdr)
00058 {
00059   return ehdr->e_machine == EM_PPC;
00060 }
00061 
00062 /* Return nonzero iff ELF header is compatible with the running host,
00063    but not this loader.  */
00064 static inline int
00065 elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
00066 {
00067   return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
00068 }
00069 
00070 
00071 /* Return the run-time load address of the shared object, assuming it
00072    was originally linked at zero.  */
00073 static inline Elf64_Addr
00074 elf_machine_load_address (void) __attribute__ ((const));
00075 
00076 static inline Elf64_Addr
00077 elf_machine_load_address (void)
00078 {
00079   Elf64_Addr ret;
00080 
00081   /* The first entry in .got (and thus the first entry in .toc) is the
00082      link-time TOC_base, ie. r2.  So the difference between that and
00083      the current r2 set by the kernel is how far the shared lib has
00084      moved.  */
00085   asm (       "      ld     %0,-32768(2)\n"
00086        "      subf   %0,%0,2\n"
00087        : "=r" (ret));
00088   return ret;
00089 }
00090 
00091 /* Return the link-time address of _DYNAMIC.  */
00092 static inline Elf64_Addr
00093 elf_machine_dynamic (void)
00094 {
00095   Elf64_Addr runtime_dynamic;
00096   /* It's easier to get the run-time address.  */
00097   asm (       "      addis  %0,2,_DYNAMIC@toc@ha\n"
00098        "      addi   %0,%0,_DYNAMIC@toc@l\n"
00099        : "=b" (runtime_dynamic));
00100   /* Then subtract off the load address offset.  */
00101   return runtime_dynamic - elf_machine_load_address() ;
00102 }
00103 
00104 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
00105 
00106 /* The PLT uses Elf64_Rela relocs.  */
00107 #define elf_machine_relplt elf_machine_rela
00108 
00109 
00110 #ifdef HAVE_INLINED_SYSCALLS
00111 /* We do not need _dl_starting_up.  */
00112 # define DL_STARTING_UP_DEF
00113 #else
00114 # define DL_STARTING_UP_DEF \
00115 ".LC__dl_starting_up:\n"  \
00116 "      .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n"
00117 #endif
00118 
00119 
00120 /* Initial entry point code for the dynamic linker.  The C function
00121    `_dl_start' is the real entry point; its return value is the user
00122    program's entry point.  */
00123 #define RTLD_START \
00124   asm (".pushsection \".text\"\n"                              \
00125 "      .align 2\n"                                             \
00126 "      .type  " BODY_PREFIX "_start,@function\n"               \
00127 "      .pushsection \".opd\",\"aw\"\n"                                \
00128 "      .align 3\n"                                             \
00129 "      .globl _start\n"                                        \
00130 "      " ENTRY_2(_start) "\n"                                         \
00131 "_start:\n"                                                    \
00132 "      " OPD_ENT(_start) "\n"                                         \
00133 "      .popsection\n"                                                 \
00134 BODY_PREFIX "_start:\n"                                               \
00135 /* We start with the following on the stack, from top:                \
00136    argc (4 bytes);                                             \
00137    arguments for program (terminated by NULL);                        \
00138    environment variables (terminated by NULL);                        \
00139    arguments for the program loader.  */                       \
00140 "      mr     3,1\n"                                           \
00141 "      li     4,0\n"                                           \
00142 "      stdu   4,-128(1)\n"                                     \
00143 /* Call _dl_start with one parameter pointing at argc.  */            \
00144 "      bl     " DOT_PREFIX "_dl_start\n"                       \
00145 "      nop\n"                                                  \
00146 /* Transfer control to _dl_start_user!  */                            \
00147 "      b      " DOT_PREFIX "_dl_start_user\n"                         \
00148 ".LT__start:\n"                                                       \
00149 "      .long 0\n"                                              \
00150 "      .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n"        \
00151 "      .long .LT__start-" BODY_PREFIX "_start\n"               \
00152 "      .short .LT__start_name_end-.LT__start_name_start\n"            \
00153 ".LT__start_name_start:\n"                                     \
00154 "      .ascii \"_start\"\n"                                    \
00155 ".LT__start_name_end:\n"                                       \
00156 "      .align 2\n"                                             \
00157 "      " END_2(_start) "\n"                                    \
00158 "      .globl _dl_start_user\n"                                \
00159 "      .pushsection \".opd\",\"aw\"\n"                                \
00160 "_dl_start_user:\n"                                            \
00161 "      " OPD_ENT(_dl_start_user) "\n"                                 \
00162 "      .popsection\n"                                                 \
00163 "      .pushsection  \".toc\",\"aw\"\n"                        \
00164 DL_STARTING_UP_DEF                                             \
00165 ".LC__rtld_global:\n"                                                 \
00166 "      .tc _rtld_global[TC],_rtld_global\n"                           \
00167 ".LC__dl_argc:\n"                                              \
00168 "      .tc _dl_argc[TC],_dl_argc\n"                                   \
00169 ".LC__dl_argv:\n"                                              \
00170 "      .tc _dl_argv_internal[TC],_dl_argv_internal\n"                 \
00171 ".LC__dl_fini:\n"                                              \
00172 "      .tc _dl_fini[TC],_dl_fini\n"                                   \
00173 "      .popsection\n"                                                 \
00174 "      .type  " BODY_PREFIX "_dl_start_user,@function\n"              \
00175 "      " ENTRY_2(_dl_start_user) "\n"                                 \
00176 /* Now, we do our main work of calling initialisation procedures.     \
00177    The ELF ABI doesn't say anything about parameters for these,              \
00178    so we just pass argc, argv, and the environment.                   \
00179    Changing these is strongly discouraged (not least because argc is  \
00180    passed by value!).  */                                      \
00181 BODY_PREFIX "_dl_start_user:\n"                                       \
00182 /* the address of _start in r30.  */                                  \
00183 "      mr     30,3\n"                                                 \
00184 /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28.  */        \
00185 "      ld     28,.LC__rtld_global@toc(2)\n"                           \
00186 "      ld     29,.LC__dl_argc@toc(2)\n"                        \
00187 "      ld     27,.LC__dl_argv@toc(2)\n"                        \
00188 /* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1).  */       \
00189 "      ld     3,0(28)\n"                                       \
00190 "      lwa    4,0(29)\n"                                       \
00191 "      ld     5,0(27)\n"                                       \
00192 "      sldi   6,4,3\n"                                         \
00193 "      add    6,5,6\n"                                         \
00194 "      addi   6,6,8\n"                                         \
00195 "      bl     " DOT_PREFIX "_dl_init\n"                        \
00196 "      nop\n"                                                  \
00197 /* Now, to conform to the ELF ABI, we have to:                        \
00198    Pass argc (actually _dl_argc) in r3;  */                           \
00199 "      lwa    3,0(29)\n"                                       \
00200 /* Pass argv (actually _dl_argv) in r4;  */                           \
00201 "      ld     4,0(27)\n"                                       \
00202 /* Pass argv+argc+1 in r5;  */                                        \
00203 "      sldi   5,3,3\n"                                         \
00204 "      add    6,4,5\n"                                         \
00205 "      addi   5,6,8\n"                                         \
00206 /* Pass the auxilary vector in r6. This is passed to us just after    \
00207    _envp.  */                                                  \
00208 "2:    ldu    0,8(6)\n"                                        \
00209 "      cmpdi  0,0\n"                                           \
00210 "      bne    2b\n"                                            \
00211 "      addi   6,6,8\n"                                         \
00212 /* Pass a termination function pointer (in this case _dl_fini) in     \
00213    r7.  */                                                     \
00214 "      ld     7,.LC__dl_fini@toc(2)\n"                         \
00215 /* Pass the stack pointer in r1 (so far so good), pointing to a NULL  \
00216    value.  This lets our startup code distinguish between a program   \
00217    linked statically, which linux will call with argc on top of the   \
00218    stack which will hopefully never be zero, and a dynamically linked \
00219    program which will always have a NULL on the top of the stack.     \
00220    Take the opportunity to clear LR, so anyone who accidentally              \
00221    returns from _start gets SEGV.  Also clear the next few words of   \
00222    the stack.  */                                              \
00223 "      li     31,0\n"                                                 \
00224 "      std    31,0(1)\n"                                       \
00225 "      mtlr   31\n"                                            \
00226 "      std    31,8(1)\n"                                       \
00227 "      std    31,16(1)\n"                                      \
00228 "      std    31,24(1)\n"                                      \
00229 /* Now, call the start function descriptor at r30...  */              \
00230 "      .globl ._dl_main_dispatch\n"                                   \
00231 "._dl_main_dispatch:\n"                                               \
00232 "      ld     0,0(30)\n"                                       \
00233 "      ld     2,8(30)\n"                                       \
00234 "      mtctr  0\n"                                             \
00235 "      ld     11,16(30)\n"                                     \
00236 "      bctr\n"                                                        \
00237 ".LT__dl_start_user:\n"                                               \
00238 "      .long 0\n"                                              \
00239 "      .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n"        \
00240 "      .long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n"      \
00241 "      .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \
00242 ".LT__dl_start_user_name_start:\n"                             \
00243 "      .ascii \"_dl_start_user\"\n"                                   \
00244 ".LT__dl_start_user_name_end:\n"                               \
00245 "      .align 2\n"                                             \
00246 "      " END_2(_dl_start_user) "\n"                                   \
00247 "      .popsection");
00248 
00249 /* ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to
00250    one of the main executable's symbols, as for a COPY reloc.
00251 
00252    To make function pointer comparisons work on most targets, the
00253    relevant ABI states that the address of a non-local function in a
00254    dynamically linked executable is the address of the PLT entry for
00255    that function.  This is quite reasonable since using the real
00256    function address in a non-PIC executable would typically require
00257    dynamic relocations in .text, something to be avoided.  For such
00258    functions, the linker emits a SHN_UNDEF symbol in the executable
00259    with value equal to the PLT entry address.  Normally, SHN_UNDEF
00260    symbols have a value of zero, so this is a clue to ld.so that it
00261    should treat these symbols specially.  For relocations not in
00262    ELF_RTYPE_CLASS_PLT (eg. those on function pointers), ld.so should
00263    use the value of the executable SHN_UNDEF symbol, ie. the PLT entry
00264    address.  For relocations in ELF_RTYPE_CLASS_PLT (eg. the relocs in
00265    the PLT itself), ld.so should use the value of the corresponding
00266    defined symbol in the object that defines the function, ie. the
00267    real function address.  This complicates ld.so in that there are
00268    now two possible values for a given symbol, and it gets even worse
00269    because protected symbols need yet another set of rules.
00270 
00271    On PowerPC64 we don't need any of this.  The linker won't emit
00272    SHN_UNDEF symbols with non-zero values.  ld.so can make all
00273    relocations behave "normally", ie. always use the real address
00274    like PLT relocations.  So always set ELF_RTYPE_CLASS_PLT.  */
00275 
00276 #define elf_machine_type_class(type) \
00277   (ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
00278 
00279 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
00280 #define ELF_MACHINE_JMP_SLOT       R_PPC64_JMP_SLOT
00281 
00282 /* The PowerPC never uses REL relocations.  */
00283 #define ELF_MACHINE_NO_REL 1
00284 
00285 /* Stuff for the PLT.  */
00286 #define PLT_INITIAL_ENTRY_WORDS 3
00287 #define GLINK_INITIAL_ENTRY_WORDS 8
00288 
00289 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
00290 #define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
00291 #define PPC_DCBF(where) asm volatile ("dcbf 0,%0" : : "r"(where) : "memory")
00292 #define PPC_SYNC asm volatile ("sync" : : : "memory")
00293 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
00294 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
00295 #define PPC_DIE asm volatile ("tweq 0,0")
00296 /* Use this when you've modified some code, but it won't be in the
00297    instruction fetch queue (or when it doesn't matter if it is). */
00298 #define MODIFIED_CODE_NOQUEUE(where) \
00299      do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
00300 /* Use this when it might be in the instruction queue. */
00301 #define MODIFIED_CODE(where) \
00302      do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
00303 
00304 /* Set up the loaded object described by MAP so its unrelocated PLT
00305    entries will jump to the on-demand fixup code in dl-runtime.c.  */
00306 static inline int __attribute__ ((always_inline))
00307 elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
00308 {
00309   if (map->l_info[DT_JMPREL])
00310     {
00311       Elf64_Word i;
00312       Elf64_Word *glink = NULL;
00313       Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]);
00314       Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
00315                                 / sizeof (Elf64_Rela));
00316       Elf64_Addr l_addr = map->l_addr;
00317       Elf64_Dyn **info = map->l_info;
00318       char *p;
00319 
00320       extern void _dl_runtime_resolve (void);
00321       extern void _dl_profile_resolve (void);
00322 
00323       /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section.
00324         elf_get_dynamic_info takes care of the standard entries but
00325         doesn't know exactly what to do with processor specific
00326         entires.  */
00327       if (info[DT_PPC64(GLINK)] != NULL)
00328        info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr;
00329 
00330       if (lazy)
00331        {
00332          /* The function descriptor of the appropriate trampline
00333             routine is used to set the 1st and 2nd doubleword of the
00334             plt_reserve.  */
00335          Elf64_FuncDesc *resolve_fd;
00336          Elf64_Word glink_offset;
00337          /* the plt_reserve area is the 1st 3 doublewords of the PLT */
00338          Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
00339          Elf64_Word offset;
00340 
00341          resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
00342                                       : _dl_runtime_resolve);
00343          if (profile && GLRO(dl_profile) != NULL
00344              && _dl_name_match_p (GLRO(dl_profile), map))
00345            /* This is the object we are looking for.  Say that we really
00346               want profiling and the timers are started.  */
00347            GL(dl_profile_map) = map;
00348 
00349 
00350          /* We need to stuff the address/TOC of _dl_runtime_resolve
00351             into doublewords 0 and 1 of plt_reserve.  Then we need to
00352             stuff the map address into doubleword 2 of plt_reserve.
00353             This allows the GLINK0 code to transfer control to the
00354             correct trampoline which will transfer control to fixup
00355             in dl-machine.c.  */
00356          plt_reserve->fd_func = resolve_fd->fd_func;
00357          plt_reserve->fd_toc  = resolve_fd->fd_toc;
00358          plt_reserve->fd_aux  = (Elf64_Addr) map;
00359 #ifdef RTLD_BOOTSTRAP
00360          /* When we're bootstrapping, the opd entry will not have
00361             been relocated yet.  */
00362          plt_reserve->fd_func += l_addr;
00363          plt_reserve->fd_toc  += l_addr;
00364 #endif
00365 
00366          /* Set up the lazy PLT entries.  */
00367          glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]);
00368          offset = PLT_INITIAL_ENTRY_WORDS;
00369          glink_offset = GLINK_INITIAL_ENTRY_WORDS;
00370          for (i = 0; i < num_plt_entries; i++)
00371            {
00372 
00373              plt[offset] = (Elf64_Xword) &glink[glink_offset];
00374              offset += 3;
00375              /* The first 32k entries of glink can set an index and
00376                branch using two instructions;  Past that point,
00377                glink uses three instructions.  */
00378              if (i < 0x8000)
00379               glink_offset += 2;
00380              else
00381               glink_offset += 3;
00382            }
00383 
00384          /* Now, we've modified data.  We need to write the changes from
00385             the data cache to a second-level unified cache, then make
00386             sure that stale data in the instruction cache is removed.
00387             (In a multiprocessor system, the effect is more complex.)
00388             Most of the PLT shouldn't be in the instruction cache, but
00389             there may be a little overlap at the start and the end.
00390 
00391             Assumes that dcbst and icbi apply to lines of 16 bytes or
00392             more.  Current known line sizes are 16, 32, and 128 bytes.  */
00393 
00394          for (p = (char *) plt; p < (char *) &plt[offset]; p += 16)
00395            PPC_DCBST (p);
00396          PPC_SYNC;
00397        }
00398     }
00399   return lazy;
00400 }
00401 
00402 /* Change the PLT entry whose reloc is 'reloc' to call the actual
00403    routine.  */
00404 static inline Elf64_Addr __attribute__ ((always_inline))
00405 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
00406                      const Elf64_Rela *reloc,
00407                      Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
00408 {
00409   Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
00410   Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
00411   Elf64_Addr offset = 0;
00412 
00413   PPC_DCBT (&plt->fd_aux);
00414   PPC_DCBT (&plt->fd_func);
00415   PPC_DCBT (&rel->fd_aux);
00416   PPC_DCBT (&rel->fd_func);
00417 
00418   /* If sym_map is NULL, it's a weak undefined sym;  Leave the plt zero.  */
00419   if (sym_map == NULL)
00420     return 0;
00421 
00422   /* If the opd entry is not yet relocated (because it's from a shared
00423      object that hasn't been processed yet), then manually reloc it.  */
00424   if (map != sym_map && !sym_map->l_relocated
00425 #if !defined RTLD_BOOTSTRAP && defined SHARED
00426       /* Bootstrap map doesn't have l_relocated set for it.  */
00427       && sym_map != &GL(dl_rtld_map)
00428 #endif
00429       )
00430     offset = sym_map->l_addr;
00431 
00432   /* For PPC64, fixup_plt copies the function descriptor from opd
00433      over the corresponding PLT entry.
00434      Initially, PLT Entry[i] is set up for lazy linking, or is zero.
00435      For lazy linking, the fd_toc and fd_aux entries are irrelevant,
00436      so for thread safety we write them before changing fd_func.  */
00437 
00438   plt->fd_aux = rel->fd_aux + offset;
00439   plt->fd_toc = rel->fd_toc + offset;
00440   PPC_DCBF (&plt->fd_toc);
00441   PPC_ISYNC;
00442 
00443   plt->fd_func = rel->fd_func + offset;
00444   PPC_DCBST (&plt->fd_func);
00445   PPC_ISYNC;
00446 
00447   return finaladdr;
00448 }
00449 
00450 static inline void __attribute__ ((always_inline))
00451 elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
00452 {
00453   Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
00454   Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
00455 
00456   plt->fd_func = rel->fd_func;
00457   plt->fd_aux = rel->fd_aux;
00458   plt->fd_toc = rel->fd_toc;
00459   PPC_DCBST (&plt->fd_func);
00460   PPC_DCBST (&plt->fd_aux);
00461   PPC_DCBST (&plt->fd_toc);
00462   PPC_SYNC;
00463 }
00464 
00465 /* Return the final value of a plt relocation.  */
00466 static inline Elf64_Addr
00467 elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
00468                      Elf64_Addr value)
00469 {
00470   return value + reloc->r_addend;
00471 }
00472 
00473 
00474 /* Names of the architecture-specific auditing callback functions.  */
00475 #define ARCH_LA_PLTENTER ppc64_gnu_pltenter
00476 #define ARCH_LA_PLTEXIT ppc64_gnu_pltexit
00477 
00478 #endif /* dl_machine_h */
00479 
00480 #ifdef RESOLVE_MAP
00481 
00482 #define PPC_LO(v) ((v) & 0xffff)
00483 #define PPC_HI(v) (((v) >> 16) & 0xffff)
00484 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
00485 #define PPC_HIGHER(v) (((v) >> 32) & 0xffff)
00486 #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000)
00487 #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff)
00488 #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000)
00489 #define BIT_INSERT(var, val, mask) \
00490   ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask)))
00491 
00492 #define dont_expect(X) __builtin_expect ((X), 0)
00493 
00494 extern void _dl_reloc_overflow (struct link_map *map,
00495                                 const char *name,
00496                                 Elf64_Addr *const reloc_addr,
00497                                 const Elf64_Sym *refsym)
00498                                 attribute_hidden;
00499 
00500 auto inline void __attribute__ ((always_inline))
00501 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
00502                         void *const reloc_addr_arg)
00503 {
00504   Elf64_Addr *const reloc_addr = reloc_addr_arg;
00505   *reloc_addr = l_addr + reloc->r_addend;
00506 }
00507 
00508 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00509 /* This computes the value used by TPREL* relocs.  */
00510 auto inline Elf64_Addr __attribute__ ((always_inline, const))
00511 elf_machine_tprel (struct link_map *map,
00512                  struct link_map *sym_map,
00513                  const Elf64_Sym *sym,
00514                  const Elf64_Rela *reloc)
00515 {
00516 # ifndef RTLD_BOOTSTRAP
00517   if (sym_map)
00518     {
00519       CHECK_STATIC_TLS (map, sym_map);
00520 # endif
00521       return TLS_TPREL_VALUE (sym_map, sym, reloc);
00522 # ifndef RTLD_BOOTSTRAP
00523     }
00524 # endif
00525   return 0;
00526 }
00527 #endif
00528 
00529 /* Perform the relocation specified by RELOC and SYM (which is fully
00530    resolved).  MAP is the object containing the reloc.  */
00531 auto inline void __attribute__ ((always_inline))
00532 elf_machine_rela (struct link_map *map,
00533                 const Elf64_Rela *reloc,
00534                 const Elf64_Sym *sym,
00535                 const struct r_found_version *version,
00536                 void *const reloc_addr_arg)
00537 {
00538   Elf64_Addr *const reloc_addr = reloc_addr_arg;
00539   const int r_type = ELF64_R_TYPE (reloc->r_info);
00540 #ifndef RTLD_BOOTSTRAP
00541   const Elf64_Sym *const refsym = sym;
00542 #endif
00543 
00544   if (r_type == R_PPC64_RELATIVE)
00545     {
00546       *reloc_addr = map->l_addr + reloc->r_addend;
00547       return;
00548     }
00549 
00550   if (__builtin_expect (r_type == R_PPC64_NONE, 0))
00551     return;
00552 
00553   /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt.  */
00554   struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
00555   Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value)
00556                     + reloc->r_addend);
00557 
00558   /* For relocs that don't edit code, return.
00559      For relocs that might edit instructions, break from the switch.  */
00560   switch (r_type)
00561     {
00562     case R_PPC64_ADDR64:
00563     case R_PPC64_GLOB_DAT:
00564       *reloc_addr = value;
00565       return;
00566 
00567     case R_PPC64_JMP_SLOT:
00568 #ifdef RESOLVE_CONFLICT_FIND_MAP
00569       elf_machine_plt_conflict (reloc_addr, value);
00570 #else
00571       elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
00572 #endif
00573       return;
00574 
00575 #if !defined RTLD_BOOTSTRAP || USE___THREAD
00576     case R_PPC64_DTPMOD64:
00577 # ifdef RTLD_BOOTSTRAP
00578       /* During startup the dynamic linker is always index 1.  */
00579       *reloc_addr = 1;
00580 # else
00581       /* Get the information from the link map returned by the
00582         resolve function.  */
00583       if (sym_map != NULL)
00584         *reloc_addr = sym_map->l_tls_modid;
00585 # endif
00586       return;
00587 
00588     case R_PPC64_DTPREL64:
00589       /* During relocation all TLS symbols are defined and used.
00590          Therefore the offset is already correct.  */
00591 # ifndef RTLD_BOOTSTRAP
00592       if (sym_map != NULL)
00593        *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
00594 # endif
00595       return;
00596 
00597     case R_PPC64_TPREL64:
00598       *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc);
00599       return;
00600 
00601     case R_PPC64_TPREL16_LO_DS:
00602       value = elf_machine_tprel (map, sym_map, sym, reloc);
00603       if (dont_expect ((value & 3) != 0))
00604         _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym);
00605       *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
00606                                           value, 0xfffc);
00607       break;
00608 
00609     case R_PPC64_TPREL16_DS:
00610       value = elf_machine_tprel (map, sym_map, sym, reloc);
00611       if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
00612         _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym);
00613       *(Elf64_Half *) reloc_addr = BIT_INSERT (*(Elf64_Half *) reloc_addr,
00614                                           value, 0xfffc);
00615       break;
00616 
00617     case R_PPC64_TPREL16:
00618       value = elf_machine_tprel (map, sym_map, sym, reloc);
00619       if (dont_expect ((value + 0x8000) >= 0x10000))
00620         _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym);
00621       *(Elf64_Half *) reloc_addr = PPC_LO (value);
00622       break;
00623 
00624     case R_PPC64_TPREL16_LO:
00625       value = elf_machine_tprel (map, sym_map, sym, reloc);
00626       *(Elf64_Half *) reloc_addr = PPC_LO (value);
00627       break;
00628 
00629     case R_PPC64_TPREL16_HI:
00630       value = elf_machine_tprel (map, sym_map, sym, reloc);
00631       *(Elf64_Half *) reloc_addr = PPC_HI (value);
00632       break;
00633 
00634     case R_PPC64_TPREL16_HA:
00635       value = elf_machine_tprel (map, sym_map, sym, reloc);
00636       *(Elf64_Half *) reloc_addr = PPC_HA (value);
00637       break;
00638 
00639     case R_PPC64_TPREL16_HIGHER:
00640       value = elf_machine_tprel (map, sym_map, sym, reloc);
00641       *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
00642       break;
00643 
00644     case R_PPC64_TPREL16_HIGHEST:
00645       value = elf_machine_tprel (map, sym_map, sym, reloc);
00646       *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
00647       break;
00648 
00649     case R_PPC64_TPREL16_HIGHERA:
00650       value = elf_machine_tprel (map, sym_map, sym, reloc);
00651       *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
00652       break;
00653 
00654     case R_PPC64_TPREL16_HIGHESTA:
00655       value = elf_machine_tprel (map, sym_map, sym, reloc);
00656       *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
00657       break;
00658 #endif
00659 
00660 #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */
00661     case R_PPC64_ADDR16_LO_DS:
00662       if (dont_expect ((value & 3) != 0))
00663         _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym);
00664       BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
00665       break;
00666 
00667     case R_PPC64_ADDR16_LO:
00668       *(Elf64_Half *) reloc_addr = PPC_LO (value);
00669       break;
00670 
00671     case R_PPC64_ADDR16_HI:
00672       *(Elf64_Half *) reloc_addr = PPC_HI (value);
00673       break;
00674 
00675     case R_PPC64_ADDR16_HA:
00676       *(Elf64_Half *) reloc_addr = PPC_HA (value);
00677       break;
00678 
00679     case R_PPC64_ADDR30:
00680       {
00681         Elf64_Addr delta = value - (Elf64_Xword) reloc_addr;
00682         if (dont_expect ((delta + 0x80000000) >= 0x10000000
00683                       || (delta & 3) != 0))
00684           _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym);
00685         BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc);
00686       }
00687       break;
00688 
00689     case R_PPC64_COPY:
00690       if (dont_expect (sym == NULL))
00691        /* This can happen in trace mode when an object could not be found. */
00692         return;
00693       if (dont_expect (sym->st_size > refsym->st_size
00694                      || (GLRO(dl_verbose)
00695                         && sym->st_size < refsym->st_size)))
00696        {
00697           const char *strtab;
00698 
00699           strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00700           _dl_error_printf ("%s: Symbol `%s' has different size" \
00701                             " in shared object," \
00702                             " consider re-linking\n",
00703                             _dl_argv[0] ?: "<program name unknown>",
00704                          strtab + refsym->st_name);
00705        }
00706       memcpy (reloc_addr_arg, (char *) value,
00707              MIN (sym->st_size, refsym->st_size));
00708       return;
00709 
00710     case R_PPC64_UADDR64:
00711       /* We are big-endian.  */
00712       ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff;
00713       ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff;
00714       ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff;
00715       ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff;
00716       ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff;
00717       ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff;
00718       ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff;
00719       ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff;
00720       return;
00721 
00722     case R_PPC64_UADDR32:
00723       /* We are big-endian.  */
00724       ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff;
00725       ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff;
00726       ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff;
00727       ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff;
00728       return;
00729 
00730     case R_PPC64_ADDR32:
00731       if (dont_expect ((value + 0x80000000) >= 0x10000000))
00732         _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym);
00733       *(Elf64_Word *) reloc_addr = value;
00734       return;
00735 
00736     case R_PPC64_ADDR24:
00737       if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0))
00738         _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym);
00739       BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc);
00740       break;
00741 
00742     case R_PPC64_ADDR16:
00743       if (dont_expect ((value + 0x8000) >= 0x10000))
00744         _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym);
00745       *(Elf64_Half *) reloc_addr = value;
00746       break;
00747 
00748     case R_PPC64_UADDR16:
00749       if (dont_expect ((value + 0x8000) >= 0x10000))
00750         _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym);
00751       /* We are big-endian.  */
00752       ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff;
00753       ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff;
00754       break;
00755 
00756     case R_PPC64_ADDR16_DS:
00757       if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
00758         _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym);
00759       BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc);
00760       break;
00761 
00762     case R_PPC64_ADDR16_HIGHER:
00763       *(Elf64_Half *) reloc_addr = PPC_HIGHER (value);
00764       break;
00765 
00766     case R_PPC64_ADDR16_HIGHEST:
00767       *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value);
00768       break;
00769 
00770     case R_PPC64_ADDR16_HIGHERA:
00771       *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value);
00772       break;
00773 
00774     case R_PPC64_ADDR16_HIGHESTA:
00775       *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value);
00776       break;
00777 
00778     case R_PPC64_ADDR14:
00779     case R_PPC64_ADDR14_BRTAKEN:
00780     case R_PPC64_ADDR14_BRNTAKEN:
00781       {
00782         if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0))
00783          _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym);
00784         Elf64_Word insn = *(Elf64_Word *) reloc_addr;
00785         BIT_INSERT (insn, value, 0xfffc);
00786         if (r_type != R_PPC64_ADDR14)
00787          {
00788            insn &= ~(1 << 21);
00789            if (r_type == R_PPC64_ADDR14_BRTAKEN)
00790              insn |= 1 << 21;
00791            if ((insn & (0x14 << 21)) == (0x04 << 21))
00792              insn |= 0x02 << 21;
00793            else if ((insn & (0x14 << 21)) == (0x10 << 21))
00794              insn |= 0x08 << 21;
00795          }
00796         *(Elf64_Word *) reloc_addr = insn;
00797       }
00798       break;
00799 
00800     case R_PPC64_REL32:
00801       *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr;
00802       return;
00803 
00804     case R_PPC64_REL64:
00805       *reloc_addr = value - (Elf64_Addr) reloc_addr;
00806       return;
00807 #endif /* !RTLD_BOOTSTRAP */
00808 
00809     default:
00810       _dl_reloc_bad_type (map, r_type, 0);
00811       return;
00812     }
00813   MODIFIED_CODE_NOQUEUE (reloc_addr);
00814 }
00815 
00816 auto inline void __attribute__ ((always_inline))
00817 elf_machine_lazy_rel (struct link_map *map,
00818                     Elf64_Addr l_addr, const Elf64_Rela *reloc)
00819 {
00820   /* elf_machine_runtime_setup handles this.  */
00821 }
00822 
00823 
00824 #endif /* RESOLVE */