Home | History | Annotate | Line # | Download | only in bfd
elfnn-loongarch.c revision 1.1.1.1.4.2
      1  1.1.1.1.4.2  perseant /* LoongArch-specific support for NN-bit ELF.
      2  1.1.1.1.4.2  perseant    Copyright (C) 2021-2022 Free Software Foundation, Inc.
      3  1.1.1.1.4.2  perseant    Contributed by Loongson Ltd.
      4  1.1.1.1.4.2  perseant 
      5  1.1.1.1.4.2  perseant    This file is part of BFD, the Binary File Descriptor library.
      6  1.1.1.1.4.2  perseant 
      7  1.1.1.1.4.2  perseant    This program is free software; you can redistribute it and/or modify
      8  1.1.1.1.4.2  perseant    it under the terms of the GNU General Public License as published by
      9  1.1.1.1.4.2  perseant    the Free Software Foundation; either version 3 of the License, or
     10  1.1.1.1.4.2  perseant    (at your option) any later version.
     11  1.1.1.1.4.2  perseant 
     12  1.1.1.1.4.2  perseant    This program is distributed in the hope that it will be useful,
     13  1.1.1.1.4.2  perseant    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1.1.1.4.2  perseant    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  1.1.1.1.4.2  perseant    GNU General Public License for more details.
     16  1.1.1.1.4.2  perseant 
     17  1.1.1.1.4.2  perseant    You should have received a copy of the GNU General Public License
     18  1.1.1.1.4.2  perseant    along with this program; see the file COPYING3.  If not,
     19  1.1.1.1.4.2  perseant    see <http://www.gnu.org/licenses/>.  */
     20  1.1.1.1.4.2  perseant 
     21  1.1.1.1.4.2  perseant #include "ansidecl.h"
     22  1.1.1.1.4.2  perseant #include "sysdep.h"
     23  1.1.1.1.4.2  perseant #include "bfd.h"
     24  1.1.1.1.4.2  perseant #include "libbfd.h"
     25  1.1.1.1.4.2  perseant #define ARCH_SIZE NN
     26  1.1.1.1.4.2  perseant #include "elf-bfd.h"
     27  1.1.1.1.4.2  perseant #include "objalloc.h"
     28  1.1.1.1.4.2  perseant #include "elf/loongarch.h"
     29  1.1.1.1.4.2  perseant #include "elfxx-loongarch.h"
     30  1.1.1.1.4.2  perseant 
     31  1.1.1.1.4.2  perseant static bool
     32  1.1.1.1.4.2  perseant loongarch_info_to_howto_rela (bfd *abfd, arelent *cache_ptr,
     33  1.1.1.1.4.2  perseant 			      Elf_Internal_Rela *dst)
     34  1.1.1.1.4.2  perseant {
     35  1.1.1.1.4.2  perseant   cache_ptr->howto = loongarch_elf_rtype_to_howto (abfd,
     36  1.1.1.1.4.2  perseant 						   ELFNN_R_TYPE (dst->r_info));
     37  1.1.1.1.4.2  perseant   return cache_ptr->howto != NULL;
     38  1.1.1.1.4.2  perseant }
     39  1.1.1.1.4.2  perseant 
     40  1.1.1.1.4.2  perseant /* LoongArch ELF linker hash entry.  */
     41  1.1.1.1.4.2  perseant struct loongarch_elf_link_hash_entry
     42  1.1.1.1.4.2  perseant {
     43  1.1.1.1.4.2  perseant   struct elf_link_hash_entry elf;
     44  1.1.1.1.4.2  perseant 
     45  1.1.1.1.4.2  perseant #define GOT_UNKNOWN 0
     46  1.1.1.1.4.2  perseant #define GOT_NORMAL  1
     47  1.1.1.1.4.2  perseant #define GOT_TLS_GD  2
     48  1.1.1.1.4.2  perseant #define GOT_TLS_IE  4
     49  1.1.1.1.4.2  perseant #define GOT_TLS_LE  8
     50  1.1.1.1.4.2  perseant   char tls_type;
     51  1.1.1.1.4.2  perseant };
     52  1.1.1.1.4.2  perseant 
     53  1.1.1.1.4.2  perseant #define loongarch_elf_hash_entry(ent)	\
     54  1.1.1.1.4.2  perseant   ((struct loongarch_elf_link_hash_entry *) (ent))
     55  1.1.1.1.4.2  perseant 
     56  1.1.1.1.4.2  perseant struct _bfd_loongarch_elf_obj_tdata
     57  1.1.1.1.4.2  perseant {
     58  1.1.1.1.4.2  perseant   struct elf_obj_tdata root;
     59  1.1.1.1.4.2  perseant 
     60  1.1.1.1.4.2  perseant   /* The tls_type for each local got entry.  */
     61  1.1.1.1.4.2  perseant   char *local_got_tls_type;
     62  1.1.1.1.4.2  perseant };
     63  1.1.1.1.4.2  perseant 
     64  1.1.1.1.4.2  perseant #define _bfd_loongarch_elf_tdata(abfd)	\
     65  1.1.1.1.4.2  perseant   ((struct _bfd_loongarch_elf_obj_tdata *) (abfd)->tdata.any)
     66  1.1.1.1.4.2  perseant 
     67  1.1.1.1.4.2  perseant #define _bfd_loongarch_elf_local_got_tls_type(abfd)	\
     68  1.1.1.1.4.2  perseant   (_bfd_loongarch_elf_tdata (abfd)->local_got_tls_type)
     69  1.1.1.1.4.2  perseant 
     70  1.1.1.1.4.2  perseant #define _bfd_loongarch_elf_tls_type(abfd, h, symndx)			\
     71  1.1.1.1.4.2  perseant   (*((h) != NULL							\
     72  1.1.1.1.4.2  perseant      ? &loongarch_elf_hash_entry (h)->tls_type				\
     73  1.1.1.1.4.2  perseant      : &_bfd_loongarch_elf_local_got_tls_type (abfd)[symndx]))
     74  1.1.1.1.4.2  perseant 
     75  1.1.1.1.4.2  perseant #define is_loongarch_elf(bfd)						\
     76  1.1.1.1.4.2  perseant   (bfd_get_flavour (bfd) == bfd_target_elf_flavour			\
     77  1.1.1.1.4.2  perseant    && elf_tdata (bfd) != NULL						\
     78  1.1.1.1.4.2  perseant    && elf_object_id (bfd) == LARCH_ELF_DATA)
     79  1.1.1.1.4.2  perseant 
     80  1.1.1.1.4.2  perseant struct loongarch_elf_link_hash_table
     81  1.1.1.1.4.2  perseant {
     82  1.1.1.1.4.2  perseant   struct elf_link_hash_table elf;
     83  1.1.1.1.4.2  perseant 
     84  1.1.1.1.4.2  perseant   /* Short-cuts to get to dynamic linker sections.  */
     85  1.1.1.1.4.2  perseant   asection *sdyntdata;
     86  1.1.1.1.4.2  perseant 
     87  1.1.1.1.4.2  perseant   /* Small local sym to section mapping cache.  */
     88  1.1.1.1.4.2  perseant   struct sym_cache sym_cache;
     89  1.1.1.1.4.2  perseant 
     90  1.1.1.1.4.2  perseant   /* Used by local STT_GNU_IFUNC symbols.  */
     91  1.1.1.1.4.2  perseant   htab_t loc_hash_table;
     92  1.1.1.1.4.2  perseant   void *loc_hash_memory;
     93  1.1.1.1.4.2  perseant 
     94  1.1.1.1.4.2  perseant   /* The max alignment of output sections.  */
     95  1.1.1.1.4.2  perseant   bfd_vma max_alignment;
     96  1.1.1.1.4.2  perseant };
     97  1.1.1.1.4.2  perseant 
     98  1.1.1.1.4.2  perseant /* Get the LoongArch ELF linker hash table from a link_info structure.  */
     99  1.1.1.1.4.2  perseant #define loongarch_elf_hash_table(p)					\
    100  1.1.1.1.4.2  perseant   (elf_hash_table_id (elf_hash_table (p)) == LARCH_ELF_DATA		\
    101  1.1.1.1.4.2  perseant    ? ((struct loongarch_elf_link_hash_table *) ((p)->hash))		\
    102  1.1.1.1.4.2  perseant    : NULL)
    103  1.1.1.1.4.2  perseant 
    104  1.1.1.1.4.2  perseant #define MINUS_ONE ((bfd_vma) 0 - 1)
    105  1.1.1.1.4.2  perseant 
    106  1.1.1.1.4.2  perseant #define sec_addr(sec) ((sec)->output_section->vma + (sec)->output_offset)
    107  1.1.1.1.4.2  perseant 
    108  1.1.1.1.4.2  perseant #define LARCH_ELF_LOG_WORD_BYTES (ARCH_SIZE == 32 ? 2 : 3)
    109  1.1.1.1.4.2  perseant #define LARCH_ELF_WORD_BYTES (1 << LARCH_ELF_LOG_WORD_BYTES)
    110  1.1.1.1.4.2  perseant 
    111  1.1.1.1.4.2  perseant #define PLT_HEADER_INSNS 8
    112  1.1.1.1.4.2  perseant #define PLT_HEADER_SIZE (PLT_HEADER_INSNS * 4)
    113  1.1.1.1.4.2  perseant 
    114  1.1.1.1.4.2  perseant #define PLT_ENTRY_INSNS 4
    115  1.1.1.1.4.2  perseant #define PLT_ENTRY_SIZE (PLT_ENTRY_INSNS * 4)
    116  1.1.1.1.4.2  perseant 
    117  1.1.1.1.4.2  perseant #define GOT_ENTRY_SIZE (LARCH_ELF_WORD_BYTES)
    118  1.1.1.1.4.2  perseant 
    119  1.1.1.1.4.2  perseant #define GOTPLT_HEADER_SIZE (GOT_ENTRY_SIZE * 2)
    120  1.1.1.1.4.2  perseant 
    121  1.1.1.1.4.2  perseant #define elf_backend_want_got_plt 1
    122  1.1.1.1.4.2  perseant 
    123  1.1.1.1.4.2  perseant #define elf_backend_plt_readonly 1
    124  1.1.1.1.4.2  perseant 
    125  1.1.1.1.4.2  perseant #define elf_backend_want_plt_sym 1
    126  1.1.1.1.4.2  perseant #define elf_backend_plt_alignment 4
    127  1.1.1.1.4.2  perseant #define elf_backend_can_gc_sections 1
    128  1.1.1.1.4.2  perseant #define elf_backend_can_refcount 1
    129  1.1.1.1.4.2  perseant #define elf_backend_want_got_sym 1
    130  1.1.1.1.4.2  perseant 
    131  1.1.1.1.4.2  perseant #define elf_backend_got_header_size (GOT_ENTRY_SIZE * 1)
    132  1.1.1.1.4.2  perseant 
    133  1.1.1.1.4.2  perseant #define elf_backend_want_dynrelro 1
    134  1.1.1.1.4.2  perseant #define elf_backend_rela_normal 1
    135  1.1.1.1.4.2  perseant #define elf_backend_default_execstack 0
    136  1.1.1.1.4.2  perseant 
    137  1.1.1.1.4.2  perseant /* Generate a PLT header.  */
    138  1.1.1.1.4.2  perseant 
    139  1.1.1.1.4.2  perseant static bool
    140  1.1.1.1.4.2  perseant loongarch_make_plt_header (bfd_vma got_plt_addr, bfd_vma plt_header_addr,
    141  1.1.1.1.4.2  perseant 			   uint32_t *entry)
    142  1.1.1.1.4.2  perseant {
    143  1.1.1.1.4.2  perseant   bfd_vma pcrel = got_plt_addr - plt_header_addr;
    144  1.1.1.1.4.2  perseant   bfd_vma hi, lo;
    145  1.1.1.1.4.2  perseant 
    146  1.1.1.1.4.2  perseant   if (pcrel + 0x80000800 > 0xffffffff)
    147  1.1.1.1.4.2  perseant     {
    148  1.1.1.1.4.2  perseant       _bfd_error_handler (_("%#" PRIx64 " invaild imm"), (uint64_t) pcrel);
    149  1.1.1.1.4.2  perseant       bfd_set_error (bfd_error_bad_value);
    150  1.1.1.1.4.2  perseant       return false;
    151  1.1.1.1.4.2  perseant     }
    152  1.1.1.1.4.2  perseant   hi = ((pcrel + 0x800) >> 12) & 0xfffff;
    153  1.1.1.1.4.2  perseant   lo = pcrel & 0xfff;
    154  1.1.1.1.4.2  perseant 
    155  1.1.1.1.4.2  perseant   /* pcaddu12i  $t2, %hi(%pcrel(.got.plt))
    156  1.1.1.1.4.2  perseant      sub.[wd]   $t1, $t1, $t3
    157  1.1.1.1.4.2  perseant      ld.[wd]    $t3, $t2, %lo(%pcrel(.got.plt)) # _dl_runtime_resolve
    158  1.1.1.1.4.2  perseant      addi.[wd]  $t1, $t1, -(PLT_HEADER_SIZE + 12)
    159  1.1.1.1.4.2  perseant      addi.[wd]  $t0, $t2, %lo(%pcrel(.got.plt))
    160  1.1.1.1.4.2  perseant      srli.[wd]  $t1, $t1, log2(16 / GOT_ENTRY_SIZE)
    161  1.1.1.1.4.2  perseant      ld.[wd]    $t0, $t0, GOT_ENTRY_SIZE
    162  1.1.1.1.4.2  perseant      jirl   $r0, $t3, 0 */
    163  1.1.1.1.4.2  perseant 
    164  1.1.1.1.4.2  perseant   if (GOT_ENTRY_SIZE == 8)
    165  1.1.1.1.4.2  perseant     {
    166  1.1.1.1.4.2  perseant       entry[0] = 0x1c00000e | (hi & 0xfffff) << 5;
    167  1.1.1.1.4.2  perseant       entry[1] = 0x0011bdad;
    168  1.1.1.1.4.2  perseant       entry[2] = 0x28c001cf | (lo & 0xfff) << 10;
    169  1.1.1.1.4.2  perseant       entry[3] = 0x02c001ad | ((-(PLT_HEADER_SIZE + 12)) & 0xfff) << 10;
    170  1.1.1.1.4.2  perseant       entry[4] = 0x02c001cc | (lo & 0xfff) << 10;
    171  1.1.1.1.4.2  perseant       entry[5] = 0x004501ad | (4 - LARCH_ELF_LOG_WORD_BYTES) << 10;
    172  1.1.1.1.4.2  perseant       entry[6] = 0x28c0018c | GOT_ENTRY_SIZE << 10;
    173  1.1.1.1.4.2  perseant       entry[7] = 0x4c0001e0;
    174  1.1.1.1.4.2  perseant     }
    175  1.1.1.1.4.2  perseant   else
    176  1.1.1.1.4.2  perseant     {
    177  1.1.1.1.4.2  perseant       entry[0] = 0x1c00000e | (hi & 0xfffff) << 5;
    178  1.1.1.1.4.2  perseant       entry[1] = 0x00113dad;
    179  1.1.1.1.4.2  perseant       entry[2] = 0x288001cf | (lo & 0xfff) << 10;
    180  1.1.1.1.4.2  perseant       entry[3] = 0x028001ad | ((-(PLT_HEADER_SIZE + 12)) & 0xfff) << 10;
    181  1.1.1.1.4.2  perseant       entry[4] = 0x028001cc | (lo & 0xfff) << 10;
    182  1.1.1.1.4.2  perseant       entry[5] = 0x004481ad | (4 - LARCH_ELF_LOG_WORD_BYTES) << 10;
    183  1.1.1.1.4.2  perseant       entry[6] = 0x2880018c | GOT_ENTRY_SIZE << 10;
    184  1.1.1.1.4.2  perseant       entry[7] = 0x4c0001e0;
    185  1.1.1.1.4.2  perseant     }
    186  1.1.1.1.4.2  perseant   return true;
    187  1.1.1.1.4.2  perseant }
    188  1.1.1.1.4.2  perseant 
    189  1.1.1.1.4.2  perseant /* Generate a PLT entry.  */
    190  1.1.1.1.4.2  perseant 
    191  1.1.1.1.4.2  perseant static bool
    192  1.1.1.1.4.2  perseant loongarch_make_plt_entry (bfd_vma got_plt_entry_addr, bfd_vma plt_entry_addr,
    193  1.1.1.1.4.2  perseant 			  uint32_t *entry)
    194  1.1.1.1.4.2  perseant {
    195  1.1.1.1.4.2  perseant   bfd_vma pcrel = got_plt_entry_addr - plt_entry_addr;
    196  1.1.1.1.4.2  perseant   bfd_vma hi, lo;
    197  1.1.1.1.4.2  perseant 
    198  1.1.1.1.4.2  perseant   if (pcrel + 0x80000800 > 0xffffffff)
    199  1.1.1.1.4.2  perseant     {
    200  1.1.1.1.4.2  perseant       _bfd_error_handler (_("%#" PRIx64 " invaild imm"), (uint64_t) pcrel);
    201  1.1.1.1.4.2  perseant       bfd_set_error (bfd_error_bad_value);
    202  1.1.1.1.4.2  perseant       return false;
    203  1.1.1.1.4.2  perseant     }
    204  1.1.1.1.4.2  perseant   hi = ((pcrel + 0x800) >> 12) & 0xfffff;
    205  1.1.1.1.4.2  perseant   lo = pcrel & 0xfff;
    206  1.1.1.1.4.2  perseant 
    207  1.1.1.1.4.2  perseant   entry[0] = 0x1c00000f | (hi & 0xfffff) << 5;
    208  1.1.1.1.4.2  perseant   entry[1] = ((GOT_ENTRY_SIZE == 8 ? 0x28c001ef : 0x288001ef)
    209  1.1.1.1.4.2  perseant 	      | (lo & 0xfff) << 10);
    210  1.1.1.1.4.2  perseant   entry[2] = 0x4c0001ed;	/* jirl $r13, $15, 0 */
    211  1.1.1.1.4.2  perseant   entry[3] = 0x03400000;	/* nop */
    212  1.1.1.1.4.2  perseant 
    213  1.1.1.1.4.2  perseant   return true;
    214  1.1.1.1.4.2  perseant }
    215  1.1.1.1.4.2  perseant 
    216  1.1.1.1.4.2  perseant /* Create an entry in an LoongArch ELF linker hash table.  */
    217  1.1.1.1.4.2  perseant 
    218  1.1.1.1.4.2  perseant static struct bfd_hash_entry *
    219  1.1.1.1.4.2  perseant link_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_hash_table *table,
    220  1.1.1.1.4.2  perseant 		   const char *string)
    221  1.1.1.1.4.2  perseant {
    222  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_entry *eh;
    223  1.1.1.1.4.2  perseant 
    224  1.1.1.1.4.2  perseant   /* Allocate the structure if it has not already been allocated by a
    225  1.1.1.1.4.2  perseant      subclass.  */
    226  1.1.1.1.4.2  perseant   if (entry == NULL)
    227  1.1.1.1.4.2  perseant     {
    228  1.1.1.1.4.2  perseant       entry = bfd_hash_allocate (table, sizeof (*eh));
    229  1.1.1.1.4.2  perseant       if (entry == NULL)
    230  1.1.1.1.4.2  perseant 	return entry;
    231  1.1.1.1.4.2  perseant     }
    232  1.1.1.1.4.2  perseant 
    233  1.1.1.1.4.2  perseant   /* Call the allocation method of the superclass.  */
    234  1.1.1.1.4.2  perseant   entry = _bfd_elf_link_hash_newfunc (entry, table, string);
    235  1.1.1.1.4.2  perseant   if (entry != NULL)
    236  1.1.1.1.4.2  perseant     {
    237  1.1.1.1.4.2  perseant       eh = (struct loongarch_elf_link_hash_entry *) entry;
    238  1.1.1.1.4.2  perseant       eh->tls_type = GOT_UNKNOWN;
    239  1.1.1.1.4.2  perseant     }
    240  1.1.1.1.4.2  perseant 
    241  1.1.1.1.4.2  perseant   return entry;
    242  1.1.1.1.4.2  perseant }
    243  1.1.1.1.4.2  perseant 
    244  1.1.1.1.4.2  perseant /* Compute a hash of a local hash entry.  We use elf_link_hash_entry
    245  1.1.1.1.4.2  perseant   for local symbol so that we can handle local STT_GNU_IFUNC symbols
    246  1.1.1.1.4.2  perseant   as global symbol.  We reuse indx and dynstr_index for local symbol
    247  1.1.1.1.4.2  perseant   hash since they aren't used by global symbols in this backend.  */
    248  1.1.1.1.4.2  perseant 
    249  1.1.1.1.4.2  perseant static hashval_t
    250  1.1.1.1.4.2  perseant elfNN_loongarch_local_htab_hash (const void *ptr)
    251  1.1.1.1.4.2  perseant {
    252  1.1.1.1.4.2  perseant   struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) ptr;
    253  1.1.1.1.4.2  perseant   return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index);
    254  1.1.1.1.4.2  perseant }
    255  1.1.1.1.4.2  perseant 
    256  1.1.1.1.4.2  perseant /* Compare local hash entries.  */
    257  1.1.1.1.4.2  perseant 
    258  1.1.1.1.4.2  perseant static int
    259  1.1.1.1.4.2  perseant elfNN_loongarch_local_htab_eq (const void *ptr1, const void *ptr2)
    260  1.1.1.1.4.2  perseant {
    261  1.1.1.1.4.2  perseant   struct elf_link_hash_entry *h1 = (struct elf_link_hash_entry *) ptr1;
    262  1.1.1.1.4.2  perseant   struct elf_link_hash_entry *h2 = (struct elf_link_hash_entry *) ptr2;
    263  1.1.1.1.4.2  perseant 
    264  1.1.1.1.4.2  perseant   return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index;
    265  1.1.1.1.4.2  perseant }
    266  1.1.1.1.4.2  perseant 
    267  1.1.1.1.4.2  perseant /* Find and/or create a hash entry for local symbol.  */
    268  1.1.1.1.4.2  perseant static struct elf_link_hash_entry *
    269  1.1.1.1.4.2  perseant elfNN_loongarch_get_local_sym_hash (struct loongarch_elf_link_hash_table *htab,
    270  1.1.1.1.4.2  perseant 				    bfd *abfd, const Elf_Internal_Rela *rel,
    271  1.1.1.1.4.2  perseant 				    bool create)
    272  1.1.1.1.4.2  perseant {
    273  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_entry e, *ret;
    274  1.1.1.1.4.2  perseant   asection *sec = abfd->sections;
    275  1.1.1.1.4.2  perseant   hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id, ELFNN_R_SYM (rel->r_info));
    276  1.1.1.1.4.2  perseant   void **slot;
    277  1.1.1.1.4.2  perseant 
    278  1.1.1.1.4.2  perseant   e.elf.indx = sec->id;
    279  1.1.1.1.4.2  perseant   e.elf.dynstr_index = ELFNN_R_SYM (rel->r_info);
    280  1.1.1.1.4.2  perseant   slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h,
    281  1.1.1.1.4.2  perseant 				   create ? INSERT : NO_INSERT);
    282  1.1.1.1.4.2  perseant 
    283  1.1.1.1.4.2  perseant   if (!slot)
    284  1.1.1.1.4.2  perseant     return NULL;
    285  1.1.1.1.4.2  perseant 
    286  1.1.1.1.4.2  perseant   if (*slot)
    287  1.1.1.1.4.2  perseant     {
    288  1.1.1.1.4.2  perseant       ret = (struct loongarch_elf_link_hash_entry *) *slot;
    289  1.1.1.1.4.2  perseant       return &ret->elf;
    290  1.1.1.1.4.2  perseant     }
    291  1.1.1.1.4.2  perseant 
    292  1.1.1.1.4.2  perseant   ret = ((struct loongarch_elf_link_hash_entry *)
    293  1.1.1.1.4.2  perseant 	 objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
    294  1.1.1.1.4.2  perseant 			 sizeof (struct loongarch_elf_link_hash_entry)));
    295  1.1.1.1.4.2  perseant   if (ret)
    296  1.1.1.1.4.2  perseant     {
    297  1.1.1.1.4.2  perseant       memset (ret, 0, sizeof (*ret));
    298  1.1.1.1.4.2  perseant       ret->elf.indx = sec->id;
    299  1.1.1.1.4.2  perseant       ret->elf.pointer_equality_needed = 0;
    300  1.1.1.1.4.2  perseant       ret->elf.dynstr_index = ELFNN_R_SYM (rel->r_info);
    301  1.1.1.1.4.2  perseant       ret->elf.dynindx = -1;
    302  1.1.1.1.4.2  perseant       ret->elf.needs_plt = 0;
    303  1.1.1.1.4.2  perseant       ret->elf.plt.refcount = -1;
    304  1.1.1.1.4.2  perseant       ret->elf.got.refcount = -1;
    305  1.1.1.1.4.2  perseant       ret->elf.def_dynamic = 0;
    306  1.1.1.1.4.2  perseant       ret->elf.def_regular = 1;
    307  1.1.1.1.4.2  perseant       ret->elf.ref_dynamic = 0; /* This should be always 0 for local.  */
    308  1.1.1.1.4.2  perseant       ret->elf.ref_regular = 0;
    309  1.1.1.1.4.2  perseant       ret->elf.forced_local = 1;
    310  1.1.1.1.4.2  perseant       ret->elf.root.type = bfd_link_hash_defined;
    311  1.1.1.1.4.2  perseant       *slot = ret;
    312  1.1.1.1.4.2  perseant     }
    313  1.1.1.1.4.2  perseant   return &ret->elf;
    314  1.1.1.1.4.2  perseant }
    315  1.1.1.1.4.2  perseant 
    316  1.1.1.1.4.2  perseant /* Destroy an LoongArch elf linker hash table.  */
    317  1.1.1.1.4.2  perseant 
    318  1.1.1.1.4.2  perseant static void
    319  1.1.1.1.4.2  perseant elfNN_loongarch_link_hash_table_free (bfd *obfd)
    320  1.1.1.1.4.2  perseant {
    321  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *ret;
    322  1.1.1.1.4.2  perseant   ret = (struct loongarch_elf_link_hash_table *) obfd->link.hash;
    323  1.1.1.1.4.2  perseant 
    324  1.1.1.1.4.2  perseant   if (ret->loc_hash_table)
    325  1.1.1.1.4.2  perseant     htab_delete (ret->loc_hash_table);
    326  1.1.1.1.4.2  perseant   if (ret->loc_hash_memory)
    327  1.1.1.1.4.2  perseant     objalloc_free ((struct objalloc *) ret->loc_hash_memory);
    328  1.1.1.1.4.2  perseant 
    329  1.1.1.1.4.2  perseant   _bfd_elf_link_hash_table_free (obfd);
    330  1.1.1.1.4.2  perseant }
    331  1.1.1.1.4.2  perseant 
    332  1.1.1.1.4.2  perseant /* Create a LoongArch ELF linker hash table.  */
    333  1.1.1.1.4.2  perseant 
    334  1.1.1.1.4.2  perseant static struct bfd_link_hash_table *
    335  1.1.1.1.4.2  perseant loongarch_elf_link_hash_table_create (bfd *abfd)
    336  1.1.1.1.4.2  perseant {
    337  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *ret;
    338  1.1.1.1.4.2  perseant   bfd_size_type amt = sizeof (struct loongarch_elf_link_hash_table);
    339  1.1.1.1.4.2  perseant 
    340  1.1.1.1.4.2  perseant   ret = (struct loongarch_elf_link_hash_table *) bfd_zmalloc (amt);
    341  1.1.1.1.4.2  perseant   if (ret == NULL)
    342  1.1.1.1.4.2  perseant     return NULL;
    343  1.1.1.1.4.2  perseant 
    344  1.1.1.1.4.2  perseant   if (!_bfd_elf_link_hash_table_init
    345  1.1.1.1.4.2  perseant       (&ret->elf, abfd, link_hash_newfunc,
    346  1.1.1.1.4.2  perseant        sizeof (struct loongarch_elf_link_hash_entry), LARCH_ELF_DATA))
    347  1.1.1.1.4.2  perseant     {
    348  1.1.1.1.4.2  perseant       free (ret);
    349  1.1.1.1.4.2  perseant       return NULL;
    350  1.1.1.1.4.2  perseant     }
    351  1.1.1.1.4.2  perseant 
    352  1.1.1.1.4.2  perseant   ret->max_alignment = MINUS_ONE;
    353  1.1.1.1.4.2  perseant 
    354  1.1.1.1.4.2  perseant   ret->loc_hash_table = htab_try_create (1024, elfNN_loongarch_local_htab_hash,
    355  1.1.1.1.4.2  perseant 					 elfNN_loongarch_local_htab_eq, NULL);
    356  1.1.1.1.4.2  perseant   ret->loc_hash_memory = objalloc_create ();
    357  1.1.1.1.4.2  perseant   if (!ret->loc_hash_table || !ret->loc_hash_memory)
    358  1.1.1.1.4.2  perseant     {
    359  1.1.1.1.4.2  perseant       elfNN_loongarch_link_hash_table_free (abfd);
    360  1.1.1.1.4.2  perseant       return NULL;
    361  1.1.1.1.4.2  perseant     }
    362  1.1.1.1.4.2  perseant   ret->elf.root.hash_table_free = elfNN_loongarch_link_hash_table_free;
    363  1.1.1.1.4.2  perseant 
    364  1.1.1.1.4.2  perseant   return &ret->elf.root;
    365  1.1.1.1.4.2  perseant }
    366  1.1.1.1.4.2  perseant 
    367  1.1.1.1.4.2  perseant /* Merge backend specific data from an object file to the output
    368  1.1.1.1.4.2  perseant    object file when linking.  */
    369  1.1.1.1.4.2  perseant 
    370  1.1.1.1.4.2  perseant static bool
    371  1.1.1.1.4.2  perseant elfNN_loongarch_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
    372  1.1.1.1.4.2  perseant {
    373  1.1.1.1.4.2  perseant   bfd *obfd = info->output_bfd;
    374  1.1.1.1.4.2  perseant   flagword in_flags = elf_elfheader (ibfd)->e_flags;
    375  1.1.1.1.4.2  perseant   flagword out_flags = elf_elfheader (obfd)->e_flags;
    376  1.1.1.1.4.2  perseant 
    377  1.1.1.1.4.2  perseant   if (!is_loongarch_elf (ibfd) || !is_loongarch_elf (obfd))
    378  1.1.1.1.4.2  perseant     return true;
    379  1.1.1.1.4.2  perseant 
    380  1.1.1.1.4.2  perseant   if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
    381  1.1.1.1.4.2  perseant     {
    382  1.1.1.1.4.2  perseant       _bfd_error_handler (_("%pB: ABI is incompatible with that of "
    383  1.1.1.1.4.2  perseant 			    "the selected emulation:\n"
    384  1.1.1.1.4.2  perseant 			    "  target emulation `%s' does not match `%s'"),
    385  1.1.1.1.4.2  perseant 			  ibfd, bfd_get_target (ibfd), bfd_get_target (obfd));
    386  1.1.1.1.4.2  perseant       return false;
    387  1.1.1.1.4.2  perseant     }
    388  1.1.1.1.4.2  perseant 
    389  1.1.1.1.4.2  perseant   if (!_bfd_elf_merge_object_attributes (ibfd, info))
    390  1.1.1.1.4.2  perseant     return false;
    391  1.1.1.1.4.2  perseant 
    392  1.1.1.1.4.2  perseant   /* If the input BFD is not a dynamic object and it does not contain any
    393  1.1.1.1.4.2  perseant      non-data sections, do not account its ABI.  For example, various
    394  1.1.1.1.4.2  perseant      packages produces such data-only relocatable objects with
    395  1.1.1.1.4.2  perseant      `ld -r -b binary` or `objcopy`, and these objects have zero e_flags.
    396  1.1.1.1.4.2  perseant      But they are compatible with all ABIs.  */
    397  1.1.1.1.4.2  perseant   if (!(ibfd->flags & DYNAMIC))
    398  1.1.1.1.4.2  perseant     {
    399  1.1.1.1.4.2  perseant       asection *sec;
    400  1.1.1.1.4.2  perseant       bool have_code_sections = false;
    401  1.1.1.1.4.2  perseant       for (sec = ibfd->sections; sec != NULL; sec = sec->next)
    402  1.1.1.1.4.2  perseant 	if ((bfd_section_flags (sec)
    403  1.1.1.1.4.2  perseant 	     & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
    404  1.1.1.1.4.2  perseant 	    == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
    405  1.1.1.1.4.2  perseant 	  {
    406  1.1.1.1.4.2  perseant 	    have_code_sections = true;
    407  1.1.1.1.4.2  perseant 	    break;
    408  1.1.1.1.4.2  perseant 	  }
    409  1.1.1.1.4.2  perseant       if (!have_code_sections)
    410  1.1.1.1.4.2  perseant 	return true;
    411  1.1.1.1.4.2  perseant     }
    412  1.1.1.1.4.2  perseant 
    413  1.1.1.1.4.2  perseant   if (!elf_flags_init (obfd))
    414  1.1.1.1.4.2  perseant     {
    415  1.1.1.1.4.2  perseant       elf_flags_init (obfd) = true;
    416  1.1.1.1.4.2  perseant       elf_elfheader (obfd)->e_flags = in_flags;
    417  1.1.1.1.4.2  perseant       return true;
    418  1.1.1.1.4.2  perseant     }
    419  1.1.1.1.4.2  perseant   else if (out_flags != in_flags)
    420  1.1.1.1.4.2  perseant     {
    421  1.1.1.1.4.2  perseant       if ((EF_LOONGARCH_IS_OBJ_V0 (out_flags)
    422  1.1.1.1.4.2  perseant 	   && EF_LOONGARCH_IS_OBJ_V1 (in_flags))
    423  1.1.1.1.4.2  perseant 	  || (EF_LOONGARCH_IS_OBJ_V0 (in_flags)
    424  1.1.1.1.4.2  perseant 	      && EF_LOONGARCH_IS_OBJ_V1 (out_flags)))
    425  1.1.1.1.4.2  perseant 	{
    426  1.1.1.1.4.2  perseant 	  elf_elfheader (obfd)->e_flags |= EF_LOONGARCH_OBJABI_V1;
    427  1.1.1.1.4.2  perseant 	  out_flags = elf_elfheader (obfd)->e_flags;
    428  1.1.1.1.4.2  perseant 	  in_flags = out_flags;
    429  1.1.1.1.4.2  perseant 	}
    430  1.1.1.1.4.2  perseant     }
    431  1.1.1.1.4.2  perseant 
    432  1.1.1.1.4.2  perseant   /* Disallow linking different ABIs.  */
    433  1.1.1.1.4.2  perseant   /* Only check relocation version.
    434  1.1.1.1.4.2  perseant      The obj_v0 is compatible with obj_v1.  */
    435  1.1.1.1.4.2  perseant   if (EF_LOONGARCH_ABI(out_flags ^ in_flags) & EF_LOONGARCH_ABI_MASK)
    436  1.1.1.1.4.2  perseant     {
    437  1.1.1.1.4.2  perseant       _bfd_error_handler (_("%pB: can't link different ABI object."), ibfd);
    438  1.1.1.1.4.2  perseant       goto fail;
    439  1.1.1.1.4.2  perseant     }
    440  1.1.1.1.4.2  perseant 
    441  1.1.1.1.4.2  perseant   return true;
    442  1.1.1.1.4.2  perseant 
    443  1.1.1.1.4.2  perseant  fail:
    444  1.1.1.1.4.2  perseant   bfd_set_error (bfd_error_bad_value);
    445  1.1.1.1.4.2  perseant   return false;
    446  1.1.1.1.4.2  perseant }
    447  1.1.1.1.4.2  perseant 
    448  1.1.1.1.4.2  perseant /* Create the .got section.  */
    449  1.1.1.1.4.2  perseant 
    450  1.1.1.1.4.2  perseant static bool
    451  1.1.1.1.4.2  perseant loongarch_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
    452  1.1.1.1.4.2  perseant {
    453  1.1.1.1.4.2  perseant   flagword flags;
    454  1.1.1.1.4.2  perseant   char *name;
    455  1.1.1.1.4.2  perseant   asection *s, *s_got;
    456  1.1.1.1.4.2  perseant   struct elf_link_hash_entry *h;
    457  1.1.1.1.4.2  perseant   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
    458  1.1.1.1.4.2  perseant   struct elf_link_hash_table *htab = elf_hash_table (info);
    459  1.1.1.1.4.2  perseant 
    460  1.1.1.1.4.2  perseant   /* This function may be called more than once.  */
    461  1.1.1.1.4.2  perseant   if (htab->sgot != NULL)
    462  1.1.1.1.4.2  perseant     return true;
    463  1.1.1.1.4.2  perseant 
    464  1.1.1.1.4.2  perseant   flags = bed->dynamic_sec_flags;
    465  1.1.1.1.4.2  perseant   name = bed->rela_plts_and_copies_p ? ".rela.got" : ".rel.got";
    466  1.1.1.1.4.2  perseant   s = bfd_make_section_anyway_with_flags (abfd, name, flags | SEC_READONLY);
    467  1.1.1.1.4.2  perseant 
    468  1.1.1.1.4.2  perseant   if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align))
    469  1.1.1.1.4.2  perseant     return false;
    470  1.1.1.1.4.2  perseant   htab->srelgot = s;
    471  1.1.1.1.4.2  perseant 
    472  1.1.1.1.4.2  perseant   s = s_got = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
    473  1.1.1.1.4.2  perseant   if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align))
    474  1.1.1.1.4.2  perseant     return false;
    475  1.1.1.1.4.2  perseant   htab->sgot = s;
    476  1.1.1.1.4.2  perseant 
    477  1.1.1.1.4.2  perseant   /* The first bit of the global offset table is the header.  */
    478  1.1.1.1.4.2  perseant   s->size += bed->got_header_size;
    479  1.1.1.1.4.2  perseant 
    480  1.1.1.1.4.2  perseant   if (bed->want_got_plt)
    481  1.1.1.1.4.2  perseant     {
    482  1.1.1.1.4.2  perseant       s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
    483  1.1.1.1.4.2  perseant       if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align))
    484  1.1.1.1.4.2  perseant 	return false;
    485  1.1.1.1.4.2  perseant       htab->sgotplt = s;
    486  1.1.1.1.4.2  perseant 
    487  1.1.1.1.4.2  perseant       /* Reserve room for the header.  */
    488  1.1.1.1.4.2  perseant       s->size = GOTPLT_HEADER_SIZE;
    489  1.1.1.1.4.2  perseant     }
    490  1.1.1.1.4.2  perseant 
    491  1.1.1.1.4.2  perseant   if (bed->want_got_sym)
    492  1.1.1.1.4.2  perseant     {
    493  1.1.1.1.4.2  perseant       /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
    494  1.1.1.1.4.2  perseant 	 section.  We don't do this in the linker script because we don't want
    495  1.1.1.1.4.2  perseant 	 to define the symbol if we are not creating a global offset table.  */
    496  1.1.1.1.4.2  perseant       h = _bfd_elf_define_linkage_sym (abfd, info, s_got,
    497  1.1.1.1.4.2  perseant 				       "_GLOBAL_OFFSET_TABLE_");
    498  1.1.1.1.4.2  perseant       elf_hash_table (info)->hgot = h;
    499  1.1.1.1.4.2  perseant       if (h == NULL)
    500  1.1.1.1.4.2  perseant 	return false;
    501  1.1.1.1.4.2  perseant     }
    502  1.1.1.1.4.2  perseant   return true;
    503  1.1.1.1.4.2  perseant }
    504  1.1.1.1.4.2  perseant 
    505  1.1.1.1.4.2  perseant /* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
    506  1.1.1.1.4.2  perseant    .rela.bss sections in DYNOBJ, and set up shortcuts to them in our
    507  1.1.1.1.4.2  perseant    hash table.  */
    508  1.1.1.1.4.2  perseant 
    509  1.1.1.1.4.2  perseant static bool
    510  1.1.1.1.4.2  perseant loongarch_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
    511  1.1.1.1.4.2  perseant {
    512  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab;
    513  1.1.1.1.4.2  perseant 
    514  1.1.1.1.4.2  perseant   htab = loongarch_elf_hash_table (info);
    515  1.1.1.1.4.2  perseant   BFD_ASSERT (htab != NULL);
    516  1.1.1.1.4.2  perseant 
    517  1.1.1.1.4.2  perseant   if (!loongarch_elf_create_got_section (dynobj, info))
    518  1.1.1.1.4.2  perseant     return false;
    519  1.1.1.1.4.2  perseant 
    520  1.1.1.1.4.2  perseant   if (!_bfd_elf_create_dynamic_sections (dynobj, info))
    521  1.1.1.1.4.2  perseant     return false;
    522  1.1.1.1.4.2  perseant 
    523  1.1.1.1.4.2  perseant   if (!bfd_link_pic (info))
    524  1.1.1.1.4.2  perseant     htab->sdyntdata
    525  1.1.1.1.4.2  perseant       = bfd_make_section_anyway_with_flags (dynobj, ".tdata.dyn",
    526  1.1.1.1.4.2  perseant 					    SEC_ALLOC | SEC_THREAD_LOCAL);
    527  1.1.1.1.4.2  perseant 
    528  1.1.1.1.4.2  perseant   if (!htab->elf.splt || !htab->elf.srelplt || !htab->elf.sdynbss
    529  1.1.1.1.4.2  perseant       || (!bfd_link_pic (info) && (!htab->elf.srelbss || !htab->sdyntdata)))
    530  1.1.1.1.4.2  perseant     abort ();
    531  1.1.1.1.4.2  perseant 
    532  1.1.1.1.4.2  perseant   return true;
    533  1.1.1.1.4.2  perseant }
    534  1.1.1.1.4.2  perseant 
    535  1.1.1.1.4.2  perseant static bool
    536  1.1.1.1.4.2  perseant loongarch_elf_record_tls_and_got_reference (bfd *abfd,
    537  1.1.1.1.4.2  perseant 					    struct bfd_link_info *info,
    538  1.1.1.1.4.2  perseant 					    struct elf_link_hash_entry *h,
    539  1.1.1.1.4.2  perseant 					    unsigned long symndx,
    540  1.1.1.1.4.2  perseant 					    char tls_type)
    541  1.1.1.1.4.2  perseant {
    542  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
    543  1.1.1.1.4.2  perseant   Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
    544  1.1.1.1.4.2  perseant 
    545  1.1.1.1.4.2  perseant   /* This is a global offset table entry for a local symbol.  */
    546  1.1.1.1.4.2  perseant   if (elf_local_got_refcounts (abfd) == NULL)
    547  1.1.1.1.4.2  perseant     {
    548  1.1.1.1.4.2  perseant       bfd_size_type size =
    549  1.1.1.1.4.2  perseant 	symtab_hdr->sh_info * (sizeof (bfd_vma) + sizeof (tls_type));
    550  1.1.1.1.4.2  perseant       if (!(elf_local_got_refcounts (abfd) = bfd_zalloc (abfd, size)))
    551  1.1.1.1.4.2  perseant 	return false;
    552  1.1.1.1.4.2  perseant       _bfd_loongarch_elf_local_got_tls_type (abfd) =
    553  1.1.1.1.4.2  perseant 	(char *) (elf_local_got_refcounts (abfd) + symtab_hdr->sh_info);
    554  1.1.1.1.4.2  perseant     }
    555  1.1.1.1.4.2  perseant 
    556  1.1.1.1.4.2  perseant   switch (tls_type)
    557  1.1.1.1.4.2  perseant     {
    558  1.1.1.1.4.2  perseant     case GOT_NORMAL:
    559  1.1.1.1.4.2  perseant     case GOT_TLS_GD:
    560  1.1.1.1.4.2  perseant     case GOT_TLS_IE:
    561  1.1.1.1.4.2  perseant       /* Need GOT.  */
    562  1.1.1.1.4.2  perseant       if (htab->elf.sgot == NULL
    563  1.1.1.1.4.2  perseant 	  && !loongarch_elf_create_got_section (htab->elf.dynobj, info))
    564  1.1.1.1.4.2  perseant 	return false;
    565  1.1.1.1.4.2  perseant       if (h)
    566  1.1.1.1.4.2  perseant 	{
    567  1.1.1.1.4.2  perseant 	  if (h->got.refcount < 0)
    568  1.1.1.1.4.2  perseant 	    h->got.refcount = 0;
    569  1.1.1.1.4.2  perseant 	  h->got.refcount++;
    570  1.1.1.1.4.2  perseant 	}
    571  1.1.1.1.4.2  perseant       else
    572  1.1.1.1.4.2  perseant 	elf_local_got_refcounts (abfd)[symndx]++;
    573  1.1.1.1.4.2  perseant       break;
    574  1.1.1.1.4.2  perseant     case GOT_TLS_LE:
    575  1.1.1.1.4.2  perseant       /* No need for GOT.  */
    576  1.1.1.1.4.2  perseant       break;
    577  1.1.1.1.4.2  perseant     default:
    578  1.1.1.1.4.2  perseant       _bfd_error_handler (_("Internal error: unreachable."));
    579  1.1.1.1.4.2  perseant       return false;
    580  1.1.1.1.4.2  perseant     }
    581  1.1.1.1.4.2  perseant 
    582  1.1.1.1.4.2  perseant   char *new_tls_type = &_bfd_loongarch_elf_tls_type (abfd, h, symndx);
    583  1.1.1.1.4.2  perseant   *new_tls_type |= tls_type;
    584  1.1.1.1.4.2  perseant   if ((*new_tls_type & GOT_NORMAL) && (*new_tls_type & ~GOT_NORMAL))
    585  1.1.1.1.4.2  perseant     {
    586  1.1.1.1.4.2  perseant       _bfd_error_handler (_("%pB: `%s' accessed both as normal and "
    587  1.1.1.1.4.2  perseant 			    "thread local symbol"),
    588  1.1.1.1.4.2  perseant 			  abfd,
    589  1.1.1.1.4.2  perseant 			  h ? h->root.root.string : "<local>");
    590  1.1.1.1.4.2  perseant       return false;
    591  1.1.1.1.4.2  perseant     }
    592  1.1.1.1.4.2  perseant 
    593  1.1.1.1.4.2  perseant   return true;
    594  1.1.1.1.4.2  perseant }
    595  1.1.1.1.4.2  perseant 
    596  1.1.1.1.4.2  perseant /* Look through the relocs for a section during the first phase, and
    597  1.1.1.1.4.2  perseant    allocate space in the global offset table or procedure linkage
    598  1.1.1.1.4.2  perseant    table.  */
    599  1.1.1.1.4.2  perseant 
    600  1.1.1.1.4.2  perseant static bool
    601  1.1.1.1.4.2  perseant loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
    602  1.1.1.1.4.2  perseant 			    asection *sec, const Elf_Internal_Rela *relocs)
    603  1.1.1.1.4.2  perseant {
    604  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab;
    605  1.1.1.1.4.2  perseant   Elf_Internal_Shdr *symtab_hdr;
    606  1.1.1.1.4.2  perseant   struct elf_link_hash_entry **sym_hashes;
    607  1.1.1.1.4.2  perseant   const Elf_Internal_Rela *rel;
    608  1.1.1.1.4.2  perseant   asection *sreloc = NULL;
    609  1.1.1.1.4.2  perseant 
    610  1.1.1.1.4.2  perseant   if (bfd_link_relocatable (info))
    611  1.1.1.1.4.2  perseant     return true;
    612  1.1.1.1.4.2  perseant 
    613  1.1.1.1.4.2  perseant   htab = loongarch_elf_hash_table (info);
    614  1.1.1.1.4.2  perseant   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
    615  1.1.1.1.4.2  perseant   sym_hashes = elf_sym_hashes (abfd);
    616  1.1.1.1.4.2  perseant 
    617  1.1.1.1.4.2  perseant   if (htab->elf.dynobj == NULL)
    618  1.1.1.1.4.2  perseant     htab->elf.dynobj = abfd;
    619  1.1.1.1.4.2  perseant 
    620  1.1.1.1.4.2  perseant   for (rel = relocs; rel < relocs + sec->reloc_count; rel++)
    621  1.1.1.1.4.2  perseant     {
    622  1.1.1.1.4.2  perseant       unsigned int r_type;
    623  1.1.1.1.4.2  perseant       unsigned int r_symndx;
    624  1.1.1.1.4.2  perseant       struct elf_link_hash_entry *h;
    625  1.1.1.1.4.2  perseant       Elf_Internal_Sym *isym = NULL;
    626  1.1.1.1.4.2  perseant 
    627  1.1.1.1.4.2  perseant       r_symndx = ELFNN_R_SYM (rel->r_info);
    628  1.1.1.1.4.2  perseant       r_type = ELFNN_R_TYPE (rel->r_info);
    629  1.1.1.1.4.2  perseant 
    630  1.1.1.1.4.2  perseant       if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
    631  1.1.1.1.4.2  perseant 	{
    632  1.1.1.1.4.2  perseant 	  _bfd_error_handler (_("%pB: bad symbol index: %d"), abfd, r_symndx);
    633  1.1.1.1.4.2  perseant 	  return false;
    634  1.1.1.1.4.2  perseant 	}
    635  1.1.1.1.4.2  perseant 
    636  1.1.1.1.4.2  perseant       if (r_symndx < symtab_hdr->sh_info)
    637  1.1.1.1.4.2  perseant 	{
    638  1.1.1.1.4.2  perseant 	  /* A local symbol.  */
    639  1.1.1.1.4.2  perseant 	  isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd, r_symndx);
    640  1.1.1.1.4.2  perseant 	  if (isym == NULL)
    641  1.1.1.1.4.2  perseant 	    return false;
    642  1.1.1.1.4.2  perseant 
    643  1.1.1.1.4.2  perseant 	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
    644  1.1.1.1.4.2  perseant 	    {
    645  1.1.1.1.4.2  perseant 	      h = elfNN_loongarch_get_local_sym_hash (htab, abfd, rel, true);
    646  1.1.1.1.4.2  perseant 	      if (h == NULL)
    647  1.1.1.1.4.2  perseant 		return false;
    648  1.1.1.1.4.2  perseant 
    649  1.1.1.1.4.2  perseant 	      h->type = STT_GNU_IFUNC;
    650  1.1.1.1.4.2  perseant 	      h->ref_regular = 1;
    651  1.1.1.1.4.2  perseant 	    }
    652  1.1.1.1.4.2  perseant 	  else
    653  1.1.1.1.4.2  perseant 	    h = NULL;
    654  1.1.1.1.4.2  perseant 	}
    655  1.1.1.1.4.2  perseant       else
    656  1.1.1.1.4.2  perseant 	{
    657  1.1.1.1.4.2  perseant 	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
    658  1.1.1.1.4.2  perseant 	  while (h->root.type == bfd_link_hash_indirect
    659  1.1.1.1.4.2  perseant 		 || h->root.type == bfd_link_hash_warning)
    660  1.1.1.1.4.2  perseant 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    661  1.1.1.1.4.2  perseant 	}
    662  1.1.1.1.4.2  perseant 
    663  1.1.1.1.4.2  perseant       /* It is referenced by a non-shared object.  */
    664  1.1.1.1.4.2  perseant       if (h != NULL)
    665  1.1.1.1.4.2  perseant 	h->ref_regular = 1;
    666  1.1.1.1.4.2  perseant 
    667  1.1.1.1.4.2  perseant       if (h && h->type == STT_GNU_IFUNC)
    668  1.1.1.1.4.2  perseant 	{
    669  1.1.1.1.4.2  perseant 	  if (htab->elf.dynobj == NULL)
    670  1.1.1.1.4.2  perseant 	    htab->elf.dynobj = abfd;
    671  1.1.1.1.4.2  perseant 
    672  1.1.1.1.4.2  perseant 	  /* Create 'irelifunc' in PIC object.  */
    673  1.1.1.1.4.2  perseant 	  if (bfd_link_pic (info)
    674  1.1.1.1.4.2  perseant 	      && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
    675  1.1.1.1.4.2  perseant 	    return false;
    676  1.1.1.1.4.2  perseant 	  /* If '.plt' not represent, create '.iplt' to deal with ifunc.  */
    677  1.1.1.1.4.2  perseant 	  else if (!htab->elf.splt
    678  1.1.1.1.4.2  perseant 		   && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
    679  1.1.1.1.4.2  perseant 	    return false;
    680  1.1.1.1.4.2  perseant 	  /* Create the ifunc sections, iplt and ipltgot, for static
    681  1.1.1.1.4.2  perseant 	     executables.  */
    682  1.1.1.1.4.2  perseant 	  if ((r_type == R_LARCH_64 || r_type == R_LARCH_32)
    683  1.1.1.1.4.2  perseant 	      && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
    684  1.1.1.1.4.2  perseant 	    return false;
    685  1.1.1.1.4.2  perseant 
    686  1.1.1.1.4.2  perseant 	  if (h->plt.refcount < 0)
    687  1.1.1.1.4.2  perseant 	    h->plt.refcount = 0;
    688  1.1.1.1.4.2  perseant 	  h->plt.refcount++;
    689  1.1.1.1.4.2  perseant 	  h->needs_plt = 1;
    690  1.1.1.1.4.2  perseant 
    691  1.1.1.1.4.2  perseant 	  elf_tdata (info->output_bfd)->has_gnu_osabi |= elf_gnu_osabi_ifunc;
    692  1.1.1.1.4.2  perseant 	}
    693  1.1.1.1.4.2  perseant 
    694  1.1.1.1.4.2  perseant       int need_dynreloc = 0;
    695  1.1.1.1.4.2  perseant       int only_need_pcrel = 0;
    696  1.1.1.1.4.2  perseant 
    697  1.1.1.1.4.2  perseant       switch (r_type)
    698  1.1.1.1.4.2  perseant 	{
    699  1.1.1.1.4.2  perseant 	case R_LARCH_GOT_PC_HI20:
    700  1.1.1.1.4.2  perseant 	case R_LARCH_GOT_HI20:
    701  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_GPREL:
    702  1.1.1.1.4.2  perseant 	  /* For la.global.  */
    703  1.1.1.1.4.2  perseant 	  if (h)
    704  1.1.1.1.4.2  perseant 	    h->pointer_equality_needed = 1;
    705  1.1.1.1.4.2  perseant 	  if (!loongarch_elf_record_tls_and_got_reference (abfd, info, h,
    706  1.1.1.1.4.2  perseant 							   r_symndx,
    707  1.1.1.1.4.2  perseant 							   GOT_NORMAL))
    708  1.1.1.1.4.2  perseant 	    return false;
    709  1.1.1.1.4.2  perseant 	  break;
    710  1.1.1.1.4.2  perseant 
    711  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LD_PC_HI20:
    712  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LD_HI20:
    713  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_GD_PC_HI20:
    714  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_GD_HI20:
    715  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_TLS_GD:
    716  1.1.1.1.4.2  perseant 	  if (!loongarch_elf_record_tls_and_got_reference (abfd, info, h,
    717  1.1.1.1.4.2  perseant 							   r_symndx,
    718  1.1.1.1.4.2  perseant 							   GOT_TLS_GD))
    719  1.1.1.1.4.2  perseant 	    return false;
    720  1.1.1.1.4.2  perseant 	  break;
    721  1.1.1.1.4.2  perseant 
    722  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE_PC_HI20:
    723  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE_HI20:
    724  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_TLS_GOT:
    725  1.1.1.1.4.2  perseant 	  if (bfd_link_pic (info))
    726  1.1.1.1.4.2  perseant 	    /* May fail for lazy-bind.  */
    727  1.1.1.1.4.2  perseant 	    info->flags |= DF_STATIC_TLS;
    728  1.1.1.1.4.2  perseant 
    729  1.1.1.1.4.2  perseant 	  if (!loongarch_elf_record_tls_and_got_reference (abfd, info, h,
    730  1.1.1.1.4.2  perseant 							   r_symndx,
    731  1.1.1.1.4.2  perseant 							   GOT_TLS_IE))
    732  1.1.1.1.4.2  perseant 	    return false;
    733  1.1.1.1.4.2  perseant 	  break;
    734  1.1.1.1.4.2  perseant 
    735  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LE_HI20:
    736  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_TLS_TPREL:
    737  1.1.1.1.4.2  perseant 	  if (!bfd_link_executable (info))
    738  1.1.1.1.4.2  perseant 	    return false;
    739  1.1.1.1.4.2  perseant 
    740  1.1.1.1.4.2  perseant 	  info->flags |= DF_STATIC_TLS;
    741  1.1.1.1.4.2  perseant 
    742  1.1.1.1.4.2  perseant 	  if (!loongarch_elf_record_tls_and_got_reference (abfd, info, h,
    743  1.1.1.1.4.2  perseant 							   r_symndx,
    744  1.1.1.1.4.2  perseant 							   GOT_TLS_LE))
    745  1.1.1.1.4.2  perseant 	    return false;
    746  1.1.1.1.4.2  perseant 	  break;
    747  1.1.1.1.4.2  perseant 
    748  1.1.1.1.4.2  perseant 	case R_LARCH_ABS_HI20:
    749  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_ABSOLUTE:
    750  1.1.1.1.4.2  perseant 	  if (h != NULL)
    751  1.1.1.1.4.2  perseant 	    /* If this reloc is in a read-only section, we might
    752  1.1.1.1.4.2  perseant 	       need a copy reloc.  We can't check reliably at this
    753  1.1.1.1.4.2  perseant 	       stage whether the section is read-only, as input
    754  1.1.1.1.4.2  perseant 	       sections have not yet been mapped to output sections.
    755  1.1.1.1.4.2  perseant 	       Tentatively set the flag for now, and correct in
    756  1.1.1.1.4.2  perseant 	       adjust_dynamic_symbol.  */
    757  1.1.1.1.4.2  perseant 	    h->non_got_ref = 1;
    758  1.1.1.1.4.2  perseant 	  break;
    759  1.1.1.1.4.2  perseant 
    760  1.1.1.1.4.2  perseant 	case R_LARCH_PCALA_HI20:
    761  1.1.1.1.4.2  perseant 	  if (h != NULL)
    762  1.1.1.1.4.2  perseant 	    {
    763  1.1.1.1.4.2  perseant 	      /* For pcalau12i + jirl.  */
    764  1.1.1.1.4.2  perseant 	      h->needs_plt = 1;
    765  1.1.1.1.4.2  perseant 	      if (h->plt.refcount < 0)
    766  1.1.1.1.4.2  perseant 		h->plt.refcount = 0;
    767  1.1.1.1.4.2  perseant 	      h->plt.refcount++;
    768  1.1.1.1.4.2  perseant 
    769  1.1.1.1.4.2  perseant 	      h->non_got_ref = 1;
    770  1.1.1.1.4.2  perseant 	      h->pointer_equality_needed = 1;
    771  1.1.1.1.4.2  perseant 	    }
    772  1.1.1.1.4.2  perseant 
    773  1.1.1.1.4.2  perseant 	  break;
    774  1.1.1.1.4.2  perseant 
    775  1.1.1.1.4.2  perseant 	case R_LARCH_B21:
    776  1.1.1.1.4.2  perseant 	case R_LARCH_B16:
    777  1.1.1.1.4.2  perseant 	case R_LARCH_B26:
    778  1.1.1.1.4.2  perseant 	  if (h != NULL)
    779  1.1.1.1.4.2  perseant 	    {
    780  1.1.1.1.4.2  perseant 	      h->needs_plt = 1;
    781  1.1.1.1.4.2  perseant 	      if (!bfd_link_pic (info))
    782  1.1.1.1.4.2  perseant 		h->non_got_ref = 1;
    783  1.1.1.1.4.2  perseant 
    784  1.1.1.1.4.2  perseant 	      /* We try to create PLT stub for all non-local function.  */
    785  1.1.1.1.4.2  perseant 	      if (h->plt.refcount < 0)
    786  1.1.1.1.4.2  perseant 		h->plt.refcount = 0;
    787  1.1.1.1.4.2  perseant 	      h->plt.refcount++;
    788  1.1.1.1.4.2  perseant 	    }
    789  1.1.1.1.4.2  perseant 
    790  1.1.1.1.4.2  perseant 	  break;
    791  1.1.1.1.4.2  perseant 
    792  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_PCREL:
    793  1.1.1.1.4.2  perseant 	  if (h != NULL)
    794  1.1.1.1.4.2  perseant 	    {
    795  1.1.1.1.4.2  perseant 	      if (!bfd_link_pic (info))
    796  1.1.1.1.4.2  perseant 		h->non_got_ref = 1;
    797  1.1.1.1.4.2  perseant 
    798  1.1.1.1.4.2  perseant 	      /* We try to create PLT stub for all non-local function.  */
    799  1.1.1.1.4.2  perseant 	      if (h->plt.refcount < 0)
    800  1.1.1.1.4.2  perseant 		h->plt.refcount = 0;
    801  1.1.1.1.4.2  perseant 	      h->plt.refcount++;
    802  1.1.1.1.4.2  perseant 	      h->pointer_equality_needed = 1;
    803  1.1.1.1.4.2  perseant 	    }
    804  1.1.1.1.4.2  perseant 
    805  1.1.1.1.4.2  perseant 	  break;
    806  1.1.1.1.4.2  perseant 
    807  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_PLT_PCREL:
    808  1.1.1.1.4.2  perseant 	  /* This symbol requires a procedure linkage table entry.  We
    809  1.1.1.1.4.2  perseant 	     actually build the entry in adjust_dynamic_symbol,
    810  1.1.1.1.4.2  perseant 	     because this might be a case of linking PIC code without
    811  1.1.1.1.4.2  perseant 	     linking in any dynamic objects, in which case we don't
    812  1.1.1.1.4.2  perseant 	     need to generate a procedure linkage table after all.  */
    813  1.1.1.1.4.2  perseant 	  if (h != NULL)
    814  1.1.1.1.4.2  perseant 	    {
    815  1.1.1.1.4.2  perseant 	      h->needs_plt = 1;
    816  1.1.1.1.4.2  perseant 	      if (h->plt.refcount < 0)
    817  1.1.1.1.4.2  perseant 		h->plt.refcount = 0;
    818  1.1.1.1.4.2  perseant 	      h->plt.refcount++;
    819  1.1.1.1.4.2  perseant 	    }
    820  1.1.1.1.4.2  perseant 	  break;
    821  1.1.1.1.4.2  perseant 
    822  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_DTPREL32:
    823  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_DTPREL64:
    824  1.1.1.1.4.2  perseant 	  need_dynreloc = 1;
    825  1.1.1.1.4.2  perseant 	  only_need_pcrel = 1;
    826  1.1.1.1.4.2  perseant 	  break;
    827  1.1.1.1.4.2  perseant 
    828  1.1.1.1.4.2  perseant 	case R_LARCH_JUMP_SLOT:
    829  1.1.1.1.4.2  perseant 	case R_LARCH_32:
    830  1.1.1.1.4.2  perseant 	case R_LARCH_64:
    831  1.1.1.1.4.2  perseant 
    832  1.1.1.1.4.2  perseant 	  need_dynreloc = 1;
    833  1.1.1.1.4.2  perseant 
    834  1.1.1.1.4.2  perseant 	  /* If resolved symbol is defined in this object,
    835  1.1.1.1.4.2  perseant 	     1. Under pie, the symbol is known.  We convert it
    836  1.1.1.1.4.2  perseant 	     into R_LARCH_RELATIVE and need load-addr still.
    837  1.1.1.1.4.2  perseant 	     2. Under pde, the symbol is known and we can discard R_LARCH_NN.
    838  1.1.1.1.4.2  perseant 	     3. Under dll, R_LARCH_NN can't be changed normally, since
    839  1.1.1.1.4.2  perseant 	     its defination could be covered by the one in executable.
    840  1.1.1.1.4.2  perseant 	     For symbolic, we convert it into R_LARCH_RELATIVE.
    841  1.1.1.1.4.2  perseant 	     Thus, only under pde, it needs pcrel only.  We discard it.  */
    842  1.1.1.1.4.2  perseant 	  only_need_pcrel = bfd_link_pde (info);
    843  1.1.1.1.4.2  perseant 
    844  1.1.1.1.4.2  perseant 	  if (h != NULL
    845  1.1.1.1.4.2  perseant 	      && (!bfd_link_pic (info)
    846  1.1.1.1.4.2  perseant 		  || h->type == STT_GNU_IFUNC))
    847  1.1.1.1.4.2  perseant 	    {
    848  1.1.1.1.4.2  perseant 	      /* This reloc might not bind locally.  */
    849  1.1.1.1.4.2  perseant 	      h->non_got_ref = 1;
    850  1.1.1.1.4.2  perseant 	      h->pointer_equality_needed = 1;
    851  1.1.1.1.4.2  perseant 
    852  1.1.1.1.4.2  perseant 	      if (!h->def_regular
    853  1.1.1.1.4.2  perseant 		  || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
    854  1.1.1.1.4.2  perseant 		{
    855  1.1.1.1.4.2  perseant 		  /* We may need a .plt entry if the symbol is a function
    856  1.1.1.1.4.2  perseant 		     defined in a shared lib or is a function referenced
    857  1.1.1.1.4.2  perseant 		     from the code or read-only section.  */
    858  1.1.1.1.4.2  perseant 		  h->plt.refcount += 1;
    859  1.1.1.1.4.2  perseant 		}
    860  1.1.1.1.4.2  perseant 	    }
    861  1.1.1.1.4.2  perseant 	  break;
    862  1.1.1.1.4.2  perseant 
    863  1.1.1.1.4.2  perseant 	case R_LARCH_GNU_VTINHERIT:
    864  1.1.1.1.4.2  perseant 	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
    865  1.1.1.1.4.2  perseant 	    return false;
    866  1.1.1.1.4.2  perseant 	  break;
    867  1.1.1.1.4.2  perseant 
    868  1.1.1.1.4.2  perseant 	case R_LARCH_GNU_VTENTRY:
    869  1.1.1.1.4.2  perseant 	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
    870  1.1.1.1.4.2  perseant 	    return false;
    871  1.1.1.1.4.2  perseant 	  break;
    872  1.1.1.1.4.2  perseant 
    873  1.1.1.1.4.2  perseant 	default:
    874  1.1.1.1.4.2  perseant 	  break;
    875  1.1.1.1.4.2  perseant 	}
    876  1.1.1.1.4.2  perseant 
    877  1.1.1.1.4.2  perseant       /* Record some info for sizing and allocating dynamic entry.  */
    878  1.1.1.1.4.2  perseant       if (need_dynreloc && (sec->flags & SEC_ALLOC))
    879  1.1.1.1.4.2  perseant 	{
    880  1.1.1.1.4.2  perseant 	  /* When creating a shared object, we must copy these
    881  1.1.1.1.4.2  perseant 	     relocs into the output file.  We create a reloc
    882  1.1.1.1.4.2  perseant 	     section in dynobj and make room for the reloc.  */
    883  1.1.1.1.4.2  perseant 	  struct elf_dyn_relocs *p;
    884  1.1.1.1.4.2  perseant 	  struct elf_dyn_relocs **head;
    885  1.1.1.1.4.2  perseant 
    886  1.1.1.1.4.2  perseant 	  if (sreloc == NULL)
    887  1.1.1.1.4.2  perseant 	    {
    888  1.1.1.1.4.2  perseant 	      sreloc
    889  1.1.1.1.4.2  perseant 		= _bfd_elf_make_dynamic_reloc_section (sec, htab->elf.dynobj,
    890  1.1.1.1.4.2  perseant 						       LARCH_ELF_LOG_WORD_BYTES,
    891  1.1.1.1.4.2  perseant 						       abfd, /*rela?*/ true);
    892  1.1.1.1.4.2  perseant 	      if (sreloc == NULL)
    893  1.1.1.1.4.2  perseant 		return false;
    894  1.1.1.1.4.2  perseant 	    }
    895  1.1.1.1.4.2  perseant 
    896  1.1.1.1.4.2  perseant 	  /* If this is a global symbol, we count the number of
    897  1.1.1.1.4.2  perseant 	     relocations we need for this symbol.  */
    898  1.1.1.1.4.2  perseant 	  if (h != NULL)
    899  1.1.1.1.4.2  perseant 	    head = &h->dyn_relocs;
    900  1.1.1.1.4.2  perseant 	  else
    901  1.1.1.1.4.2  perseant 	    {
    902  1.1.1.1.4.2  perseant 	      /* Track dynamic relocs needed for local syms too.
    903  1.1.1.1.4.2  perseant 		 We really need local syms available to do this
    904  1.1.1.1.4.2  perseant 		 easily.  Oh well.  */
    905  1.1.1.1.4.2  perseant 
    906  1.1.1.1.4.2  perseant 	      asection *s;
    907  1.1.1.1.4.2  perseant 	      void *vpp;
    908  1.1.1.1.4.2  perseant 
    909  1.1.1.1.4.2  perseant 	      s = bfd_section_from_elf_index (abfd, isym->st_shndx);
    910  1.1.1.1.4.2  perseant 	      if (s == NULL)
    911  1.1.1.1.4.2  perseant 		s = sec;
    912  1.1.1.1.4.2  perseant 
    913  1.1.1.1.4.2  perseant 	      vpp = &elf_section_data (s)->local_dynrel;
    914  1.1.1.1.4.2  perseant 	      head = (struct elf_dyn_relocs **) vpp;
    915  1.1.1.1.4.2  perseant 	    }
    916  1.1.1.1.4.2  perseant 
    917  1.1.1.1.4.2  perseant 	  p = *head;
    918  1.1.1.1.4.2  perseant 	  if (p == NULL || p->sec != sec)
    919  1.1.1.1.4.2  perseant 	    {
    920  1.1.1.1.4.2  perseant 	      bfd_size_type amt = sizeof *p;
    921  1.1.1.1.4.2  perseant 	      p = (struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj, amt);
    922  1.1.1.1.4.2  perseant 	      if (p == NULL)
    923  1.1.1.1.4.2  perseant 		return false;
    924  1.1.1.1.4.2  perseant 	      p->next = *head;
    925  1.1.1.1.4.2  perseant 	      *head = p;
    926  1.1.1.1.4.2  perseant 	      p->sec = sec;
    927  1.1.1.1.4.2  perseant 	      p->count = 0;
    928  1.1.1.1.4.2  perseant 	      p->pc_count = 0;
    929  1.1.1.1.4.2  perseant 	    }
    930  1.1.1.1.4.2  perseant 
    931  1.1.1.1.4.2  perseant 	  p->count++;
    932  1.1.1.1.4.2  perseant 	  p->pc_count += only_need_pcrel;
    933  1.1.1.1.4.2  perseant 	}
    934  1.1.1.1.4.2  perseant     }
    935  1.1.1.1.4.2  perseant 
    936  1.1.1.1.4.2  perseant   return true;
    937  1.1.1.1.4.2  perseant }
    938  1.1.1.1.4.2  perseant 
    939  1.1.1.1.4.2  perseant /* Find dynamic relocs for H that apply to read-only sections.  */
    940  1.1.1.1.4.2  perseant 
    941  1.1.1.1.4.2  perseant static asection *
    942  1.1.1.1.4.2  perseant readonly_dynrelocs (struct elf_link_hash_entry *h)
    943  1.1.1.1.4.2  perseant {
    944  1.1.1.1.4.2  perseant   struct elf_dyn_relocs *p;
    945  1.1.1.1.4.2  perseant 
    946  1.1.1.1.4.2  perseant   for (p = h->dyn_relocs; p != NULL; p = p->next)
    947  1.1.1.1.4.2  perseant     {
    948  1.1.1.1.4.2  perseant       asection *s = p->sec->output_section;
    949  1.1.1.1.4.2  perseant 
    950  1.1.1.1.4.2  perseant       if (s != NULL && (s->flags & SEC_READONLY) != 0)
    951  1.1.1.1.4.2  perseant 	return p->sec;
    952  1.1.1.1.4.2  perseant     }
    953  1.1.1.1.4.2  perseant   return NULL;
    954  1.1.1.1.4.2  perseant }
    955  1.1.1.1.4.2  perseant 
    956  1.1.1.1.4.2  perseant /* Adjust a symbol defined by a dynamic object and referenced by a
    957  1.1.1.1.4.2  perseant    regular object.  The current definition is in some section of the
    958  1.1.1.1.4.2  perseant    dynamic object, but we're not including those sections.  We have to
    959  1.1.1.1.4.2  perseant    change the definition to something the rest of the link can
    960  1.1.1.1.4.2  perseant    understand.  */
    961  1.1.1.1.4.2  perseant static bool
    962  1.1.1.1.4.2  perseant loongarch_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
    963  1.1.1.1.4.2  perseant 				     struct elf_link_hash_entry *h)
    964  1.1.1.1.4.2  perseant {
    965  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab;
    966  1.1.1.1.4.2  perseant   bfd *dynobj;
    967  1.1.1.1.4.2  perseant 
    968  1.1.1.1.4.2  perseant   htab = loongarch_elf_hash_table (info);
    969  1.1.1.1.4.2  perseant   BFD_ASSERT (htab != NULL);
    970  1.1.1.1.4.2  perseant 
    971  1.1.1.1.4.2  perseant   dynobj = htab->elf.dynobj;
    972  1.1.1.1.4.2  perseant 
    973  1.1.1.1.4.2  perseant   /* Make sure we know what is going on here.  */
    974  1.1.1.1.4.2  perseant   BFD_ASSERT (dynobj != NULL
    975  1.1.1.1.4.2  perseant 	      && (h->needs_plt || h->type == STT_GNU_IFUNC || h->is_weakalias
    976  1.1.1.1.4.2  perseant 		  || (h->def_dynamic && h->ref_regular && !h->def_regular)));
    977  1.1.1.1.4.2  perseant 
    978  1.1.1.1.4.2  perseant   /* If this is a function, put it in the procedure linkage table.  We
    979  1.1.1.1.4.2  perseant      will fill in the contents of the procedure linkage table later
    980  1.1.1.1.4.2  perseant      (although we could actually do it here).  */
    981  1.1.1.1.4.2  perseant   if (h->type == STT_FUNC || h->type == STT_GNU_IFUNC || h->needs_plt)
    982  1.1.1.1.4.2  perseant     {
    983  1.1.1.1.4.2  perseant       if (h->plt.refcount < 0
    984  1.1.1.1.4.2  perseant 	  || (h->type != STT_GNU_IFUNC
    985  1.1.1.1.4.2  perseant 	      && (SYMBOL_REFERENCES_LOCAL (info, h)
    986  1.1.1.1.4.2  perseant 		  || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
    987  1.1.1.1.4.2  perseant 		      && h->root.type == bfd_link_hash_undefweak))))
    988  1.1.1.1.4.2  perseant 	{
    989  1.1.1.1.4.2  perseant 	  /* This case can occur if we saw a R_LARCH_SOP_PUSH_PLT_PCREL reloc
    990  1.1.1.1.4.2  perseant 	     in an input file, but the symbol was never referred to by a
    991  1.1.1.1.4.2  perseant 	     dynamic object, or if all references were garbage collected.
    992  1.1.1.1.4.2  perseant 	     In such a case, we don't actually need to build a PLT entry.  */
    993  1.1.1.1.4.2  perseant 	  h->plt.offset = MINUS_ONE;
    994  1.1.1.1.4.2  perseant 	  h->needs_plt = 0;
    995  1.1.1.1.4.2  perseant 	}
    996  1.1.1.1.4.2  perseant       else
    997  1.1.1.1.4.2  perseant 	h->needs_plt = 1;
    998  1.1.1.1.4.2  perseant 
    999  1.1.1.1.4.2  perseant       return true;
   1000  1.1.1.1.4.2  perseant     }
   1001  1.1.1.1.4.2  perseant   else
   1002  1.1.1.1.4.2  perseant     h->plt.offset = MINUS_ONE;
   1003  1.1.1.1.4.2  perseant 
   1004  1.1.1.1.4.2  perseant   /* If this is a weak symbol, and there is a real definition, the
   1005  1.1.1.1.4.2  perseant      processor independent code will have arranged for us to see the
   1006  1.1.1.1.4.2  perseant      real definition first, and we can just use the same value.  */
   1007  1.1.1.1.4.2  perseant   if (h->is_weakalias)
   1008  1.1.1.1.4.2  perseant     {
   1009  1.1.1.1.4.2  perseant       struct elf_link_hash_entry *def = weakdef (h);
   1010  1.1.1.1.4.2  perseant       BFD_ASSERT (def->root.type == bfd_link_hash_defined);
   1011  1.1.1.1.4.2  perseant       h->root.u.def.section = def->root.u.def.section;
   1012  1.1.1.1.4.2  perseant       h->root.u.def.value = def->root.u.def.value;
   1013  1.1.1.1.4.2  perseant       return true;
   1014  1.1.1.1.4.2  perseant     }
   1015  1.1.1.1.4.2  perseant 
   1016  1.1.1.1.4.2  perseant   /* R_LARCH_COPY is not adept glibc, not to generate.  */
   1017  1.1.1.1.4.2  perseant   /* Can not print anything, because make check ld.  */
   1018  1.1.1.1.4.2  perseant   return true;
   1019  1.1.1.1.4.2  perseant }
   1020  1.1.1.1.4.2  perseant 
   1021  1.1.1.1.4.2  perseant /* Allocate space in .plt, .got and associated reloc sections for
   1022  1.1.1.1.4.2  perseant    dynamic relocs.  */
   1023  1.1.1.1.4.2  perseant 
   1024  1.1.1.1.4.2  perseant static bool
   1025  1.1.1.1.4.2  perseant allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   1026  1.1.1.1.4.2  perseant {
   1027  1.1.1.1.4.2  perseant   struct bfd_link_info *info;
   1028  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab;
   1029  1.1.1.1.4.2  perseant   struct elf_dyn_relocs *p;
   1030  1.1.1.1.4.2  perseant 
   1031  1.1.1.1.4.2  perseant   if (h->root.type == bfd_link_hash_indirect)
   1032  1.1.1.1.4.2  perseant     return true;
   1033  1.1.1.1.4.2  perseant 
   1034  1.1.1.1.4.2  perseant   if (h->type == STT_GNU_IFUNC
   1035  1.1.1.1.4.2  perseant       && h->def_regular)
   1036  1.1.1.1.4.2  perseant     return true;
   1037  1.1.1.1.4.2  perseant 
   1038  1.1.1.1.4.2  perseant   info = (struct bfd_link_info *) inf;
   1039  1.1.1.1.4.2  perseant   htab = loongarch_elf_hash_table (info);
   1040  1.1.1.1.4.2  perseant   bool dyn = htab->elf.dynamic_sections_created;
   1041  1.1.1.1.4.2  perseant   BFD_ASSERT (htab != NULL);
   1042  1.1.1.1.4.2  perseant 
   1043  1.1.1.1.4.2  perseant   do
   1044  1.1.1.1.4.2  perseant     {
   1045  1.1.1.1.4.2  perseant       asection *plt, *gotplt, *relplt;
   1046  1.1.1.1.4.2  perseant 
   1047  1.1.1.1.4.2  perseant       if (!h->needs_plt)
   1048  1.1.1.1.4.2  perseant 	break;
   1049  1.1.1.1.4.2  perseant 
   1050  1.1.1.1.4.2  perseant       h->needs_plt = 0;
   1051  1.1.1.1.4.2  perseant 
   1052  1.1.1.1.4.2  perseant       if (htab->elf.splt)
   1053  1.1.1.1.4.2  perseant 	{
   1054  1.1.1.1.4.2  perseant 	  if (h->dynindx == -1 && !h->forced_local && dyn
   1055  1.1.1.1.4.2  perseant 	      && h->root.type == bfd_link_hash_undefweak)
   1056  1.1.1.1.4.2  perseant 	    {
   1057  1.1.1.1.4.2  perseant 	      if (!bfd_elf_link_record_dynamic_symbol (info, h))
   1058  1.1.1.1.4.2  perseant 		return false;
   1059  1.1.1.1.4.2  perseant 	    }
   1060  1.1.1.1.4.2  perseant 
   1061  1.1.1.1.4.2  perseant 	  if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)
   1062  1.1.1.1.4.2  perseant 	      && h->type != STT_GNU_IFUNC)
   1063  1.1.1.1.4.2  perseant 	    break;
   1064  1.1.1.1.4.2  perseant 
   1065  1.1.1.1.4.2  perseant 	  plt = htab->elf.splt;
   1066  1.1.1.1.4.2  perseant 	  gotplt = htab->elf.sgotplt;
   1067  1.1.1.1.4.2  perseant 	  relplt = htab->elf.srelplt;
   1068  1.1.1.1.4.2  perseant 	}
   1069  1.1.1.1.4.2  perseant       else if (htab->elf.iplt)
   1070  1.1.1.1.4.2  perseant 	{
   1071  1.1.1.1.4.2  perseant 	  /* .iplt only for IFUNC.  */
   1072  1.1.1.1.4.2  perseant 	  if (h->type != STT_GNU_IFUNC)
   1073  1.1.1.1.4.2  perseant 	    break;
   1074  1.1.1.1.4.2  perseant 
   1075  1.1.1.1.4.2  perseant 	  plt = htab->elf.iplt;
   1076  1.1.1.1.4.2  perseant 	  gotplt = htab->elf.igotplt;
   1077  1.1.1.1.4.2  perseant 	  relplt = htab->elf.irelplt;
   1078  1.1.1.1.4.2  perseant 	}
   1079  1.1.1.1.4.2  perseant       else
   1080  1.1.1.1.4.2  perseant 	break;
   1081  1.1.1.1.4.2  perseant 
   1082  1.1.1.1.4.2  perseant       if (plt->size == 0)
   1083  1.1.1.1.4.2  perseant 	plt->size = PLT_HEADER_SIZE;
   1084  1.1.1.1.4.2  perseant 
   1085  1.1.1.1.4.2  perseant       h->plt.offset = plt->size;
   1086  1.1.1.1.4.2  perseant       plt->size += PLT_ENTRY_SIZE;
   1087  1.1.1.1.4.2  perseant       gotplt->size += GOT_ENTRY_SIZE;
   1088  1.1.1.1.4.2  perseant       relplt->size += sizeof (ElfNN_External_Rela);
   1089  1.1.1.1.4.2  perseant 
   1090  1.1.1.1.4.2  perseant       /* If this symbol is not defined in a regular file, and we are
   1091  1.1.1.1.4.2  perseant 	 not generating a shared library, then set the symbol to this
   1092  1.1.1.1.4.2  perseant 	 location in the .plt.  This is required to make function
   1093  1.1.1.1.4.2  perseant 	 pointers compare as equal between the normal executable and
   1094  1.1.1.1.4.2  perseant 	 the shared library.  */
   1095  1.1.1.1.4.2  perseant       if (!bfd_link_pic (info)
   1096  1.1.1.1.4.2  perseant 	  && !h->def_regular)
   1097  1.1.1.1.4.2  perseant 	{
   1098  1.1.1.1.4.2  perseant 	  h->root.u.def.section = plt;
   1099  1.1.1.1.4.2  perseant 	  h->root.u.def.value = h->plt.offset;
   1100  1.1.1.1.4.2  perseant 	}
   1101  1.1.1.1.4.2  perseant 
   1102  1.1.1.1.4.2  perseant       h->needs_plt = 1;
   1103  1.1.1.1.4.2  perseant     }
   1104  1.1.1.1.4.2  perseant   while (0);
   1105  1.1.1.1.4.2  perseant 
   1106  1.1.1.1.4.2  perseant   if (!h->needs_plt)
   1107  1.1.1.1.4.2  perseant     h->plt.offset = MINUS_ONE;
   1108  1.1.1.1.4.2  perseant 
   1109  1.1.1.1.4.2  perseant   if (0 < h->got.refcount)
   1110  1.1.1.1.4.2  perseant     {
   1111  1.1.1.1.4.2  perseant       asection *s;
   1112  1.1.1.1.4.2  perseant       int tls_type = loongarch_elf_hash_entry (h)->tls_type;
   1113  1.1.1.1.4.2  perseant 
   1114  1.1.1.1.4.2  perseant       /* Make sure this symbol is output as a dynamic symbol.
   1115  1.1.1.1.4.2  perseant 	 Undefined weak syms won't yet be marked as dynamic.  */
   1116  1.1.1.1.4.2  perseant       if (h->dynindx == -1 && !h->forced_local && dyn
   1117  1.1.1.1.4.2  perseant 	  && h->root.type == bfd_link_hash_undefweak)
   1118  1.1.1.1.4.2  perseant 	{
   1119  1.1.1.1.4.2  perseant 	  if (!bfd_elf_link_record_dynamic_symbol (info, h))
   1120  1.1.1.1.4.2  perseant 	    return false;
   1121  1.1.1.1.4.2  perseant 	}
   1122  1.1.1.1.4.2  perseant 
   1123  1.1.1.1.4.2  perseant       s = htab->elf.sgot;
   1124  1.1.1.1.4.2  perseant       h->got.offset = s->size;
   1125  1.1.1.1.4.2  perseant       if (tls_type & (GOT_TLS_GD | GOT_TLS_IE))
   1126  1.1.1.1.4.2  perseant 	{
   1127  1.1.1.1.4.2  perseant 	  /* TLS_GD needs two dynamic relocs and two GOT slots.  */
   1128  1.1.1.1.4.2  perseant 	  if (tls_type & GOT_TLS_GD)
   1129  1.1.1.1.4.2  perseant 	    {
   1130  1.1.1.1.4.2  perseant 	      s->size += 2 * GOT_ENTRY_SIZE;
   1131  1.1.1.1.4.2  perseant 	      if (bfd_link_executable (info))
   1132  1.1.1.1.4.2  perseant 		{
   1133  1.1.1.1.4.2  perseant 		  /* Link exe and not defined local.  */
   1134  1.1.1.1.4.2  perseant 		  if (!SYMBOL_REFERENCES_LOCAL (info, h))
   1135  1.1.1.1.4.2  perseant 		    htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
   1136  1.1.1.1.4.2  perseant 		}
   1137  1.1.1.1.4.2  perseant 	      else
   1138  1.1.1.1.4.2  perseant 		{
   1139  1.1.1.1.4.2  perseant 		  if (SYMBOL_REFERENCES_LOCAL (info, h))
   1140  1.1.1.1.4.2  perseant 		    htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
   1141  1.1.1.1.4.2  perseant 		  else
   1142  1.1.1.1.4.2  perseant 		    htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
   1143  1.1.1.1.4.2  perseant 		}
   1144  1.1.1.1.4.2  perseant 	    }
   1145  1.1.1.1.4.2  perseant 
   1146  1.1.1.1.4.2  perseant 	  /* TLS_IE needs one dynamic reloc and one GOT slot.  */
   1147  1.1.1.1.4.2  perseant 	  if (tls_type & GOT_TLS_IE)
   1148  1.1.1.1.4.2  perseant 	    {
   1149  1.1.1.1.4.2  perseant 	      s->size += GOT_ENTRY_SIZE;
   1150  1.1.1.1.4.2  perseant 
   1151  1.1.1.1.4.2  perseant 	      if (bfd_link_executable (info))
   1152  1.1.1.1.4.2  perseant 		{
   1153  1.1.1.1.4.2  perseant 		  /* Link exe and not defined local.  */
   1154  1.1.1.1.4.2  perseant 		  if (!SYMBOL_REFERENCES_LOCAL (info, h))
   1155  1.1.1.1.4.2  perseant 		    htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
   1156  1.1.1.1.4.2  perseant 		}
   1157  1.1.1.1.4.2  perseant 	      else
   1158  1.1.1.1.4.2  perseant 		{
   1159  1.1.1.1.4.2  perseant 		  htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
   1160  1.1.1.1.4.2  perseant 		}
   1161  1.1.1.1.4.2  perseant 	    }
   1162  1.1.1.1.4.2  perseant 	}
   1163  1.1.1.1.4.2  perseant       else
   1164  1.1.1.1.4.2  perseant 	{
   1165  1.1.1.1.4.2  perseant 	  s->size += GOT_ENTRY_SIZE;
   1166  1.1.1.1.4.2  perseant 	  if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
   1167  1.1.1.1.4.2  perseant 	       || h->root.type != bfd_link_hash_undefweak)
   1168  1.1.1.1.4.2  perseant 	      && (bfd_link_pic (info)
   1169  1.1.1.1.4.2  perseant 		  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
   1170  1.1.1.1.4.2  perseant 						      h))
   1171  1.1.1.1.4.2  perseant 	      && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
   1172  1.1.1.1.4.2  perseant 	      /* Undefined weak symbol in static PIE resolves to 0 without
   1173  1.1.1.1.4.2  perseant 		 any dynamic relocations.  */
   1174  1.1.1.1.4.2  perseant 	    htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
   1175  1.1.1.1.4.2  perseant 	}
   1176  1.1.1.1.4.2  perseant     }
   1177  1.1.1.1.4.2  perseant   else
   1178  1.1.1.1.4.2  perseant     h->got.offset = MINUS_ONE;
   1179  1.1.1.1.4.2  perseant 
   1180  1.1.1.1.4.2  perseant   if (h->dyn_relocs == NULL)
   1181  1.1.1.1.4.2  perseant     return true;
   1182  1.1.1.1.4.2  perseant 
   1183  1.1.1.1.4.2  perseant   /* Extra dynamic relocate,
   1184  1.1.1.1.4.2  perseant    * R_LARCH_64
   1185  1.1.1.1.4.2  perseant    * R_LARCH_TLS_DTPRELNN
   1186  1.1.1.1.4.2  perseant    * R_LARCH_JUMP_SLOT
   1187  1.1.1.1.4.2  perseant    * R_LARCH_NN.  */
   1188  1.1.1.1.4.2  perseant 
   1189  1.1.1.1.4.2  perseant   if (SYMBOL_CALLS_LOCAL (info, h))
   1190  1.1.1.1.4.2  perseant     {
   1191  1.1.1.1.4.2  perseant       struct elf_dyn_relocs **pp;
   1192  1.1.1.1.4.2  perseant 
   1193  1.1.1.1.4.2  perseant       for (pp = &h->dyn_relocs; (p = *pp) != NULL;)
   1194  1.1.1.1.4.2  perseant 	{
   1195  1.1.1.1.4.2  perseant 	  p->count -= p->pc_count;
   1196  1.1.1.1.4.2  perseant 	  p->pc_count = 0;
   1197  1.1.1.1.4.2  perseant 	  if (p->count == 0)
   1198  1.1.1.1.4.2  perseant 	    *pp = p->next;
   1199  1.1.1.1.4.2  perseant 	  else
   1200  1.1.1.1.4.2  perseant 	    pp = &p->next;
   1201  1.1.1.1.4.2  perseant 	}
   1202  1.1.1.1.4.2  perseant     }
   1203  1.1.1.1.4.2  perseant 
   1204  1.1.1.1.4.2  perseant   if (h->root.type == bfd_link_hash_undefweak)
   1205  1.1.1.1.4.2  perseant     {
   1206  1.1.1.1.4.2  perseant       if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
   1207  1.1.1.1.4.2  perseant 	  || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
   1208  1.1.1.1.4.2  perseant 	  || (!bfd_link_pic (info) && h->non_got_ref))
   1209  1.1.1.1.4.2  perseant 	h->dyn_relocs = NULL;
   1210  1.1.1.1.4.2  perseant       else if (h->dynindx == -1 && !h->forced_local)
   1211  1.1.1.1.4.2  perseant 	{
   1212  1.1.1.1.4.2  perseant 	  /* Make sure this symbol is output as a dynamic symbol.
   1213  1.1.1.1.4.2  perseant 	     Undefined weak syms won't yet be marked as dynamic.  */
   1214  1.1.1.1.4.2  perseant 	  if (!bfd_elf_link_record_dynamic_symbol (info, h))
   1215  1.1.1.1.4.2  perseant 	    return false;
   1216  1.1.1.1.4.2  perseant 
   1217  1.1.1.1.4.2  perseant 	  if (h->dynindx == -1)
   1218  1.1.1.1.4.2  perseant 	    h->dyn_relocs = NULL;
   1219  1.1.1.1.4.2  perseant 	}
   1220  1.1.1.1.4.2  perseant     }
   1221  1.1.1.1.4.2  perseant 
   1222  1.1.1.1.4.2  perseant   for (p = h->dyn_relocs; p != NULL; p = p->next)
   1223  1.1.1.1.4.2  perseant     {
   1224  1.1.1.1.4.2  perseant       asection *sreloc = elf_section_data (p->sec)->sreloc;
   1225  1.1.1.1.4.2  perseant       sreloc->size += p->count * sizeof (ElfNN_External_Rela);
   1226  1.1.1.1.4.2  perseant     }
   1227  1.1.1.1.4.2  perseant 
   1228  1.1.1.1.4.2  perseant   return true;
   1229  1.1.1.1.4.2  perseant }
   1230  1.1.1.1.4.2  perseant 
   1231  1.1.1.1.4.2  perseant /* A modified version of _bfd_elf_allocate_ifunc_dyn_relocs.
   1232  1.1.1.1.4.2  perseant    For local def and ref ifunc,
   1233  1.1.1.1.4.2  perseant    dynamic relocations are stored in
   1234  1.1.1.1.4.2  perseant    1.  rela.srelgot section in dynamic object (dll or exec).
   1235  1.1.1.1.4.2  perseant    2.  rela.irelplt section in static executable.
   1236  1.1.1.1.4.2  perseant    Unlike _bfd_elf_allocate_ifunc_dyn_relocs, rela.srelgot is used
   1237  1.1.1.1.4.2  perseant    instead of rela.srelplt.  Glibc ELF loader will not support
   1238  1.1.1.1.4.2  perseant    R_LARCH_IRELATIVE relocation in rela.plt.  */
   1239  1.1.1.1.4.2  perseant 
   1240  1.1.1.1.4.2  perseant static bool
   1241  1.1.1.1.4.2  perseant local_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
   1242  1.1.1.1.4.2  perseant 				    struct elf_link_hash_entry *h,
   1243  1.1.1.1.4.2  perseant 				    struct elf_dyn_relocs **head,
   1244  1.1.1.1.4.2  perseant 				    unsigned int plt_entry_size,
   1245  1.1.1.1.4.2  perseant 				    unsigned int plt_header_size,
   1246  1.1.1.1.4.2  perseant 				    unsigned int got_entry_size,
   1247  1.1.1.1.4.2  perseant 				    bool avoid_plt)
   1248  1.1.1.1.4.2  perseant {
   1249  1.1.1.1.4.2  perseant   asection *plt, *gotplt, *relplt;
   1250  1.1.1.1.4.2  perseant   struct elf_dyn_relocs *p;
   1251  1.1.1.1.4.2  perseant   unsigned int sizeof_reloc;
   1252  1.1.1.1.4.2  perseant   const struct elf_backend_data *bed;
   1253  1.1.1.1.4.2  perseant   struct elf_link_hash_table *htab;
   1254  1.1.1.1.4.2  perseant   /* If AVOID_PLT is TRUE, don't use PLT if possible.  */
   1255  1.1.1.1.4.2  perseant   bool use_plt = !avoid_plt || h->plt.refcount > 0;
   1256  1.1.1.1.4.2  perseant   bool need_dynreloc = !use_plt || bfd_link_pic (info);
   1257  1.1.1.1.4.2  perseant 
   1258  1.1.1.1.4.2  perseant   /* When a PIC object references a STT_GNU_IFUNC symbol defined
   1259  1.1.1.1.4.2  perseant      in executable or it isn't referenced via PLT, the address of
   1260  1.1.1.1.4.2  perseant      the resolved function may be used.  But in non-PIC executable,
   1261  1.1.1.1.4.2  perseant      the address of its plt slot may be used.  Pointer equality may
   1262  1.1.1.1.4.2  perseant      not work correctly.  PIE or non-PLT reference should be used if
   1263  1.1.1.1.4.2  perseant      pointer equality is required here.
   1264  1.1.1.1.4.2  perseant 
   1265  1.1.1.1.4.2  perseant      If STT_GNU_IFUNC symbol is defined in position-dependent executable,
   1266  1.1.1.1.4.2  perseant      backend should change it to the normal function and set its address
   1267  1.1.1.1.4.2  perseant      to its PLT entry which should be resolved by R_*_IRELATIVE at
   1268  1.1.1.1.4.2  perseant      run-time.  All external references should be resolved to its PLT in
   1269  1.1.1.1.4.2  perseant      executable.  */
   1270  1.1.1.1.4.2  perseant   if (!need_dynreloc
   1271  1.1.1.1.4.2  perseant       && !(bfd_link_pde (info) && h->def_regular)
   1272  1.1.1.1.4.2  perseant       && (h->dynindx != -1
   1273  1.1.1.1.4.2  perseant 	  || info->export_dynamic)
   1274  1.1.1.1.4.2  perseant       && h->pointer_equality_needed)
   1275  1.1.1.1.4.2  perseant     {
   1276  1.1.1.1.4.2  perseant       info->callbacks->einfo
   1277  1.1.1.1.4.2  perseant 	/* xgettext:c-format.  */
   1278  1.1.1.1.4.2  perseant 	(_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
   1279  1.1.1.1.4.2  perseant 	   "equality in `%pB' can not be used when making an "
   1280  1.1.1.1.4.2  perseant 	   "executable; recompile with -fPIE and relink with -pie\n"),
   1281  1.1.1.1.4.2  perseant 	 h->root.root.string,
   1282  1.1.1.1.4.2  perseant 	 h->root.u.def.section->owner);
   1283  1.1.1.1.4.2  perseant       bfd_set_error (bfd_error_bad_value);
   1284  1.1.1.1.4.2  perseant       return false;
   1285  1.1.1.1.4.2  perseant     }
   1286  1.1.1.1.4.2  perseant 
   1287  1.1.1.1.4.2  perseant   htab = elf_hash_table (info);
   1288  1.1.1.1.4.2  perseant 
   1289  1.1.1.1.4.2  perseant   /* When the symbol is marked with regular reference, if PLT isn't used
   1290  1.1.1.1.4.2  perseant      or we are building a PIC object, we must keep dynamic relocation
   1291  1.1.1.1.4.2  perseant      if there is non-GOT reference and use PLT if there is PC-relative
   1292  1.1.1.1.4.2  perseant      reference.  */
   1293  1.1.1.1.4.2  perseant   if (need_dynreloc && h->ref_regular)
   1294  1.1.1.1.4.2  perseant     {
   1295  1.1.1.1.4.2  perseant       bool keep = false;
   1296  1.1.1.1.4.2  perseant       for (p = *head; p != NULL; p = p->next)
   1297  1.1.1.1.4.2  perseant 	if (p->count)
   1298  1.1.1.1.4.2  perseant 	  {
   1299  1.1.1.1.4.2  perseant 	    h->non_got_ref = 1;
   1300  1.1.1.1.4.2  perseant 	    /* Need dynamic relocations for non-GOT reference.  */
   1301  1.1.1.1.4.2  perseant 	    keep = true;
   1302  1.1.1.1.4.2  perseant 	    if (p->pc_count)
   1303  1.1.1.1.4.2  perseant 	      {
   1304  1.1.1.1.4.2  perseant 		/* Must use PLT for PC-relative reference.  */
   1305  1.1.1.1.4.2  perseant 		use_plt = true;
   1306  1.1.1.1.4.2  perseant 		need_dynreloc = bfd_link_pic (info);
   1307  1.1.1.1.4.2  perseant 		break;
   1308  1.1.1.1.4.2  perseant 	      }
   1309  1.1.1.1.4.2  perseant 	  }
   1310  1.1.1.1.4.2  perseant       if (keep)
   1311  1.1.1.1.4.2  perseant 	goto keep;
   1312  1.1.1.1.4.2  perseant     }
   1313  1.1.1.1.4.2  perseant 
   1314  1.1.1.1.4.2  perseant   /* Support garbage collection against STT_GNU_IFUNC symbols.  */
   1315  1.1.1.1.4.2  perseant   if (h->plt.refcount <= 0 && h->got.refcount <= 0)
   1316  1.1.1.1.4.2  perseant     {
   1317  1.1.1.1.4.2  perseant       h->got = htab->init_got_offset;
   1318  1.1.1.1.4.2  perseant       h->plt = htab->init_plt_offset;
   1319  1.1.1.1.4.2  perseant       *head = NULL;
   1320  1.1.1.1.4.2  perseant       return true;
   1321  1.1.1.1.4.2  perseant     }
   1322  1.1.1.1.4.2  perseant 
   1323  1.1.1.1.4.2  perseant   /* Return and discard space for dynamic relocations against it if
   1324  1.1.1.1.4.2  perseant      it is never referenced.  */
   1325  1.1.1.1.4.2  perseant   if (!h->ref_regular)
   1326  1.1.1.1.4.2  perseant     {
   1327  1.1.1.1.4.2  perseant       if (h->plt.refcount > 0
   1328  1.1.1.1.4.2  perseant 	  || h->got.refcount > 0)
   1329  1.1.1.1.4.2  perseant 	abort ();
   1330  1.1.1.1.4.2  perseant       h->got = htab->init_got_offset;
   1331  1.1.1.1.4.2  perseant       h->plt = htab->init_plt_offset;
   1332  1.1.1.1.4.2  perseant       *head = NULL;
   1333  1.1.1.1.4.2  perseant       return true;
   1334  1.1.1.1.4.2  perseant     }
   1335  1.1.1.1.4.2  perseant 
   1336  1.1.1.1.4.2  perseant  keep:
   1337  1.1.1.1.4.2  perseant   bed = get_elf_backend_data (info->output_bfd);
   1338  1.1.1.1.4.2  perseant   if (bed->rela_plts_and_copies_p)
   1339  1.1.1.1.4.2  perseant     sizeof_reloc = bed->s->sizeof_rela;
   1340  1.1.1.1.4.2  perseant   else
   1341  1.1.1.1.4.2  perseant     sizeof_reloc = bed->s->sizeof_rel;
   1342  1.1.1.1.4.2  perseant 
   1343  1.1.1.1.4.2  perseant   /* When building a static executable, use iplt, igot.plt and
   1344  1.1.1.1.4.2  perseant      rela.iplt sections for STT_GNU_IFUNC symbols.  */
   1345  1.1.1.1.4.2  perseant   if (htab->splt != NULL)
   1346  1.1.1.1.4.2  perseant     {
   1347  1.1.1.1.4.2  perseant       plt = htab->splt;
   1348  1.1.1.1.4.2  perseant       gotplt = htab->sgotplt;
   1349  1.1.1.1.4.2  perseant       /* Change dynamic info of ifunc gotplt from srelplt to srelgot.  */
   1350  1.1.1.1.4.2  perseant       relplt = htab->srelgot;
   1351  1.1.1.1.4.2  perseant 
   1352  1.1.1.1.4.2  perseant       /* If this is the first plt entry and PLT is used, make room for
   1353  1.1.1.1.4.2  perseant 	 the special first entry.  */
   1354  1.1.1.1.4.2  perseant       if (plt->size == 0 && use_plt)
   1355  1.1.1.1.4.2  perseant 	plt->size += plt_header_size;
   1356  1.1.1.1.4.2  perseant     }
   1357  1.1.1.1.4.2  perseant   else
   1358  1.1.1.1.4.2  perseant     {
   1359  1.1.1.1.4.2  perseant       plt = htab->iplt;
   1360  1.1.1.1.4.2  perseant       gotplt = htab->igotplt;
   1361  1.1.1.1.4.2  perseant       relplt = htab->irelplt;
   1362  1.1.1.1.4.2  perseant     }
   1363  1.1.1.1.4.2  perseant 
   1364  1.1.1.1.4.2  perseant   if (use_plt)
   1365  1.1.1.1.4.2  perseant     {
   1366  1.1.1.1.4.2  perseant       /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
   1367  1.1.1.1.4.2  perseant 	 the original value for R_*_IRELATIVE.  */
   1368  1.1.1.1.4.2  perseant       h->plt.offset = plt->size;
   1369  1.1.1.1.4.2  perseant 
   1370  1.1.1.1.4.2  perseant       /* Make room for this entry in the plt/iplt section.  */
   1371  1.1.1.1.4.2  perseant       plt->size += plt_entry_size;
   1372  1.1.1.1.4.2  perseant 
   1373  1.1.1.1.4.2  perseant       /* We also need to make an entry in the got.plt/got.iplt section,
   1374  1.1.1.1.4.2  perseant 	 which will be placed in the got section by the linker script.  */
   1375  1.1.1.1.4.2  perseant       gotplt->size += got_entry_size;
   1376  1.1.1.1.4.2  perseant     }
   1377  1.1.1.1.4.2  perseant 
   1378  1.1.1.1.4.2  perseant   /* We also need to make an entry in the rela.plt/.rela.iplt
   1379  1.1.1.1.4.2  perseant      section for GOTPLT relocation if PLT is used.  */
   1380  1.1.1.1.4.2  perseant   if (use_plt)
   1381  1.1.1.1.4.2  perseant     {
   1382  1.1.1.1.4.2  perseant       relplt->size += sizeof_reloc;
   1383  1.1.1.1.4.2  perseant       relplt->reloc_count++;
   1384  1.1.1.1.4.2  perseant     }
   1385  1.1.1.1.4.2  perseant 
   1386  1.1.1.1.4.2  perseant   /* We need dynamic relocation for STT_GNU_IFUNC symbol only when
   1387  1.1.1.1.4.2  perseant      there is a non-GOT reference in a PIC object or PLT isn't used.  */
   1388  1.1.1.1.4.2  perseant   if (!need_dynreloc || !h->non_got_ref)
   1389  1.1.1.1.4.2  perseant     *head = NULL;
   1390  1.1.1.1.4.2  perseant 
   1391  1.1.1.1.4.2  perseant   /* Finally, allocate space.  */
   1392  1.1.1.1.4.2  perseant   p = *head;
   1393  1.1.1.1.4.2  perseant   if (p != NULL)
   1394  1.1.1.1.4.2  perseant     {
   1395  1.1.1.1.4.2  perseant       bfd_size_type count = 0;
   1396  1.1.1.1.4.2  perseant       do
   1397  1.1.1.1.4.2  perseant 	{
   1398  1.1.1.1.4.2  perseant 	  count += p->count;
   1399  1.1.1.1.4.2  perseant 	  p = p->next;
   1400  1.1.1.1.4.2  perseant 	}
   1401  1.1.1.1.4.2  perseant       while (p != NULL);
   1402  1.1.1.1.4.2  perseant 
   1403  1.1.1.1.4.2  perseant       htab->ifunc_resolvers = count != 0;
   1404  1.1.1.1.4.2  perseant 
   1405  1.1.1.1.4.2  perseant       /* Dynamic relocations are stored in
   1406  1.1.1.1.4.2  perseant 	 1.  rela.srelgot section in PIC object.
   1407  1.1.1.1.4.2  perseant 	 2.  rela.srelgot section in dynamic executable.
   1408  1.1.1.1.4.2  perseant 	 3.  rela.irelplt section in static executable.  */
   1409  1.1.1.1.4.2  perseant       if (htab->splt != NULL)
   1410  1.1.1.1.4.2  perseant 	htab->srelgot->size += count * sizeof_reloc;
   1411  1.1.1.1.4.2  perseant       else
   1412  1.1.1.1.4.2  perseant 	{
   1413  1.1.1.1.4.2  perseant 	  relplt->size += count * sizeof_reloc;
   1414  1.1.1.1.4.2  perseant 	  relplt->reloc_count += count;
   1415  1.1.1.1.4.2  perseant 	}
   1416  1.1.1.1.4.2  perseant     }
   1417  1.1.1.1.4.2  perseant 
   1418  1.1.1.1.4.2  perseant   /* For STT_GNU_IFUNC symbol, got.plt has the real function address
   1419  1.1.1.1.4.2  perseant      and got has the PLT entry adddress.  We will load the GOT entry
   1420  1.1.1.1.4.2  perseant      with the PLT entry in finish_dynamic_symbol if it is used.  For
   1421  1.1.1.1.4.2  perseant      branch, it uses got.plt.  For symbol value, if PLT is used,
   1422  1.1.1.1.4.2  perseant      1.  Use got.plt in a PIC object if it is forced local or not
   1423  1.1.1.1.4.2  perseant      dynamic.
   1424  1.1.1.1.4.2  perseant      2.  Use got.plt in a non-PIC object if pointer equality isn't
   1425  1.1.1.1.4.2  perseant      needed.
   1426  1.1.1.1.4.2  perseant      3.  Use got.plt in PIE.
   1427  1.1.1.1.4.2  perseant      4.  Use got.plt if got isn't used.
   1428  1.1.1.1.4.2  perseant      5.  Otherwise use got so that it can be shared among different
   1429  1.1.1.1.4.2  perseant      objects at run-time.
   1430  1.1.1.1.4.2  perseant      If PLT isn't used, always use got for symbol value.
   1431  1.1.1.1.4.2  perseant      We only need to relocate got entry in PIC object or in dynamic
   1432  1.1.1.1.4.2  perseant      executable without PLT.  */
   1433  1.1.1.1.4.2  perseant   if (use_plt
   1434  1.1.1.1.4.2  perseant       && (h->got.refcount <= 0
   1435  1.1.1.1.4.2  perseant 	  || (bfd_link_pic (info)
   1436  1.1.1.1.4.2  perseant 	      && (h->dynindx == -1
   1437  1.1.1.1.4.2  perseant 		  || h->forced_local))
   1438  1.1.1.1.4.2  perseant 	  || (
   1439  1.1.1.1.4.2  perseant 	      !h->pointer_equality_needed)
   1440  1.1.1.1.4.2  perseant 	  || htab->sgot == NULL))
   1441  1.1.1.1.4.2  perseant     {
   1442  1.1.1.1.4.2  perseant       /* Use got.plt.  */
   1443  1.1.1.1.4.2  perseant       h->got.offset = (bfd_vma) -1;
   1444  1.1.1.1.4.2  perseant     }
   1445  1.1.1.1.4.2  perseant   else
   1446  1.1.1.1.4.2  perseant     {
   1447  1.1.1.1.4.2  perseant       if (!use_plt)
   1448  1.1.1.1.4.2  perseant 	{
   1449  1.1.1.1.4.2  perseant 	  /* PLT isn't used.  */
   1450  1.1.1.1.4.2  perseant 	  h->plt.offset = (bfd_vma) -1;
   1451  1.1.1.1.4.2  perseant 	}
   1452  1.1.1.1.4.2  perseant       if (h->got.refcount <= 0)
   1453  1.1.1.1.4.2  perseant 	{
   1454  1.1.1.1.4.2  perseant 	  /* GOT isn't need when there are only relocations for static
   1455  1.1.1.1.4.2  perseant 	     pointers.  */
   1456  1.1.1.1.4.2  perseant 	  h->got.offset = (bfd_vma) -1;
   1457  1.1.1.1.4.2  perseant 	}
   1458  1.1.1.1.4.2  perseant       else
   1459  1.1.1.1.4.2  perseant 	{
   1460  1.1.1.1.4.2  perseant 	  h->got.offset = htab->sgot->size;
   1461  1.1.1.1.4.2  perseant 	  htab->sgot->size += got_entry_size;
   1462  1.1.1.1.4.2  perseant 	  /* Need to relocate the GOT entry in a PIC object or PLT isn't
   1463  1.1.1.1.4.2  perseant 	     used.  Otherwise, the GOT entry will be filled with the PLT
   1464  1.1.1.1.4.2  perseant 	     entry and dynamic GOT relocation isn't needed.  */
   1465  1.1.1.1.4.2  perseant 	  if (need_dynreloc)
   1466  1.1.1.1.4.2  perseant 	    {
   1467  1.1.1.1.4.2  perseant 	      /* For non-static executable, dynamic GOT relocation is in
   1468  1.1.1.1.4.2  perseant 		 rela.got section, but for static executable, it is
   1469  1.1.1.1.4.2  perseant 		 in rela.iplt section.  */
   1470  1.1.1.1.4.2  perseant 	      if (htab->splt != NULL)
   1471  1.1.1.1.4.2  perseant 		htab->srelgot->size += sizeof_reloc;
   1472  1.1.1.1.4.2  perseant 	      else
   1473  1.1.1.1.4.2  perseant 		{
   1474  1.1.1.1.4.2  perseant 		  relplt->size += sizeof_reloc;
   1475  1.1.1.1.4.2  perseant 		  relplt->reloc_count++;
   1476  1.1.1.1.4.2  perseant 		}
   1477  1.1.1.1.4.2  perseant 	    }
   1478  1.1.1.1.4.2  perseant 	}
   1479  1.1.1.1.4.2  perseant     }
   1480  1.1.1.1.4.2  perseant 
   1481  1.1.1.1.4.2  perseant   return true;
   1482  1.1.1.1.4.2  perseant }
   1483  1.1.1.1.4.2  perseant 
   1484  1.1.1.1.4.2  perseant /* Allocate space in .plt, .got and associated reloc sections for
   1485  1.1.1.1.4.2  perseant    ifunc dynamic relocs.  */
   1486  1.1.1.1.4.2  perseant 
   1487  1.1.1.1.4.2  perseant static bool
   1488  1.1.1.1.4.2  perseant elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   1489  1.1.1.1.4.2  perseant {
   1490  1.1.1.1.4.2  perseant   struct bfd_link_info *info;
   1491  1.1.1.1.4.2  perseant   /* An example of a bfd_link_hash_indirect symbol is versioned
   1492  1.1.1.1.4.2  perseant      symbol. For example: __gxx_personality_v0(bfd_link_hash_indirect)
   1493  1.1.1.1.4.2  perseant      -> __gxx_personality_v0(bfd_link_hash_defined)
   1494  1.1.1.1.4.2  perseant 
   1495  1.1.1.1.4.2  perseant      There is no need to process bfd_link_hash_indirect symbols here
   1496  1.1.1.1.4.2  perseant      because we will also be presented with the concrete instance of
   1497  1.1.1.1.4.2  perseant      the symbol and loongarch_elf_copy_indirect_symbol () will have been
   1498  1.1.1.1.4.2  perseant      called to copy all relevant data from the generic to the concrete
   1499  1.1.1.1.4.2  perseant      symbol instance.  */
   1500  1.1.1.1.4.2  perseant   if (h->root.type == bfd_link_hash_indirect)
   1501  1.1.1.1.4.2  perseant     return true;
   1502  1.1.1.1.4.2  perseant 
   1503  1.1.1.1.4.2  perseant   if (h->root.type == bfd_link_hash_warning)
   1504  1.1.1.1.4.2  perseant     h = (struct elf_link_hash_entry *) h->root.u.i.link;
   1505  1.1.1.1.4.2  perseant 
   1506  1.1.1.1.4.2  perseant   info = (struct bfd_link_info *) inf;
   1507  1.1.1.1.4.2  perseant 
   1508  1.1.1.1.4.2  perseant   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
   1509  1.1.1.1.4.2  perseant      here if it is defined and referenced in a non-shared object.  */
   1510  1.1.1.1.4.2  perseant   if (h->type == STT_GNU_IFUNC && h->def_regular)
   1511  1.1.1.1.4.2  perseant     {
   1512  1.1.1.1.4.2  perseant       if (SYMBOL_REFERENCES_LOCAL (info, h))
   1513  1.1.1.1.4.2  perseant 	return local_allocate_ifunc_dyn_relocs (info, h,
   1514  1.1.1.1.4.2  perseant 						&h->dyn_relocs,
   1515  1.1.1.1.4.2  perseant 						PLT_ENTRY_SIZE,
   1516  1.1.1.1.4.2  perseant 						PLT_HEADER_SIZE,
   1517  1.1.1.1.4.2  perseant 						GOT_ENTRY_SIZE,
   1518  1.1.1.1.4.2  perseant 						false);
   1519  1.1.1.1.4.2  perseant       else
   1520  1.1.1.1.4.2  perseant 	return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
   1521  1.1.1.1.4.2  perseant 						   &h->dyn_relocs,
   1522  1.1.1.1.4.2  perseant 						   PLT_ENTRY_SIZE,
   1523  1.1.1.1.4.2  perseant 						   PLT_HEADER_SIZE,
   1524  1.1.1.1.4.2  perseant 						   GOT_ENTRY_SIZE,
   1525  1.1.1.1.4.2  perseant 						   false);
   1526  1.1.1.1.4.2  perseant     }
   1527  1.1.1.1.4.2  perseant 
   1528  1.1.1.1.4.2  perseant   return true;
   1529  1.1.1.1.4.2  perseant }
   1530  1.1.1.1.4.2  perseant 
   1531  1.1.1.1.4.2  perseant /* Allocate space in .plt, .got and associated reloc sections for
   1532  1.1.1.1.4.2  perseant    ifunc dynamic relocs.  */
   1533  1.1.1.1.4.2  perseant 
   1534  1.1.1.1.4.2  perseant static bool
   1535  1.1.1.1.4.2  perseant elfNN_allocate_local_ifunc_dynrelocs (void **slot, void *inf)
   1536  1.1.1.1.4.2  perseant {
   1537  1.1.1.1.4.2  perseant   struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot;
   1538  1.1.1.1.4.2  perseant 
   1539  1.1.1.1.4.2  perseant   if (h->type != STT_GNU_IFUNC
   1540  1.1.1.1.4.2  perseant       || !h->def_regular
   1541  1.1.1.1.4.2  perseant       || !h->ref_regular
   1542  1.1.1.1.4.2  perseant       || !h->forced_local
   1543  1.1.1.1.4.2  perseant       || h->root.type != bfd_link_hash_defined)
   1544  1.1.1.1.4.2  perseant     abort ();
   1545  1.1.1.1.4.2  perseant 
   1546  1.1.1.1.4.2  perseant   return elfNN_allocate_ifunc_dynrelocs (h, inf);
   1547  1.1.1.1.4.2  perseant }
   1548  1.1.1.1.4.2  perseant 
   1549  1.1.1.1.4.2  perseant /* Set DF_TEXTREL if we find any dynamic relocs that apply to
   1550  1.1.1.1.4.2  perseant    read-only sections.  */
   1551  1.1.1.1.4.2  perseant 
   1552  1.1.1.1.4.2  perseant static bool
   1553  1.1.1.1.4.2  perseant maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
   1554  1.1.1.1.4.2  perseant {
   1555  1.1.1.1.4.2  perseant   asection *sec;
   1556  1.1.1.1.4.2  perseant 
   1557  1.1.1.1.4.2  perseant   if (h->root.type == bfd_link_hash_indirect)
   1558  1.1.1.1.4.2  perseant     return true;
   1559  1.1.1.1.4.2  perseant 
   1560  1.1.1.1.4.2  perseant   sec = readonly_dynrelocs (h);
   1561  1.1.1.1.4.2  perseant   if (sec != NULL)
   1562  1.1.1.1.4.2  perseant     {
   1563  1.1.1.1.4.2  perseant       struct bfd_link_info *info = (struct bfd_link_info *) info_p;
   1564  1.1.1.1.4.2  perseant 
   1565  1.1.1.1.4.2  perseant       info->flags |= DF_TEXTREL;
   1566  1.1.1.1.4.2  perseant       info->callbacks->minfo (_("%pB: dynamic relocation against `%pT' in "
   1567  1.1.1.1.4.2  perseant 				"read-only section `%pA'\n"),
   1568  1.1.1.1.4.2  perseant 			      sec->owner, h->root.root.string, sec);
   1569  1.1.1.1.4.2  perseant 
   1570  1.1.1.1.4.2  perseant       /* Not an error, just cut short the traversal.  */
   1571  1.1.1.1.4.2  perseant       return false;
   1572  1.1.1.1.4.2  perseant     }
   1573  1.1.1.1.4.2  perseant   return true;
   1574  1.1.1.1.4.2  perseant }
   1575  1.1.1.1.4.2  perseant 
   1576  1.1.1.1.4.2  perseant static bool
   1577  1.1.1.1.4.2  perseant loongarch_elf_size_dynamic_sections (bfd *output_bfd,
   1578  1.1.1.1.4.2  perseant 				     struct bfd_link_info *info)
   1579  1.1.1.1.4.2  perseant {
   1580  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab;
   1581  1.1.1.1.4.2  perseant   bfd *dynobj;
   1582  1.1.1.1.4.2  perseant   asection *s;
   1583  1.1.1.1.4.2  perseant   bfd *ibfd;
   1584  1.1.1.1.4.2  perseant 
   1585  1.1.1.1.4.2  perseant   htab = loongarch_elf_hash_table (info);
   1586  1.1.1.1.4.2  perseant   BFD_ASSERT (htab != NULL);
   1587  1.1.1.1.4.2  perseant   dynobj = htab->elf.dynobj;
   1588  1.1.1.1.4.2  perseant   BFD_ASSERT (dynobj != NULL);
   1589  1.1.1.1.4.2  perseant 
   1590  1.1.1.1.4.2  perseant   if (htab->elf.dynamic_sections_created)
   1591  1.1.1.1.4.2  perseant     {
   1592  1.1.1.1.4.2  perseant       /* Set the contents of the .interp section to the interpreter.  */
   1593  1.1.1.1.4.2  perseant       if (bfd_link_executable (info) && !info->nointerp)
   1594  1.1.1.1.4.2  perseant 	{
   1595  1.1.1.1.4.2  perseant 	  const char *interpreter;
   1596  1.1.1.1.4.2  perseant 	  s = bfd_get_linker_section (dynobj, ".interp");
   1597  1.1.1.1.4.2  perseant 	  BFD_ASSERT (s != NULL);
   1598  1.1.1.1.4.2  perseant 
   1599  1.1.1.1.4.2  perseant 	  if (elf_elfheader (output_bfd)->e_ident[EI_CLASS] == ELFCLASS32)
   1600  1.1.1.1.4.2  perseant 	    interpreter = "/lib32/ld.so.1";
   1601  1.1.1.1.4.2  perseant 	  else if (elf_elfheader (output_bfd)->e_ident[EI_CLASS] == ELFCLASS64)
   1602  1.1.1.1.4.2  perseant 	    interpreter = "/lib64/ld.so.1";
   1603  1.1.1.1.4.2  perseant 	  else
   1604  1.1.1.1.4.2  perseant 	    interpreter = "/lib/ld.so.1";
   1605  1.1.1.1.4.2  perseant 
   1606  1.1.1.1.4.2  perseant 	  s->contents = (unsigned char *) interpreter;
   1607  1.1.1.1.4.2  perseant 	  s->size = strlen (interpreter) + 1;
   1608  1.1.1.1.4.2  perseant 	}
   1609  1.1.1.1.4.2  perseant     }
   1610  1.1.1.1.4.2  perseant 
   1611  1.1.1.1.4.2  perseant   /* Set up .got offsets for local syms, and space for local dynamic
   1612  1.1.1.1.4.2  perseant      relocs.  */
   1613  1.1.1.1.4.2  perseant   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
   1614  1.1.1.1.4.2  perseant     {
   1615  1.1.1.1.4.2  perseant       bfd_signed_vma *local_got;
   1616  1.1.1.1.4.2  perseant       bfd_signed_vma *end_local_got;
   1617  1.1.1.1.4.2  perseant       char *local_tls_type;
   1618  1.1.1.1.4.2  perseant       bfd_size_type locsymcount;
   1619  1.1.1.1.4.2  perseant       Elf_Internal_Shdr *symtab_hdr;
   1620  1.1.1.1.4.2  perseant       asection *srel;
   1621  1.1.1.1.4.2  perseant 
   1622  1.1.1.1.4.2  perseant       if (!is_loongarch_elf (ibfd))
   1623  1.1.1.1.4.2  perseant 	continue;
   1624  1.1.1.1.4.2  perseant 
   1625  1.1.1.1.4.2  perseant       for (s = ibfd->sections; s != NULL; s = s->next)
   1626  1.1.1.1.4.2  perseant 	{
   1627  1.1.1.1.4.2  perseant 	  struct elf_dyn_relocs *p;
   1628  1.1.1.1.4.2  perseant 
   1629  1.1.1.1.4.2  perseant 	  for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
   1630  1.1.1.1.4.2  perseant 	    {
   1631  1.1.1.1.4.2  perseant 	      p->count -= p->pc_count;
   1632  1.1.1.1.4.2  perseant 	      if (!bfd_is_abs_section (p->sec)
   1633  1.1.1.1.4.2  perseant 		  && bfd_is_abs_section (p->sec->output_section))
   1634  1.1.1.1.4.2  perseant 		{
   1635  1.1.1.1.4.2  perseant 		  /* Input section has been discarded, either because
   1636  1.1.1.1.4.2  perseant 		     it is a copy of a linkonce section or due to
   1637  1.1.1.1.4.2  perseant 		     linker script /DISCARD/, so we'll be discarding
   1638  1.1.1.1.4.2  perseant 		     the relocs too.  */
   1639  1.1.1.1.4.2  perseant 		}
   1640  1.1.1.1.4.2  perseant 	      else if (0 < p->count)
   1641  1.1.1.1.4.2  perseant 		{
   1642  1.1.1.1.4.2  perseant 		  srel = elf_section_data (p->sec)->sreloc;
   1643  1.1.1.1.4.2  perseant 		  srel->size += p->count * sizeof (ElfNN_External_Rela);
   1644  1.1.1.1.4.2  perseant 		  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
   1645  1.1.1.1.4.2  perseant 		    info->flags |= DF_TEXTREL;
   1646  1.1.1.1.4.2  perseant 		}
   1647  1.1.1.1.4.2  perseant 	    }
   1648  1.1.1.1.4.2  perseant 	}
   1649  1.1.1.1.4.2  perseant 
   1650  1.1.1.1.4.2  perseant       local_got = elf_local_got_refcounts (ibfd);
   1651  1.1.1.1.4.2  perseant       if (!local_got)
   1652  1.1.1.1.4.2  perseant 	continue;
   1653  1.1.1.1.4.2  perseant 
   1654  1.1.1.1.4.2  perseant       symtab_hdr = &elf_symtab_hdr (ibfd);
   1655  1.1.1.1.4.2  perseant       locsymcount = symtab_hdr->sh_info;
   1656  1.1.1.1.4.2  perseant       end_local_got = local_got + locsymcount;
   1657  1.1.1.1.4.2  perseant       local_tls_type = _bfd_loongarch_elf_local_got_tls_type (ibfd);
   1658  1.1.1.1.4.2  perseant       s = htab->elf.sgot;
   1659  1.1.1.1.4.2  perseant       srel = htab->elf.srelgot;
   1660  1.1.1.1.4.2  perseant       for (; local_got < end_local_got; ++local_got, ++local_tls_type)
   1661  1.1.1.1.4.2  perseant 	{
   1662  1.1.1.1.4.2  perseant 	  if (0 < *local_got)
   1663  1.1.1.1.4.2  perseant 	    {
   1664  1.1.1.1.4.2  perseant 	      *local_got = s->size;
   1665  1.1.1.1.4.2  perseant 
   1666  1.1.1.1.4.2  perseant 	      /* TLS gd use two got.  */
   1667  1.1.1.1.4.2  perseant 	      if (*local_tls_type & GOT_TLS_GD)
   1668  1.1.1.1.4.2  perseant 		s->size += GOT_ENTRY_SIZE * 2;
   1669  1.1.1.1.4.2  perseant 	      else
   1670  1.1.1.1.4.2  perseant 		/* Normal got, tls ie/ld use one got.  */
   1671  1.1.1.1.4.2  perseant 		s->size += GOT_ENTRY_SIZE;
   1672  1.1.1.1.4.2  perseant 
   1673  1.1.1.1.4.2  perseant 	      if (bfd_link_executable (info)
   1674  1.1.1.1.4.2  perseant 		  && (*local_tls_type & (GOT_TLS_GD| GOT_TLS_IE)))
   1675  1.1.1.1.4.2  perseant 		;/* Do nothing.  */
   1676  1.1.1.1.4.2  perseant 	      else
   1677  1.1.1.1.4.2  perseant 		{
   1678  1.1.1.1.4.2  perseant 		  srel->size += sizeof (ElfNN_External_Rela);
   1679  1.1.1.1.4.2  perseant 		}
   1680  1.1.1.1.4.2  perseant 	    }
   1681  1.1.1.1.4.2  perseant 	  else
   1682  1.1.1.1.4.2  perseant 	    *local_got = MINUS_ONE;
   1683  1.1.1.1.4.2  perseant 	}
   1684  1.1.1.1.4.2  perseant     }
   1685  1.1.1.1.4.2  perseant 
   1686  1.1.1.1.4.2  perseant   /* Allocate global sym .plt and .got entries, and space for global
   1687  1.1.1.1.4.2  perseant      sym dynamic relocs.  */
   1688  1.1.1.1.4.2  perseant   elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
   1689  1.1.1.1.4.2  perseant 
   1690  1.1.1.1.4.2  perseant   /* Allocate global ifunc sym .plt and .got entries, and space for global
   1691  1.1.1.1.4.2  perseant      ifunc sym dynamic relocs.  */
   1692  1.1.1.1.4.2  perseant   elf_link_hash_traverse (&htab->elf, elfNN_allocate_ifunc_dynrelocs, info);
   1693  1.1.1.1.4.2  perseant 
   1694  1.1.1.1.4.2  perseant   /* Allocate .plt and .got entries, and space for local ifunc symbols.  */
   1695  1.1.1.1.4.2  perseant   htab_traverse (htab->loc_hash_table,
   1696  1.1.1.1.4.2  perseant 		 (void *) elfNN_allocate_local_ifunc_dynrelocs, info);
   1697  1.1.1.1.4.2  perseant 
   1698  1.1.1.1.4.2  perseant   /* Don't allocate .got.plt section if there are no PLT.  */
   1699  1.1.1.1.4.2  perseant   if (htab->elf.sgotplt && htab->elf.sgotplt->size == GOTPLT_HEADER_SIZE
   1700  1.1.1.1.4.2  perseant       && (htab->elf.splt == NULL || htab->elf.splt->size == 0))
   1701  1.1.1.1.4.2  perseant     htab->elf.sgotplt->size = 0;
   1702  1.1.1.1.4.2  perseant 
   1703  1.1.1.1.4.2  perseant   /* The check_relocs and adjust_dynamic_symbol entry points have
   1704  1.1.1.1.4.2  perseant      determined the sizes of the various dynamic sections.  Allocate
   1705  1.1.1.1.4.2  perseant      memory for them.  */
   1706  1.1.1.1.4.2  perseant   for (s = dynobj->sections; s != NULL; s = s->next)
   1707  1.1.1.1.4.2  perseant     {
   1708  1.1.1.1.4.2  perseant       if ((s->flags & SEC_LINKER_CREATED) == 0)
   1709  1.1.1.1.4.2  perseant 	continue;
   1710  1.1.1.1.4.2  perseant 
   1711  1.1.1.1.4.2  perseant       if (s == htab->elf.splt || s == htab->elf.iplt || s == htab->elf.sgot
   1712  1.1.1.1.4.2  perseant 	  || s == htab->elf.sgotplt || s == htab->elf.igotplt
   1713  1.1.1.1.4.2  perseant 	  || s == htab->elf.sdynbss || s == htab->elf.sdynrelro)
   1714  1.1.1.1.4.2  perseant 	{
   1715  1.1.1.1.4.2  perseant 	  /* Strip this section if we don't need it; see the
   1716  1.1.1.1.4.2  perseant 	     comment below.  */
   1717  1.1.1.1.4.2  perseant 	}
   1718  1.1.1.1.4.2  perseant       else if (strncmp (s->name, ".rela", 5) == 0)
   1719  1.1.1.1.4.2  perseant 	{
   1720  1.1.1.1.4.2  perseant 	  if (s->size != 0)
   1721  1.1.1.1.4.2  perseant 	    {
   1722  1.1.1.1.4.2  perseant 	      /* We use the reloc_count field as a counter if we need
   1723  1.1.1.1.4.2  perseant 		 to copy relocs into the output file.  */
   1724  1.1.1.1.4.2  perseant 	      s->reloc_count = 0;
   1725  1.1.1.1.4.2  perseant 	    }
   1726  1.1.1.1.4.2  perseant 	}
   1727  1.1.1.1.4.2  perseant       else
   1728  1.1.1.1.4.2  perseant 	{
   1729  1.1.1.1.4.2  perseant 	  /* It's not one of our sections.  */
   1730  1.1.1.1.4.2  perseant 	  continue;
   1731  1.1.1.1.4.2  perseant 	}
   1732  1.1.1.1.4.2  perseant 
   1733  1.1.1.1.4.2  perseant       if (s->size == 0)
   1734  1.1.1.1.4.2  perseant 	{
   1735  1.1.1.1.4.2  perseant 	  /* If we don't need this section, strip it from the
   1736  1.1.1.1.4.2  perseant 	     output file.  This is mostly to handle .rela.bss and
   1737  1.1.1.1.4.2  perseant 	     .rela.plt.  We must create both sections in
   1738  1.1.1.1.4.2  perseant 	     create_dynamic_sections, because they must be created
   1739  1.1.1.1.4.2  perseant 	     before the linker maps input sections to output
   1740  1.1.1.1.4.2  perseant 	     sections.  The linker does that before
   1741  1.1.1.1.4.2  perseant 	     adjust_dynamic_symbol is called, and it is that
   1742  1.1.1.1.4.2  perseant 	     function which decides whether anything needs to go
   1743  1.1.1.1.4.2  perseant 	     into these sections.  */
   1744  1.1.1.1.4.2  perseant 	  s->flags |= SEC_EXCLUDE;
   1745  1.1.1.1.4.2  perseant 	  continue;
   1746  1.1.1.1.4.2  perseant 	}
   1747  1.1.1.1.4.2  perseant 
   1748  1.1.1.1.4.2  perseant       if ((s->flags & SEC_HAS_CONTENTS) == 0)
   1749  1.1.1.1.4.2  perseant 	continue;
   1750  1.1.1.1.4.2  perseant 
   1751  1.1.1.1.4.2  perseant       /* Allocate memory for the section contents.  Zero the memory
   1752  1.1.1.1.4.2  perseant 	 for the benefit of .rela.plt, which has 4 unused entries
   1753  1.1.1.1.4.2  perseant 	 at the beginning, and we don't want garbage.  */
   1754  1.1.1.1.4.2  perseant       s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
   1755  1.1.1.1.4.2  perseant       if (s->contents == NULL)
   1756  1.1.1.1.4.2  perseant 	return false;
   1757  1.1.1.1.4.2  perseant     }
   1758  1.1.1.1.4.2  perseant 
   1759  1.1.1.1.4.2  perseant   if (elf_hash_table (info)->dynamic_sections_created)
   1760  1.1.1.1.4.2  perseant     {
   1761  1.1.1.1.4.2  perseant       /* Add some entries to the .dynamic section.  We fill in the
   1762  1.1.1.1.4.2  perseant 	 values later, in loongarch_elf_finish_dynamic_sections, but we
   1763  1.1.1.1.4.2  perseant 	 must add the entries now so that we get the correct size for
   1764  1.1.1.1.4.2  perseant 	 the .dynamic section.  The DT_DEBUG entry is filled in by the
   1765  1.1.1.1.4.2  perseant 	 dynamic linker and used by the debugger.  */
   1766  1.1.1.1.4.2  perseant #define add_dynamic_entry(TAG, VAL) _bfd_elf_add_dynamic_entry (info, TAG, VAL)
   1767  1.1.1.1.4.2  perseant 
   1768  1.1.1.1.4.2  perseant       if (bfd_link_executable (info))
   1769  1.1.1.1.4.2  perseant 	{
   1770  1.1.1.1.4.2  perseant 	  if (!add_dynamic_entry (DT_DEBUG, 0))
   1771  1.1.1.1.4.2  perseant 	    return false;
   1772  1.1.1.1.4.2  perseant 	}
   1773  1.1.1.1.4.2  perseant 
   1774  1.1.1.1.4.2  perseant       if (htab->elf.srelplt->size != 0)
   1775  1.1.1.1.4.2  perseant 	{
   1776  1.1.1.1.4.2  perseant 	  if (!add_dynamic_entry (DT_PLTGOT, 0)
   1777  1.1.1.1.4.2  perseant 	      || !add_dynamic_entry (DT_PLTRELSZ, 0)
   1778  1.1.1.1.4.2  perseant 	      || !add_dynamic_entry (DT_PLTREL, DT_RELA)
   1779  1.1.1.1.4.2  perseant 	      || !add_dynamic_entry (DT_JMPREL, 0))
   1780  1.1.1.1.4.2  perseant 	    return false;
   1781  1.1.1.1.4.2  perseant 	}
   1782  1.1.1.1.4.2  perseant 
   1783  1.1.1.1.4.2  perseant       if (!add_dynamic_entry (DT_RELA, 0)
   1784  1.1.1.1.4.2  perseant 	  || !add_dynamic_entry (DT_RELASZ, 0)
   1785  1.1.1.1.4.2  perseant 	  || !add_dynamic_entry (DT_RELAENT, sizeof (ElfNN_External_Rela)))
   1786  1.1.1.1.4.2  perseant 	return false;
   1787  1.1.1.1.4.2  perseant 
   1788  1.1.1.1.4.2  perseant       /* If any dynamic relocs apply to a read-only section,
   1789  1.1.1.1.4.2  perseant 	 then we need a DT_TEXTREL entry.  */
   1790  1.1.1.1.4.2  perseant       if ((info->flags & DF_TEXTREL) == 0)
   1791  1.1.1.1.4.2  perseant 	elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info);
   1792  1.1.1.1.4.2  perseant 
   1793  1.1.1.1.4.2  perseant       if (info->flags & DF_TEXTREL)
   1794  1.1.1.1.4.2  perseant 	{
   1795  1.1.1.1.4.2  perseant 	  if (!add_dynamic_entry (DT_TEXTREL, 0))
   1796  1.1.1.1.4.2  perseant 	    return false;
   1797  1.1.1.1.4.2  perseant 	  /* Clear the DF_TEXTREL flag.  It will be set again if we
   1798  1.1.1.1.4.2  perseant 	     write out an actual text relocation; we may not, because
   1799  1.1.1.1.4.2  perseant 	     at this point we do not know whether e.g.  any .eh_frame
   1800  1.1.1.1.4.2  perseant 	     absolute relocations have been converted to PC-relative.  */
   1801  1.1.1.1.4.2  perseant 	  info->flags &= ~DF_TEXTREL;
   1802  1.1.1.1.4.2  perseant 	}
   1803  1.1.1.1.4.2  perseant     }
   1804  1.1.1.1.4.2  perseant #undef add_dynamic_entry
   1805  1.1.1.1.4.2  perseant 
   1806  1.1.1.1.4.2  perseant   return true;
   1807  1.1.1.1.4.2  perseant }
   1808  1.1.1.1.4.2  perseant 
   1809  1.1.1.1.4.2  perseant #define LARCH_LD_STACK_DEPTH 16
   1810  1.1.1.1.4.2  perseant static int64_t larch_opc_stack[LARCH_LD_STACK_DEPTH];
   1811  1.1.1.1.4.2  perseant static size_t larch_stack_top = 0;
   1812  1.1.1.1.4.2  perseant 
   1813  1.1.1.1.4.2  perseant static bfd_reloc_status_type
   1814  1.1.1.1.4.2  perseant loongarch_push (int64_t val)
   1815  1.1.1.1.4.2  perseant {
   1816  1.1.1.1.4.2  perseant   if (LARCH_LD_STACK_DEPTH <= larch_stack_top)
   1817  1.1.1.1.4.2  perseant     return bfd_reloc_outofrange;
   1818  1.1.1.1.4.2  perseant   larch_opc_stack[larch_stack_top++] = val;
   1819  1.1.1.1.4.2  perseant   return bfd_reloc_ok;
   1820  1.1.1.1.4.2  perseant }
   1821  1.1.1.1.4.2  perseant 
   1822  1.1.1.1.4.2  perseant static bfd_reloc_status_type
   1823  1.1.1.1.4.2  perseant loongarch_pop (int64_t *val)
   1824  1.1.1.1.4.2  perseant {
   1825  1.1.1.1.4.2  perseant   if (larch_stack_top == 0)
   1826  1.1.1.1.4.2  perseant     return bfd_reloc_outofrange;
   1827  1.1.1.1.4.2  perseant   BFD_ASSERT (val);
   1828  1.1.1.1.4.2  perseant   *val = larch_opc_stack[--larch_stack_top];
   1829  1.1.1.1.4.2  perseant   return bfd_reloc_ok;
   1830  1.1.1.1.4.2  perseant }
   1831  1.1.1.1.4.2  perseant 
   1832  1.1.1.1.4.2  perseant static bfd_reloc_status_type
   1833  1.1.1.1.4.2  perseant loongarch_top (int64_t *val)
   1834  1.1.1.1.4.2  perseant {
   1835  1.1.1.1.4.2  perseant   if (larch_stack_top == 0)
   1836  1.1.1.1.4.2  perseant     return bfd_reloc_outofrange;
   1837  1.1.1.1.4.2  perseant   BFD_ASSERT (val);
   1838  1.1.1.1.4.2  perseant   *val = larch_opc_stack[larch_stack_top - 1];
   1839  1.1.1.1.4.2  perseant   return bfd_reloc_ok;
   1840  1.1.1.1.4.2  perseant }
   1841  1.1.1.1.4.2  perseant 
   1842  1.1.1.1.4.2  perseant static void
   1843  1.1.1.1.4.2  perseant loongarch_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
   1844  1.1.1.1.4.2  perseant {
   1845  1.1.1.1.4.2  perseant   BFD_ASSERT (s && s->contents);
   1846  1.1.1.1.4.2  perseant   const struct elf_backend_data *bed;
   1847  1.1.1.1.4.2  perseant   bfd_byte *loc;
   1848  1.1.1.1.4.2  perseant 
   1849  1.1.1.1.4.2  perseant   bed = get_elf_backend_data (abfd);
   1850  1.1.1.1.4.2  perseant   if (!(s->size > s->reloc_count * bed->s->sizeof_rela))
   1851  1.1.1.1.4.2  perseant     BFD_ASSERT (s->size > s->reloc_count * bed->s->sizeof_rela);
   1852  1.1.1.1.4.2  perseant   loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela);
   1853  1.1.1.1.4.2  perseant   bed->s->swap_reloca_out (abfd, rel, loc);
   1854  1.1.1.1.4.2  perseant }
   1855  1.1.1.1.4.2  perseant 
   1856  1.1.1.1.4.2  perseant /* Check rel->r_offset in range of contents.  */
   1857  1.1.1.1.4.2  perseant static bfd_reloc_status_type
   1858  1.1.1.1.4.2  perseant loongarch_check_offset (const Elf_Internal_Rela *rel,
   1859  1.1.1.1.4.2  perseant 			const asection *input_section)
   1860  1.1.1.1.4.2  perseant {
   1861  1.1.1.1.4.2  perseant   if (0 == strcmp(input_section->name, ".text")
   1862  1.1.1.1.4.2  perseant       && rel->r_offset > input_section->size)
   1863  1.1.1.1.4.2  perseant     return bfd_reloc_overflow;
   1864  1.1.1.1.4.2  perseant 
   1865  1.1.1.1.4.2  perseant   return bfd_reloc_ok;
   1866  1.1.1.1.4.2  perseant }
   1867  1.1.1.1.4.2  perseant 
   1868  1.1.1.1.4.2  perseant #define LARCH_RELOC_PERFORM_3OP(op1, op2, op3)	      \
   1869  1.1.1.1.4.2  perseant   ({						      \
   1870  1.1.1.1.4.2  perseant     bfd_reloc_status_type ret = loongarch_pop (&op2); \
   1871  1.1.1.1.4.2  perseant     if (ret == bfd_reloc_ok)			      \
   1872  1.1.1.1.4.2  perseant       {						      \
   1873  1.1.1.1.4.2  perseant 	ret = loongarch_pop (&op1);		      \
   1874  1.1.1.1.4.2  perseant 	if (ret == bfd_reloc_ok)		      \
   1875  1.1.1.1.4.2  perseant 	  ret = loongarch_push (op3);		      \
   1876  1.1.1.1.4.2  perseant       }						      \
   1877  1.1.1.1.4.2  perseant     ret;					      \
   1878  1.1.1.1.4.2  perseant    })
   1879  1.1.1.1.4.2  perseant 
   1880  1.1.1.1.4.2  perseant static bfd_reloc_status_type
   1881  1.1.1.1.4.2  perseant loongarch_reloc_rewrite_imm_insn (const Elf_Internal_Rela *rel,
   1882  1.1.1.1.4.2  perseant 				  const asection *input_section ATTRIBUTE_UNUSED,
   1883  1.1.1.1.4.2  perseant 				  reloc_howto_type *howto, bfd *input_bfd,
   1884  1.1.1.1.4.2  perseant 				  bfd_byte *contents, bfd_vma reloc_val)
   1885  1.1.1.1.4.2  perseant {
   1886  1.1.1.1.4.2  perseant   int bits = bfd_get_reloc_size (howto) * 8;
   1887  1.1.1.1.4.2  perseant   uint32_t insn = bfd_get (bits, input_bfd, contents + rel->r_offset);
   1888  1.1.1.1.4.2  perseant 
   1889  1.1.1.1.4.2  perseant   if (!loongarch_adjust_reloc_bitsfield(howto, &reloc_val))
   1890  1.1.1.1.4.2  perseant     return bfd_reloc_overflow;
   1891  1.1.1.1.4.2  perseant 
   1892  1.1.1.1.4.2  perseant   insn = (insn & (uint32_t)howto->src_mask)
   1893  1.1.1.1.4.2  perseant     | ((insn & (~(uint32_t)howto->dst_mask)) | reloc_val);
   1894  1.1.1.1.4.2  perseant 
   1895  1.1.1.1.4.2  perseant   bfd_put (bits, input_bfd, insn, contents + rel->r_offset);
   1896  1.1.1.1.4.2  perseant 
   1897  1.1.1.1.4.2  perseant   return bfd_reloc_ok;
   1898  1.1.1.1.4.2  perseant }
   1899  1.1.1.1.4.2  perseant 
   1900  1.1.1.1.4.2  perseant static bfd_reloc_status_type
   1901  1.1.1.1.4.2  perseant perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
   1902  1.1.1.1.4.2  perseant 		    reloc_howto_type *howto, bfd_vma value,
   1903  1.1.1.1.4.2  perseant 		    bfd *input_bfd, bfd_byte *contents)
   1904  1.1.1.1.4.2  perseant {
   1905  1.1.1.1.4.2  perseant   int64_t opr1, opr2, opr3;
   1906  1.1.1.1.4.2  perseant   bfd_reloc_status_type r = bfd_reloc_ok;
   1907  1.1.1.1.4.2  perseant   int bits = bfd_get_reloc_size (howto) * 8;
   1908  1.1.1.1.4.2  perseant 
   1909  1.1.1.1.4.2  perseant   switch (ELFNN_R_TYPE (rel->r_info))
   1910  1.1.1.1.4.2  perseant     {
   1911  1.1.1.1.4.2  perseant     case R_LARCH_SOP_PUSH_PCREL:
   1912  1.1.1.1.4.2  perseant     case R_LARCH_SOP_PUSH_ABSOLUTE:
   1913  1.1.1.1.4.2  perseant     case R_LARCH_SOP_PUSH_GPREL:
   1914  1.1.1.1.4.2  perseant     case R_LARCH_SOP_PUSH_TLS_TPREL:
   1915  1.1.1.1.4.2  perseant     case R_LARCH_SOP_PUSH_TLS_GOT:
   1916  1.1.1.1.4.2  perseant     case R_LARCH_SOP_PUSH_TLS_GD:
   1917  1.1.1.1.4.2  perseant     case R_LARCH_SOP_PUSH_PLT_PCREL:
   1918  1.1.1.1.4.2  perseant       r = loongarch_push (value);
   1919  1.1.1.1.4.2  perseant       break;
   1920  1.1.1.1.4.2  perseant 
   1921  1.1.1.1.4.2  perseant     case R_LARCH_SOP_PUSH_DUP:
   1922  1.1.1.1.4.2  perseant       r = loongarch_pop (&opr1);
   1923  1.1.1.1.4.2  perseant       if (r == bfd_reloc_ok)
   1924  1.1.1.1.4.2  perseant 	{
   1925  1.1.1.1.4.2  perseant 	  r = loongarch_push (opr1);
   1926  1.1.1.1.4.2  perseant 	  if (r == bfd_reloc_ok)
   1927  1.1.1.1.4.2  perseant 	    r = loongarch_push (opr1);
   1928  1.1.1.1.4.2  perseant 	}
   1929  1.1.1.1.4.2  perseant       break;
   1930  1.1.1.1.4.2  perseant 
   1931  1.1.1.1.4.2  perseant     case R_LARCH_SOP_ASSERT:
   1932  1.1.1.1.4.2  perseant       r = loongarch_pop (&opr1);
   1933  1.1.1.1.4.2  perseant       if (r != bfd_reloc_ok || !opr1)
   1934  1.1.1.1.4.2  perseant 	r = bfd_reloc_notsupported;
   1935  1.1.1.1.4.2  perseant       break;
   1936  1.1.1.1.4.2  perseant 
   1937  1.1.1.1.4.2  perseant     case R_LARCH_SOP_NOT:
   1938  1.1.1.1.4.2  perseant       r = loongarch_pop (&opr1);
   1939  1.1.1.1.4.2  perseant       if (r == bfd_reloc_ok)
   1940  1.1.1.1.4.2  perseant 	r = loongarch_push (!opr1);
   1941  1.1.1.1.4.2  perseant       break;
   1942  1.1.1.1.4.2  perseant 
   1943  1.1.1.1.4.2  perseant     case R_LARCH_SOP_SUB:
   1944  1.1.1.1.4.2  perseant       r = LARCH_RELOC_PERFORM_3OP (opr1, opr2, opr1 - opr2);
   1945  1.1.1.1.4.2  perseant       break;
   1946  1.1.1.1.4.2  perseant 
   1947  1.1.1.1.4.2  perseant     case R_LARCH_SOP_SL:
   1948  1.1.1.1.4.2  perseant       r = LARCH_RELOC_PERFORM_3OP (opr1, opr2, opr1 << opr2);
   1949  1.1.1.1.4.2  perseant       break;
   1950  1.1.1.1.4.2  perseant 
   1951  1.1.1.1.4.2  perseant     case R_LARCH_SOP_SR:
   1952  1.1.1.1.4.2  perseant       r = LARCH_RELOC_PERFORM_3OP (opr1, opr2, opr1 >> opr2);
   1953  1.1.1.1.4.2  perseant       break;
   1954  1.1.1.1.4.2  perseant 
   1955  1.1.1.1.4.2  perseant     case R_LARCH_SOP_AND:
   1956  1.1.1.1.4.2  perseant       r = LARCH_RELOC_PERFORM_3OP (opr1, opr2, opr1 & opr2);
   1957  1.1.1.1.4.2  perseant       break;
   1958  1.1.1.1.4.2  perseant 
   1959  1.1.1.1.4.2  perseant     case R_LARCH_SOP_ADD:
   1960  1.1.1.1.4.2  perseant       r = LARCH_RELOC_PERFORM_3OP (opr1, opr2, opr1 + opr2);
   1961  1.1.1.1.4.2  perseant       break;
   1962  1.1.1.1.4.2  perseant 
   1963  1.1.1.1.4.2  perseant     case R_LARCH_SOP_IF_ELSE:
   1964  1.1.1.1.4.2  perseant       r = loongarch_pop (&opr3);
   1965  1.1.1.1.4.2  perseant       if (r == bfd_reloc_ok)
   1966  1.1.1.1.4.2  perseant 	{
   1967  1.1.1.1.4.2  perseant 	  r = loongarch_pop (&opr2);
   1968  1.1.1.1.4.2  perseant 	  if (r == bfd_reloc_ok)
   1969  1.1.1.1.4.2  perseant 	    {
   1970  1.1.1.1.4.2  perseant 	      r = loongarch_pop (&opr1);
   1971  1.1.1.1.4.2  perseant 	      if (r == bfd_reloc_ok)
   1972  1.1.1.1.4.2  perseant 		r = loongarch_push (opr1 ? opr2 : opr3);
   1973  1.1.1.1.4.2  perseant 	    }
   1974  1.1.1.1.4.2  perseant 	}
   1975  1.1.1.1.4.2  perseant       break;
   1976  1.1.1.1.4.2  perseant 
   1977  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_S_10_5:
   1978  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_S_10_12:
   1979  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_S_10_16:
   1980  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_S_10_16_S2:
   1981  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:
   1982  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:
   1983  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_S_5_20:
   1984  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_U_10_12:
   1985  1.1.1.1.4.2  perseant     case R_LARCH_SOP_POP_32_U:
   1986  1.1.1.1.4.2  perseant       r = loongarch_pop (&opr1);
   1987  1.1.1.1.4.2  perseant       if (r != bfd_reloc_ok)
   1988  1.1.1.1.4.2  perseant 	break;
   1989  1.1.1.1.4.2  perseant       r = loongarch_check_offset (rel, input_section);
   1990  1.1.1.1.4.2  perseant       if (r != bfd_reloc_ok)
   1991  1.1.1.1.4.2  perseant 	break;
   1992  1.1.1.1.4.2  perseant 
   1993  1.1.1.1.4.2  perseant       r = loongarch_reloc_rewrite_imm_insn (rel, input_section,
   1994  1.1.1.1.4.2  perseant 					    howto, input_bfd,
   1995  1.1.1.1.4.2  perseant 					    contents, (bfd_vma)opr1);
   1996  1.1.1.1.4.2  perseant       break;
   1997  1.1.1.1.4.2  perseant 
   1998  1.1.1.1.4.2  perseant     case R_LARCH_TLS_DTPREL32:
   1999  1.1.1.1.4.2  perseant     case R_LARCH_32:
   2000  1.1.1.1.4.2  perseant     case R_LARCH_TLS_DTPREL64:
   2001  1.1.1.1.4.2  perseant     case R_LARCH_64:
   2002  1.1.1.1.4.2  perseant       r = loongarch_check_offset (rel, input_section);
   2003  1.1.1.1.4.2  perseant       if (r != bfd_reloc_ok)
   2004  1.1.1.1.4.2  perseant 	break;
   2005  1.1.1.1.4.2  perseant 
   2006  1.1.1.1.4.2  perseant       bfd_put (bits, input_bfd, value, contents + rel->r_offset);
   2007  1.1.1.1.4.2  perseant       break;
   2008  1.1.1.1.4.2  perseant 
   2009  1.1.1.1.4.2  perseant     case R_LARCH_ADD8:
   2010  1.1.1.1.4.2  perseant     case R_LARCH_ADD16:
   2011  1.1.1.1.4.2  perseant     case R_LARCH_ADD24:
   2012  1.1.1.1.4.2  perseant     case R_LARCH_ADD32:
   2013  1.1.1.1.4.2  perseant     case R_LARCH_ADD64:
   2014  1.1.1.1.4.2  perseant       r = loongarch_check_offset (rel, input_section);
   2015  1.1.1.1.4.2  perseant       if (r != bfd_reloc_ok)
   2016  1.1.1.1.4.2  perseant 	break;
   2017  1.1.1.1.4.2  perseant 
   2018  1.1.1.1.4.2  perseant       opr1 = bfd_get (bits, input_bfd, contents + rel->r_offset);
   2019  1.1.1.1.4.2  perseant       bfd_put (bits, input_bfd, opr1 + value, contents + rel->r_offset);
   2020  1.1.1.1.4.2  perseant       break;
   2021  1.1.1.1.4.2  perseant 
   2022  1.1.1.1.4.2  perseant     case R_LARCH_SUB8:
   2023  1.1.1.1.4.2  perseant     case R_LARCH_SUB16:
   2024  1.1.1.1.4.2  perseant     case R_LARCH_SUB24:
   2025  1.1.1.1.4.2  perseant     case R_LARCH_SUB32:
   2026  1.1.1.1.4.2  perseant     case R_LARCH_SUB64:
   2027  1.1.1.1.4.2  perseant       r = loongarch_check_offset (rel, input_section);
   2028  1.1.1.1.4.2  perseant       if (r != bfd_reloc_ok)
   2029  1.1.1.1.4.2  perseant 	break;
   2030  1.1.1.1.4.2  perseant 
   2031  1.1.1.1.4.2  perseant       opr1 = bfd_get (bits, input_bfd, contents + rel->r_offset);
   2032  1.1.1.1.4.2  perseant       bfd_put (bits, input_bfd, opr1 - value, contents + rel->r_offset);
   2033  1.1.1.1.4.2  perseant       break;
   2034  1.1.1.1.4.2  perseant 
   2035  1.1.1.1.4.2  perseant     /* For eh_frame and debug info.  */
   2036  1.1.1.1.4.2  perseant     case R_LARCH_32_PCREL:
   2037  1.1.1.1.4.2  perseant       value -= sec_addr (input_section) + rel->r_offset;
   2038  1.1.1.1.4.2  perseant       value += rel->r_addend;
   2039  1.1.1.1.4.2  perseant       bfd_vma word = bfd_get (howto->bitsize, input_bfd,
   2040  1.1.1.1.4.2  perseant 			      contents + rel->r_offset);
   2041  1.1.1.1.4.2  perseant       word = (word & ~howto->dst_mask) | (value & howto->dst_mask);
   2042  1.1.1.1.4.2  perseant       bfd_put (howto->bitsize, input_bfd, word, contents + rel->r_offset);
   2043  1.1.1.1.4.2  perseant       r = bfd_reloc_ok;
   2044  1.1.1.1.4.2  perseant       break;
   2045  1.1.1.1.4.2  perseant 
   2046  1.1.1.1.4.2  perseant     /* New reloc type.
   2047  1.1.1.1.4.2  perseant        R_LARCH_B16 ~ R_LARCH_TLS_GD_HI20.  */
   2048  1.1.1.1.4.2  perseant     case R_LARCH_B16:
   2049  1.1.1.1.4.2  perseant     case R_LARCH_B21:
   2050  1.1.1.1.4.2  perseant     case R_LARCH_B26:
   2051  1.1.1.1.4.2  perseant     case R_LARCH_ABS_HI20:
   2052  1.1.1.1.4.2  perseant     case R_LARCH_ABS_LO12:
   2053  1.1.1.1.4.2  perseant     case R_LARCH_ABS64_LO20:
   2054  1.1.1.1.4.2  perseant     case R_LARCH_ABS64_HI12:
   2055  1.1.1.1.4.2  perseant     case R_LARCH_PCALA_HI20:
   2056  1.1.1.1.4.2  perseant     case R_LARCH_PCALA_LO12:
   2057  1.1.1.1.4.2  perseant     case R_LARCH_PCALA64_LO20:
   2058  1.1.1.1.4.2  perseant     case R_LARCH_PCALA64_HI12:
   2059  1.1.1.1.4.2  perseant     case R_LARCH_GOT_PC_HI20:
   2060  1.1.1.1.4.2  perseant     case R_LARCH_GOT_PC_LO12:
   2061  1.1.1.1.4.2  perseant     case R_LARCH_GOT64_PC_LO20:
   2062  1.1.1.1.4.2  perseant     case R_LARCH_GOT64_PC_HI12:
   2063  1.1.1.1.4.2  perseant     case R_LARCH_GOT_HI20:
   2064  1.1.1.1.4.2  perseant     case R_LARCH_GOT_LO12:
   2065  1.1.1.1.4.2  perseant     case R_LARCH_GOT64_LO20:
   2066  1.1.1.1.4.2  perseant     case R_LARCH_GOT64_HI12:
   2067  1.1.1.1.4.2  perseant     case R_LARCH_TLS_LE_HI20:
   2068  1.1.1.1.4.2  perseant     case R_LARCH_TLS_LE_LO12:
   2069  1.1.1.1.4.2  perseant     case R_LARCH_TLS_LE64_LO20:
   2070  1.1.1.1.4.2  perseant     case R_LARCH_TLS_LE64_HI12:
   2071  1.1.1.1.4.2  perseant     case R_LARCH_TLS_IE_PC_HI20:
   2072  1.1.1.1.4.2  perseant     case R_LARCH_TLS_IE_PC_LO12:
   2073  1.1.1.1.4.2  perseant     case R_LARCH_TLS_IE64_PC_LO20:
   2074  1.1.1.1.4.2  perseant     case R_LARCH_TLS_IE64_PC_HI12:
   2075  1.1.1.1.4.2  perseant     case R_LARCH_TLS_IE_HI20:
   2076  1.1.1.1.4.2  perseant     case R_LARCH_TLS_IE_LO12:
   2077  1.1.1.1.4.2  perseant     case R_LARCH_TLS_IE64_LO20:
   2078  1.1.1.1.4.2  perseant     case R_LARCH_TLS_IE64_HI12:
   2079  1.1.1.1.4.2  perseant     case R_LARCH_TLS_LD_PC_HI20:
   2080  1.1.1.1.4.2  perseant     case R_LARCH_TLS_LD_HI20:
   2081  1.1.1.1.4.2  perseant     case R_LARCH_TLS_GD_PC_HI20:
   2082  1.1.1.1.4.2  perseant     case R_LARCH_TLS_GD_HI20:
   2083  1.1.1.1.4.2  perseant       r = loongarch_check_offset (rel, input_section);
   2084  1.1.1.1.4.2  perseant       if (r != bfd_reloc_ok)
   2085  1.1.1.1.4.2  perseant 	break;
   2086  1.1.1.1.4.2  perseant 
   2087  1.1.1.1.4.2  perseant       r = loongarch_reloc_rewrite_imm_insn (rel, input_section,
   2088  1.1.1.1.4.2  perseant 					    howto, input_bfd,
   2089  1.1.1.1.4.2  perseant 					    contents, value);
   2090  1.1.1.1.4.2  perseant       break;
   2091  1.1.1.1.4.2  perseant 
   2092  1.1.1.1.4.2  perseant     case R_LARCH_RELAX:
   2093  1.1.1.1.4.2  perseant       break;
   2094  1.1.1.1.4.2  perseant 
   2095  1.1.1.1.4.2  perseant     default:
   2096  1.1.1.1.4.2  perseant       r = bfd_reloc_notsupported;
   2097  1.1.1.1.4.2  perseant     }
   2098  1.1.1.1.4.2  perseant   return r;
   2099  1.1.1.1.4.2  perseant }
   2100  1.1.1.1.4.2  perseant 
   2101  1.1.1.1.4.2  perseant #define LARCH_RECENT_RELOC_QUEUE_LENGTH 72
   2102  1.1.1.1.4.2  perseant static struct
   2103  1.1.1.1.4.2  perseant {
   2104  1.1.1.1.4.2  perseant   bfd *bfd;
   2105  1.1.1.1.4.2  perseant   asection *section;
   2106  1.1.1.1.4.2  perseant   bfd_vma r_offset;
   2107  1.1.1.1.4.2  perseant   int r_type;
   2108  1.1.1.1.4.2  perseant   bfd_vma relocation;
   2109  1.1.1.1.4.2  perseant   Elf_Internal_Sym *sym;
   2110  1.1.1.1.4.2  perseant   struct elf_link_hash_entry *h;
   2111  1.1.1.1.4.2  perseant   bfd_vma addend;
   2112  1.1.1.1.4.2  perseant   int64_t top_then;
   2113  1.1.1.1.4.2  perseant } larch_reloc_queue[LARCH_RECENT_RELOC_QUEUE_LENGTH];
   2114  1.1.1.1.4.2  perseant static size_t larch_reloc_queue_head = 0;
   2115  1.1.1.1.4.2  perseant static size_t larch_reloc_queue_tail = 0;
   2116  1.1.1.1.4.2  perseant 
   2117  1.1.1.1.4.2  perseant static const char *
   2118  1.1.1.1.4.2  perseant loongarch_sym_name (bfd *input_bfd, struct elf_link_hash_entry *h,
   2119  1.1.1.1.4.2  perseant 		    Elf_Internal_Sym *sym)
   2120  1.1.1.1.4.2  perseant {
   2121  1.1.1.1.4.2  perseant   const char *ret = NULL;
   2122  1.1.1.1.4.2  perseant   if (sym)
   2123  1.1.1.1.4.2  perseant     ret = bfd_elf_string_from_elf_section (input_bfd,
   2124  1.1.1.1.4.2  perseant 					   elf_symtab_hdr (input_bfd).sh_link,
   2125  1.1.1.1.4.2  perseant 					   sym->st_name);
   2126  1.1.1.1.4.2  perseant   else if (h)
   2127  1.1.1.1.4.2  perseant     ret = h->root.root.string;
   2128  1.1.1.1.4.2  perseant 
   2129  1.1.1.1.4.2  perseant   if (ret == NULL || *ret == '\0')
   2130  1.1.1.1.4.2  perseant     ret = "<nameless>";
   2131  1.1.1.1.4.2  perseant   return ret;
   2132  1.1.1.1.4.2  perseant }
   2133  1.1.1.1.4.2  perseant 
   2134  1.1.1.1.4.2  perseant static void
   2135  1.1.1.1.4.2  perseant loongarch_record_one_reloc (bfd *abfd, asection *section, int r_type,
   2136  1.1.1.1.4.2  perseant 			    bfd_vma r_offset, Elf_Internal_Sym *sym,
   2137  1.1.1.1.4.2  perseant 			    struct elf_link_hash_entry *h, bfd_vma addend)
   2138  1.1.1.1.4.2  perseant {
   2139  1.1.1.1.4.2  perseant   if ((larch_reloc_queue_head == 0
   2140  1.1.1.1.4.2  perseant        && larch_reloc_queue_tail == LARCH_RECENT_RELOC_QUEUE_LENGTH - 1)
   2141  1.1.1.1.4.2  perseant       || larch_reloc_queue_head == larch_reloc_queue_tail + 1)
   2142  1.1.1.1.4.2  perseant     larch_reloc_queue_head =
   2143  1.1.1.1.4.2  perseant       (larch_reloc_queue_head + 1) % LARCH_RECENT_RELOC_QUEUE_LENGTH;
   2144  1.1.1.1.4.2  perseant   larch_reloc_queue[larch_reloc_queue_tail].bfd = abfd;
   2145  1.1.1.1.4.2  perseant   larch_reloc_queue[larch_reloc_queue_tail].section = section;
   2146  1.1.1.1.4.2  perseant   larch_reloc_queue[larch_reloc_queue_tail].r_offset = r_offset;
   2147  1.1.1.1.4.2  perseant   larch_reloc_queue[larch_reloc_queue_tail].r_type = r_type;
   2148  1.1.1.1.4.2  perseant   larch_reloc_queue[larch_reloc_queue_tail].sym = sym;
   2149  1.1.1.1.4.2  perseant   larch_reloc_queue[larch_reloc_queue_tail].h = h;
   2150  1.1.1.1.4.2  perseant   larch_reloc_queue[larch_reloc_queue_tail].addend = addend;
   2151  1.1.1.1.4.2  perseant   loongarch_top (&larch_reloc_queue[larch_reloc_queue_tail].top_then);
   2152  1.1.1.1.4.2  perseant   larch_reloc_queue_tail =
   2153  1.1.1.1.4.2  perseant     (larch_reloc_queue_tail + 1) % LARCH_RECENT_RELOC_QUEUE_LENGTH;
   2154  1.1.1.1.4.2  perseant }
   2155  1.1.1.1.4.2  perseant 
   2156  1.1.1.1.4.2  perseant static void
   2157  1.1.1.1.4.2  perseant loongarch_dump_reloc_record (void (*p) (const char *fmt, ...))
   2158  1.1.1.1.4.2  perseant {
   2159  1.1.1.1.4.2  perseant   size_t i = larch_reloc_queue_head;
   2160  1.1.1.1.4.2  perseant   bfd *a_bfd = NULL;
   2161  1.1.1.1.4.2  perseant   asection *section = NULL;
   2162  1.1.1.1.4.2  perseant   bfd_vma r_offset = 0;
   2163  1.1.1.1.4.2  perseant   int inited = 0;
   2164  1.1.1.1.4.2  perseant   p ("Dump relocate record:\n");
   2165  1.1.1.1.4.2  perseant   p ("stack top\t\trelocation name\t\tsymbol");
   2166  1.1.1.1.4.2  perseant   while (i != larch_reloc_queue_tail)
   2167  1.1.1.1.4.2  perseant     {
   2168  1.1.1.1.4.2  perseant       if (a_bfd != larch_reloc_queue[i].bfd
   2169  1.1.1.1.4.2  perseant 	  || section != larch_reloc_queue[i].section
   2170  1.1.1.1.4.2  perseant 	  || r_offset != larch_reloc_queue[i].r_offset)
   2171  1.1.1.1.4.2  perseant 	{
   2172  1.1.1.1.4.2  perseant 	  a_bfd = larch_reloc_queue[i].bfd;
   2173  1.1.1.1.4.2  perseant 	  section = larch_reloc_queue[i].section;
   2174  1.1.1.1.4.2  perseant 	  r_offset = larch_reloc_queue[i].r_offset;
   2175  1.1.1.1.4.2  perseant 	  p ("\nat %pB(%pA+0x%v):\n", larch_reloc_queue[i].bfd,
   2176  1.1.1.1.4.2  perseant 	     larch_reloc_queue[i].section, larch_reloc_queue[i].r_offset);
   2177  1.1.1.1.4.2  perseant 	}
   2178  1.1.1.1.4.2  perseant 
   2179  1.1.1.1.4.2  perseant       if (!inited)
   2180  1.1.1.1.4.2  perseant 	inited = 1, p ("...\n");
   2181  1.1.1.1.4.2  perseant 
   2182  1.1.1.1.4.2  perseant       reloc_howto_type *howto =
   2183  1.1.1.1.4.2  perseant 	loongarch_elf_rtype_to_howto (larch_reloc_queue[i].bfd,
   2184  1.1.1.1.4.2  perseant 				      larch_reloc_queue[i].r_type);
   2185  1.1.1.1.4.2  perseant       p ("0x%V %s\t`%s'", (bfd_vma) larch_reloc_queue[i].top_then,
   2186  1.1.1.1.4.2  perseant 	 howto ? howto->name : "<unknown reloc>",
   2187  1.1.1.1.4.2  perseant 	 loongarch_sym_name (larch_reloc_queue[i].bfd, larch_reloc_queue[i].h,
   2188  1.1.1.1.4.2  perseant 			     larch_reloc_queue[i].sym));
   2189  1.1.1.1.4.2  perseant 
   2190  1.1.1.1.4.2  perseant       long addend = larch_reloc_queue[i].addend;
   2191  1.1.1.1.4.2  perseant       if (addend < 0)
   2192  1.1.1.1.4.2  perseant 	p (" - %ld", -addend);
   2193  1.1.1.1.4.2  perseant       else if (0 < addend)
   2194  1.1.1.1.4.2  perseant 	p (" + %ld(0x%v)", addend, larch_reloc_queue[i].addend);
   2195  1.1.1.1.4.2  perseant 
   2196  1.1.1.1.4.2  perseant       p ("\n");
   2197  1.1.1.1.4.2  perseant       i = (i + 1) % LARCH_RECENT_RELOC_QUEUE_LENGTH;
   2198  1.1.1.1.4.2  perseant     }
   2199  1.1.1.1.4.2  perseant   p ("\n"
   2200  1.1.1.1.4.2  perseant      "-- Record dump end --\n\n");
   2201  1.1.1.1.4.2  perseant }
   2202  1.1.1.1.4.2  perseant 
   2203  1.1.1.1.4.2  perseant static bool
   2204  1.1.1.1.4.2  perseant loongarch_reloc_is_fatal (struct bfd_link_info *info,
   2205  1.1.1.1.4.2  perseant 			  bfd *input_bfd,
   2206  1.1.1.1.4.2  perseant 			  asection *input_section,
   2207  1.1.1.1.4.2  perseant 			  Elf_Internal_Rela *rel,
   2208  1.1.1.1.4.2  perseant 			  reloc_howto_type *howto,
   2209  1.1.1.1.4.2  perseant 			  bfd_reloc_status_type rtype,
   2210  1.1.1.1.4.2  perseant 			  bool is_undefweak,
   2211  1.1.1.1.4.2  perseant 			  const char *name,
   2212  1.1.1.1.4.2  perseant 			  const char *msg)
   2213  1.1.1.1.4.2  perseant {
   2214  1.1.1.1.4.2  perseant   bool fatal = true;
   2215  1.1.1.1.4.2  perseant   switch (rtype)
   2216  1.1.1.1.4.2  perseant     {
   2217  1.1.1.1.4.2  perseant       /* 'dangerous' means we do it but can't promise it's ok
   2218  1.1.1.1.4.2  perseant 	 'unsupport' means out of ability of relocation type
   2219  1.1.1.1.4.2  perseant 	 'undefined' means we can't deal with the undefined symbol.  */
   2220  1.1.1.1.4.2  perseant     case bfd_reloc_undefined:
   2221  1.1.1.1.4.2  perseant       info->callbacks->undefined_symbol (info, name, input_bfd, input_section,
   2222  1.1.1.1.4.2  perseant 					 rel->r_offset, true);
   2223  1.1.1.1.4.2  perseant       info->callbacks->info ("%X%pB(%pA+0x%v): error: %s against %s`%s':\n%s\n",
   2224  1.1.1.1.4.2  perseant 			     input_bfd, input_section, rel->r_offset,
   2225  1.1.1.1.4.2  perseant 			     howto->name,
   2226  1.1.1.1.4.2  perseant 			     is_undefweak ? "[undefweak] " : "", name, msg);
   2227  1.1.1.1.4.2  perseant       break;
   2228  1.1.1.1.4.2  perseant     case bfd_reloc_dangerous:
   2229  1.1.1.1.4.2  perseant       info->callbacks->info ("%pB(%pA+0x%v): warning: %s against %s`%s':\n%s\n",
   2230  1.1.1.1.4.2  perseant 			     input_bfd, input_section, rel->r_offset,
   2231  1.1.1.1.4.2  perseant 			     howto->name,
   2232  1.1.1.1.4.2  perseant 			     is_undefweak ? "[undefweak] " : "", name, msg);
   2233  1.1.1.1.4.2  perseant       fatal = false;
   2234  1.1.1.1.4.2  perseant       break;
   2235  1.1.1.1.4.2  perseant     case bfd_reloc_notsupported:
   2236  1.1.1.1.4.2  perseant       info->callbacks->info ("%X%pB(%pA+0x%v): error: %s against %s`%s':\n%s\n",
   2237  1.1.1.1.4.2  perseant 			     input_bfd, input_section, rel->r_offset,
   2238  1.1.1.1.4.2  perseant 			     howto->name,
   2239  1.1.1.1.4.2  perseant 			     is_undefweak ? "[undefweak] " : "", name, msg);
   2240  1.1.1.1.4.2  perseant       break;
   2241  1.1.1.1.4.2  perseant     default:
   2242  1.1.1.1.4.2  perseant       break;
   2243  1.1.1.1.4.2  perseant     }
   2244  1.1.1.1.4.2  perseant   return fatal;
   2245  1.1.1.1.4.2  perseant }
   2246  1.1.1.1.4.2  perseant 
   2247  1.1.1.1.4.2  perseant #define RELOCATE_CALC_PC32_HI20(relocation, pc) 	\
   2248  1.1.1.1.4.2  perseant   ({							\
   2249  1.1.1.1.4.2  perseant     bfd_vma lo = (relocation) & ((bfd_vma)0xfff);	\
   2250  1.1.1.1.4.2  perseant     pc = pc & (~(bfd_vma)0xfff);			\
   2251  1.1.1.1.4.2  perseant     if (lo > 0x7ff)					\
   2252  1.1.1.1.4.2  perseant       {							\
   2253  1.1.1.1.4.2  perseant 	relocation += 0x1000;				\
   2254  1.1.1.1.4.2  perseant       } 						\
   2255  1.1.1.1.4.2  perseant     relocation &= ~(bfd_vma)0xfff;			\
   2256  1.1.1.1.4.2  perseant     relocation -= pc;					\
   2257  1.1.1.1.4.2  perseant   })
   2258  1.1.1.1.4.2  perseant 
   2259  1.1.1.1.4.2  perseant #define RELOCATE_CALC_PC64_HI32(relocation, pc)  	\
   2260  1.1.1.1.4.2  perseant   ({							\
   2261  1.1.1.1.4.2  perseant     bfd_vma lo = (relocation) & ((bfd_vma)0xfff);	\
   2262  1.1.1.1.4.2  perseant     if (lo > 0x7ff)					\
   2263  1.1.1.1.4.2  perseant       { 						\
   2264  1.1.1.1.4.2  perseant 	relocation -= 0x100000000;      		\
   2265  1.1.1.1.4.2  perseant       }  						\
   2266  1.1.1.1.4.2  perseant     relocation -= (pc & ~(bfd_vma)0xffffffff);  	\
   2267  1.1.1.1.4.2  perseant   })
   2268  1.1.1.1.4.2  perseant 
   2269  1.1.1.1.4.2  perseant static int
   2270  1.1.1.1.4.2  perseant loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
   2271  1.1.1.1.4.2  perseant 				bfd *input_bfd, asection *input_section,
   2272  1.1.1.1.4.2  perseant 				bfd_byte *contents, Elf_Internal_Rela *relocs,
   2273  1.1.1.1.4.2  perseant 				Elf_Internal_Sym *local_syms,
   2274  1.1.1.1.4.2  perseant 				asection **local_sections)
   2275  1.1.1.1.4.2  perseant {
   2276  1.1.1.1.4.2  perseant   Elf_Internal_Rela *rel;
   2277  1.1.1.1.4.2  perseant   Elf_Internal_Rela *relend;
   2278  1.1.1.1.4.2  perseant   bool fatal = false;
   2279  1.1.1.1.4.2  perseant   asection *sreloc = elf_section_data (input_section)->sreloc;
   2280  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
   2281  1.1.1.1.4.2  perseant   Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd);
   2282  1.1.1.1.4.2  perseant   struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
   2283  1.1.1.1.4.2  perseant   bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd);
   2284  1.1.1.1.4.2  perseant   bool is_pic = bfd_link_pic (info);
   2285  1.1.1.1.4.2  perseant   bool is_dyn = elf_hash_table (info)->dynamic_sections_created;
   2286  1.1.1.1.4.2  perseant   asection *plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
   2287  1.1.1.1.4.2  perseant   asection *got = htab->elf.sgot;
   2288  1.1.1.1.4.2  perseant 
   2289  1.1.1.1.4.2  perseant   relend = relocs + input_section->reloc_count;
   2290  1.1.1.1.4.2  perseant   for (rel = relocs; rel < relend; rel++)
   2291  1.1.1.1.4.2  perseant     {
   2292  1.1.1.1.4.2  perseant       int r_type = ELFNN_R_TYPE (rel->r_info);
   2293  1.1.1.1.4.2  perseant       unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
   2294  1.1.1.1.4.2  perseant       bfd_vma pc = sec_addr (input_section) + rel->r_offset;
   2295  1.1.1.1.4.2  perseant       reloc_howto_type *howto = NULL;
   2296  1.1.1.1.4.2  perseant       asection *sec = NULL;
   2297  1.1.1.1.4.2  perseant       Elf_Internal_Sym *sym = NULL;
   2298  1.1.1.1.4.2  perseant       struct elf_link_hash_entry *h = NULL;
   2299  1.1.1.1.4.2  perseant       const char *name;
   2300  1.1.1.1.4.2  perseant       bfd_reloc_status_type r = bfd_reloc_ok;
   2301  1.1.1.1.4.2  perseant       bool is_ie, is_undefweak, unresolved_reloc, defined_local;
   2302  1.1.1.1.4.2  perseant       bool resolved_local, resolved_dynly, resolved_to_const;
   2303  1.1.1.1.4.2  perseant       char tls_type;
   2304  1.1.1.1.4.2  perseant       bfd_vma relocation, off, ie_off;
   2305  1.1.1.1.4.2  perseant       int i, j;
   2306  1.1.1.1.4.2  perseant 
   2307  1.1.1.1.4.2  perseant       howto = loongarch_elf_rtype_to_howto (input_bfd, r_type);
   2308  1.1.1.1.4.2  perseant       if (howto == NULL || r_type == R_LARCH_GNU_VTINHERIT
   2309  1.1.1.1.4.2  perseant 	  || r_type == R_LARCH_GNU_VTENTRY)
   2310  1.1.1.1.4.2  perseant 	continue;
   2311  1.1.1.1.4.2  perseant 
   2312  1.1.1.1.4.2  perseant       /* This is a final link.  */
   2313  1.1.1.1.4.2  perseant       if (r_symndx < symtab_hdr->sh_info)
   2314  1.1.1.1.4.2  perseant 	{
   2315  1.1.1.1.4.2  perseant 	  is_undefweak = false;
   2316  1.1.1.1.4.2  perseant 	  unresolved_reloc = false;
   2317  1.1.1.1.4.2  perseant 	  sym = local_syms + r_symndx;
   2318  1.1.1.1.4.2  perseant 	  sec = local_sections[r_symndx];
   2319  1.1.1.1.4.2  perseant 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
   2320  1.1.1.1.4.2  perseant 
   2321  1.1.1.1.4.2  perseant 	  /* Relocate against local STT_GNU_IFUNC symbol.  */
   2322  1.1.1.1.4.2  perseant 	  if (!bfd_link_relocatable (info)
   2323  1.1.1.1.4.2  perseant 	      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
   2324  1.1.1.1.4.2  perseant 	    {
   2325  1.1.1.1.4.2  perseant 	      h = elfNN_loongarch_get_local_sym_hash (htab, input_bfd, rel,
   2326  1.1.1.1.4.2  perseant 						      false);
   2327  1.1.1.1.4.2  perseant 	      if (h == NULL)
   2328  1.1.1.1.4.2  perseant 		abort ();
   2329  1.1.1.1.4.2  perseant 
   2330  1.1.1.1.4.2  perseant 	      /* Set STT_GNU_IFUNC symbol value.  */
   2331  1.1.1.1.4.2  perseant 	      h->root.u.def.value = sym->st_value;
   2332  1.1.1.1.4.2  perseant 	      h->root.u.def.section = sec;
   2333  1.1.1.1.4.2  perseant 	    }
   2334  1.1.1.1.4.2  perseant 	  defined_local = true;
   2335  1.1.1.1.4.2  perseant 	  resolved_local = true;
   2336  1.1.1.1.4.2  perseant 	  resolved_dynly = false;
   2337  1.1.1.1.4.2  perseant 	  resolved_to_const = false;
   2338  1.1.1.1.4.2  perseant 
   2339  1.1.1.1.4.2  perseant 	  /* Calc in funtion elf_link_input_bfd,
   2340  1.1.1.1.4.2  perseant 	   * if #define elf_backend_rela_normal to 1.  */
   2341  1.1.1.1.4.2  perseant 	  if (bfd_link_relocatable (info)
   2342  1.1.1.1.4.2  perseant 	      && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
   2343  1.1.1.1.4.2  perseant 	    continue;
   2344  1.1.1.1.4.2  perseant 	}
   2345  1.1.1.1.4.2  perseant       else
   2346  1.1.1.1.4.2  perseant 	{
   2347  1.1.1.1.4.2  perseant 	  bool warned, ignored;
   2348  1.1.1.1.4.2  perseant 
   2349  1.1.1.1.4.2  perseant 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
   2350  1.1.1.1.4.2  perseant 				   r_symndx, symtab_hdr, sym_hashes,
   2351  1.1.1.1.4.2  perseant 				   h, sec, relocation,
   2352  1.1.1.1.4.2  perseant 				   unresolved_reloc, warned, ignored);
   2353  1.1.1.1.4.2  perseant 	  /* Here means symbol isn't local symbol only and 'h != NULL'.  */
   2354  1.1.1.1.4.2  perseant 
   2355  1.1.1.1.4.2  perseant 	  /* The 'unresolved_syms_in_objects' specify how to deal with undefined
   2356  1.1.1.1.4.2  perseant 	     symbol.  And 'dynamic_undefined_weak' specify what to do when
   2357  1.1.1.1.4.2  perseant 	     meeting undefweak.  */
   2358  1.1.1.1.4.2  perseant 
   2359  1.1.1.1.4.2  perseant 	  if ((is_undefweak = h->root.type == bfd_link_hash_undefweak))
   2360  1.1.1.1.4.2  perseant 	    {
   2361  1.1.1.1.4.2  perseant 	      defined_local = false;
   2362  1.1.1.1.4.2  perseant 	      resolved_local = false;
   2363  1.1.1.1.4.2  perseant 	      resolved_to_const = (!is_dyn || h->dynindx == -1
   2364  1.1.1.1.4.2  perseant 				   || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
   2365  1.1.1.1.4.2  perseant 	      resolved_dynly = !resolved_local && !resolved_to_const;
   2366  1.1.1.1.4.2  perseant 	    }
   2367  1.1.1.1.4.2  perseant 	  else if (warned)
   2368  1.1.1.1.4.2  perseant 	    {
   2369  1.1.1.1.4.2  perseant 	      /* Symbol undefined offen means failed already.  I don't know why
   2370  1.1.1.1.4.2  perseant 		 'warned' here but I guess it want to continue relocating as if
   2371  1.1.1.1.4.2  perseant 		 no error occures to find other errors as more as possible.  */
   2372  1.1.1.1.4.2  perseant 
   2373  1.1.1.1.4.2  perseant 	      /* To avoid generating warning messages about truncated
   2374  1.1.1.1.4.2  perseant 		 relocations, set the relocation's address to be the same as
   2375  1.1.1.1.4.2  perseant 		 the start of this section.  */
   2376  1.1.1.1.4.2  perseant 	      relocation = (input_section->output_section
   2377  1.1.1.1.4.2  perseant 			    ? input_section->output_section->vma
   2378  1.1.1.1.4.2  perseant 			    : 0);
   2379  1.1.1.1.4.2  perseant 
   2380  1.1.1.1.4.2  perseant 	      defined_local = relocation != 0;
   2381  1.1.1.1.4.2  perseant 	      resolved_local = defined_local;
   2382  1.1.1.1.4.2  perseant 	      resolved_to_const = !resolved_local;
   2383  1.1.1.1.4.2  perseant 	      resolved_dynly = false;
   2384  1.1.1.1.4.2  perseant 	    }
   2385  1.1.1.1.4.2  perseant 	  else
   2386  1.1.1.1.4.2  perseant 	    {
   2387  1.1.1.1.4.2  perseant 	      defined_local = !unresolved_reloc && !ignored;
   2388  1.1.1.1.4.2  perseant 	      resolved_local =
   2389  1.1.1.1.4.2  perseant 		defined_local && SYMBOL_REFERENCES_LOCAL (info, h);
   2390  1.1.1.1.4.2  perseant 	      resolved_dynly = !resolved_local;
   2391  1.1.1.1.4.2  perseant 	      resolved_to_const = !resolved_local && !resolved_dynly;
   2392  1.1.1.1.4.2  perseant 	    }
   2393  1.1.1.1.4.2  perseant 	}
   2394  1.1.1.1.4.2  perseant 
   2395  1.1.1.1.4.2  perseant       name = loongarch_sym_name (input_bfd, h, sym);
   2396  1.1.1.1.4.2  perseant 
   2397  1.1.1.1.4.2  perseant       if (sec != NULL && discarded_section (sec))
   2398  1.1.1.1.4.2  perseant 	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, rel,
   2399  1.1.1.1.4.2  perseant 					 1, relend, howto, 0, contents);
   2400  1.1.1.1.4.2  perseant 
   2401  1.1.1.1.4.2  perseant       if (bfd_link_relocatable (info))
   2402  1.1.1.1.4.2  perseant 	continue;
   2403  1.1.1.1.4.2  perseant 
   2404  1.1.1.1.4.2  perseant       /* The r_symndx will be STN_UNDEF (zero) only for relocs against symbols
   2405  1.1.1.1.4.2  perseant 	 from removed linkonce sections, or sections discarded by a linker
   2406  1.1.1.1.4.2  perseant 	 script.  Also for R_*_SOP_PUSH_ABSOLUTE and PCREL to specify const.  */
   2407  1.1.1.1.4.2  perseant       if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec))
   2408  1.1.1.1.4.2  perseant 	{
   2409  1.1.1.1.4.2  perseant 	  defined_local = false;
   2410  1.1.1.1.4.2  perseant 	  resolved_local = false;
   2411  1.1.1.1.4.2  perseant 	  resolved_dynly = false;
   2412  1.1.1.1.4.2  perseant 	  resolved_to_const = true;
   2413  1.1.1.1.4.2  perseant 	}
   2414  1.1.1.1.4.2  perseant 
   2415  1.1.1.1.4.2  perseant       /* The ifunc reference generate plt.  */
   2416  1.1.1.1.4.2  perseant       if (h && h->type == STT_GNU_IFUNC && h->plt.offset != MINUS_ONE)
   2417  1.1.1.1.4.2  perseant 	{
   2418  1.1.1.1.4.2  perseant 	  defined_local = true;
   2419  1.1.1.1.4.2  perseant 	  resolved_local = true;
   2420  1.1.1.1.4.2  perseant 	  resolved_dynly = false;
   2421  1.1.1.1.4.2  perseant 	  resolved_to_const = false;
   2422  1.1.1.1.4.2  perseant 	  relocation = sec_addr (plt) + h->plt.offset;
   2423  1.1.1.1.4.2  perseant 	}
   2424  1.1.1.1.4.2  perseant 
   2425  1.1.1.1.4.2  perseant       unresolved_reloc = resolved_dynly;
   2426  1.1.1.1.4.2  perseant 
   2427  1.1.1.1.4.2  perseant       BFD_ASSERT (resolved_local + resolved_dynly + resolved_to_const == 1);
   2428  1.1.1.1.4.2  perseant 
   2429  1.1.1.1.4.2  perseant       /* BFD_ASSERT (!resolved_dynly || (h && h->dynindx != -1));.  */
   2430  1.1.1.1.4.2  perseant 
   2431  1.1.1.1.4.2  perseant       BFD_ASSERT (!resolved_local || defined_local);
   2432  1.1.1.1.4.2  perseant 
   2433  1.1.1.1.4.2  perseant       is_ie = false;
   2434  1.1.1.1.4.2  perseant       switch (r_type)
   2435  1.1.1.1.4.2  perseant 	{
   2436  1.1.1.1.4.2  perseant 	case R_LARCH_MARK_PCREL:
   2437  1.1.1.1.4.2  perseant 	case R_LARCH_MARK_LA:
   2438  1.1.1.1.4.2  perseant 	case R_LARCH_NONE:
   2439  1.1.1.1.4.2  perseant 	  r = bfd_reloc_continue;
   2440  1.1.1.1.4.2  perseant 	  unresolved_reloc = false;
   2441  1.1.1.1.4.2  perseant 	  break;
   2442  1.1.1.1.4.2  perseant 
   2443  1.1.1.1.4.2  perseant 	case R_LARCH_32:
   2444  1.1.1.1.4.2  perseant 	case R_LARCH_64:
   2445  1.1.1.1.4.2  perseant 	  if (resolved_dynly || (is_pic && resolved_local))
   2446  1.1.1.1.4.2  perseant 	    {
   2447  1.1.1.1.4.2  perseant 	      Elf_Internal_Rela outrel;
   2448  1.1.1.1.4.2  perseant 
   2449  1.1.1.1.4.2  perseant 	      /* When generating a shared object, these relocations are copied
   2450  1.1.1.1.4.2  perseant 		 into the output file to be resolved at run time.  */
   2451  1.1.1.1.4.2  perseant 
   2452  1.1.1.1.4.2  perseant 	      outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
   2453  1.1.1.1.4.2  perseant 							 input_section,
   2454  1.1.1.1.4.2  perseant 							 rel->r_offset);
   2455  1.1.1.1.4.2  perseant 
   2456  1.1.1.1.4.2  perseant 	      unresolved_reloc = (!((bfd_vma) -2 <= outrel.r_offset)
   2457  1.1.1.1.4.2  perseant 				  && (input_section->flags & SEC_ALLOC));
   2458  1.1.1.1.4.2  perseant 
   2459  1.1.1.1.4.2  perseant 	      outrel.r_offset += sec_addr (input_section);
   2460  1.1.1.1.4.2  perseant 
   2461  1.1.1.1.4.2  perseant 	      /* A pointer point to a ifunc symbol.  */
   2462  1.1.1.1.4.2  perseant 	      if (h && h->type == STT_GNU_IFUNC)
   2463  1.1.1.1.4.2  perseant 		{
   2464  1.1.1.1.4.2  perseant 		  if (h->dynindx == -1)
   2465  1.1.1.1.4.2  perseant 		    {
   2466  1.1.1.1.4.2  perseant 		      outrel.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
   2467  1.1.1.1.4.2  perseant 		      outrel.r_addend = (h->root.u.def.value
   2468  1.1.1.1.4.2  perseant 				  + h->root.u.def.section->output_section->vma
   2469  1.1.1.1.4.2  perseant 				  + h->root.u.def.section->output_offset);
   2470  1.1.1.1.4.2  perseant 		    }
   2471  1.1.1.1.4.2  perseant 		  else
   2472  1.1.1.1.4.2  perseant 		    {
   2473  1.1.1.1.4.2  perseant 		      outrel.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
   2474  1.1.1.1.4.2  perseant 		      outrel.r_addend = 0;
   2475  1.1.1.1.4.2  perseant 		    }
   2476  1.1.1.1.4.2  perseant 
   2477  1.1.1.1.4.2  perseant 		  if (SYMBOL_REFERENCES_LOCAL (info, h))
   2478  1.1.1.1.4.2  perseant 		    {
   2479  1.1.1.1.4.2  perseant 
   2480  1.1.1.1.4.2  perseant 		      if (htab->elf.splt != NULL)
   2481  1.1.1.1.4.2  perseant 			sreloc = htab->elf.srelgot;
   2482  1.1.1.1.4.2  perseant 		      else
   2483  1.1.1.1.4.2  perseant 			sreloc = htab->elf.irelplt;
   2484  1.1.1.1.4.2  perseant 		    }
   2485  1.1.1.1.4.2  perseant 		  else
   2486  1.1.1.1.4.2  perseant 		    {
   2487  1.1.1.1.4.2  perseant 
   2488  1.1.1.1.4.2  perseant 		      if (bfd_link_pic (info))
   2489  1.1.1.1.4.2  perseant 			sreloc = htab->elf.irelifunc;
   2490  1.1.1.1.4.2  perseant 		      else if (htab->elf.splt != NULL)
   2491  1.1.1.1.4.2  perseant 			sreloc = htab->elf.srelgot;
   2492  1.1.1.1.4.2  perseant 		      else
   2493  1.1.1.1.4.2  perseant 			sreloc = htab->elf.irelplt;
   2494  1.1.1.1.4.2  perseant 		    }
   2495  1.1.1.1.4.2  perseant 		}
   2496  1.1.1.1.4.2  perseant 	      else if (resolved_dynly)
   2497  1.1.1.1.4.2  perseant 		{
   2498  1.1.1.1.4.2  perseant 		  if (h->dynindx == -1)
   2499  1.1.1.1.4.2  perseant 		    {
   2500  1.1.1.1.4.2  perseant 		      if (h->root.type == bfd_link_hash_undefined)
   2501  1.1.1.1.4.2  perseant 			(*info->callbacks->undefined_symbol)
   2502  1.1.1.1.4.2  perseant 			  (info, name, input_bfd, input_section,
   2503  1.1.1.1.4.2  perseant 			   rel->r_offset, true);
   2504  1.1.1.1.4.2  perseant 
   2505  1.1.1.1.4.2  perseant 		      outrel.r_info = ELFNN_R_INFO (0, r_type);
   2506  1.1.1.1.4.2  perseant 		    }
   2507  1.1.1.1.4.2  perseant 		  else
   2508  1.1.1.1.4.2  perseant 		    outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
   2509  1.1.1.1.4.2  perseant 
   2510  1.1.1.1.4.2  perseant 		  outrel.r_addend = rel->r_addend;
   2511  1.1.1.1.4.2  perseant 		}
   2512  1.1.1.1.4.2  perseant 	      else
   2513  1.1.1.1.4.2  perseant 		{
   2514  1.1.1.1.4.2  perseant 		  outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
   2515  1.1.1.1.4.2  perseant 		  outrel.r_addend = relocation + rel->r_addend;
   2516  1.1.1.1.4.2  perseant 		}
   2517  1.1.1.1.4.2  perseant 
   2518  1.1.1.1.4.2  perseant 	      /* No alloc space of func allocate_dynrelocs.  */
   2519  1.1.1.1.4.2  perseant 	      if (unresolved_reloc
   2520  1.1.1.1.4.2  perseant 		  && !(h && (h->is_weakalias || !h->dyn_relocs)))
   2521  1.1.1.1.4.2  perseant 		loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
   2522  1.1.1.1.4.2  perseant 	    }
   2523  1.1.1.1.4.2  perseant 
   2524  1.1.1.1.4.2  perseant 	  relocation += rel->r_addend;
   2525  1.1.1.1.4.2  perseant 	  break;
   2526  1.1.1.1.4.2  perseant 
   2527  1.1.1.1.4.2  perseant 	case R_LARCH_ADD8:
   2528  1.1.1.1.4.2  perseant 	case R_LARCH_ADD16:
   2529  1.1.1.1.4.2  perseant 	case R_LARCH_ADD24:
   2530  1.1.1.1.4.2  perseant 	case R_LARCH_ADD32:
   2531  1.1.1.1.4.2  perseant 	case R_LARCH_ADD64:
   2532  1.1.1.1.4.2  perseant 	case R_LARCH_SUB8:
   2533  1.1.1.1.4.2  perseant 	case R_LARCH_SUB16:
   2534  1.1.1.1.4.2  perseant 	case R_LARCH_SUB24:
   2535  1.1.1.1.4.2  perseant 	case R_LARCH_SUB32:
   2536  1.1.1.1.4.2  perseant 	case R_LARCH_SUB64:
   2537  1.1.1.1.4.2  perseant 	  if (resolved_dynly)
   2538  1.1.1.1.4.2  perseant 	    fatal = (loongarch_reloc_is_fatal
   2539  1.1.1.1.4.2  perseant 		     (info, input_bfd, input_section, rel, howto,
   2540  1.1.1.1.4.2  perseant 		      bfd_reloc_undefined, is_undefweak, name,
   2541  1.1.1.1.4.2  perseant 		      "Can't be resolved dynamically.  "
   2542  1.1.1.1.4.2  perseant 		      "If this procedure is hand-written assembly,\n"
   2543  1.1.1.1.4.2  perseant 		      "there must be something like '.dword sym1 - sym2' "
   2544  1.1.1.1.4.2  perseant 		      "to generate these relocs\n"
   2545  1.1.1.1.4.2  perseant 		      "and we can't get known link-time address of "
   2546  1.1.1.1.4.2  perseant 		      "these symbols."));
   2547  1.1.1.1.4.2  perseant 	  else
   2548  1.1.1.1.4.2  perseant 	    relocation += rel->r_addend;
   2549  1.1.1.1.4.2  perseant 	  break;
   2550  1.1.1.1.4.2  perseant 
   2551  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_DTPREL32:
   2552  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_DTPREL64:
   2553  1.1.1.1.4.2  perseant 	  if (resolved_dynly)
   2554  1.1.1.1.4.2  perseant 	    {
   2555  1.1.1.1.4.2  perseant 	      Elf_Internal_Rela outrel;
   2556  1.1.1.1.4.2  perseant 
   2557  1.1.1.1.4.2  perseant 	      outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
   2558  1.1.1.1.4.2  perseant 							 input_section,
   2559  1.1.1.1.4.2  perseant 							 rel->r_offset);
   2560  1.1.1.1.4.2  perseant 	      unresolved_reloc = (!((bfd_vma) -2 <= outrel.r_offset)
   2561  1.1.1.1.4.2  perseant 				  && (input_section->flags & SEC_ALLOC));
   2562  1.1.1.1.4.2  perseant 	      outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
   2563  1.1.1.1.4.2  perseant 	      outrel.r_offset += sec_addr (input_section);
   2564  1.1.1.1.4.2  perseant 	      outrel.r_addend = rel->r_addend;
   2565  1.1.1.1.4.2  perseant 	      if (unresolved_reloc)
   2566  1.1.1.1.4.2  perseant 		loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
   2567  1.1.1.1.4.2  perseant 	      break;
   2568  1.1.1.1.4.2  perseant 	    }
   2569  1.1.1.1.4.2  perseant 
   2570  1.1.1.1.4.2  perseant 	  if (resolved_to_const)
   2571  1.1.1.1.4.2  perseant 	    fatal = loongarch_reloc_is_fatal (info, input_bfd, input_section,
   2572  1.1.1.1.4.2  perseant 					      rel, howto,
   2573  1.1.1.1.4.2  perseant 					      bfd_reloc_notsupported,
   2574  1.1.1.1.4.2  perseant 					      is_undefweak, name,
   2575  1.1.1.1.4.2  perseant 					      "Internal:");
   2576  1.1.1.1.4.2  perseant 	  if (resolved_local)
   2577  1.1.1.1.4.2  perseant 	    {
   2578  1.1.1.1.4.2  perseant 	      if (!elf_hash_table (info)->tls_sec)
   2579  1.1.1.1.4.2  perseant 		{
   2580  1.1.1.1.4.2  perseant 		fatal = loongarch_reloc_is_fatal (info, input_bfd,
   2581  1.1.1.1.4.2  perseant 			  input_section, rel, howto, bfd_reloc_notsupported,
   2582  1.1.1.1.4.2  perseant 			  is_undefweak, name, "TLS section not be created");
   2583  1.1.1.1.4.2  perseant 		}
   2584  1.1.1.1.4.2  perseant 	      else
   2585  1.1.1.1.4.2  perseant 		relocation -= elf_hash_table (info)->tls_sec->vma;
   2586  1.1.1.1.4.2  perseant 	    }
   2587  1.1.1.1.4.2  perseant 	  else
   2588  1.1.1.1.4.2  perseant 	    {
   2589  1.1.1.1.4.2  perseant 	    fatal = loongarch_reloc_is_fatal (info, input_bfd,
   2590  1.1.1.1.4.2  perseant 		      input_section, rel, howto, bfd_reloc_undefined,
   2591  1.1.1.1.4.2  perseant 		      is_undefweak, name,
   2592  1.1.1.1.4.2  perseant 		      "TLS LE just can be resolved local only.");
   2593  1.1.1.1.4.2  perseant 	    }
   2594  1.1.1.1.4.2  perseant 
   2595  1.1.1.1.4.2  perseant 	  break;
   2596  1.1.1.1.4.2  perseant 
   2597  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_TLS_TPREL:
   2598  1.1.1.1.4.2  perseant 	  if (resolved_local)
   2599  1.1.1.1.4.2  perseant 	    {
   2600  1.1.1.1.4.2  perseant 	      if (!elf_hash_table (info)->tls_sec)
   2601  1.1.1.1.4.2  perseant 		fatal = (loongarch_reloc_is_fatal
   2602  1.1.1.1.4.2  perseant 			 (info, input_bfd, input_section, rel, howto,
   2603  1.1.1.1.4.2  perseant 			  bfd_reloc_notsupported, is_undefweak, name,
   2604  1.1.1.1.4.2  perseant 			  "TLS section not be created"));
   2605  1.1.1.1.4.2  perseant 	      else
   2606  1.1.1.1.4.2  perseant 		relocation -= elf_hash_table (info)->tls_sec->vma;
   2607  1.1.1.1.4.2  perseant 	    }
   2608  1.1.1.1.4.2  perseant 	  else
   2609  1.1.1.1.4.2  perseant 	    fatal = (loongarch_reloc_is_fatal
   2610  1.1.1.1.4.2  perseant 		     (info, input_bfd, input_section, rel, howto,
   2611  1.1.1.1.4.2  perseant 		      bfd_reloc_undefined, is_undefweak, name,
   2612  1.1.1.1.4.2  perseant 		      "TLS LE just can be resolved local only."));
   2613  1.1.1.1.4.2  perseant 	  break;
   2614  1.1.1.1.4.2  perseant 
   2615  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_ABSOLUTE:
   2616  1.1.1.1.4.2  perseant 	  if (is_undefweak)
   2617  1.1.1.1.4.2  perseant 	    {
   2618  1.1.1.1.4.2  perseant 	      if (resolved_dynly)
   2619  1.1.1.1.4.2  perseant 		fatal = (loongarch_reloc_is_fatal
   2620  1.1.1.1.4.2  perseant 			 (info, input_bfd, input_section, rel, howto,
   2621  1.1.1.1.4.2  perseant 			  bfd_reloc_dangerous, is_undefweak, name,
   2622  1.1.1.1.4.2  perseant 			  "Someone require us to resolve undefweak "
   2623  1.1.1.1.4.2  perseant 			  "symbol dynamically.  \n"
   2624  1.1.1.1.4.2  perseant 			  "But this reloc can't be done.  "
   2625  1.1.1.1.4.2  perseant 			  "I think I can't throw error "
   2626  1.1.1.1.4.2  perseant 			  "for this\n"
   2627  1.1.1.1.4.2  perseant 			  "so I resolved it to 0.  "
   2628  1.1.1.1.4.2  perseant 			  "I suggest to re-compile with '-fpic'."));
   2629  1.1.1.1.4.2  perseant 
   2630  1.1.1.1.4.2  perseant 	      relocation = 0;
   2631  1.1.1.1.4.2  perseant 	      unresolved_reloc = false;
   2632  1.1.1.1.4.2  perseant 	      break;
   2633  1.1.1.1.4.2  perseant 	    }
   2634  1.1.1.1.4.2  perseant 
   2635  1.1.1.1.4.2  perseant 	  if (resolved_to_const)
   2636  1.1.1.1.4.2  perseant 	    {
   2637  1.1.1.1.4.2  perseant 	      relocation += rel->r_addend;
   2638  1.1.1.1.4.2  perseant 	      break;
   2639  1.1.1.1.4.2  perseant 	    }
   2640  1.1.1.1.4.2  perseant 
   2641  1.1.1.1.4.2  perseant 	  if (is_pic)
   2642  1.1.1.1.4.2  perseant 	    {
   2643  1.1.1.1.4.2  perseant 	      fatal = (loongarch_reloc_is_fatal
   2644  1.1.1.1.4.2  perseant 		       (info, input_bfd, input_section, rel, howto,
   2645  1.1.1.1.4.2  perseant 			bfd_reloc_notsupported, is_undefweak, name,
   2646  1.1.1.1.4.2  perseant 			"Under PIC we don't know load address.  Re-compile "
   2647  1.1.1.1.4.2  perseant 			"with '-fpic'?"));
   2648  1.1.1.1.4.2  perseant 	      break;
   2649  1.1.1.1.4.2  perseant 	    }
   2650  1.1.1.1.4.2  perseant 
   2651  1.1.1.1.4.2  perseant 	  if (resolved_dynly)
   2652  1.1.1.1.4.2  perseant 	    {
   2653  1.1.1.1.4.2  perseant 	      if (!(plt && h && h->plt.offset != MINUS_ONE))
   2654  1.1.1.1.4.2  perseant 		{
   2655  1.1.1.1.4.2  perseant 		  fatal = (loongarch_reloc_is_fatal
   2656  1.1.1.1.4.2  perseant 			   (info, input_bfd, input_section, rel, howto,
   2657  1.1.1.1.4.2  perseant 			    bfd_reloc_undefined, is_undefweak, name,
   2658  1.1.1.1.4.2  perseant 			    "Can't be resolved dynamically.  Try to re-compile "
   2659  1.1.1.1.4.2  perseant 			    "with '-fpic'?"));
   2660  1.1.1.1.4.2  perseant 		  break;
   2661  1.1.1.1.4.2  perseant 		}
   2662  1.1.1.1.4.2  perseant 
   2663  1.1.1.1.4.2  perseant 	      if (rel->r_addend != 0)
   2664  1.1.1.1.4.2  perseant 		{
   2665  1.1.1.1.4.2  perseant 		  fatal = (loongarch_reloc_is_fatal
   2666  1.1.1.1.4.2  perseant 			   (info, input_bfd, input_section, rel, howto,
   2667  1.1.1.1.4.2  perseant 			    bfd_reloc_notsupported, is_undefweak, name,
   2668  1.1.1.1.4.2  perseant 			    "Shouldn't be with r_addend."));
   2669  1.1.1.1.4.2  perseant 		  break;
   2670  1.1.1.1.4.2  perseant 		}
   2671  1.1.1.1.4.2  perseant 
   2672  1.1.1.1.4.2  perseant 	      relocation = sec_addr (plt) + h->plt.offset;
   2673  1.1.1.1.4.2  perseant 	      unresolved_reloc = false;
   2674  1.1.1.1.4.2  perseant 	      break;
   2675  1.1.1.1.4.2  perseant 	    }
   2676  1.1.1.1.4.2  perseant 
   2677  1.1.1.1.4.2  perseant 	  if (resolved_local)
   2678  1.1.1.1.4.2  perseant 	    {
   2679  1.1.1.1.4.2  perseant 	      relocation += rel->r_addend;
   2680  1.1.1.1.4.2  perseant 	      break;
   2681  1.1.1.1.4.2  perseant 	    }
   2682  1.1.1.1.4.2  perseant 
   2683  1.1.1.1.4.2  perseant 	  break;
   2684  1.1.1.1.4.2  perseant 
   2685  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_PCREL:
   2686  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_PLT_PCREL:
   2687  1.1.1.1.4.2  perseant 	  unresolved_reloc = false;
   2688  1.1.1.1.4.2  perseant 
   2689  1.1.1.1.4.2  perseant 	  if (is_undefweak)
   2690  1.1.1.1.4.2  perseant 	    {
   2691  1.1.1.1.4.2  perseant 	      i = 0, j = 0;
   2692  1.1.1.1.4.2  perseant 	      relocation = 0;
   2693  1.1.1.1.4.2  perseant 	      if (resolved_dynly)
   2694  1.1.1.1.4.2  perseant 		{
   2695  1.1.1.1.4.2  perseant 		  if (h && h->plt.offset != MINUS_ONE)
   2696  1.1.1.1.4.2  perseant 		    i = 1, j = 2;
   2697  1.1.1.1.4.2  perseant 		  else
   2698  1.1.1.1.4.2  perseant 		    fatal = (loongarch_reloc_is_fatal
   2699  1.1.1.1.4.2  perseant 			     (info, input_bfd, input_section, rel, howto,
   2700  1.1.1.1.4.2  perseant 			      bfd_reloc_dangerous, is_undefweak, name,
   2701  1.1.1.1.4.2  perseant 			      "Undefweak need to be resolved dynamically, "
   2702  1.1.1.1.4.2  perseant 			      "but PLT stub doesn't represent."));
   2703  1.1.1.1.4.2  perseant 		}
   2704  1.1.1.1.4.2  perseant 	    }
   2705  1.1.1.1.4.2  perseant 	  else
   2706  1.1.1.1.4.2  perseant 	    {
   2707  1.1.1.1.4.2  perseant 	      if (!(defined_local || (h && h->plt.offset != MINUS_ONE)))
   2708  1.1.1.1.4.2  perseant 		{
   2709  1.1.1.1.4.2  perseant 		  fatal = (loongarch_reloc_is_fatal
   2710  1.1.1.1.4.2  perseant 			   (info, input_bfd, input_section, rel, howto,
   2711  1.1.1.1.4.2  perseant 			    bfd_reloc_undefined, is_undefweak, name,
   2712  1.1.1.1.4.2  perseant 			    "PLT stub does not represent and "
   2713  1.1.1.1.4.2  perseant 			    "symbol not defined."));
   2714  1.1.1.1.4.2  perseant 		  break;
   2715  1.1.1.1.4.2  perseant 		}
   2716  1.1.1.1.4.2  perseant 
   2717  1.1.1.1.4.2  perseant 	      if (resolved_local)
   2718  1.1.1.1.4.2  perseant 		i = 0, j = 2;
   2719  1.1.1.1.4.2  perseant 	      else /* if (resolved_dynly) */
   2720  1.1.1.1.4.2  perseant 		{
   2721  1.1.1.1.4.2  perseant 		  if (!(h && h->plt.offset != MINUS_ONE))
   2722  1.1.1.1.4.2  perseant 		    fatal = (loongarch_reloc_is_fatal
   2723  1.1.1.1.4.2  perseant 			     (info, input_bfd, input_section, rel, howto,
   2724  1.1.1.1.4.2  perseant 			      bfd_reloc_dangerous, is_undefweak, name,
   2725  1.1.1.1.4.2  perseant 			      "Internal: PLT stub doesn't represent.  "
   2726  1.1.1.1.4.2  perseant 			      "Resolve it with pcrel"));
   2727  1.1.1.1.4.2  perseant 		  i = 1, j = 3;
   2728  1.1.1.1.4.2  perseant 		}
   2729  1.1.1.1.4.2  perseant 	    }
   2730  1.1.1.1.4.2  perseant 
   2731  1.1.1.1.4.2  perseant 	  for (; i < j; i++)
   2732  1.1.1.1.4.2  perseant 	    {
   2733  1.1.1.1.4.2  perseant 	      if ((i & 1) == 0 && defined_local)
   2734  1.1.1.1.4.2  perseant 		{
   2735  1.1.1.1.4.2  perseant 		  relocation -= pc;
   2736  1.1.1.1.4.2  perseant 		  relocation += rel->r_addend;
   2737  1.1.1.1.4.2  perseant 		  break;
   2738  1.1.1.1.4.2  perseant 		}
   2739  1.1.1.1.4.2  perseant 
   2740  1.1.1.1.4.2  perseant 	      if ((i & 1) && h && h->plt.offset != MINUS_ONE)
   2741  1.1.1.1.4.2  perseant 		{
   2742  1.1.1.1.4.2  perseant 		  if (rel->r_addend != 0)
   2743  1.1.1.1.4.2  perseant 		    {
   2744  1.1.1.1.4.2  perseant 		      fatal = (loongarch_reloc_is_fatal
   2745  1.1.1.1.4.2  perseant 			       (info, input_bfd, input_section, rel, howto,
   2746  1.1.1.1.4.2  perseant 				bfd_reloc_notsupported, is_undefweak, name,
   2747  1.1.1.1.4.2  perseant 				"PLT shouldn't be with r_addend."));
   2748  1.1.1.1.4.2  perseant 		      break;
   2749  1.1.1.1.4.2  perseant 		    }
   2750  1.1.1.1.4.2  perseant 		  relocation = sec_addr (plt) + h->plt.offset - pc;
   2751  1.1.1.1.4.2  perseant 		  break;
   2752  1.1.1.1.4.2  perseant 		}
   2753  1.1.1.1.4.2  perseant 	    }
   2754  1.1.1.1.4.2  perseant 	  break;
   2755  1.1.1.1.4.2  perseant 
   2756  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_GPREL:
   2757  1.1.1.1.4.2  perseant 	  unresolved_reloc = false;
   2758  1.1.1.1.4.2  perseant 
   2759  1.1.1.1.4.2  perseant 	  if (rel->r_addend != 0)
   2760  1.1.1.1.4.2  perseant 	    {
   2761  1.1.1.1.4.2  perseant 	      fatal = (loongarch_reloc_is_fatal
   2762  1.1.1.1.4.2  perseant 		       (info, input_bfd, input_section, rel, howto,
   2763  1.1.1.1.4.2  perseant 			bfd_reloc_notsupported, is_undefweak, name,
   2764  1.1.1.1.4.2  perseant 			"Shouldn't be with r_addend."));
   2765  1.1.1.1.4.2  perseant 	      break;
   2766  1.1.1.1.4.2  perseant 	    }
   2767  1.1.1.1.4.2  perseant 
   2768  1.1.1.1.4.2  perseant 	  if (h != NULL)
   2769  1.1.1.1.4.2  perseant 	    {
   2770  1.1.1.1.4.2  perseant 	      off = h->got.offset & (~1);
   2771  1.1.1.1.4.2  perseant 
   2772  1.1.1.1.4.2  perseant 	      if (h->got.offset == MINUS_ONE && h->type != STT_GNU_IFUNC)
   2773  1.1.1.1.4.2  perseant 		{
   2774  1.1.1.1.4.2  perseant 		  fatal = (loongarch_reloc_is_fatal
   2775  1.1.1.1.4.2  perseant 			   (info, input_bfd, input_section, rel, howto,
   2776  1.1.1.1.4.2  perseant 			    bfd_reloc_notsupported, is_undefweak, name,
   2777  1.1.1.1.4.2  perseant 			    "Internal: GOT entry doesn't represent."));
   2778  1.1.1.1.4.2  perseant 		  break;
   2779  1.1.1.1.4.2  perseant 		}
   2780  1.1.1.1.4.2  perseant 
   2781  1.1.1.1.4.2  perseant 	      /* Hidden symbol not has .got entry, only .got.plt entry
   2782  1.1.1.1.4.2  perseant 		 so gprel is (plt - got).  */
   2783  1.1.1.1.4.2  perseant 	      if (h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
   2784  1.1.1.1.4.2  perseant 		{
   2785  1.1.1.1.4.2  perseant 		  if (h->plt.offset == (bfd_vma) -1)
   2786  1.1.1.1.4.2  perseant 		    {
   2787  1.1.1.1.4.2  perseant 		      abort();
   2788  1.1.1.1.4.2  perseant 		    }
   2789  1.1.1.1.4.2  perseant 
   2790  1.1.1.1.4.2  perseant 		  bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE;
   2791  1.1.1.1.4.2  perseant 		  off = plt_index * GOT_ENTRY_SIZE;
   2792  1.1.1.1.4.2  perseant 
   2793  1.1.1.1.4.2  perseant 		  if (htab->elf.splt != NULL)
   2794  1.1.1.1.4.2  perseant 		    {
   2795  1.1.1.1.4.2  perseant 		      /* Section .plt header is 2 times of plt entry.  */
   2796  1.1.1.1.4.2  perseant 		      off = sec_addr (htab->elf.sgotplt) + off
   2797  1.1.1.1.4.2  perseant 			- sec_addr (htab->elf.sgot);
   2798  1.1.1.1.4.2  perseant 		    }
   2799  1.1.1.1.4.2  perseant 		  else
   2800  1.1.1.1.4.2  perseant 		    {
   2801  1.1.1.1.4.2  perseant 		      /* Section iplt not has plt header.  */
   2802  1.1.1.1.4.2  perseant 		      off = sec_addr (htab->elf.igotplt) + off
   2803  1.1.1.1.4.2  perseant 			- sec_addr (htab->elf.sgot);
   2804  1.1.1.1.4.2  perseant 		    }
   2805  1.1.1.1.4.2  perseant 		}
   2806  1.1.1.1.4.2  perseant 
   2807  1.1.1.1.4.2  perseant 	      if ((h->got.offset & 1) == 0)
   2808  1.1.1.1.4.2  perseant 		{
   2809  1.1.1.1.4.2  perseant 		  if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn,
   2810  1.1.1.1.4.2  perseant 							bfd_link_pic (info), h)
   2811  1.1.1.1.4.2  perseant 		      && ((bfd_link_pic (info)
   2812  1.1.1.1.4.2  perseant 			   && SYMBOL_REFERENCES_LOCAL (info, h))))
   2813  1.1.1.1.4.2  perseant 		    {
   2814  1.1.1.1.4.2  perseant 		      /* This is actually a static link, or it is a
   2815  1.1.1.1.4.2  perseant 			 -Bsymbolic link and the symbol is defined
   2816  1.1.1.1.4.2  perseant 			 locally, or the symbol was forced to be local
   2817  1.1.1.1.4.2  perseant 			 because of a version file.  We must initialize
   2818  1.1.1.1.4.2  perseant 			 this entry in the global offset table.  Since the
   2819  1.1.1.1.4.2  perseant 			 offset must always be a multiple of the word size,
   2820  1.1.1.1.4.2  perseant 			 we use the least significant bit to record whether
   2821  1.1.1.1.4.2  perseant 			 we have initialized it already.
   2822  1.1.1.1.4.2  perseant 
   2823  1.1.1.1.4.2  perseant 			 When doing a dynamic link, we create a rela.got
   2824  1.1.1.1.4.2  perseant 			 relocation entry to initialize the value.  This
   2825  1.1.1.1.4.2  perseant 			 is done in the finish_dynamic_symbol routine.  */
   2826  1.1.1.1.4.2  perseant 
   2827  1.1.1.1.4.2  perseant 		      if (resolved_dynly)
   2828  1.1.1.1.4.2  perseant 			{
   2829  1.1.1.1.4.2  perseant 			  fatal = (loongarch_reloc_is_fatal
   2830  1.1.1.1.4.2  perseant 				   (info, input_bfd, input_section, rel, howto,
   2831  1.1.1.1.4.2  perseant 				    bfd_reloc_dangerous, is_undefweak, name,
   2832  1.1.1.1.4.2  perseant 				    "Internal: here shouldn't dynamic."));
   2833  1.1.1.1.4.2  perseant 			}
   2834  1.1.1.1.4.2  perseant 
   2835  1.1.1.1.4.2  perseant 		      if (!(defined_local || resolved_to_const))
   2836  1.1.1.1.4.2  perseant 			{
   2837  1.1.1.1.4.2  perseant 			  fatal = (loongarch_reloc_is_fatal
   2838  1.1.1.1.4.2  perseant 				   (info, input_bfd, input_section, rel, howto,
   2839  1.1.1.1.4.2  perseant 				    bfd_reloc_undefined, is_undefweak, name,
   2840  1.1.1.1.4.2  perseant 				    "Internal: "));
   2841  1.1.1.1.4.2  perseant 			  break;
   2842  1.1.1.1.4.2  perseant 			}
   2843  1.1.1.1.4.2  perseant 
   2844  1.1.1.1.4.2  perseant 		      asection *s;
   2845  1.1.1.1.4.2  perseant 		      Elf_Internal_Rela outrel;
   2846  1.1.1.1.4.2  perseant 		      /* We need to generate a R_LARCH_RELATIVE reloc
   2847  1.1.1.1.4.2  perseant 			 for the dynamic linker.  */
   2848  1.1.1.1.4.2  perseant 		      s = htab->elf.srelgot;
   2849  1.1.1.1.4.2  perseant 		      if (!s)
   2850  1.1.1.1.4.2  perseant 			{
   2851  1.1.1.1.4.2  perseant 			  fatal = loongarch_reloc_is_fatal
   2852  1.1.1.1.4.2  perseant 			    (info, input_bfd,
   2853  1.1.1.1.4.2  perseant 			     input_section, rel, howto,
   2854  1.1.1.1.4.2  perseant 			     bfd_reloc_notsupported, is_undefweak, name,
   2855  1.1.1.1.4.2  perseant 			     "Internal: '.rel.got' not represent");
   2856  1.1.1.1.4.2  perseant 			  break;
   2857  1.1.1.1.4.2  perseant 			}
   2858  1.1.1.1.4.2  perseant 
   2859  1.1.1.1.4.2  perseant 		      outrel.r_offset = sec_addr (got) + off;
   2860  1.1.1.1.4.2  perseant 		      outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
   2861  1.1.1.1.4.2  perseant 		      outrel.r_addend = relocation; /* Link-time addr.  */
   2862  1.1.1.1.4.2  perseant 		      loongarch_elf_append_rela (output_bfd, s, &outrel);
   2863  1.1.1.1.4.2  perseant 		    }
   2864  1.1.1.1.4.2  perseant 		  bfd_put_NN (output_bfd, relocation, got->contents + off);
   2865  1.1.1.1.4.2  perseant 		  h->got.offset |= 1;
   2866  1.1.1.1.4.2  perseant 		}
   2867  1.1.1.1.4.2  perseant 	    }
   2868  1.1.1.1.4.2  perseant 	  else
   2869  1.1.1.1.4.2  perseant 	    {
   2870  1.1.1.1.4.2  perseant 	      if (!local_got_offsets)
   2871  1.1.1.1.4.2  perseant 		{
   2872  1.1.1.1.4.2  perseant 		  fatal = (loongarch_reloc_is_fatal
   2873  1.1.1.1.4.2  perseant 			   (info, input_bfd, input_section, rel, howto,
   2874  1.1.1.1.4.2  perseant 			    bfd_reloc_notsupported, is_undefweak, name,
   2875  1.1.1.1.4.2  perseant 			    "Internal: local got offsets not reporesent."));
   2876  1.1.1.1.4.2  perseant 		  break;
   2877  1.1.1.1.4.2  perseant 		}
   2878  1.1.1.1.4.2  perseant 
   2879  1.1.1.1.4.2  perseant 	      off = local_got_offsets[r_symndx] & (~1);
   2880  1.1.1.1.4.2  perseant 
   2881  1.1.1.1.4.2  perseant 	      if (local_got_offsets[r_symndx] == MINUS_ONE)
   2882  1.1.1.1.4.2  perseant 		{
   2883  1.1.1.1.4.2  perseant 		  fatal = (loongarch_reloc_is_fatal
   2884  1.1.1.1.4.2  perseant 			   (info, input_bfd, input_section, rel, howto,
   2885  1.1.1.1.4.2  perseant 			    bfd_reloc_notsupported, is_undefweak, name,
   2886  1.1.1.1.4.2  perseant 			    "Internal: GOT entry doesn't represent."));
   2887  1.1.1.1.4.2  perseant 		  break;
   2888  1.1.1.1.4.2  perseant 		}
   2889  1.1.1.1.4.2  perseant 
   2890  1.1.1.1.4.2  perseant 	      /* The offset must always be a multiple of the word size.
   2891  1.1.1.1.4.2  perseant 		 So, we can use the least significant bit to record
   2892  1.1.1.1.4.2  perseant 		 whether we have already processed this entry.  */
   2893  1.1.1.1.4.2  perseant 	      if ((local_got_offsets[r_symndx] & 1) == 0)
   2894  1.1.1.1.4.2  perseant 		{
   2895  1.1.1.1.4.2  perseant 		  if (is_pic)
   2896  1.1.1.1.4.2  perseant 		    {
   2897  1.1.1.1.4.2  perseant 		      asection *s;
   2898  1.1.1.1.4.2  perseant 		      Elf_Internal_Rela outrel;
   2899  1.1.1.1.4.2  perseant 		      /* We need to generate a R_LARCH_RELATIVE reloc
   2900  1.1.1.1.4.2  perseant 			 for the dynamic linker.  */
   2901  1.1.1.1.4.2  perseant 		      s = htab->elf.srelgot;
   2902  1.1.1.1.4.2  perseant 		      if (!s)
   2903  1.1.1.1.4.2  perseant 			{
   2904  1.1.1.1.4.2  perseant 			  fatal = (loongarch_reloc_is_fatal
   2905  1.1.1.1.4.2  perseant 				   (info, input_bfd, input_section, rel, howto,
   2906  1.1.1.1.4.2  perseant 				    bfd_reloc_notsupported, is_undefweak, name,
   2907  1.1.1.1.4.2  perseant 				    "Internal: '.rel.got' not represent"));
   2908  1.1.1.1.4.2  perseant 			  break;
   2909  1.1.1.1.4.2  perseant 			}
   2910  1.1.1.1.4.2  perseant 
   2911  1.1.1.1.4.2  perseant 		      outrel.r_offset = sec_addr (got) + off;
   2912  1.1.1.1.4.2  perseant 		      outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
   2913  1.1.1.1.4.2  perseant 		      outrel.r_addend = relocation; /* Link-time addr.  */
   2914  1.1.1.1.4.2  perseant 		      loongarch_elf_append_rela (output_bfd, s, &outrel);
   2915  1.1.1.1.4.2  perseant 		    }
   2916  1.1.1.1.4.2  perseant 
   2917  1.1.1.1.4.2  perseant 		  bfd_put_NN (output_bfd, relocation, got->contents + off);
   2918  1.1.1.1.4.2  perseant 		  local_got_offsets[r_symndx] |= 1;
   2919  1.1.1.1.4.2  perseant 		}
   2920  1.1.1.1.4.2  perseant 	    }
   2921  1.1.1.1.4.2  perseant 	  relocation = off;
   2922  1.1.1.1.4.2  perseant 
   2923  1.1.1.1.4.2  perseant 	  break;
   2924  1.1.1.1.4.2  perseant 
   2925  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_TLS_GOT:
   2926  1.1.1.1.4.2  perseant 	case R_LARCH_SOP_PUSH_TLS_GD:
   2927  1.1.1.1.4.2  perseant 	  {
   2928  1.1.1.1.4.2  perseant 	    unresolved_reloc = false;
   2929  1.1.1.1.4.2  perseant 	    if (r_type == R_LARCH_SOP_PUSH_TLS_GOT)
   2930  1.1.1.1.4.2  perseant 	      is_ie = true;
   2931  1.1.1.1.4.2  perseant 
   2932  1.1.1.1.4.2  perseant 	    bfd_vma got_off = 0;
   2933  1.1.1.1.4.2  perseant 	    if (h != NULL)
   2934  1.1.1.1.4.2  perseant 	      {
   2935  1.1.1.1.4.2  perseant 		got_off = h->got.offset;
   2936  1.1.1.1.4.2  perseant 		h->got.offset |= 1;
   2937  1.1.1.1.4.2  perseant 	      }
   2938  1.1.1.1.4.2  perseant 	    else
   2939  1.1.1.1.4.2  perseant 	      {
   2940  1.1.1.1.4.2  perseant 		got_off = local_got_offsets[r_symndx];
   2941  1.1.1.1.4.2  perseant 		local_got_offsets[r_symndx] |= 1;
   2942  1.1.1.1.4.2  perseant 	      }
   2943  1.1.1.1.4.2  perseant 
   2944  1.1.1.1.4.2  perseant 	    BFD_ASSERT (got_off != MINUS_ONE);
   2945  1.1.1.1.4.2  perseant 
   2946  1.1.1.1.4.2  perseant 	    ie_off = 0;
   2947  1.1.1.1.4.2  perseant 	    tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
   2948  1.1.1.1.4.2  perseant 	    if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE))
   2949  1.1.1.1.4.2  perseant 	      ie_off = 2 * GOT_ENTRY_SIZE;
   2950  1.1.1.1.4.2  perseant 
   2951  1.1.1.1.4.2  perseant 	    if ((got_off & 1) == 0)
   2952  1.1.1.1.4.2  perseant 	      {
   2953  1.1.1.1.4.2  perseant 		Elf_Internal_Rela rela;
   2954  1.1.1.1.4.2  perseant 		asection *srel = htab->elf.srelgot;
   2955  1.1.1.1.4.2  perseant 		bfd_vma tls_block_off = 0;
   2956  1.1.1.1.4.2  perseant 
   2957  1.1.1.1.4.2  perseant 		if (SYMBOL_REFERENCES_LOCAL (info, h))
   2958  1.1.1.1.4.2  perseant 		  {
   2959  1.1.1.1.4.2  perseant 		    BFD_ASSERT (elf_hash_table (info)->tls_sec);
   2960  1.1.1.1.4.2  perseant 		    tls_block_off = relocation
   2961  1.1.1.1.4.2  perseant 			- elf_hash_table (info)->tls_sec->vma;
   2962  1.1.1.1.4.2  perseant 		  }
   2963  1.1.1.1.4.2  perseant 
   2964  1.1.1.1.4.2  perseant 		if (tls_type & GOT_TLS_GD)
   2965  1.1.1.1.4.2  perseant 		  {
   2966  1.1.1.1.4.2  perseant 		    rela.r_offset = sec_addr (got) + got_off;
   2967  1.1.1.1.4.2  perseant 		    rela.r_addend = 0;
   2968  1.1.1.1.4.2  perseant 		    if (SYMBOL_REFERENCES_LOCAL (info, h))
   2969  1.1.1.1.4.2  perseant 		      {
   2970  1.1.1.1.4.2  perseant 			/* Local sym, used in exec, set module id 1.  */
   2971  1.1.1.1.4.2  perseant 			if (bfd_link_executable (info))
   2972  1.1.1.1.4.2  perseant 			  bfd_put_NN (output_bfd, 1, got->contents + got_off);
   2973  1.1.1.1.4.2  perseant 			else
   2974  1.1.1.1.4.2  perseant 			  {
   2975  1.1.1.1.4.2  perseant 			    rela.r_info = ELFNN_R_INFO (0,
   2976  1.1.1.1.4.2  perseant 							R_LARCH_TLS_DTPMODNN);
   2977  1.1.1.1.4.2  perseant 			    loongarch_elf_append_rela (output_bfd, srel, &rela);
   2978  1.1.1.1.4.2  perseant 			  }
   2979  1.1.1.1.4.2  perseant 
   2980  1.1.1.1.4.2  perseant 			bfd_put_NN (output_bfd, tls_block_off,
   2981  1.1.1.1.4.2  perseant 				    got->contents + got_off + GOT_ENTRY_SIZE);
   2982  1.1.1.1.4.2  perseant 		      }
   2983  1.1.1.1.4.2  perseant 		    /* Dynamic resolved.  */
   2984  1.1.1.1.4.2  perseant 		    else
   2985  1.1.1.1.4.2  perseant 		      {
   2986  1.1.1.1.4.2  perseant 			/* Dynamic relocate module id.  */
   2987  1.1.1.1.4.2  perseant 			rela.r_info = ELFNN_R_INFO (h->dynindx,
   2988  1.1.1.1.4.2  perseant 						    R_LARCH_TLS_DTPMODNN);
   2989  1.1.1.1.4.2  perseant 			loongarch_elf_append_rela (output_bfd, srel, &rela);
   2990  1.1.1.1.4.2  perseant 
   2991  1.1.1.1.4.2  perseant 			/* Dynamic relocate offset of block.  */
   2992  1.1.1.1.4.2  perseant 			rela.r_offset += GOT_ENTRY_SIZE;
   2993  1.1.1.1.4.2  perseant 			rela.r_info = ELFNN_R_INFO (h->dynindx,
   2994  1.1.1.1.4.2  perseant 						    R_LARCH_TLS_DTPRELNN);
   2995  1.1.1.1.4.2  perseant 			loongarch_elf_append_rela (output_bfd, srel, &rela);
   2996  1.1.1.1.4.2  perseant 		      }
   2997  1.1.1.1.4.2  perseant 		  }
   2998  1.1.1.1.4.2  perseant 		if (tls_type & GOT_TLS_IE)
   2999  1.1.1.1.4.2  perseant 		  {
   3000  1.1.1.1.4.2  perseant 		    rela.r_offset = sec_addr (got) + got_off + ie_off;
   3001  1.1.1.1.4.2  perseant 		    if (SYMBOL_REFERENCES_LOCAL (info, h))
   3002  1.1.1.1.4.2  perseant 		      {
   3003  1.1.1.1.4.2  perseant 			/* Local sym, used in exec, set module id 1.  */
   3004  1.1.1.1.4.2  perseant 			if (!bfd_link_executable (info))
   3005  1.1.1.1.4.2  perseant 			  {
   3006  1.1.1.1.4.2  perseant 			    rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN);
   3007  1.1.1.1.4.2  perseant 			    rela.r_addend = tls_block_off;
   3008  1.1.1.1.4.2  perseant 			    loongarch_elf_append_rela (output_bfd, srel, &rela);
   3009  1.1.1.1.4.2  perseant 			  }
   3010  1.1.1.1.4.2  perseant 
   3011  1.1.1.1.4.2  perseant 			bfd_put_NN (output_bfd, tls_block_off,
   3012  1.1.1.1.4.2  perseant 				    got->contents + got_off + ie_off);
   3013  1.1.1.1.4.2  perseant 		      }
   3014  1.1.1.1.4.2  perseant 		    /* Dynamic resolved.  */
   3015  1.1.1.1.4.2  perseant 		    else
   3016  1.1.1.1.4.2  perseant 		      {
   3017  1.1.1.1.4.2  perseant 			/* Dynamic relocate offset of block.  */
   3018  1.1.1.1.4.2  perseant 			rela.r_info = ELFNN_R_INFO (h->dynindx,
   3019  1.1.1.1.4.2  perseant 						    R_LARCH_TLS_TPRELNN);
   3020  1.1.1.1.4.2  perseant 			rela.r_addend = 0;
   3021  1.1.1.1.4.2  perseant 			loongarch_elf_append_rela (output_bfd, srel, &rela);
   3022  1.1.1.1.4.2  perseant 		      }
   3023  1.1.1.1.4.2  perseant 		  }
   3024  1.1.1.1.4.2  perseant 	      }
   3025  1.1.1.1.4.2  perseant 
   3026  1.1.1.1.4.2  perseant 	    relocation = (got_off & (~(bfd_vma)1)) + (is_ie ? ie_off : 0);
   3027  1.1.1.1.4.2  perseant 	  }
   3028  1.1.1.1.4.2  perseant 	  break;
   3029  1.1.1.1.4.2  perseant 
   3030  1.1.1.1.4.2  perseant 	/* New reloc types.  */
   3031  1.1.1.1.4.2  perseant 	case R_LARCH_B21:
   3032  1.1.1.1.4.2  perseant 	case R_LARCH_B26:
   3033  1.1.1.1.4.2  perseant 	case R_LARCH_B16:
   3034  1.1.1.1.4.2  perseant 	  unresolved_reloc = false;
   3035  1.1.1.1.4.2  perseant 	  if (is_undefweak)
   3036  1.1.1.1.4.2  perseant 	    {
   3037  1.1.1.1.4.2  perseant 	      relocation = 0;
   3038  1.1.1.1.4.2  perseant 	    }
   3039  1.1.1.1.4.2  perseant 
   3040  1.1.1.1.4.2  perseant 	  if (resolved_local)
   3041  1.1.1.1.4.2  perseant 	    {
   3042  1.1.1.1.4.2  perseant 	      relocation -= pc;
   3043  1.1.1.1.4.2  perseant 	      relocation += rel->r_addend;
   3044  1.1.1.1.4.2  perseant 	    }
   3045  1.1.1.1.4.2  perseant 	  else if (resolved_dynly)
   3046  1.1.1.1.4.2  perseant 	    {
   3047  1.1.1.1.4.2  perseant 	      BFD_ASSERT (h
   3048  1.1.1.1.4.2  perseant 			  && (h->plt.offset != MINUS_ONE
   3049  1.1.1.1.4.2  perseant 			      || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
   3050  1.1.1.1.4.2  perseant 			  && rel->r_addend == 0);
   3051  1.1.1.1.4.2  perseant 	      if (h && h->plt.offset == MINUS_ONE
   3052  1.1.1.1.4.2  perseant 		  && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
   3053  1.1.1.1.4.2  perseant 		{
   3054  1.1.1.1.4.2  perseant 		  relocation -= pc;
   3055  1.1.1.1.4.2  perseant 		  relocation += rel->r_addend;
   3056  1.1.1.1.4.2  perseant 		}
   3057  1.1.1.1.4.2  perseant 	      else
   3058  1.1.1.1.4.2  perseant 		relocation = sec_addr (plt) + h->plt.offset - pc;
   3059  1.1.1.1.4.2  perseant 	    }
   3060  1.1.1.1.4.2  perseant 
   3061  1.1.1.1.4.2  perseant 	  break;
   3062  1.1.1.1.4.2  perseant 
   3063  1.1.1.1.4.2  perseant 	case R_LARCH_ABS_HI20:
   3064  1.1.1.1.4.2  perseant 	case R_LARCH_ABS_LO12:
   3065  1.1.1.1.4.2  perseant 	case R_LARCH_ABS64_LO20:
   3066  1.1.1.1.4.2  perseant 	case R_LARCH_ABS64_HI12:
   3067  1.1.1.1.4.2  perseant 	  BFD_ASSERT (!is_pic);
   3068  1.1.1.1.4.2  perseant 
   3069  1.1.1.1.4.2  perseant 	  if (is_undefweak)
   3070  1.1.1.1.4.2  perseant 	    {
   3071  1.1.1.1.4.2  perseant 	      BFD_ASSERT (resolved_dynly);
   3072  1.1.1.1.4.2  perseant 	      relocation = 0;
   3073  1.1.1.1.4.2  perseant 	      break;
   3074  1.1.1.1.4.2  perseant 	    }
   3075  1.1.1.1.4.2  perseant 	  else if (resolved_to_const || resolved_local)
   3076  1.1.1.1.4.2  perseant 	    {
   3077  1.1.1.1.4.2  perseant 	      relocation += rel->r_addend;
   3078  1.1.1.1.4.2  perseant 	    }
   3079  1.1.1.1.4.2  perseant 	  else if (resolved_dynly)
   3080  1.1.1.1.4.2  perseant 	    {
   3081  1.1.1.1.4.2  perseant 	      unresolved_reloc = false;
   3082  1.1.1.1.4.2  perseant 	      BFD_ASSERT ((plt && h && h->plt.offset != MINUS_ONE)
   3083  1.1.1.1.4.2  perseant 			  && rel->r_addend == 0);
   3084  1.1.1.1.4.2  perseant 	      relocation = sec_addr (plt) + h->plt.offset;
   3085  1.1.1.1.4.2  perseant 	    }
   3086  1.1.1.1.4.2  perseant 
   3087  1.1.1.1.4.2  perseant 	  break;
   3088  1.1.1.1.4.2  perseant 
   3089  1.1.1.1.4.2  perseant 	case R_LARCH_PCALA_HI20:
   3090  1.1.1.1.4.2  perseant 	  unresolved_reloc = false;
   3091  1.1.1.1.4.2  perseant 	  if (h && h->plt.offset != MINUS_ONE)
   3092  1.1.1.1.4.2  perseant 	    relocation = sec_addr (plt) + h->plt.offset;
   3093  1.1.1.1.4.2  perseant 	  else
   3094  1.1.1.1.4.2  perseant 	    relocation += rel->r_addend;
   3095  1.1.1.1.4.2  perseant 
   3096  1.1.1.1.4.2  perseant 	  RELOCATE_CALC_PC32_HI20 (relocation, pc);
   3097  1.1.1.1.4.2  perseant 
   3098  1.1.1.1.4.2  perseant 	  break;
   3099  1.1.1.1.4.2  perseant 
   3100  1.1.1.1.4.2  perseant 	case R_LARCH_PCALA_LO12:
   3101  1.1.1.1.4.2  perseant 	  /* Not support if sym_addr in 2k page edge.
   3102  1.1.1.1.4.2  perseant 	     pcalau12i pc_hi20 (sym_addr)
   3103  1.1.1.1.4.2  perseant 	     ld.w/d pc_lo12 (sym_addr)
   3104  1.1.1.1.4.2  perseant 	     ld.w/d pc_lo12 (sym_addr + x)
   3105  1.1.1.1.4.2  perseant 	     ...
   3106  1.1.1.1.4.2  perseant 	     can not calc correct address
   3107  1.1.1.1.4.2  perseant 	     if sym_addr < 0x800 && sym_addr + x >= 0x800.  */
   3108  1.1.1.1.4.2  perseant 
   3109  1.1.1.1.4.2  perseant 	  if (h && h->plt.offset != MINUS_ONE)
   3110  1.1.1.1.4.2  perseant 	    relocation = sec_addr (plt) + h->plt.offset;
   3111  1.1.1.1.4.2  perseant 	  else
   3112  1.1.1.1.4.2  perseant 	    relocation += rel->r_addend;
   3113  1.1.1.1.4.2  perseant 
   3114  1.1.1.1.4.2  perseant 	  relocation &= 0xfff;
   3115  1.1.1.1.4.2  perseant 	  /* Signed extend.  */
   3116  1.1.1.1.4.2  perseant 	  relocation = (relocation ^ 0x800) - 0x800;
   3117  1.1.1.1.4.2  perseant 
   3118  1.1.1.1.4.2  perseant 	  /* For 2G jump, generate pcalau12i, jirl.  */
   3119  1.1.1.1.4.2  perseant 	  /* If use jirl, turns to R_LARCH_B16.  */
   3120  1.1.1.1.4.2  perseant 	  uint32_t insn = bfd_get (32, input_bfd, contents + rel->r_offset);
   3121  1.1.1.1.4.2  perseant 	  if ((insn & 0x4c000000) == 0x4c000000)
   3122  1.1.1.1.4.2  perseant 	    {
   3123  1.1.1.1.4.2  perseant 	      rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_B16);
   3124  1.1.1.1.4.2  perseant 	      howto = loongarch_elf_rtype_to_howto (input_bfd, R_LARCH_B16);
   3125  1.1.1.1.4.2  perseant 	    }
   3126  1.1.1.1.4.2  perseant 	  break;
   3127  1.1.1.1.4.2  perseant 
   3128  1.1.1.1.4.2  perseant 	case R_LARCH_PCALA64_LO20:
   3129  1.1.1.1.4.2  perseant 	case R_LARCH_PCALA64_HI12:
   3130  1.1.1.1.4.2  perseant 	  if (h && h->plt.offset != MINUS_ONE)
   3131  1.1.1.1.4.2  perseant 	    relocation = sec_addr (plt) + h->plt.offset;
   3132  1.1.1.1.4.2  perseant 	  else
   3133  1.1.1.1.4.2  perseant 	    relocation += rel->r_addend;
   3134  1.1.1.1.4.2  perseant 
   3135  1.1.1.1.4.2  perseant 	  RELOCATE_CALC_PC64_HI32 (relocation, pc);
   3136  1.1.1.1.4.2  perseant 
   3137  1.1.1.1.4.2  perseant 	  break;
   3138  1.1.1.1.4.2  perseant 
   3139  1.1.1.1.4.2  perseant 	case R_LARCH_GOT_PC_HI20:
   3140  1.1.1.1.4.2  perseant 	case R_LARCH_GOT_HI20:
   3141  1.1.1.1.4.2  perseant 	  /* Calc got offset.  */
   3142  1.1.1.1.4.2  perseant 	    {
   3143  1.1.1.1.4.2  perseant 	      unresolved_reloc = false;
   3144  1.1.1.1.4.2  perseant 	      BFD_ASSERT (rel->r_addend == 0);
   3145  1.1.1.1.4.2  perseant 
   3146  1.1.1.1.4.2  perseant 	      bfd_vma got_off = 0;
   3147  1.1.1.1.4.2  perseant 	      if (h != NULL)
   3148  1.1.1.1.4.2  perseant 		{
   3149  1.1.1.1.4.2  perseant 		  /* GOT ref or ifunc.  */
   3150  1.1.1.1.4.2  perseant 		  BFD_ASSERT (h->got.offset != MINUS_ONE
   3151  1.1.1.1.4.2  perseant 			      || h->type == STT_GNU_IFUNC);
   3152  1.1.1.1.4.2  perseant 
   3153  1.1.1.1.4.2  perseant 		  got_off = h->got.offset  & (~(bfd_vma)1);
   3154  1.1.1.1.4.2  perseant 		  /* Hidden symbol not has got entry,
   3155  1.1.1.1.4.2  perseant 		   * only got.plt entry so it is (plt - got).  */
   3156  1.1.1.1.4.2  perseant 		  if (h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
   3157  1.1.1.1.4.2  perseant 		    {
   3158  1.1.1.1.4.2  perseant 		      bfd_vma idx;
   3159  1.1.1.1.4.2  perseant 		      if (htab->elf.splt != NULL)
   3160  1.1.1.1.4.2  perseant 			{
   3161  1.1.1.1.4.2  perseant 			  idx = (h->plt.offset - PLT_HEADER_SIZE)
   3162  1.1.1.1.4.2  perseant 			    / PLT_ENTRY_SIZE;
   3163  1.1.1.1.4.2  perseant 			  got_off = sec_addr (htab->elf.sgotplt)
   3164  1.1.1.1.4.2  perseant 			    + GOTPLT_HEADER_SIZE
   3165  1.1.1.1.4.2  perseant 			    + (idx * GOT_ENTRY_SIZE)
   3166  1.1.1.1.4.2  perseant 			    - sec_addr (htab->elf.sgot);
   3167  1.1.1.1.4.2  perseant 			}
   3168  1.1.1.1.4.2  perseant 		      else
   3169  1.1.1.1.4.2  perseant 			{
   3170  1.1.1.1.4.2  perseant 			  idx = h->plt.offset / PLT_ENTRY_SIZE;
   3171  1.1.1.1.4.2  perseant 			  got_off = sec_addr (htab->elf.sgotplt)
   3172  1.1.1.1.4.2  perseant 			    + (idx * GOT_ENTRY_SIZE)
   3173  1.1.1.1.4.2  perseant 			    - sec_addr (htab->elf.sgot);
   3174  1.1.1.1.4.2  perseant 			}
   3175  1.1.1.1.4.2  perseant 		    }
   3176  1.1.1.1.4.2  perseant 
   3177  1.1.1.1.4.2  perseant 		  if ((h->got.offset & 1) == 0)
   3178  1.1.1.1.4.2  perseant 		    {
   3179  1.1.1.1.4.2  perseant 		      /* We need to generate a R_LARCH_RELATIVE reloc once
   3180  1.1.1.1.4.2  perseant 		       * in loongarch_elf_finish_dynamic_symbol or now,
   3181  1.1.1.1.4.2  perseant 		       * call finish_dyn && nopic
   3182  1.1.1.1.4.2  perseant 		       * or !call finish_dyn && pic.  */
   3183  1.1.1.1.4.2  perseant 		      if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn,
   3184  1.1.1.1.4.2  perseant 							    bfd_link_pic (info),
   3185  1.1.1.1.4.2  perseant 							    h)
   3186  1.1.1.1.4.2  perseant 			  && bfd_link_pic (info)
   3187  1.1.1.1.4.2  perseant 			  && SYMBOL_REFERENCES_LOCAL (info, h))
   3188  1.1.1.1.4.2  perseant 			{
   3189  1.1.1.1.4.2  perseant 			  Elf_Internal_Rela rela;
   3190  1.1.1.1.4.2  perseant 			  rela.r_offset = sec_addr (got) + got_off;
   3191  1.1.1.1.4.2  perseant 			  rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
   3192  1.1.1.1.4.2  perseant 			  rela.r_addend = relocation;
   3193  1.1.1.1.4.2  perseant 			  loongarch_elf_append_rela (output_bfd,
   3194  1.1.1.1.4.2  perseant 						     htab->elf.srelgot, &rela);
   3195  1.1.1.1.4.2  perseant 			}
   3196  1.1.1.1.4.2  perseant 		      h->got.offset |= 1;
   3197  1.1.1.1.4.2  perseant 		      bfd_put_NN (output_bfd, relocation,
   3198  1.1.1.1.4.2  perseant 				  got->contents + got_off);
   3199  1.1.1.1.4.2  perseant 		    }
   3200  1.1.1.1.4.2  perseant 		}
   3201  1.1.1.1.4.2  perseant 	      else
   3202  1.1.1.1.4.2  perseant 		{
   3203  1.1.1.1.4.2  perseant 		  BFD_ASSERT (local_got_offsets
   3204  1.1.1.1.4.2  perseant 			      && local_got_offsets[r_symndx] != MINUS_ONE);
   3205  1.1.1.1.4.2  perseant 
   3206  1.1.1.1.4.2  perseant 		  got_off = local_got_offsets[r_symndx] & (~(bfd_vma)1);
   3207  1.1.1.1.4.2  perseant 		  if ((local_got_offsets[r_symndx] & 1) == 0)
   3208  1.1.1.1.4.2  perseant 		    {
   3209  1.1.1.1.4.2  perseant 		      if (bfd_link_pic (info))
   3210  1.1.1.1.4.2  perseant 			{
   3211  1.1.1.1.4.2  perseant 			  Elf_Internal_Rela rela;
   3212  1.1.1.1.4.2  perseant 			  rela.r_offset = sec_addr (got) + got_off;
   3213  1.1.1.1.4.2  perseant 			  rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
   3214  1.1.1.1.4.2  perseant 			  rela.r_addend = relocation;
   3215  1.1.1.1.4.2  perseant 			  loongarch_elf_append_rela (output_bfd,
   3216  1.1.1.1.4.2  perseant 						     htab->elf.srelgot, &rela);
   3217  1.1.1.1.4.2  perseant 			}
   3218  1.1.1.1.4.2  perseant 		      local_got_offsets[r_symndx] |= 1;
   3219  1.1.1.1.4.2  perseant 		    }
   3220  1.1.1.1.4.2  perseant 		  bfd_put_NN (output_bfd, relocation, got->contents + got_off);
   3221  1.1.1.1.4.2  perseant 		}
   3222  1.1.1.1.4.2  perseant 
   3223  1.1.1.1.4.2  perseant 	      relocation = got_off + sec_addr (got);
   3224  1.1.1.1.4.2  perseant 	    }
   3225  1.1.1.1.4.2  perseant 
   3226  1.1.1.1.4.2  perseant 	  if (r_type == R_LARCH_GOT_PC_HI20)
   3227  1.1.1.1.4.2  perseant 	    RELOCATE_CALC_PC32_HI20 (relocation, pc);
   3228  1.1.1.1.4.2  perseant 
   3229  1.1.1.1.4.2  perseant 	  break;
   3230  1.1.1.1.4.2  perseant 
   3231  1.1.1.1.4.2  perseant 	case R_LARCH_GOT_PC_LO12:
   3232  1.1.1.1.4.2  perseant 	case R_LARCH_GOT64_PC_LO20:
   3233  1.1.1.1.4.2  perseant 	case R_LARCH_GOT64_PC_HI12:
   3234  1.1.1.1.4.2  perseant 	case R_LARCH_GOT_LO12:
   3235  1.1.1.1.4.2  perseant 	case R_LARCH_GOT64_LO20:
   3236  1.1.1.1.4.2  perseant 	case R_LARCH_GOT64_HI12:
   3237  1.1.1.1.4.2  perseant 	    {
   3238  1.1.1.1.4.2  perseant 	      unresolved_reloc = false;
   3239  1.1.1.1.4.2  perseant 	      bfd_vma got_off;
   3240  1.1.1.1.4.2  perseant 	      if (h)
   3241  1.1.1.1.4.2  perseant 		got_off = h->got.offset & (~(bfd_vma)1);
   3242  1.1.1.1.4.2  perseant 	      else
   3243  1.1.1.1.4.2  perseant 		got_off = local_got_offsets[r_symndx] & (~(bfd_vma)1);
   3244  1.1.1.1.4.2  perseant 
   3245  1.1.1.1.4.2  perseant 	      if (h && h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
   3246  1.1.1.1.4.2  perseant 		{
   3247  1.1.1.1.4.2  perseant 		  bfd_vma idx;
   3248  1.1.1.1.4.2  perseant 		  if (htab->elf.splt != NULL)
   3249  1.1.1.1.4.2  perseant 		    idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
   3250  1.1.1.1.4.2  perseant 		  else
   3251  1.1.1.1.4.2  perseant 		    idx = h->plt.offset / PLT_ENTRY_SIZE;
   3252  1.1.1.1.4.2  perseant 
   3253  1.1.1.1.4.2  perseant 		  got_off = sec_addr (htab->elf.sgotplt)
   3254  1.1.1.1.4.2  perseant 		    + GOTPLT_HEADER_SIZE
   3255  1.1.1.1.4.2  perseant 		    + (idx * GOT_ENTRY_SIZE)
   3256  1.1.1.1.4.2  perseant 		    - sec_addr (htab->elf.sgot);
   3257  1.1.1.1.4.2  perseant 		}
   3258  1.1.1.1.4.2  perseant 	      relocation = got_off + sec_addr (got);
   3259  1.1.1.1.4.2  perseant 	    }
   3260  1.1.1.1.4.2  perseant 
   3261  1.1.1.1.4.2  perseant 	  if (r_type == R_LARCH_GOT_PC_LO12)
   3262  1.1.1.1.4.2  perseant 	    relocation &= (bfd_vma)0xfff;
   3263  1.1.1.1.4.2  perseant 	  else if (r_type == R_LARCH_GOT64_PC_LO20
   3264  1.1.1.1.4.2  perseant 		   || r_type == R_LARCH_GOT64_PC_HI12)
   3265  1.1.1.1.4.2  perseant 	    RELOCATE_CALC_PC64_HI32 (relocation, pc);
   3266  1.1.1.1.4.2  perseant 
   3267  1.1.1.1.4.2  perseant 	  break;
   3268  1.1.1.1.4.2  perseant 
   3269  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LE_HI20:
   3270  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LE_LO12:
   3271  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LE64_LO20:
   3272  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LE64_HI12:
   3273  1.1.1.1.4.2  perseant 	  BFD_ASSERT (resolved_local && elf_hash_table (info)->tls_sec);
   3274  1.1.1.1.4.2  perseant 
   3275  1.1.1.1.4.2  perseant 	  relocation -= elf_hash_table (info)->tls_sec->vma;
   3276  1.1.1.1.4.2  perseant 	  break;
   3277  1.1.1.1.4.2  perseant 
   3278  1.1.1.1.4.2  perseant 	/* TLS IE LD/GD process separately is troublesome.
   3279  1.1.1.1.4.2  perseant 	   When a symbol is both ie and LD/GD, h->got.off |= 1
   3280  1.1.1.1.4.2  perseant 	   make only one type be relocated.  We must use
   3281  1.1.1.1.4.2  perseant 	   h->got.offset |= 1 and h->got.offset |= 2
   3282  1.1.1.1.4.2  perseant 	   diff IE and LD/GD.  And all (got_off & (~(bfd_vma)1))
   3283  1.1.1.1.4.2  perseant 	   (IE LD/GD and reusable GOT reloc) must change to
   3284  1.1.1.1.4.2  perseant 	   (got_off & (~(bfd_vma)3)), beause we use lowest 2 bits
   3285  1.1.1.1.4.2  perseant 	   as a tag.
   3286  1.1.1.1.4.2  perseant 	   Now, LD and GD is both GOT_TLS_GD type, LD seems to
   3287  1.1.1.1.4.2  perseant 	   can be omitted.  */
   3288  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE_PC_HI20:
   3289  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE_HI20:
   3290  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LD_PC_HI20:
   3291  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_LD_HI20:
   3292  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_GD_PC_HI20:
   3293  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_GD_HI20:
   3294  1.1.1.1.4.2  perseant 	  BFD_ASSERT (rel->r_addend == 0);
   3295  1.1.1.1.4.2  perseant 	  unresolved_reloc = false;
   3296  1.1.1.1.4.2  perseant 
   3297  1.1.1.1.4.2  perseant 	  if (r_type == R_LARCH_TLS_IE_PC_HI20
   3298  1.1.1.1.4.2  perseant 	      || r_type == R_LARCH_TLS_IE_HI20)
   3299  1.1.1.1.4.2  perseant 	    is_ie = true;
   3300  1.1.1.1.4.2  perseant 
   3301  1.1.1.1.4.2  perseant 	  bfd_vma got_off = 0;
   3302  1.1.1.1.4.2  perseant 	  if (h != NULL)
   3303  1.1.1.1.4.2  perseant 	    {
   3304  1.1.1.1.4.2  perseant 	      got_off = h->got.offset;
   3305  1.1.1.1.4.2  perseant 	      h->got.offset |= 1;
   3306  1.1.1.1.4.2  perseant 	    }
   3307  1.1.1.1.4.2  perseant 	  else
   3308  1.1.1.1.4.2  perseant 	    {
   3309  1.1.1.1.4.2  perseant 	      got_off = local_got_offsets[r_symndx];
   3310  1.1.1.1.4.2  perseant 	      local_got_offsets[r_symndx] |= 1;
   3311  1.1.1.1.4.2  perseant 	    }
   3312  1.1.1.1.4.2  perseant 
   3313  1.1.1.1.4.2  perseant 	  BFD_ASSERT (got_off != MINUS_ONE);
   3314  1.1.1.1.4.2  perseant 
   3315  1.1.1.1.4.2  perseant 	  ie_off = 0;
   3316  1.1.1.1.4.2  perseant 	  tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
   3317  1.1.1.1.4.2  perseant 	  if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE))
   3318  1.1.1.1.4.2  perseant 	    ie_off = 2 * GOT_ENTRY_SIZE;
   3319  1.1.1.1.4.2  perseant 
   3320  1.1.1.1.4.2  perseant 	  if ((got_off & 1) == 0)
   3321  1.1.1.1.4.2  perseant 	    {
   3322  1.1.1.1.4.2  perseant 	      Elf_Internal_Rela rela;
   3323  1.1.1.1.4.2  perseant 	      asection *relgot = htab->elf.srelgot;
   3324  1.1.1.1.4.2  perseant 	      bfd_vma tls_block_off = 0;
   3325  1.1.1.1.4.2  perseant 
   3326  1.1.1.1.4.2  perseant 	      if (SYMBOL_REFERENCES_LOCAL (info, h))
   3327  1.1.1.1.4.2  perseant 		{
   3328  1.1.1.1.4.2  perseant 		  BFD_ASSERT (elf_hash_table (info)->tls_sec);
   3329  1.1.1.1.4.2  perseant 		  tls_block_off = relocation
   3330  1.1.1.1.4.2  perseant 		      - elf_hash_table (info)->tls_sec->vma;
   3331  1.1.1.1.4.2  perseant 		}
   3332  1.1.1.1.4.2  perseant 
   3333  1.1.1.1.4.2  perseant 	      if (tls_type & GOT_TLS_GD)
   3334  1.1.1.1.4.2  perseant 		{
   3335  1.1.1.1.4.2  perseant 		  rela.r_offset = sec_addr (got) + got_off;
   3336  1.1.1.1.4.2  perseant 		  rela.r_addend = 0;
   3337  1.1.1.1.4.2  perseant 		  if (SYMBOL_REFERENCES_LOCAL (info, h))
   3338  1.1.1.1.4.2  perseant 		    {
   3339  1.1.1.1.4.2  perseant 		      /* Local sym, used in exec, set module id 1.  */
   3340  1.1.1.1.4.2  perseant 		      if (bfd_link_executable (info))
   3341  1.1.1.1.4.2  perseant 			bfd_put_NN (output_bfd, 1, got->contents + got_off);
   3342  1.1.1.1.4.2  perseant 		      else
   3343  1.1.1.1.4.2  perseant 			{
   3344  1.1.1.1.4.2  perseant 			  rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_DTPMODNN);
   3345  1.1.1.1.4.2  perseant 			  loongarch_elf_append_rela (output_bfd, relgot, &rela);
   3346  1.1.1.1.4.2  perseant 			}
   3347  1.1.1.1.4.2  perseant 
   3348  1.1.1.1.4.2  perseant 		      bfd_put_NN (output_bfd, tls_block_off,
   3349  1.1.1.1.4.2  perseant 				  got->contents + got_off + GOT_ENTRY_SIZE);
   3350  1.1.1.1.4.2  perseant 		    }
   3351  1.1.1.1.4.2  perseant 		  /* Dynamic resolved.  */
   3352  1.1.1.1.4.2  perseant 		  else
   3353  1.1.1.1.4.2  perseant 		    {
   3354  1.1.1.1.4.2  perseant 		      /* Dynamic relocate module id.  */
   3355  1.1.1.1.4.2  perseant 		      rela.r_info = ELFNN_R_INFO (h->dynindx,
   3356  1.1.1.1.4.2  perseant 						  R_LARCH_TLS_DTPMODNN);
   3357  1.1.1.1.4.2  perseant 		      loongarch_elf_append_rela (output_bfd, relgot, &rela);
   3358  1.1.1.1.4.2  perseant 
   3359  1.1.1.1.4.2  perseant 		      /* Dynamic relocate offset of block.  */
   3360  1.1.1.1.4.2  perseant 		      rela.r_offset += GOT_ENTRY_SIZE;
   3361  1.1.1.1.4.2  perseant 		      rela.r_info = ELFNN_R_INFO (h->dynindx,
   3362  1.1.1.1.4.2  perseant 						  R_LARCH_TLS_DTPRELNN);
   3363  1.1.1.1.4.2  perseant 		      loongarch_elf_append_rela (output_bfd, relgot, &rela);
   3364  1.1.1.1.4.2  perseant 		    }
   3365  1.1.1.1.4.2  perseant 		}
   3366  1.1.1.1.4.2  perseant 	      if (tls_type & GOT_TLS_IE)
   3367  1.1.1.1.4.2  perseant 		{
   3368  1.1.1.1.4.2  perseant 		  rela.r_offset = sec_addr (got) + got_off + ie_off;
   3369  1.1.1.1.4.2  perseant 		  if (SYMBOL_REFERENCES_LOCAL (info, h))
   3370  1.1.1.1.4.2  perseant 		    {
   3371  1.1.1.1.4.2  perseant 		      /* Local sym, used in exec, set module id 1.  */
   3372  1.1.1.1.4.2  perseant 		      if (!bfd_link_executable (info))
   3373  1.1.1.1.4.2  perseant 			{
   3374  1.1.1.1.4.2  perseant 			  rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN);
   3375  1.1.1.1.4.2  perseant 			  rela.r_addend = tls_block_off;
   3376  1.1.1.1.4.2  perseant 			  loongarch_elf_append_rela (output_bfd, relgot, &rela);
   3377  1.1.1.1.4.2  perseant 			}
   3378  1.1.1.1.4.2  perseant 
   3379  1.1.1.1.4.2  perseant 		      bfd_put_NN (output_bfd, tls_block_off,
   3380  1.1.1.1.4.2  perseant 				  got->contents + got_off + ie_off);
   3381  1.1.1.1.4.2  perseant 		    }
   3382  1.1.1.1.4.2  perseant 		  /* Dynamic resolved.  */
   3383  1.1.1.1.4.2  perseant 		  else
   3384  1.1.1.1.4.2  perseant 		    {
   3385  1.1.1.1.4.2  perseant 		      /* Dynamic relocate offset of block.  */
   3386  1.1.1.1.4.2  perseant 		      rela.r_info = ELFNN_R_INFO (h->dynindx,
   3387  1.1.1.1.4.2  perseant 						  R_LARCH_TLS_TPRELNN);
   3388  1.1.1.1.4.2  perseant 		      rela.r_addend = 0;
   3389  1.1.1.1.4.2  perseant 		      loongarch_elf_append_rela (output_bfd, relgot, &rela);
   3390  1.1.1.1.4.2  perseant 		    }
   3391  1.1.1.1.4.2  perseant 		}
   3392  1.1.1.1.4.2  perseant 	    }
   3393  1.1.1.1.4.2  perseant 	  relocation = (got_off & (~(bfd_vma)1)) + sec_addr (got)
   3394  1.1.1.1.4.2  perseant 			+ (is_ie ? ie_off : 0);
   3395  1.1.1.1.4.2  perseant 
   3396  1.1.1.1.4.2  perseant 	  if (r_type == R_LARCH_TLS_LD_PC_HI20
   3397  1.1.1.1.4.2  perseant 	      || r_type == R_LARCH_TLS_GD_PC_HI20
   3398  1.1.1.1.4.2  perseant 	      || r_type == R_LARCH_TLS_IE_PC_HI20)
   3399  1.1.1.1.4.2  perseant 	    RELOCATE_CALC_PC32_HI20 (relocation, pc);
   3400  1.1.1.1.4.2  perseant 
   3401  1.1.1.1.4.2  perseant 	  break;
   3402  1.1.1.1.4.2  perseant 
   3403  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE_PC_LO12:
   3404  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE64_PC_LO20:
   3405  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE64_PC_HI12:
   3406  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE_LO12:
   3407  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE64_LO20:
   3408  1.1.1.1.4.2  perseant 	case R_LARCH_TLS_IE64_HI12:
   3409  1.1.1.1.4.2  perseant 	  unresolved_reloc = false;
   3410  1.1.1.1.4.2  perseant 
   3411  1.1.1.1.4.2  perseant 	  if (h)
   3412  1.1.1.1.4.2  perseant 	    relocation = sec_addr (got) + (h->got.offset & (~(bfd_vma)3));
   3413  1.1.1.1.4.2  perseant 	  else
   3414  1.1.1.1.4.2  perseant 	    relocation = sec_addr (got)
   3415  1.1.1.1.4.2  perseant 	      + (local_got_offsets[r_symndx] & (~(bfd_vma)3));
   3416  1.1.1.1.4.2  perseant 
   3417  1.1.1.1.4.2  perseant 	  tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
   3418  1.1.1.1.4.2  perseant 	  /* Use both TLS_GD and TLS_IE.  */
   3419  1.1.1.1.4.2  perseant 	  if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE))
   3420  1.1.1.1.4.2  perseant 	    relocation += 2 * GOT_ENTRY_SIZE;
   3421  1.1.1.1.4.2  perseant 
   3422  1.1.1.1.4.2  perseant 	  if (r_type == R_LARCH_TLS_IE_PC_LO12)
   3423  1.1.1.1.4.2  perseant 	    relocation &= (bfd_vma)0xfff;
   3424  1.1.1.1.4.2  perseant 	  else if (r_type == R_LARCH_TLS_IE64_PC_LO20
   3425  1.1.1.1.4.2  perseant 		   || r_type == R_LARCH_TLS_IE64_PC_HI12)
   3426  1.1.1.1.4.2  perseant 	    RELOCATE_CALC_PC64_HI32 (relocation, pc);
   3427  1.1.1.1.4.2  perseant 
   3428  1.1.1.1.4.2  perseant 	  break;
   3429  1.1.1.1.4.2  perseant 
   3430  1.1.1.1.4.2  perseant 	case R_LARCH_RELAX:
   3431  1.1.1.1.4.2  perseant 	  break;
   3432  1.1.1.1.4.2  perseant 
   3433  1.1.1.1.4.2  perseant 	default:
   3434  1.1.1.1.4.2  perseant 	  break;
   3435  1.1.1.1.4.2  perseant 	}
   3436  1.1.1.1.4.2  perseant 
   3437  1.1.1.1.4.2  perseant       if (fatal)
   3438  1.1.1.1.4.2  perseant 	break;
   3439  1.1.1.1.4.2  perseant 
   3440  1.1.1.1.4.2  perseant       do
   3441  1.1.1.1.4.2  perseant 	{
   3442  1.1.1.1.4.2  perseant 	  /* 'unresolved_reloc' means we haven't done it yet.
   3443  1.1.1.1.4.2  perseant 	     We need help of dynamic linker to fix this memory location up.  */
   3444  1.1.1.1.4.2  perseant 	  if (!unresolved_reloc)
   3445  1.1.1.1.4.2  perseant 	    break;
   3446  1.1.1.1.4.2  perseant 
   3447  1.1.1.1.4.2  perseant 	  if (_bfd_elf_section_offset (output_bfd, info, input_section,
   3448  1.1.1.1.4.2  perseant 				       rel->r_offset) == MINUS_ONE)
   3449  1.1.1.1.4.2  perseant 	    /* WHY? May because it's invalid so skip checking.
   3450  1.1.1.1.4.2  perseant 	       But why dynamic reloc a invalid section?  */
   3451  1.1.1.1.4.2  perseant 	    break;
   3452  1.1.1.1.4.2  perseant 
   3453  1.1.1.1.4.2  perseant 	  if (input_section->output_section->flags & SEC_DEBUGGING)
   3454  1.1.1.1.4.2  perseant 	    {
   3455  1.1.1.1.4.2  perseant 	      fatal = (loongarch_reloc_is_fatal
   3456  1.1.1.1.4.2  perseant 		       (info, input_bfd, input_section, rel, howto,
   3457  1.1.1.1.4.2  perseant 			bfd_reloc_dangerous, is_undefweak, name,
   3458  1.1.1.1.4.2  perseant 			"Seems dynamic linker not process "
   3459  1.1.1.1.4.2  perseant 			"sections 'SEC_DEBUGGING'."));
   3460  1.1.1.1.4.2  perseant 	    }
   3461  1.1.1.1.4.2  perseant 	  if (!is_dyn)
   3462  1.1.1.1.4.2  perseant 	    break;
   3463  1.1.1.1.4.2  perseant 
   3464  1.1.1.1.4.2  perseant 	  if ((info->flags & DF_TEXTREL) == 0)
   3465  1.1.1.1.4.2  perseant 	    if (input_section->output_section->flags & SEC_READONLY)
   3466  1.1.1.1.4.2  perseant 	      info->flags |= DF_TEXTREL;
   3467  1.1.1.1.4.2  perseant 	}
   3468  1.1.1.1.4.2  perseant       while (0);
   3469  1.1.1.1.4.2  perseant 
   3470  1.1.1.1.4.2  perseant       if (fatal)
   3471  1.1.1.1.4.2  perseant 	break;
   3472  1.1.1.1.4.2  perseant 
   3473  1.1.1.1.4.2  perseant       loongarch_record_one_reloc (input_bfd, input_section, r_type,
   3474  1.1.1.1.4.2  perseant 				  rel->r_offset, sym, h, rel->r_addend);
   3475  1.1.1.1.4.2  perseant 
   3476  1.1.1.1.4.2  perseant       if (r != bfd_reloc_continue)
   3477  1.1.1.1.4.2  perseant 	r = perform_relocation (rel, input_section, howto, relocation,
   3478  1.1.1.1.4.2  perseant 				input_bfd, contents);
   3479  1.1.1.1.4.2  perseant 
   3480  1.1.1.1.4.2  perseant       switch (r)
   3481  1.1.1.1.4.2  perseant 	{
   3482  1.1.1.1.4.2  perseant 	case bfd_reloc_dangerous:
   3483  1.1.1.1.4.2  perseant 	case bfd_reloc_continue:
   3484  1.1.1.1.4.2  perseant 	case bfd_reloc_ok:
   3485  1.1.1.1.4.2  perseant 	  continue;
   3486  1.1.1.1.4.2  perseant 
   3487  1.1.1.1.4.2  perseant 	case bfd_reloc_overflow:
   3488  1.1.1.1.4.2  perseant 	  /* Overflow value can't be filled in.  */
   3489  1.1.1.1.4.2  perseant 	  loongarch_dump_reloc_record (info->callbacks->info);
   3490  1.1.1.1.4.2  perseant 	  info->callbacks->reloc_overflow
   3491  1.1.1.1.4.2  perseant 	    (info, h ? &h->root : NULL, name, howto->name, rel->r_addend,
   3492  1.1.1.1.4.2  perseant 	     input_bfd, input_section, rel->r_offset);
   3493  1.1.1.1.4.2  perseant 	  break;
   3494  1.1.1.1.4.2  perseant 
   3495  1.1.1.1.4.2  perseant 	case bfd_reloc_outofrange:
   3496  1.1.1.1.4.2  perseant 	  /* Stack state incorrect.  */
   3497  1.1.1.1.4.2  perseant 	  loongarch_dump_reloc_record (info->callbacks->info);
   3498  1.1.1.1.4.2  perseant 	  info->callbacks->info
   3499  1.1.1.1.4.2  perseant 	    ("%X%H: Internal stack state is incorrect.\n"
   3500  1.1.1.1.4.2  perseant 	     "Want to push to full stack or pop from empty stack?\n",
   3501  1.1.1.1.4.2  perseant 	     input_bfd, input_section, rel->r_offset);
   3502  1.1.1.1.4.2  perseant 	  break;
   3503  1.1.1.1.4.2  perseant 
   3504  1.1.1.1.4.2  perseant 	case bfd_reloc_notsupported:
   3505  1.1.1.1.4.2  perseant 	  info->callbacks->info ("%X%H: Unknown relocation type.\n", input_bfd,
   3506  1.1.1.1.4.2  perseant 				 input_section, rel->r_offset);
   3507  1.1.1.1.4.2  perseant 	  break;
   3508  1.1.1.1.4.2  perseant 
   3509  1.1.1.1.4.2  perseant 	default:
   3510  1.1.1.1.4.2  perseant 	  info->callbacks->info ("%X%H: Internal: unknown error.\n", input_bfd,
   3511  1.1.1.1.4.2  perseant 				 input_section, rel->r_offset);
   3512  1.1.1.1.4.2  perseant 	  break;
   3513  1.1.1.1.4.2  perseant 	}
   3514  1.1.1.1.4.2  perseant 
   3515  1.1.1.1.4.2  perseant       fatal = true;
   3516  1.1.1.1.4.2  perseant     }
   3517  1.1.1.1.4.2  perseant 
   3518  1.1.1.1.4.2  perseant   return !fatal;
   3519  1.1.1.1.4.2  perseant }
   3520  1.1.1.1.4.2  perseant 
   3521  1.1.1.1.4.2  perseant /* Finish up dynamic symbol handling.  We set the contents of various
   3522  1.1.1.1.4.2  perseant    dynamic sections here.  */
   3523  1.1.1.1.4.2  perseant 
   3524  1.1.1.1.4.2  perseant static bool
   3525  1.1.1.1.4.2  perseant loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
   3526  1.1.1.1.4.2  perseant 				     struct bfd_link_info *info,
   3527  1.1.1.1.4.2  perseant 				     struct elf_link_hash_entry *h,
   3528  1.1.1.1.4.2  perseant 				     Elf_Internal_Sym *sym)
   3529  1.1.1.1.4.2  perseant {
   3530  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
   3531  1.1.1.1.4.2  perseant   const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
   3532  1.1.1.1.4.2  perseant   asection *rela_dyn = bfd_get_section_by_name (output_bfd, ".rela.dyn");
   3533  1.1.1.1.4.2  perseant   struct bfd_link_order *lo = NULL;
   3534  1.1.1.1.4.2  perseant   Elf_Internal_Rela *slot = NULL, *last_slot = NULL;
   3535  1.1.1.1.4.2  perseant 
   3536  1.1.1.1.4.2  perseant   if (rela_dyn)
   3537  1.1.1.1.4.2  perseant     lo = rela_dyn->map_head.link_order;
   3538  1.1.1.1.4.2  perseant 
   3539  1.1.1.1.4.2  perseant   if (h->plt.offset != MINUS_ONE)
   3540  1.1.1.1.4.2  perseant     {
   3541  1.1.1.1.4.2  perseant       size_t i, plt_idx;
   3542  1.1.1.1.4.2  perseant       asection *plt, *gotplt, *relplt;
   3543  1.1.1.1.4.2  perseant       bfd_vma got_address;
   3544  1.1.1.1.4.2  perseant       uint32_t plt_entry[PLT_ENTRY_INSNS];
   3545  1.1.1.1.4.2  perseant       bfd_byte *loc;
   3546  1.1.1.1.4.2  perseant       Elf_Internal_Rela rela;
   3547  1.1.1.1.4.2  perseant       asection *rela_sec = NULL;
   3548  1.1.1.1.4.2  perseant 
   3549  1.1.1.1.4.2  perseant       if (htab->elf.splt)
   3550  1.1.1.1.4.2  perseant 	{
   3551  1.1.1.1.4.2  perseant 	  BFD_ASSERT ((h->type == STT_GNU_IFUNC
   3552  1.1.1.1.4.2  perseant 		       && SYMBOL_REFERENCES_LOCAL (info, h))
   3553  1.1.1.1.4.2  perseant 		      || h->dynindx != -1);
   3554  1.1.1.1.4.2  perseant 
   3555  1.1.1.1.4.2  perseant 	  plt = htab->elf.splt;
   3556  1.1.1.1.4.2  perseant 	  gotplt = htab->elf.sgotplt;
   3557  1.1.1.1.4.2  perseant 	  if (h->type == STT_GNU_IFUNC && SYMBOL_REFERENCES_LOCAL (info, h))
   3558  1.1.1.1.4.2  perseant 	    relplt = htab->elf.srelgot;
   3559  1.1.1.1.4.2  perseant 	  else
   3560  1.1.1.1.4.2  perseant 	    relplt = htab->elf.srelplt;
   3561  1.1.1.1.4.2  perseant 	  plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
   3562  1.1.1.1.4.2  perseant 	  got_address =
   3563  1.1.1.1.4.2  perseant 	    sec_addr (gotplt) + GOTPLT_HEADER_SIZE + plt_idx * GOT_ENTRY_SIZE;
   3564  1.1.1.1.4.2  perseant 	}
   3565  1.1.1.1.4.2  perseant       else /* if (htab->elf.iplt) */
   3566  1.1.1.1.4.2  perseant 	{
   3567  1.1.1.1.4.2  perseant 	  BFD_ASSERT (h->type == STT_GNU_IFUNC
   3568  1.1.1.1.4.2  perseant 		      && SYMBOL_REFERENCES_LOCAL (info, h));
   3569  1.1.1.1.4.2  perseant 
   3570  1.1.1.1.4.2  perseant 	  plt = htab->elf.iplt;
   3571  1.1.1.1.4.2  perseant 	  gotplt = htab->elf.igotplt;
   3572  1.1.1.1.4.2  perseant 	  relplt = htab->elf.irelplt;
   3573  1.1.1.1.4.2  perseant 	  plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
   3574  1.1.1.1.4.2  perseant 	  got_address = sec_addr (gotplt) + plt_idx * GOT_ENTRY_SIZE;
   3575  1.1.1.1.4.2  perseant 	}
   3576  1.1.1.1.4.2  perseant 
   3577  1.1.1.1.4.2  perseant       /* Find out where the .plt entry should go.  */
   3578  1.1.1.1.4.2  perseant       loc = plt->contents + h->plt.offset;
   3579  1.1.1.1.4.2  perseant 
   3580  1.1.1.1.4.2  perseant       /* Fill in the PLT entry itself.  */
   3581  1.1.1.1.4.2  perseant       if (!loongarch_make_plt_entry (got_address,
   3582  1.1.1.1.4.2  perseant 				     sec_addr (plt) + h->plt.offset,
   3583  1.1.1.1.4.2  perseant 				     plt_entry))
   3584  1.1.1.1.4.2  perseant 	return false;
   3585  1.1.1.1.4.2  perseant 
   3586  1.1.1.1.4.2  perseant       for (i = 0; i < PLT_ENTRY_INSNS; i++)
   3587  1.1.1.1.4.2  perseant 	bfd_put_32 (output_bfd, plt_entry[i], loc + 4 * i);
   3588  1.1.1.1.4.2  perseant 
   3589  1.1.1.1.4.2  perseant       /* Fill in the initial value of the got.plt entry.  */
   3590  1.1.1.1.4.2  perseant       loc = gotplt->contents + (got_address - sec_addr (gotplt));
   3591  1.1.1.1.4.2  perseant       bfd_put_NN (output_bfd, sec_addr (plt), loc);
   3592  1.1.1.1.4.2  perseant 
   3593  1.1.1.1.4.2  perseant       rela.r_offset = got_address;
   3594  1.1.1.1.4.2  perseant 
   3595  1.1.1.1.4.2  perseant       /* TRUE if this is a PLT reference to a local IFUNC.  */
   3596  1.1.1.1.4.2  perseant       if (PLT_LOCAL_IFUNC_P (info, h)
   3597  1.1.1.1.4.2  perseant 	  && (relplt == htab->elf.srelgot
   3598  1.1.1.1.4.2  perseant 	      || relplt == htab->elf.irelplt))
   3599  1.1.1.1.4.2  perseant 	{
   3600  1.1.1.1.4.2  perseant 	  rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
   3601  1.1.1.1.4.2  perseant 	  rela.r_addend = (h->root.u.def.value
   3602  1.1.1.1.4.2  perseant 			       + h->root.u.def.section->output_section->vma
   3603  1.1.1.1.4.2  perseant 			       + h->root.u.def.section->output_offset);
   3604  1.1.1.1.4.2  perseant 
   3605  1.1.1.1.4.2  perseant 	  /* Find the space after dyn sort.  */
   3606  1.1.1.1.4.2  perseant 	  while (slot == last_slot || slot->r_offset != 0)
   3607  1.1.1.1.4.2  perseant 	    {
   3608  1.1.1.1.4.2  perseant 	      if (slot != last_slot)
   3609  1.1.1.1.4.2  perseant 		{
   3610  1.1.1.1.4.2  perseant 		  slot++;
   3611  1.1.1.1.4.2  perseant 		  continue;
   3612  1.1.1.1.4.2  perseant 		}
   3613  1.1.1.1.4.2  perseant 
   3614  1.1.1.1.4.2  perseant 	      BFD_ASSERT (lo != NULL);
   3615  1.1.1.1.4.2  perseant 	      rela_sec = lo->u.indirect.section;
   3616  1.1.1.1.4.2  perseant 	      lo = lo->next;
   3617  1.1.1.1.4.2  perseant 
   3618  1.1.1.1.4.2  perseant 	      slot = (Elf_Internal_Rela *)rela_sec->contents;
   3619  1.1.1.1.4.2  perseant 	      last_slot = (Elf_Internal_Rela *)(rela_sec->contents +
   3620  1.1.1.1.4.2  perseant 						rela_sec->size);
   3621  1.1.1.1.4.2  perseant 	    }
   3622  1.1.1.1.4.2  perseant 
   3623  1.1.1.1.4.2  perseant 	  bed->s->swap_reloca_out (output_bfd, &rela, (bfd_byte *)slot);
   3624  1.1.1.1.4.2  perseant 	  rela_sec->reloc_count++;
   3625  1.1.1.1.4.2  perseant 	}
   3626  1.1.1.1.4.2  perseant       else
   3627  1.1.1.1.4.2  perseant 	{
   3628  1.1.1.1.4.2  perseant 	  /* Fill in the entry in the rela.plt section.  */
   3629  1.1.1.1.4.2  perseant 	  rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_JUMP_SLOT);
   3630  1.1.1.1.4.2  perseant 	  rela.r_addend = 0;
   3631  1.1.1.1.4.2  perseant 	  loc = relplt->contents + plt_idx * sizeof (ElfNN_External_Rela);
   3632  1.1.1.1.4.2  perseant 	  bed->s->swap_reloca_out (output_bfd, &rela, loc);
   3633  1.1.1.1.4.2  perseant 	}
   3634  1.1.1.1.4.2  perseant 
   3635  1.1.1.1.4.2  perseant       if (!h->def_regular)
   3636  1.1.1.1.4.2  perseant 	{
   3637  1.1.1.1.4.2  perseant 	  /* Mark the symbol as undefined, rather than as defined in
   3638  1.1.1.1.4.2  perseant 	     the .plt section.  Leave the value alone.  */
   3639  1.1.1.1.4.2  perseant 	  sym->st_shndx = SHN_UNDEF;
   3640  1.1.1.1.4.2  perseant 	  /* If the symbol is weak, we do need to clear the value.
   3641  1.1.1.1.4.2  perseant 	     Otherwise, the PLT entry would provide a definition for
   3642  1.1.1.1.4.2  perseant 	     the symbol even if the symbol wasn't defined anywhere,
   3643  1.1.1.1.4.2  perseant 	     and so the symbol would never be NULL.  */
   3644  1.1.1.1.4.2  perseant 	  if (!h->ref_regular_nonweak)
   3645  1.1.1.1.4.2  perseant 	    sym->st_value = 0;
   3646  1.1.1.1.4.2  perseant 	}
   3647  1.1.1.1.4.2  perseant     }
   3648  1.1.1.1.4.2  perseant 
   3649  1.1.1.1.4.2  perseant   if (h->got.offset != MINUS_ONE
   3650  1.1.1.1.4.2  perseant       /* TLS got entry have been handled in elf_relocate_section.  */
   3651  1.1.1.1.4.2  perseant       && !(loongarch_elf_hash_entry (h)->tls_type & (GOT_TLS_GD | GOT_TLS_IE))
   3652  1.1.1.1.4.2  perseant       /* Have allocated got entry but not allocated rela before.  */
   3653  1.1.1.1.4.2  perseant       && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
   3654  1.1.1.1.4.2  perseant     {
   3655  1.1.1.1.4.2  perseant       asection *sgot, *srela;
   3656  1.1.1.1.4.2  perseant       Elf_Internal_Rela rela;
   3657  1.1.1.1.4.2  perseant       bfd_vma off = h->got.offset & ~(bfd_vma)1;
   3658  1.1.1.1.4.2  perseant 
   3659  1.1.1.1.4.2  perseant       /* This symbol has an entry in the GOT.  Set it up.  */
   3660  1.1.1.1.4.2  perseant       sgot = htab->elf.sgot;
   3661  1.1.1.1.4.2  perseant       srela = htab->elf.srelgot;
   3662  1.1.1.1.4.2  perseant       BFD_ASSERT (sgot && srela);
   3663  1.1.1.1.4.2  perseant 
   3664  1.1.1.1.4.2  perseant       rela.r_offset = sec_addr (sgot) + off;
   3665  1.1.1.1.4.2  perseant 
   3666  1.1.1.1.4.2  perseant       if (h->def_regular
   3667  1.1.1.1.4.2  perseant 	  && h->type == STT_GNU_IFUNC)
   3668  1.1.1.1.4.2  perseant 	{
   3669  1.1.1.1.4.2  perseant 	  if(h->plt.offset == MINUS_ONE)
   3670  1.1.1.1.4.2  perseant 	    {
   3671  1.1.1.1.4.2  perseant 	      if (htab->elf.splt == NULL)
   3672  1.1.1.1.4.2  perseant 		srela = htab->elf.irelplt;
   3673  1.1.1.1.4.2  perseant 
   3674  1.1.1.1.4.2  perseant 	      if (SYMBOL_REFERENCES_LOCAL (info, h))
   3675  1.1.1.1.4.2  perseant 		{
   3676  1.1.1.1.4.2  perseant 		  asection *sec = h->root.u.def.section;
   3677  1.1.1.1.4.2  perseant 		  rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
   3678  1.1.1.1.4.2  perseant 		  rela.r_addend = h->root.u.def.value + sec->output_section->vma
   3679  1.1.1.1.4.2  perseant 		    + sec->output_offset;
   3680  1.1.1.1.4.2  perseant 		  bfd_put_NN (output_bfd, 0, sgot->contents + off);
   3681  1.1.1.1.4.2  perseant 		}
   3682  1.1.1.1.4.2  perseant 	      else
   3683  1.1.1.1.4.2  perseant 		{
   3684  1.1.1.1.4.2  perseant 		  BFD_ASSERT (h->dynindx != -1);
   3685  1.1.1.1.4.2  perseant 		  rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
   3686  1.1.1.1.4.2  perseant 		  rela.r_addend = 0;
   3687  1.1.1.1.4.2  perseant 		  bfd_put_NN (output_bfd, (bfd_vma) 0, sgot->contents + off);
   3688  1.1.1.1.4.2  perseant 		}
   3689  1.1.1.1.4.2  perseant 	    }
   3690  1.1.1.1.4.2  perseant 	  else if(bfd_link_pic (info))
   3691  1.1.1.1.4.2  perseant 	    {
   3692  1.1.1.1.4.2  perseant 	      rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
   3693  1.1.1.1.4.2  perseant 	      rela.r_addend = 0;
   3694  1.1.1.1.4.2  perseant 	      bfd_put_NN (output_bfd, rela.r_addend, sgot->contents + off);
   3695  1.1.1.1.4.2  perseant 	    }
   3696  1.1.1.1.4.2  perseant 	  else
   3697  1.1.1.1.4.2  perseant 	    {
   3698  1.1.1.1.4.2  perseant 	      asection *plt;
   3699  1.1.1.1.4.2  perseant 	      /* For non-shared object, we can't use .got.plt, which
   3700  1.1.1.1.4.2  perseant 		 contains the real function address if we need pointer
   3701  1.1.1.1.4.2  perseant 		 equality.  We load the GOT entry with the PLT entry.  */
   3702  1.1.1.1.4.2  perseant 	      plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
   3703  1.1.1.1.4.2  perseant 	      bfd_put_NN (output_bfd,
   3704  1.1.1.1.4.2  perseant 			  (plt->output_section->vma
   3705  1.1.1.1.4.2  perseant 			   + plt->output_offset
   3706  1.1.1.1.4.2  perseant 			   + h->plt.offset),
   3707  1.1.1.1.4.2  perseant 			  sgot->contents + off);
   3708  1.1.1.1.4.2  perseant 	      return true;
   3709  1.1.1.1.4.2  perseant 	    }
   3710  1.1.1.1.4.2  perseant 	}
   3711  1.1.1.1.4.2  perseant       else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))
   3712  1.1.1.1.4.2  perseant 	{
   3713  1.1.1.1.4.2  perseant 	  asection *sec = h->root.u.def.section;
   3714  1.1.1.1.4.2  perseant 	  rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
   3715  1.1.1.1.4.2  perseant 	  rela.r_addend = (h->root.u.def.value + sec->output_section->vma
   3716  1.1.1.1.4.2  perseant 			   + sec->output_offset);
   3717  1.1.1.1.4.2  perseant 	}
   3718  1.1.1.1.4.2  perseant       else
   3719  1.1.1.1.4.2  perseant 	{
   3720  1.1.1.1.4.2  perseant 	  BFD_ASSERT (h->dynindx != -1);
   3721  1.1.1.1.4.2  perseant 	  rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
   3722  1.1.1.1.4.2  perseant 	  rela.r_addend = 0;
   3723  1.1.1.1.4.2  perseant 	}
   3724  1.1.1.1.4.2  perseant 
   3725  1.1.1.1.4.2  perseant       loongarch_elf_append_rela (output_bfd, srela, &rela);
   3726  1.1.1.1.4.2  perseant     }
   3727  1.1.1.1.4.2  perseant 
   3728  1.1.1.1.4.2  perseant   /* Mark some specially defined symbols as absolute.  */
   3729  1.1.1.1.4.2  perseant   if (h == htab->elf.hdynamic || h == htab->elf.hgot || h == htab->elf.hplt)
   3730  1.1.1.1.4.2  perseant     sym->st_shndx = SHN_ABS;
   3731  1.1.1.1.4.2  perseant 
   3732  1.1.1.1.4.2  perseant   return true;
   3733  1.1.1.1.4.2  perseant }
   3734  1.1.1.1.4.2  perseant 
   3735  1.1.1.1.4.2  perseant /* Finish up the dynamic sections.  */
   3736  1.1.1.1.4.2  perseant 
   3737  1.1.1.1.4.2  perseant static bool
   3738  1.1.1.1.4.2  perseant loongarch_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, bfd *dynobj,
   3739  1.1.1.1.4.2  perseant 		      asection *sdyn)
   3740  1.1.1.1.4.2  perseant {
   3741  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
   3742  1.1.1.1.4.2  perseant   const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
   3743  1.1.1.1.4.2  perseant   size_t dynsize = bed->s->sizeof_dyn, skipped_size = 0;
   3744  1.1.1.1.4.2  perseant   bfd_byte *dyncon, *dynconend;
   3745  1.1.1.1.4.2  perseant 
   3746  1.1.1.1.4.2  perseant   dynconend = sdyn->contents + sdyn->size;
   3747  1.1.1.1.4.2  perseant   for (dyncon = sdyn->contents; dyncon < dynconend; dyncon += dynsize)
   3748  1.1.1.1.4.2  perseant     {
   3749  1.1.1.1.4.2  perseant       Elf_Internal_Dyn dyn;
   3750  1.1.1.1.4.2  perseant       asection *s;
   3751  1.1.1.1.4.2  perseant       int skipped = 0;
   3752  1.1.1.1.4.2  perseant 
   3753  1.1.1.1.4.2  perseant       bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
   3754  1.1.1.1.4.2  perseant 
   3755  1.1.1.1.4.2  perseant       switch (dyn.d_tag)
   3756  1.1.1.1.4.2  perseant 	{
   3757  1.1.1.1.4.2  perseant 	case DT_PLTGOT:
   3758  1.1.1.1.4.2  perseant 	  s = htab->elf.sgotplt;
   3759  1.1.1.1.4.2  perseant 	  dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
   3760  1.1.1.1.4.2  perseant 	  break;
   3761  1.1.1.1.4.2  perseant 	case DT_JMPREL:
   3762  1.1.1.1.4.2  perseant 	  s = htab->elf.srelplt;
   3763  1.1.1.1.4.2  perseant 	  dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
   3764  1.1.1.1.4.2  perseant 	  break;
   3765  1.1.1.1.4.2  perseant 	case DT_PLTRELSZ:
   3766  1.1.1.1.4.2  perseant 	  s = htab->elf.srelplt;
   3767  1.1.1.1.4.2  perseant 	  dyn.d_un.d_val = s->size;
   3768  1.1.1.1.4.2  perseant 	  break;
   3769  1.1.1.1.4.2  perseant 	case DT_TEXTREL:
   3770  1.1.1.1.4.2  perseant 	  if ((info->flags & DF_TEXTREL) == 0)
   3771  1.1.1.1.4.2  perseant 	    skipped = 1;
   3772  1.1.1.1.4.2  perseant 	  break;
   3773  1.1.1.1.4.2  perseant 	case DT_FLAGS:
   3774  1.1.1.1.4.2  perseant 	  if ((info->flags & DF_TEXTREL) == 0)
   3775  1.1.1.1.4.2  perseant 	    dyn.d_un.d_val &= ~DF_TEXTREL;
   3776  1.1.1.1.4.2  perseant 	  break;
   3777  1.1.1.1.4.2  perseant 	}
   3778  1.1.1.1.4.2  perseant       if (skipped)
   3779  1.1.1.1.4.2  perseant 	skipped_size += dynsize;
   3780  1.1.1.1.4.2  perseant       else
   3781  1.1.1.1.4.2  perseant 	bed->s->swap_dyn_out (output_bfd, &dyn, dyncon - skipped_size);
   3782  1.1.1.1.4.2  perseant     }
   3783  1.1.1.1.4.2  perseant   /* Wipe out any trailing entries if we shifted down a dynamic tag.  */
   3784  1.1.1.1.4.2  perseant   memset (dyncon - skipped_size, 0, skipped_size);
   3785  1.1.1.1.4.2  perseant   return true;
   3786  1.1.1.1.4.2  perseant }
   3787  1.1.1.1.4.2  perseant 
   3788  1.1.1.1.4.2  perseant /* Finish up local dynamic symbol handling.  We set the contents of
   3789  1.1.1.1.4.2  perseant    various dynamic sections here.  */
   3790  1.1.1.1.4.2  perseant 
   3791  1.1.1.1.4.2  perseant static bool
   3792  1.1.1.1.4.2  perseant elfNN_loongarch_finish_local_dynamic_symbol (void **slot, void *inf)
   3793  1.1.1.1.4.2  perseant {
   3794  1.1.1.1.4.2  perseant   struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot;
   3795  1.1.1.1.4.2  perseant   struct bfd_link_info *info = (struct bfd_link_info *) inf;
   3796  1.1.1.1.4.2  perseant 
   3797  1.1.1.1.4.2  perseant   return loongarch_elf_finish_dynamic_symbol (info->output_bfd, info, h, NULL);
   3798  1.1.1.1.4.2  perseant }
   3799  1.1.1.1.4.2  perseant 
   3800  1.1.1.1.4.2  perseant static bool
   3801  1.1.1.1.4.2  perseant loongarch_elf_finish_dynamic_sections (bfd *output_bfd,
   3802  1.1.1.1.4.2  perseant 				       struct bfd_link_info *info)
   3803  1.1.1.1.4.2  perseant {
   3804  1.1.1.1.4.2  perseant   bfd *dynobj;
   3805  1.1.1.1.4.2  perseant   asection *sdyn, *plt, *gotplt = NULL;
   3806  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab;
   3807  1.1.1.1.4.2  perseant 
   3808  1.1.1.1.4.2  perseant   htab = loongarch_elf_hash_table (info);
   3809  1.1.1.1.4.2  perseant   BFD_ASSERT (htab);
   3810  1.1.1.1.4.2  perseant   dynobj = htab->elf.dynobj;
   3811  1.1.1.1.4.2  perseant   sdyn = bfd_get_linker_section (dynobj, ".dynamic");
   3812  1.1.1.1.4.2  perseant 
   3813  1.1.1.1.4.2  perseant   if (elf_hash_table (info)->dynamic_sections_created)
   3814  1.1.1.1.4.2  perseant     {
   3815  1.1.1.1.4.2  perseant       BFD_ASSERT (htab->elf.splt && sdyn);
   3816  1.1.1.1.4.2  perseant 
   3817  1.1.1.1.4.2  perseant       if (!loongarch_finish_dyn (output_bfd, info, dynobj, sdyn))
   3818  1.1.1.1.4.2  perseant 	return false;
   3819  1.1.1.1.4.2  perseant     }
   3820  1.1.1.1.4.2  perseant 
   3821  1.1.1.1.4.2  perseant   plt = htab->elf.splt;
   3822  1.1.1.1.4.2  perseant   gotplt = htab->elf.sgotplt;
   3823  1.1.1.1.4.2  perseant 
   3824  1.1.1.1.4.2  perseant   if (plt && 0 < plt->size)
   3825  1.1.1.1.4.2  perseant     {
   3826  1.1.1.1.4.2  perseant       size_t i;
   3827  1.1.1.1.4.2  perseant       uint32_t plt_header[PLT_HEADER_INSNS];
   3828  1.1.1.1.4.2  perseant       if (!loongarch_make_plt_header (sec_addr (gotplt), sec_addr (plt),
   3829  1.1.1.1.4.2  perseant 				      plt_header))
   3830  1.1.1.1.4.2  perseant 	return false;
   3831  1.1.1.1.4.2  perseant 
   3832  1.1.1.1.4.2  perseant       for (i = 0; i < PLT_HEADER_INSNS; i++)
   3833  1.1.1.1.4.2  perseant 	bfd_put_32 (output_bfd, plt_header[i], plt->contents + 4 * i);
   3834  1.1.1.1.4.2  perseant 
   3835  1.1.1.1.4.2  perseant       elf_section_data (plt->output_section)->this_hdr.sh_entsize =
   3836  1.1.1.1.4.2  perseant 	PLT_ENTRY_SIZE;
   3837  1.1.1.1.4.2  perseant     }
   3838  1.1.1.1.4.2  perseant 
   3839  1.1.1.1.4.2  perseant   if (htab->elf.sgotplt)
   3840  1.1.1.1.4.2  perseant     {
   3841  1.1.1.1.4.2  perseant       asection *output_section = htab->elf.sgotplt->output_section;
   3842  1.1.1.1.4.2  perseant 
   3843  1.1.1.1.4.2  perseant       if (bfd_is_abs_section (output_section))
   3844  1.1.1.1.4.2  perseant 	{
   3845  1.1.1.1.4.2  perseant 	  _bfd_error_handler (_("discarded output section: `%pA'"),
   3846  1.1.1.1.4.2  perseant 			      htab->elf.sgotplt);
   3847  1.1.1.1.4.2  perseant 	  return false;
   3848  1.1.1.1.4.2  perseant 	}
   3849  1.1.1.1.4.2  perseant 
   3850  1.1.1.1.4.2  perseant       if (0 < htab->elf.sgotplt->size)
   3851  1.1.1.1.4.2  perseant 	{
   3852  1.1.1.1.4.2  perseant 	  /* Write the first two entries in .got.plt, needed for the dynamic
   3853  1.1.1.1.4.2  perseant 	     linker.  */
   3854  1.1.1.1.4.2  perseant 	  bfd_put_NN (output_bfd, MINUS_ONE, htab->elf.sgotplt->contents);
   3855  1.1.1.1.4.2  perseant 
   3856  1.1.1.1.4.2  perseant 	  bfd_put_NN (output_bfd, (bfd_vma) 0,
   3857  1.1.1.1.4.2  perseant 		      htab->elf.sgotplt->contents + GOT_ENTRY_SIZE);
   3858  1.1.1.1.4.2  perseant 	}
   3859  1.1.1.1.4.2  perseant 
   3860  1.1.1.1.4.2  perseant       elf_section_data (output_section)->this_hdr.sh_entsize = GOT_ENTRY_SIZE;
   3861  1.1.1.1.4.2  perseant     }
   3862  1.1.1.1.4.2  perseant 
   3863  1.1.1.1.4.2  perseant   if (htab->elf.sgot)
   3864  1.1.1.1.4.2  perseant     {
   3865  1.1.1.1.4.2  perseant       asection *output_section = htab->elf.sgot->output_section;
   3866  1.1.1.1.4.2  perseant 
   3867  1.1.1.1.4.2  perseant       if (0 < htab->elf.sgot->size)
   3868  1.1.1.1.4.2  perseant 	{
   3869  1.1.1.1.4.2  perseant 	  /* Set the first entry in the global offset table to the address of
   3870  1.1.1.1.4.2  perseant 	     the dynamic section.  */
   3871  1.1.1.1.4.2  perseant 	  bfd_vma val = sdyn ? sec_addr (sdyn) : 0;
   3872  1.1.1.1.4.2  perseant 	  bfd_put_NN (output_bfd, val, htab->elf.sgot->contents);
   3873  1.1.1.1.4.2  perseant 	}
   3874  1.1.1.1.4.2  perseant 
   3875  1.1.1.1.4.2  perseant       elf_section_data (output_section)->this_hdr.sh_entsize = GOT_ENTRY_SIZE;
   3876  1.1.1.1.4.2  perseant     }
   3877  1.1.1.1.4.2  perseant 
   3878  1.1.1.1.4.2  perseant   /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols.  */
   3879  1.1.1.1.4.2  perseant   htab_traverse (htab->loc_hash_table,
   3880  1.1.1.1.4.2  perseant 		 (void *) elfNN_loongarch_finish_local_dynamic_symbol, info);
   3881  1.1.1.1.4.2  perseant 
   3882  1.1.1.1.4.2  perseant   return true;
   3883  1.1.1.1.4.2  perseant }
   3884  1.1.1.1.4.2  perseant 
   3885  1.1.1.1.4.2  perseant /* Return address for Ith PLT stub in section PLT, for relocation REL
   3886  1.1.1.1.4.2  perseant    or (bfd_vma) -1 if it should not be included.  */
   3887  1.1.1.1.4.2  perseant 
   3888  1.1.1.1.4.2  perseant static bfd_vma
   3889  1.1.1.1.4.2  perseant loongarch_elf_plt_sym_val (bfd_vma i, const asection *plt,
   3890  1.1.1.1.4.2  perseant 			   const arelent *rel ATTRIBUTE_UNUSED)
   3891  1.1.1.1.4.2  perseant {
   3892  1.1.1.1.4.2  perseant   return plt->vma + PLT_HEADER_SIZE + i * PLT_ENTRY_SIZE;
   3893  1.1.1.1.4.2  perseant }
   3894  1.1.1.1.4.2  perseant 
   3895  1.1.1.1.4.2  perseant static enum elf_reloc_type_class
   3896  1.1.1.1.4.2  perseant loongarch_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
   3897  1.1.1.1.4.2  perseant 			    const asection *rel_sec ATTRIBUTE_UNUSED,
   3898  1.1.1.1.4.2  perseant 			    const Elf_Internal_Rela *rela)
   3899  1.1.1.1.4.2  perseant {
   3900  1.1.1.1.4.2  perseant   struct loongarch_elf_link_hash_table *htab;
   3901  1.1.1.1.4.2  perseant   htab = loongarch_elf_hash_table (info);
   3902  1.1.1.1.4.2  perseant 
   3903  1.1.1.1.4.2  perseant   if (htab->elf.dynsym != NULL && htab->elf.dynsym->contents != NULL)
   3904  1.1.1.1.4.2  perseant     {
   3905  1.1.1.1.4.2  perseant       /* Check relocation against STT_GNU_IFUNC symbol if there are
   3906  1.1.1.1.4.2  perseant 	 dynamic symbols.  */
   3907  1.1.1.1.4.2  perseant       bfd *abfd = info->output_bfd;
   3908  1.1.1.1.4.2  perseant       const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   3909  1.1.1.1.4.2  perseant       unsigned long r_symndx = ELFNN_R_SYM (rela->r_info);
   3910  1.1.1.1.4.2  perseant       if (r_symndx != STN_UNDEF)
   3911  1.1.1.1.4.2  perseant 	{
   3912  1.1.1.1.4.2  perseant 	  Elf_Internal_Sym sym;
   3913  1.1.1.1.4.2  perseant 	  if (!bed->s->swap_symbol_in (abfd,
   3914  1.1.1.1.4.2  perseant 				       htab->elf.dynsym->contents
   3915  1.1.1.1.4.2  perseant 				       + r_symndx * bed->s->sizeof_sym,
   3916  1.1.1.1.4.2  perseant 				       0, &sym))
   3917  1.1.1.1.4.2  perseant 	    {
   3918  1.1.1.1.4.2  perseant 	      /* xgettext:c-format  */
   3919  1.1.1.1.4.2  perseant 	      _bfd_error_handler (_("%pB symbol number %lu references"
   3920  1.1.1.1.4.2  perseant 				    " nonexistent SHT_SYMTAB_SHNDX section"),
   3921  1.1.1.1.4.2  perseant 				  abfd, r_symndx);
   3922  1.1.1.1.4.2  perseant 	      /* Ideally an error class should be returned here.  */
   3923  1.1.1.1.4.2  perseant 	    }
   3924  1.1.1.1.4.2  perseant 	  else if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
   3925  1.1.1.1.4.2  perseant 	    return reloc_class_ifunc;
   3926  1.1.1.1.4.2  perseant 	}
   3927  1.1.1.1.4.2  perseant     }
   3928  1.1.1.1.4.2  perseant 
   3929  1.1.1.1.4.2  perseant   switch (ELFNN_R_TYPE (rela->r_info))
   3930  1.1.1.1.4.2  perseant     {
   3931  1.1.1.1.4.2  perseant     case R_LARCH_IRELATIVE:
   3932  1.1.1.1.4.2  perseant       return reloc_class_ifunc;
   3933  1.1.1.1.4.2  perseant     case R_LARCH_RELATIVE:
   3934  1.1.1.1.4.2  perseant       return reloc_class_relative;
   3935  1.1.1.1.4.2  perseant     case R_LARCH_JUMP_SLOT:
   3936  1.1.1.1.4.2  perseant       return reloc_class_plt;
   3937  1.1.1.1.4.2  perseant     case R_LARCH_COPY:
   3938  1.1.1.1.4.2  perseant       return reloc_class_copy;
   3939  1.1.1.1.4.2  perseant     default:
   3940  1.1.1.1.4.2  perseant       return reloc_class_normal;
   3941  1.1.1.1.4.2  perseant     }
   3942  1.1.1.1.4.2  perseant }
   3943  1.1.1.1.4.2  perseant 
   3944  1.1.1.1.4.2  perseant /* Copy the extra info we tack onto an elf_link_hash_entry.  */
   3945  1.1.1.1.4.2  perseant 
   3946  1.1.1.1.4.2  perseant static void
   3947  1.1.1.1.4.2  perseant loongarch_elf_copy_indirect_symbol (struct bfd_link_info *info,
   3948  1.1.1.1.4.2  perseant 				    struct elf_link_hash_entry *dir,
   3949  1.1.1.1.4.2  perseant 				    struct elf_link_hash_entry *ind)
   3950  1.1.1.1.4.2  perseant {
   3951  1.1.1.1.4.2  perseant   struct elf_link_hash_entry *edir, *eind;
   3952  1.1.1.1.4.2  perseant 
   3953  1.1.1.1.4.2  perseant   edir = dir;
   3954  1.1.1.1.4.2  perseant   eind = ind;
   3955  1.1.1.1.4.2  perseant 
   3956  1.1.1.1.4.2  perseant   if (eind->dyn_relocs != NULL)
   3957  1.1.1.1.4.2  perseant     {
   3958  1.1.1.1.4.2  perseant       if (edir->dyn_relocs != NULL)
   3959  1.1.1.1.4.2  perseant 	{
   3960  1.1.1.1.4.2  perseant 	  struct elf_dyn_relocs **pp;
   3961  1.1.1.1.4.2  perseant 	  struct elf_dyn_relocs *p;
   3962  1.1.1.1.4.2  perseant 
   3963  1.1.1.1.4.2  perseant 	  /* Add reloc counts against the indirect sym to the direct sym
   3964  1.1.1.1.4.2  perseant 	     list.  Merge any entries against the same section.  */
   3965  1.1.1.1.4.2  perseant 	  for (pp = &eind->dyn_relocs; (p = *pp) != NULL;)
   3966  1.1.1.1.4.2  perseant 	    {
   3967  1.1.1.1.4.2  perseant 	      struct elf_dyn_relocs *q;
   3968  1.1.1.1.4.2  perseant 
   3969  1.1.1.1.4.2  perseant 	      for (q = edir->dyn_relocs; q != NULL; q = q->next)
   3970  1.1.1.1.4.2  perseant 		if (q->sec == p->sec)
   3971  1.1.1.1.4.2  perseant 		  {
   3972  1.1.1.1.4.2  perseant 		    q->pc_count += p->pc_count;
   3973  1.1.1.1.4.2  perseant 		    q->count += p->count;
   3974  1.1.1.1.4.2  perseant 		    *pp = p->next;
   3975  1.1.1.1.4.2  perseant 		    break;
   3976  1.1.1.1.4.2  perseant 		  }
   3977  1.1.1.1.4.2  perseant 	      if (q == NULL)
   3978  1.1.1.1.4.2  perseant 		pp = &p->next;
   3979  1.1.1.1.4.2  perseant 	    }
   3980  1.1.1.1.4.2  perseant 	  *pp = edir->dyn_relocs;
   3981  1.1.1.1.4.2  perseant 	}
   3982  1.1.1.1.4.2  perseant 
   3983  1.1.1.1.4.2  perseant       edir->dyn_relocs = eind->dyn_relocs;
   3984  1.1.1.1.4.2  perseant       eind->dyn_relocs = NULL;
   3985  1.1.1.1.4.2  perseant     }
   3986  1.1.1.1.4.2  perseant 
   3987  1.1.1.1.4.2  perseant   if (ind->root.type == bfd_link_hash_indirect && dir->got.refcount < 0)
   3988  1.1.1.1.4.2  perseant     {
   3989  1.1.1.1.4.2  perseant       loongarch_elf_hash_entry(edir)->tls_type
   3990  1.1.1.1.4.2  perseant 	= loongarch_elf_hash_entry(eind)->tls_type;
   3991  1.1.1.1.4.2  perseant       loongarch_elf_hash_entry(eind)->tls_type = GOT_UNKNOWN;
   3992  1.1.1.1.4.2  perseant     }
   3993  1.1.1.1.4.2  perseant   _bfd_elf_link_hash_copy_indirect (info, dir, ind);
   3994  1.1.1.1.4.2  perseant }
   3995  1.1.1.1.4.2  perseant 
   3996  1.1.1.1.4.2  perseant #define PRSTATUS_SIZE		    0x1d8
   3997  1.1.1.1.4.2  perseant #define PRSTATUS_OFFSET_PR_CURSIG   0xc
   3998  1.1.1.1.4.2  perseant #define PRSTATUS_OFFSET_PR_PID	    0x20
   3999  1.1.1.1.4.2  perseant #define ELF_GREGSET_T_SIZE	    0x168
   4000  1.1.1.1.4.2  perseant #define PRSTATUS_OFFSET_PR_REG	    0x70
   4001  1.1.1.1.4.2  perseant 
   4002  1.1.1.1.4.2  perseant /* Support for core dump NOTE sections.  */
   4003  1.1.1.1.4.2  perseant 
   4004  1.1.1.1.4.2  perseant static bool
   4005  1.1.1.1.4.2  perseant loongarch_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
   4006  1.1.1.1.4.2  perseant {
   4007  1.1.1.1.4.2  perseant   switch (note->descsz)
   4008  1.1.1.1.4.2  perseant     {
   4009  1.1.1.1.4.2  perseant     default:
   4010  1.1.1.1.4.2  perseant       return false;
   4011  1.1.1.1.4.2  perseant 
   4012  1.1.1.1.4.2  perseant     /* The sizeof (struct elf_prstatus) on Linux/LoongArch.  */
   4013  1.1.1.1.4.2  perseant     case PRSTATUS_SIZE:
   4014  1.1.1.1.4.2  perseant       /* pr_cursig  */
   4015  1.1.1.1.4.2  perseant       elf_tdata (abfd)->core->signal =
   4016  1.1.1.1.4.2  perseant 	bfd_get_16 (abfd, note->descdata + PRSTATUS_OFFSET_PR_CURSIG);
   4017  1.1.1.1.4.2  perseant 
   4018  1.1.1.1.4.2  perseant       /* pr_pid  */
   4019  1.1.1.1.4.2  perseant       elf_tdata (abfd)->core->lwpid =
   4020  1.1.1.1.4.2  perseant 	bfd_get_32 (abfd, note->descdata + PRSTATUS_OFFSET_PR_PID);
   4021  1.1.1.1.4.2  perseant       break;
   4022  1.1.1.1.4.2  perseant     }
   4023  1.1.1.1.4.2  perseant 
   4024  1.1.1.1.4.2  perseant   /* Make a ".reg/999" section.  */
   4025  1.1.1.1.4.2  perseant   return _bfd_elfcore_make_pseudosection (abfd, ".reg", ELF_GREGSET_T_SIZE,
   4026  1.1.1.1.4.2  perseant 					  note->descpos
   4027  1.1.1.1.4.2  perseant 					  + PRSTATUS_OFFSET_PR_REG);
   4028  1.1.1.1.4.2  perseant }
   4029  1.1.1.1.4.2  perseant 
   4030  1.1.1.1.4.2  perseant #define PRPSINFO_SIZE		    0x88
   4031  1.1.1.1.4.2  perseant #define PRPSINFO_OFFSET_PR_PID	    0x18
   4032  1.1.1.1.4.2  perseant #define PRPSINFO_OFFSET_PR_FNAME    0x28
   4033  1.1.1.1.4.2  perseant #define PRPSINFO_SIZEOF_PR_FNAME    0x10
   4034  1.1.1.1.4.2  perseant #define PRPSINFO_OFFSET_PR_PS_ARGS  0x38
   4035  1.1.1.1.4.2  perseant #define PRPSINFO_SIZEOF_PR_PS_ARGS  0x50
   4036  1.1.1.1.4.2  perseant 
   4037  1.1.1.1.4.2  perseant static bool
   4038  1.1.1.1.4.2  perseant loongarch_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   4039  1.1.1.1.4.2  perseant {
   4040  1.1.1.1.4.2  perseant   switch (note->descsz)
   4041  1.1.1.1.4.2  perseant     {
   4042  1.1.1.1.4.2  perseant     default:
   4043  1.1.1.1.4.2  perseant       return false;
   4044  1.1.1.1.4.2  perseant 
   4045  1.1.1.1.4.2  perseant     /* The sizeof (prpsinfo_t) on Linux/LoongArch.  */
   4046  1.1.1.1.4.2  perseant     case PRPSINFO_SIZE:
   4047  1.1.1.1.4.2  perseant       /* pr_pid  */
   4048  1.1.1.1.4.2  perseant       elf_tdata (abfd)->core->pid =
   4049  1.1.1.1.4.2  perseant 	bfd_get_32 (abfd, note->descdata + PRPSINFO_OFFSET_PR_PID);
   4050  1.1.1.1.4.2  perseant 
   4051  1.1.1.1.4.2  perseant       /* pr_fname  */
   4052  1.1.1.1.4.2  perseant       elf_tdata (abfd)->core->program =
   4053  1.1.1.1.4.2  perseant 	_bfd_elfcore_strndup (abfd, note->descdata + PRPSINFO_OFFSET_PR_FNAME,
   4054  1.1.1.1.4.2  perseant 			      PRPSINFO_SIZEOF_PR_FNAME);
   4055  1.1.1.1.4.2  perseant 
   4056  1.1.1.1.4.2  perseant       /* pr_psargs  */
   4057  1.1.1.1.4.2  perseant       elf_tdata (abfd)->core->command =
   4058  1.1.1.1.4.2  perseant 	_bfd_elfcore_strndup (abfd, note->descdata + PRPSINFO_OFFSET_PR_PS_ARGS,
   4059  1.1.1.1.4.2  perseant 			      PRPSINFO_SIZEOF_PR_PS_ARGS);
   4060  1.1.1.1.4.2  perseant       break;
   4061  1.1.1.1.4.2  perseant     }
   4062  1.1.1.1.4.2  perseant 
   4063  1.1.1.1.4.2  perseant   /* Note that for some reason, a spurious space is tacked
   4064  1.1.1.1.4.2  perseant      onto the end of the args in some (at least one anyway)
   4065  1.1.1.1.4.2  perseant      implementations, so strip it off if it exists.  */
   4066  1.1.1.1.4.2  perseant 
   4067  1.1.1.1.4.2  perseant   {
   4068  1.1.1.1.4.2  perseant     char *command = elf_tdata (abfd)->core->command;
   4069  1.1.1.1.4.2  perseant     int n = strlen (command);
   4070  1.1.1.1.4.2  perseant 
   4071  1.1.1.1.4.2  perseant     if (0 < n && command[n - 1] == ' ')
   4072  1.1.1.1.4.2  perseant       command[n - 1] = '\0';
   4073  1.1.1.1.4.2  perseant   }
   4074  1.1.1.1.4.2  perseant 
   4075  1.1.1.1.4.2  perseant   return true;
   4076  1.1.1.1.4.2  perseant }
   4077  1.1.1.1.4.2  perseant 
   4078  1.1.1.1.4.2  perseant /* Set the right mach type.  */
   4079  1.1.1.1.4.2  perseant static bool
   4080  1.1.1.1.4.2  perseant loongarch_elf_object_p (bfd *abfd)
   4081  1.1.1.1.4.2  perseant {
   4082  1.1.1.1.4.2  perseant   /* There are only two mach types in LoongArch currently.  */
   4083  1.1.1.1.4.2  perseant   if (strcmp (abfd->xvec->name, "elf64-loongarch") == 0)
   4084  1.1.1.1.4.2  perseant     bfd_default_set_arch_mach (abfd, bfd_arch_loongarch, bfd_mach_loongarch64);
   4085  1.1.1.1.4.2  perseant   else
   4086  1.1.1.1.4.2  perseant     bfd_default_set_arch_mach (abfd, bfd_arch_loongarch, bfd_mach_loongarch32);
   4087  1.1.1.1.4.2  perseant   return true;
   4088  1.1.1.1.4.2  perseant }
   4089  1.1.1.1.4.2  perseant 
   4090  1.1.1.1.4.2  perseant static asection *
   4091  1.1.1.1.4.2  perseant loongarch_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info,
   4092  1.1.1.1.4.2  perseant 			    Elf_Internal_Rela *rel,
   4093  1.1.1.1.4.2  perseant 			    struct elf_link_hash_entry *h,
   4094  1.1.1.1.4.2  perseant 			    Elf_Internal_Sym *sym)
   4095  1.1.1.1.4.2  perseant {
   4096  1.1.1.1.4.2  perseant   if (h != NULL)
   4097  1.1.1.1.4.2  perseant     switch (ELFNN_R_TYPE (rel->r_info))
   4098  1.1.1.1.4.2  perseant       {
   4099  1.1.1.1.4.2  perseant       case R_LARCH_GNU_VTINHERIT:
   4100  1.1.1.1.4.2  perseant       case R_LARCH_GNU_VTENTRY:
   4101  1.1.1.1.4.2  perseant 	return NULL;
   4102  1.1.1.1.4.2  perseant       }
   4103  1.1.1.1.4.2  perseant 
   4104  1.1.1.1.4.2  perseant   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
   4105  1.1.1.1.4.2  perseant }
   4106  1.1.1.1.4.2  perseant 
   4107  1.1.1.1.4.2  perseant /* Return TRUE if symbol H should be hashed in the `.gnu.hash' section.  For
   4108  1.1.1.1.4.2  perseant    executable PLT slots where the executable never takes the address of those
   4109  1.1.1.1.4.2  perseant    functions, the function symbols are not added to the hash table.  */
   4110  1.1.1.1.4.2  perseant 
   4111  1.1.1.1.4.2  perseant static bool
   4112  1.1.1.1.4.2  perseant elf_loongarch64_hash_symbol (struct elf_link_hash_entry *h)
   4113  1.1.1.1.4.2  perseant {
   4114  1.1.1.1.4.2  perseant   if (h->plt.offset != (bfd_vma) -1
   4115  1.1.1.1.4.2  perseant       && !h->def_regular
   4116  1.1.1.1.4.2  perseant       && !h->pointer_equality_needed)
   4117  1.1.1.1.4.2  perseant     return false;
   4118  1.1.1.1.4.2  perseant 
   4119  1.1.1.1.4.2  perseant   return _bfd_elf_hash_symbol (h);
   4120  1.1.1.1.4.2  perseant }
   4121  1.1.1.1.4.2  perseant 
   4122  1.1.1.1.4.2  perseant #define TARGET_LITTLE_SYM loongarch_elfNN_vec
   4123  1.1.1.1.4.2  perseant #define TARGET_LITTLE_NAME "elfNN-loongarch"
   4124  1.1.1.1.4.2  perseant #define ELF_ARCH bfd_arch_loongarch
   4125  1.1.1.1.4.2  perseant #define ELF_TARGET_ID LARCH_ELF_DATA
   4126  1.1.1.1.4.2  perseant #define ELF_MACHINE_CODE EM_LOONGARCH
   4127  1.1.1.1.4.2  perseant #define ELF_MAXPAGESIZE 0x4000
   4128  1.1.1.1.4.2  perseant #define bfd_elfNN_bfd_reloc_type_lookup loongarch_reloc_type_lookup
   4129  1.1.1.1.4.2  perseant #define bfd_elfNN_bfd_link_hash_table_create				  \
   4130  1.1.1.1.4.2  perseant   loongarch_elf_link_hash_table_create
   4131  1.1.1.1.4.2  perseant #define bfd_elfNN_bfd_reloc_name_lookup loongarch_reloc_name_lookup
   4132  1.1.1.1.4.2  perseant #define elf_info_to_howto_rel NULL /* Fall through to elf_info_to_howto.  */
   4133  1.1.1.1.4.2  perseant #define elf_info_to_howto loongarch_info_to_howto_rela
   4134  1.1.1.1.4.2  perseant #define bfd_elfNN_bfd_merge_private_bfd_data				  \
   4135  1.1.1.1.4.2  perseant   elfNN_loongarch_merge_private_bfd_data
   4136  1.1.1.1.4.2  perseant 
   4137  1.1.1.1.4.2  perseant #define elf_backend_reloc_type_class loongarch_reloc_type_class
   4138  1.1.1.1.4.2  perseant #define elf_backend_copy_indirect_symbol loongarch_elf_copy_indirect_symbol
   4139  1.1.1.1.4.2  perseant #define elf_backend_create_dynamic_sections				   \
   4140  1.1.1.1.4.2  perseant   loongarch_elf_create_dynamic_sections
   4141  1.1.1.1.4.2  perseant #define elf_backend_check_relocs loongarch_elf_check_relocs
   4142  1.1.1.1.4.2  perseant #define elf_backend_adjust_dynamic_symbol loongarch_elf_adjust_dynamic_symbol
   4143  1.1.1.1.4.2  perseant #define elf_backend_size_dynamic_sections loongarch_elf_size_dynamic_sections
   4144  1.1.1.1.4.2  perseant #define elf_backend_relocate_section loongarch_elf_relocate_section
   4145  1.1.1.1.4.2  perseant #define elf_backend_finish_dynamic_symbol loongarch_elf_finish_dynamic_symbol
   4146  1.1.1.1.4.2  perseant #define elf_backend_finish_dynamic_sections				   \
   4147  1.1.1.1.4.2  perseant   loongarch_elf_finish_dynamic_sections
   4148  1.1.1.1.4.2  perseant #define elf_backend_object_p loongarch_elf_object_p
   4149  1.1.1.1.4.2  perseant #define elf_backend_gc_mark_hook loongarch_elf_gc_mark_hook
   4150  1.1.1.1.4.2  perseant #define elf_backend_plt_sym_val loongarch_elf_plt_sym_val
   4151  1.1.1.1.4.2  perseant #define elf_backend_grok_prstatus loongarch_elf_grok_prstatus
   4152  1.1.1.1.4.2  perseant #define elf_backend_grok_psinfo loongarch_elf_grok_psinfo
   4153  1.1.1.1.4.2  perseant #define elf_backend_hash_symbol elf_loongarch64_hash_symbol
   4154  1.1.1.1.4.2  perseant 
   4155  1.1.1.1.4.2  perseant #include "elfNN-target.h"
   4156