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