(root)/
glibc-2.38/
sysdeps/
powerpc/
powerpc32/
dl-machine.c
       1  /* Machine-dependent ELF dynamic relocation functions.  PowerPC version.
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <unistd.h>
      20  #include <string.h>
      21  #include <sys/param.h>
      22  #include <link.h>
      23  #include <ldsodefs.h>
      24  #include <elf/dynamic-link.h>
      25  #include <dl-machine.h>
      26  #include <_itoa.h>
      27  
      28  /* Stuff for the PLT.  */
      29  #define PLT_INITIAL_ENTRY_WORDS 18
      30  #define PLT_LONGBRANCH_ENTRY_WORDS 0
      31  #define PLT_TRAMPOLINE_ENTRY_WORDS 6
      32  #define PLT_DOUBLE_SIZE (1<<13)
      33  #define PLT_ENTRY_START_WORDS(entry_number) \
      34    (PLT_INITIAL_ENTRY_WORDS + (entry_number)*2				\
      35     + ((entry_number) > PLT_DOUBLE_SIZE					\
      36        ? ((entry_number) - PLT_DOUBLE_SIZE)*2				\
      37        : 0))
      38  #define PLT_DATA_START_WORDS(num_entries) PLT_ENTRY_START_WORDS(num_entries)
      39  
      40  /* Macros to build PowerPC opcode words.  */
      41  #define OPCODE_ADDI(rd,ra,simm) \
      42    (0x38000000 | (rd) << 21 | (ra) << 16 | ((simm) & 0xffff))
      43  #define OPCODE_ADDIS(rd,ra,simm) \
      44    (0x3c000000 | (rd) << 21 | (ra) << 16 | ((simm) & 0xffff))
      45  #define OPCODE_ADD(rd,ra,rb) \
      46    (0x7c000214 | (rd) << 21 | (ra) << 16 | (rb) << 11)
      47  #define OPCODE_B(target) (0x48000000 | ((target) & 0x03fffffc))
      48  #define OPCODE_BA(target) (0x48000002 | ((target) & 0x03fffffc))
      49  #define OPCODE_BCTR() 0x4e800420
      50  #define OPCODE_LWZ(rd,d,ra) \
      51    (0x80000000 | (rd) << 21 | (ra) << 16 | ((d) & 0xffff))
      52  #define OPCODE_LWZU(rd,d,ra) \
      53    (0x84000000 | (rd) << 21 | (ra) << 16 | ((d) & 0xffff))
      54  #define OPCODE_MTCTR(rd) (0x7C0903A6 | (rd) << 21)
      55  #define OPCODE_RLWINM(ra,rs,sh,mb,me) \
      56    (0x54000000 | (rs) << 21 | (ra) << 16 | (sh) << 11 | (mb) << 6 | (me) << 1)
      57  
      58  #define OPCODE_LI(rd,simm)    OPCODE_ADDI(rd,0,simm)
      59  #define OPCODE_ADDIS_HI(rd,ra,value) \
      60    OPCODE_ADDIS(rd,ra,((value) + 0x8000) >> 16)
      61  #define OPCODE_LIS_HI(rd,value) OPCODE_ADDIS_HI(rd,0,value)
      62  #define OPCODE_SLWI(ra,rs,sh) OPCODE_RLWINM(ra,rs,sh,0,31-sh)
      63  
      64  
      65  #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
      66  #define PPC_SYNC asm volatile ("sync" : : : "memory")
      67  #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
      68  #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory")
      69  #define PPC_DIE asm volatile ("tweq 0,0")
      70  
      71  /* Use this when you've modified some code, but it won't be in the
      72     instruction fetch queue (or when it doesn't matter if it is). */
      73  #define MODIFIED_CODE_NOQUEUE(where) \
      74       do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
      75  /* Use this when it might be in the instruction queue. */
      76  #define MODIFIED_CODE(where) \
      77       do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
      78  
      79  
      80  /* The idea here is that to conform to the ABI, we are supposed to try
      81     to load dynamic objects between 0x10000 (we actually use 0x40000 as
      82     the lower bound, to increase the chance of a memory reference from
      83     a null pointer giving a segfault) and the program's load address;
      84     this may allow us to use a branch instruction in the PLT rather
      85     than a computed jump.  The address is only used as a preference for
      86     mmap, so if we get it wrong the worst that happens is that it gets
      87     mapped somewhere else.  */
      88  
      89  ElfW(Addr)
      90  __elf_preferred_address (struct link_map *loader, size_t maplength,
      91  			 ElfW(Addr) mapstartpref)
      92  {
      93    ElfW(Addr) low, high;
      94    struct link_map *l;
      95    Lmid_t nsid;
      96  
      97    /* If the object has a preference, load it there!  */
      98    if (mapstartpref != 0)
      99      return mapstartpref;
     100  
     101    /* Otherwise, quickly look for a suitable gap between 0x3FFFF and
     102       0x70000000.  0x3FFFF is so that references off NULL pointers will
     103       cause a segfault, 0x70000000 is just paranoia (it should always
     104       be superseded by the program's load address).  */
     105    low =  0x0003FFFF;
     106    high = 0x70000000;
     107    for (nsid = 0; nsid < DL_NNS; ++nsid)
     108      for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
     109        {
     110  	ElfW(Addr) mapstart, mapend;
     111  	mapstart = l->l_map_start & ~(GLRO(dl_pagesize) - 1);
     112  	mapend = l->l_map_end | (GLRO(dl_pagesize) - 1);
     113  	assert (mapend > mapstart);
     114  
     115  	/* Prefer gaps below the main executable, note that l ==
     116  	   _dl_loaded does not work for static binaries loading
     117  	   e.g. libnss_*.so.  */
     118  	if ((mapend >= high || l->l_type == lt_executable)
     119  	    && high >= mapstart)
     120  	  high = mapstart;
     121  	else if (mapend >= low && low >= mapstart)
     122  	  low = mapend;
     123  	else if (high >= mapend && mapstart >= low)
     124  	  {
     125  	    if (high - mapend >= mapstart - low)
     126  	      low = mapend;
     127  	    else
     128  	      high = mapstart;
     129  	  }
     130        }
     131  
     132    high -= 0x10000; /* Allow some room between objects.  */
     133    maplength = (maplength | (GLRO(dl_pagesize) - 1)) + 1;
     134    if (high <= low || high - low < maplength )
     135      return 0;
     136    return high - maplength;  /* Both high and maplength are page-aligned.  */
     137  }
     138  
     139  /* Set up the loaded object described by L so its unrelocated PLT
     140     entries will jump to the on-demand fixup code in dl-runtime.c.
     141     Also install a small trampoline to be used by entries that have
     142     been relocated to an address too far away for a single branch.  */
     143  
     144  /* There are many kinds of PLT entries:
     145  
     146     (1)	A direct jump to the actual routine, either a relative or
     147  	absolute branch.  These are set up in __elf_machine_fixup_plt.
     148  
     149     (2)	Short lazy entries.  These cover the first 8192 slots in
     150          the PLT, and look like (where 'index' goes from 0 to 8191):
     151  
     152  	li %r11, index*4
     153  	b  &plt[PLT_TRAMPOLINE_ENTRY_WORDS+1]
     154  
     155     (3)	Short indirect jumps.  These replace (2) when a direct jump
     156  	wouldn't reach.  They look the same except that the branch
     157  	is 'b &plt[PLT_LONGBRANCH_ENTRY_WORDS]'.
     158  
     159     (4)  Long lazy entries.  These cover the slots when a short entry
     160  	won't fit ('index*4' overflows its field), and look like:
     161  
     162  	lis %r11, %hi(index*4 + &plt[PLT_DATA_START_WORDS])
     163  	lwzu %r12, %r11, %lo(index*4 + &plt[PLT_DATA_START_WORDS])
     164  	b  &plt[PLT_TRAMPOLINE_ENTRY_WORDS]
     165  	bctr
     166  
     167     (5)	Long indirect jumps.  These replace (4) when a direct jump
     168  	wouldn't reach.  They look like:
     169  
     170  	lis %r11, %hi(index*4 + &plt[PLT_DATA_START_WORDS])
     171  	lwz %r12, %r11, %lo(index*4 + &plt[PLT_DATA_START_WORDS])
     172  	mtctr %r12
     173  	bctr
     174  
     175     (6) Long direct jumps.  These are used when thread-safety is not
     176         required.  They look like:
     177  
     178         lis %r12, %hi(finaladdr)
     179         addi %r12, %r12, %lo(finaladdr)
     180         mtctr %r12
     181         bctr
     182  
     183  
     184     The lazy entries, (2) and (4), are set up here in
     185     __elf_machine_runtime_setup.  (1), (3), and (5) are set up in
     186     __elf_machine_fixup_plt.  (1), (3), and (6) can also be constructed
     187     in __process_machine_rela.
     188  
     189     The reason for the somewhat strange construction of the long
     190     entries, (4) and (5), is that we need to ensure thread-safety.  For
     191     (1) and (3), this is obvious because only one instruction is
     192     changed and the PPC architecture guarantees that aligned stores are
     193     atomic.  For (5), this is more tricky.  When changing (4) to (5),
     194     the `b' instruction is first changed to `mtctr'; this is safe
     195     and is why the `lwzu' instruction is not just a simple `addi'.
     196     Once this is done, and is visible to all processors, the `lwzu' can
     197     safely be changed to a `lwz'.  */
     198  int
     199  __elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
     200  {
     201    if (map->l_info[DT_JMPREL])
     202      {
     203        Elf32_Word i;
     204        Elf32_Word *plt = (Elf32_Word *) D_PTR (map, l_info[DT_PLTGOT]);
     205        Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
     206  				    / sizeof (Elf32_Rela));
     207        Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
     208        Elf32_Word data_words = (Elf32_Word) (plt + rel_offset_words);
     209        Elf32_Word size_modified;
     210  
     211        extern void _dl_runtime_resolve (void);
     212        extern void _dl_prof_resolve (void);
     213  
     214        /* Convert the index in r11 into an actual address, and get the
     215  	 word at that address.  */
     216        plt[PLT_LONGBRANCH_ENTRY_WORDS] = OPCODE_ADDIS_HI (11, 11, data_words);
     217        plt[PLT_LONGBRANCH_ENTRY_WORDS + 1] = OPCODE_LWZ (11, data_words, 11);
     218  
     219        /* Call the procedure at that address.  */
     220        plt[PLT_LONGBRANCH_ENTRY_WORDS + 2] = OPCODE_MTCTR (11);
     221        plt[PLT_LONGBRANCH_ENTRY_WORDS + 3] = OPCODE_BCTR ();
     222  
     223        if (lazy)
     224  	{
     225  	  Elf32_Word *tramp = plt + PLT_TRAMPOLINE_ENTRY_WORDS;
     226  	  Elf32_Word dlrr;
     227  	  Elf32_Word offset;
     228  
     229  #ifndef PROF
     230  	  dlrr = (Elf32_Word) (profile
     231  			       ? _dl_prof_resolve
     232  			       : _dl_runtime_resolve);
     233  	  if (profile && GLRO(dl_profile) != NULL
     234  	      && _dl_name_match_p (GLRO(dl_profile), map))
     235  	    /* This is the object we are looking for.  Say that we really
     236  	       want profiling and the timers are started.  */
     237  	    GL(dl_profile_map) = map;
     238  #else
     239  	  dlrr = (Elf32_Word) _dl_runtime_resolve;
     240  #endif
     241  
     242  	  /* For the long entries, subtract off data_words.  */
     243  	  tramp[0] = OPCODE_ADDIS_HI (11, 11, -data_words);
     244  	  tramp[1] = OPCODE_ADDI (11, 11, -data_words);
     245  
     246  	  /* Multiply index of entry by 3 (in r11).  */
     247  	  tramp[2] = OPCODE_SLWI (12, 11, 1);
     248  	  tramp[3] = OPCODE_ADD (11, 12, 11);
     249  	  if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000)
     250  	    {
     251  	      /* Load address of link map in r12.  */
     252  	      tramp[4] = OPCODE_LI (12, (Elf32_Word) map);
     253  	      tramp[5] = OPCODE_ADDIS_HI (12, 12, (Elf32_Word) map);
     254  
     255  	      /* Call _dl_runtime_resolve.  */
     256  	      tramp[6] = OPCODE_BA (dlrr);
     257  	    }
     258  	  else
     259  	    {
     260  	      /* Get address of _dl_runtime_resolve in CTR.  */
     261  	      tramp[4] = OPCODE_LI (12, dlrr);
     262  	      tramp[5] = OPCODE_ADDIS_HI (12, 12, dlrr);
     263  	      tramp[6] = OPCODE_MTCTR (12);
     264  
     265  	      /* Load address of link map in r12.  */
     266  	      tramp[7] = OPCODE_LI (12, (Elf32_Word) map);
     267  	      tramp[8] = OPCODE_ADDIS_HI (12, 12, (Elf32_Word) map);
     268  
     269  	      /* Call _dl_runtime_resolve.  */
     270  	      tramp[9] = OPCODE_BCTR ();
     271  	    }
     272  
     273  	  /* Set up the lazy PLT entries.  */
     274  	  offset = PLT_INITIAL_ENTRY_WORDS;
     275  	  i = 0;
     276  	  while (i < num_plt_entries && i < PLT_DOUBLE_SIZE)
     277  	    {
     278  	      plt[offset  ] = OPCODE_LI (11, i * 4);
     279  	      plt[offset+1] = OPCODE_B ((PLT_TRAMPOLINE_ENTRY_WORDS + 2
     280  					 - (offset+1))
     281  					* 4);
     282  	      i++;
     283  	      offset += 2;
     284  	    }
     285  	  while (i < num_plt_entries)
     286  	    {
     287  	      plt[offset  ] = OPCODE_LIS_HI (11, i * 4 + data_words);
     288  	      plt[offset+1] = OPCODE_LWZU (12, i * 4 + data_words, 11);
     289  	      plt[offset+2] = OPCODE_B ((PLT_TRAMPOLINE_ENTRY_WORDS
     290  					 - (offset+2))
     291  					* 4);
     292  	      plt[offset+3] = OPCODE_BCTR ();
     293  	      i++;
     294  	      offset += 4;
     295  	    }
     296  	}
     297  
     298        /* Now, we've modified code.  We need to write the changes from
     299  	 the data cache to a second-level unified cache, then make
     300  	 sure that stale data in the instruction cache is removed.
     301  	 (In a multiprocessor system, the effect is more complex.)
     302  	 Most of the PLT shouldn't be in the instruction cache, but
     303  	 there may be a little overlap at the start and the end.
     304  
     305  	 Assumes that dcbst and icbi apply to lines of 16 bytes or
     306  	 more.  Current known line sizes are 16, 32, and 128 bytes.
     307  	 The following gets the cache line size, when available.  */
     308  
     309        /* Default minimum 4 words per cache line.  */
     310        int line_size_words = 4;
     311  
     312        if (lazy && GLRO(dl_cache_line_size) != 0)
     313  	/* Convert bytes to words.  */
     314  	line_size_words = GLRO(dl_cache_line_size) / 4;
     315  
     316        size_modified = lazy ? rel_offset_words : 6;
     317        for (i = 0; i < size_modified; i += line_size_words)
     318          PPC_DCBST (plt + i);
     319        PPC_DCBST (plt + size_modified - 1);
     320        PPC_SYNC;
     321  
     322        for (i = 0; i < size_modified; i += line_size_words)
     323          PPC_ICBI (plt + i);
     324        PPC_ICBI (plt + size_modified - 1);
     325        PPC_ISYNC;
     326      }
     327  
     328    return lazy;
     329  }
     330  
     331  Elf32_Addr
     332  __elf_machine_fixup_plt (struct link_map *map,
     333  			 Elf32_Addr *reloc_addr, Elf32_Addr finaladdr)
     334  {
     335    Elf32_Sword delta = finaladdr - (Elf32_Word) reloc_addr;
     336    if (delta << 6 >> 6 == delta)
     337      *reloc_addr = OPCODE_B (delta);
     338    else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
     339      *reloc_addr = OPCODE_BA (finaladdr);
     340    else
     341      {
     342        Elf32_Word *plt, *data_words;
     343        Elf32_Word index, offset, num_plt_entries;
     344  
     345        num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
     346  			 / sizeof (Elf32_Rela));
     347        plt = (Elf32_Word *) D_PTR (map, l_info[DT_PLTGOT]);
     348        offset = reloc_addr - plt;
     349        index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
     350        data_words = plt + PLT_DATA_START_WORDS (num_plt_entries);
     351  
     352        reloc_addr += 1;
     353  
     354        if (index < PLT_DOUBLE_SIZE)
     355  	{
     356  	  data_words[index] = finaladdr;
     357  	  PPC_SYNC;
     358  	  *reloc_addr = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS - (offset+1))
     359  				  * 4);
     360  	}
     361        else
     362  	{
     363  	  index -= (index - PLT_DOUBLE_SIZE)/2;
     364  
     365  	  data_words[index] = finaladdr;
     366  	  PPC_SYNC;
     367  
     368  	  reloc_addr[1] = OPCODE_MTCTR (12);
     369  	  MODIFIED_CODE_NOQUEUE (reloc_addr + 1);
     370  	  PPC_SYNC;
     371  
     372  	  reloc_addr[0] = OPCODE_LWZ (12,
     373  				      (Elf32_Word) (data_words + index), 11);
     374  	}
     375      }
     376    MODIFIED_CODE (reloc_addr);
     377    return finaladdr;
     378  }
     379  
     380  void
     381  _dl_reloc_overflow (struct link_map *map,
     382  		    const char *name,
     383  		    Elf32_Addr *const reloc_addr,
     384  		    const Elf32_Sym *refsym)
     385  {
     386    char buffer[128];
     387    char *t;
     388    t = stpcpy (buffer, name);
     389    t = stpcpy (t, " relocation at 0x00000000");
     390    _itoa_word ((unsigned) reloc_addr, t, 16, 0);
     391    if (refsym)
     392      {
     393        const char *strtab;
     394  
     395        strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
     396        t = stpcpy (t, " for symbol `");
     397        t = stpcpy (t, strtab + refsym->st_name);
     398        t = stpcpy (t, "'");
     399      }
     400    t = stpcpy (t, " out of range");
     401    _dl_signal_error (0, map->l_name, NULL, buffer);
     402  }
     403  
     404  void
     405  __process_machine_rela (struct link_map *map,
     406  			const Elf32_Rela *reloc,
     407  			struct link_map *sym_map,
     408  			const Elf32_Sym *sym,
     409  			const Elf32_Sym *refsym,
     410  			Elf32_Addr *const reloc_addr,
     411  			Elf32_Addr const finaladdr,
     412  			int rinfo, bool skip_ifunc)
     413  {
     414    union unaligned
     415      {
     416        uint16_t u2;
     417        uint32_t u4;
     418      } __attribute__((__packed__));
     419  
     420    switch (rinfo)
     421      {
     422      case R_PPC_NONE:
     423        return;
     424  
     425      case R_PPC_ADDR32:
     426      case R_PPC_GLOB_DAT:
     427      case R_PPC_RELATIVE:
     428        *reloc_addr = finaladdr;
     429        return;
     430  
     431      case R_PPC_IRELATIVE:
     432        if (__glibc_likely (!skip_ifunc))
     433  	*reloc_addr = ((Elf32_Addr (*) (void)) finaladdr) ();
     434        return;
     435  
     436      case R_PPC_UADDR32:
     437        ((union unaligned *) reloc_addr)->u4 = finaladdr;
     438        break;
     439  
     440      case R_PPC_ADDR24:
     441        if (__glibc_unlikely (finaladdr > 0x01fffffc && finaladdr < 0xfe000000))
     442  	_dl_reloc_overflow (map,  "R_PPC_ADDR24", reloc_addr, refsym);
     443        *reloc_addr = (*reloc_addr & 0xfc000003) | (finaladdr & 0x3fffffc);
     444        break;
     445  
     446      case R_PPC_ADDR16:
     447        if (__glibc_unlikely (finaladdr > 0x7fff && finaladdr < 0xffff8000))
     448  	_dl_reloc_overflow (map,  "R_PPC_ADDR16", reloc_addr, refsym);
     449        *(Elf32_Half*) reloc_addr = finaladdr;
     450        break;
     451  
     452      case R_PPC_UADDR16:
     453        if (__glibc_unlikely (finaladdr > 0x7fff && finaladdr < 0xffff8000))
     454  	_dl_reloc_overflow (map,  "R_PPC_UADDR16", reloc_addr, refsym);
     455        ((union unaligned *) reloc_addr)->u2 = finaladdr;
     456        break;
     457  
     458      case R_PPC_ADDR16_LO:
     459        *(Elf32_Half*) reloc_addr = finaladdr;
     460        break;
     461  
     462      case R_PPC_ADDR16_HI:
     463        *(Elf32_Half*) reloc_addr = finaladdr >> 16;
     464        break;
     465  
     466      case R_PPC_ADDR16_HA:
     467        *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
     468        break;
     469  
     470      case R_PPC_ADDR14:
     471      case R_PPC_ADDR14_BRTAKEN:
     472      case R_PPC_ADDR14_BRNTAKEN:
     473        if (__glibc_unlikely (finaladdr > 0x7fff && finaladdr < 0xffff8000))
     474  	_dl_reloc_overflow (map,  "R_PPC_ADDR14", reloc_addr, refsym);
     475        *reloc_addr = (*reloc_addr & 0xffff0003) | (finaladdr & 0xfffc);
     476        if (rinfo != R_PPC_ADDR14)
     477  	*reloc_addr = ((*reloc_addr & 0xffdfffff)
     478  		       | ((rinfo == R_PPC_ADDR14_BRTAKEN)
     479  			  ^ (finaladdr >> 31)) << 21);
     480        break;
     481  
     482      case R_PPC_REL24:
     483        {
     484  	Elf32_Sword delta = finaladdr - (Elf32_Word) reloc_addr;
     485  	if (delta << 6 >> 6 != delta)
     486  	  _dl_reloc_overflow (map,  "R_PPC_REL24", reloc_addr, refsym);
     487  	*reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
     488        }
     489        break;
     490  
     491      case R_PPC_COPY:
     492        if (sym == NULL)
     493  	/* This can happen in trace mode when an object could not be
     494  	   found.  */
     495  	return;
     496        if (sym->st_size > refsym->st_size
     497  	  || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
     498  	{
     499  	  const char *strtab;
     500  
     501  	  strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
     502  	  _dl_error_printf ("\
     503  %s: Symbol `%s' has different size in shared object, consider re-linking\n",
     504  			    RTLD_PROGNAME, strtab + refsym->st_name);
     505  	}
     506        memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
     507  						   refsym->st_size));
     508        return;
     509  
     510      case R_PPC_REL32:
     511        *reloc_addr = finaladdr - (Elf32_Word) reloc_addr;
     512        return;
     513  
     514      case R_PPC_JMP_SLOT:
     515        /* It used to be that elf_machine_fixup_plt was used here,
     516  	 but that doesn't work when ld.so relocates itself
     517  	 for the second time.  On the bright side, there's
     518           no need to worry about thread-safety here.  */
     519        {
     520  	Elf32_Sword delta = finaladdr - (Elf32_Word) reloc_addr;
     521  	if (delta << 6 >> 6 == delta)
     522  	  *reloc_addr = OPCODE_B (delta);
     523  	else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
     524  	  *reloc_addr = OPCODE_BA (finaladdr);
     525  	else
     526  	  {
     527  	    Elf32_Word *plt, *data_words;
     528  	    Elf32_Word index, offset, num_plt_entries;
     529  
     530  	    plt = (Elf32_Word *) D_PTR (map, l_info[DT_PLTGOT]);
     531  	    offset = reloc_addr - plt;
     532  
     533  	    if (offset < PLT_DOUBLE_SIZE*2 + PLT_INITIAL_ENTRY_WORDS)
     534  	      {
     535  		index = (offset - PLT_INITIAL_ENTRY_WORDS)/2;
     536  		num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
     537  				   / sizeof (Elf32_Rela));
     538  		data_words = plt + PLT_DATA_START_WORDS (num_plt_entries);
     539  		data_words[index] = finaladdr;
     540  		reloc_addr[0] = OPCODE_LI (11, index * 4);
     541  		reloc_addr[1] = OPCODE_B ((PLT_LONGBRANCH_ENTRY_WORDS
     542  					   - (offset+1))
     543  					  * 4);
     544  		MODIFIED_CODE_NOQUEUE (reloc_addr + 1);
     545  	      }
     546  	    else
     547  	      {
     548  		reloc_addr[0] = OPCODE_LIS_HI (12, finaladdr);
     549  		reloc_addr[1] = OPCODE_ADDI (12, 12, finaladdr);
     550  		reloc_addr[2] = OPCODE_MTCTR (12);
     551  		reloc_addr[3] = OPCODE_BCTR ();
     552  		MODIFIED_CODE_NOQUEUE (reloc_addr + 3);
     553  	      }
     554  	  }
     555        }
     556        break;
     557  
     558  #define DO_TLS_RELOC(suffix)						      \
     559      case R_PPC_DTPREL##suffix:						      \
     560        /* During relocation all TLS symbols are defined and used.	      \
     561  	 Therefore the offset is already correct.  */			      \
     562        if (sym_map != NULL)						      \
     563  	do_reloc##suffix ("R_PPC_DTPREL"#suffix,			      \
     564  			  TLS_DTPREL_VALUE (sym, reloc));		      \
     565        break;								      \
     566      case R_PPC_TPREL##suffix:						      \
     567        if (sym_map != NULL)						      \
     568  	{								      \
     569  	  CHECK_STATIC_TLS (map, sym_map);				      \
     570  	  do_reloc##suffix ("R_PPC_TPREL"#suffix,			      \
     571  			    TLS_TPREL_VALUE (sym_map, sym, reloc));	      \
     572  	}								      \
     573        break;
     574  
     575      inline void do_reloc16 (const char *r_name, Elf32_Addr value)
     576        {
     577  	if (__glibc_unlikely (value > 0x7fff && value < 0xffff8000))
     578  	  _dl_reloc_overflow (map, r_name, reloc_addr, refsym);
     579  	*(Elf32_Half *) reloc_addr = value;
     580        }
     581      inline void do_reloc16_LO (const char *r_name, Elf32_Addr value)
     582        {
     583  	*(Elf32_Half *) reloc_addr = value;
     584        }
     585      inline void do_reloc16_HI (const char *r_name, Elf32_Addr value)
     586        {
     587  	*(Elf32_Half *) reloc_addr = value >> 16;
     588        }
     589      inline void do_reloc16_HA (const char *r_name, Elf32_Addr value)
     590        {
     591  	*(Elf32_Half *) reloc_addr = (value + 0x8000) >> 16;
     592        }
     593      DO_TLS_RELOC (16)
     594      DO_TLS_RELOC (16_LO)
     595      DO_TLS_RELOC (16_HI)
     596      DO_TLS_RELOC (16_HA)
     597  
     598      default:
     599        _dl_reloc_bad_type (map, rinfo, 0);
     600        return;
     601      }
     602  
     603    MODIFIED_CODE_NOQUEUE (reloc_addr);
     604  }