xref: /netbsd-src/external/gpl3/binutils.old/dist/bfd/elfxx-loongarch.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1 /* LoongArch-specific support for ELF.
2    Copyright (C) 2021-2022 Free Software Foundation, Inc.
3    Contributed by Loongson Ltd.
4 
5    Based on RISC-V target.
6 
7    This file is part of BFD, the Binary File Descriptor library.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; see the file COPYING3.  If not,
21    see <http://www.gnu.org/licenses/>.  */
22 
23 #include "sysdep.h"
24 #include "bfd.h"
25 #include "libbfd.h"
26 #include "elf-bfd.h"
27 #include "elf/loongarch.h"
28 #include "elfxx-loongarch.h"
29 
30 #define ALL_ONES (~ (bfd_vma) 0)
31 
32 typedef struct loongarch_reloc_howto_type_struct
33 {
34   /* The first must be reloc_howto_type!  */
35   reloc_howto_type howto;
36   bfd_reloc_code_real_type bfd_type;
37   bool (*adjust_reloc_bits)(reloc_howto_type *, bfd_vma *);
38 }loongarch_reloc_howto_type;
39 
40 #define LOONGARCH_DEFAULT_HOWTO(r_name)					    \
41   { HOWTO (R_LARCH_##r_name, 0, 4, 32, false, 0, complain_overflow_signed,  \
42 	bfd_elf_generic_reloc, "R_LARCH_" #r_name, false, 0, ALL_ONES,	    \
43 	false), BFD_RELOC_LARCH_##r_name, NULL }
44 
45 #define LOONGARCH_HOWTO(type, right, size, bits, pcrel, left, ovf, func,  \
46 	    name, inplace, src_mask, dst_mask, pcrel_off, btype, afunc)	  \
47   { HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,	  \
48 	  inplace, src_mask, dst_mask, pcrel_off), btype, afunc }
49 
50 #define LOONGARCH_EMPTY_HOWTO(C) \
51   { EMPTY_HOWTO(C), BFD_RELOC_NONE, NULL }
52 
53 bool loongarch_gen_adjust_reloc_bits (reloc_howto_type *howto, bfd_vma *val);
54 bool loongarch_adjust_reloc_bits_l16_xx5_h5 (reloc_howto_type *howto,
55 					     bfd_vma *fix_val);
56 bool loongarch_adjust_reloc_bits_l16_h10 (reloc_howto_type *howto,
57 					  bfd_vma *val);
58 
59 
60 /* This does not include any relocation information, but should be
61    good enough for GDB or objdump to read the file.  */
62 static loongarch_reloc_howto_type loongarch_howto_table[] =
63 {
64   /* No relocation.  */
65     LOONGARCH_HOWTO (R_LARCH_NONE,	  /* type (0).  */
66 	 0,				  /* rightshift */
67 	 0,				  /* size */
68 	 0,				  /* bitsize */
69 	 false,				  /* pc_relative */
70 	 0,				  /* bitpos */
71 	 complain_overflow_dont,	  /* complain_on_overflow */
72 	 bfd_elf_generic_reloc,		  /* special_function */
73 	 "R_LARCH_NONE",		  /* name */
74 	 false,				  /* partial_inplace */
75 	 0,				  /* src_mask */
76 	 0,				  /* dst_mask */
77 	 false,				  /* pcrel_offset */
78 	 BFD_RELOC_NONE,		  /* bfd_reloc_code_real_type */
79 	 NULL),				  /* adjust_reloc_bits */
80 
81   /* 32 bit relocation.  */
82   LOONGARCH_HOWTO (R_LARCH_32,		  /* type (1).  */
83 	 0,				  /* rightshift */
84 	 4,				  /* size */
85 	 32,				  /* bitsize */
86 	 false,				  /* pc_relative */
87 	 0,				  /* bitpos */
88 	 complain_overflow_dont,	  /* complain_on_overflow */
89 	 bfd_elf_generic_reloc,		  /* special_function */
90 	 "R_LARCH_32",			  /* name */
91 	 false,				  /* partial_inplace */
92 	 0,				  /* src_mask */
93 	 ALL_ONES,			  /* dst_mask */
94 	 false,				  /* pcrel_offset */
95 	 BFD_RELOC_32,			  /* bfd_reloc_code_real_type */
96 	 NULL),				  /* adjust_reloc_bits */
97 
98   /* 64 bit relocation.  */
99   LOONGARCH_HOWTO (R_LARCH_64,		  /* type (2).  */
100 	 0,				  /* rightshift */
101 	 8,				  /* size */
102 	 64,				  /* bitsize */
103 	 false,				  /* pc_relative */
104 	 0,				  /* bitpos */
105 	 complain_overflow_dont,	  /* complain_on_overflow */
106 	 bfd_elf_generic_reloc,		  /* special_function */
107 	 "R_LARCH_64",			  /* name */
108 	 false,				  /* partial_inplace */
109 	 0,				  /* src_mask */
110 	 ALL_ONES,			  /* dst_mask */
111 	 false,				  /* pcrel_offset */
112 	 BFD_RELOC_64,			  /* bfd_reloc_code_real_type */
113 	 NULL),				  /* adjust_reloc_bits */
114 
115   LOONGARCH_HOWTO (R_LARCH_RELATIVE,	  /* type (3).  */
116 	 0,				  /* rightshift */
117 	 4,				  /* size */
118 	 32,				  /* bitsize */
119 	 false,				  /* pc_relative */
120 	 0,				  /* bitpos */
121 	 complain_overflow_dont,	  /* complain_on_overflow */
122 	 bfd_elf_generic_reloc,		  /* special_function */
123 	 "R_LARCH_RELATIVE",		  /* name */
124 	 false,				  /* partial_inplace */
125 	 0,				  /* src_mask */
126 	 ALL_ONES,			  /* dst_mask */
127 	 false,				  /* pcrel_offset */
128 	 BFD_RELOC_NONE,		  /* undefined?  */
129 	 NULL),				  /* adjust_reloc_bits */
130 
131   LOONGARCH_HOWTO (R_LARCH_COPY,	  /* type (4).  */
132 	 0,				  /* rightshift */
133 	 0,				  /* this one is variable size */
134 	 0,				  /* bitsize */
135 	 false,				  /* pc_relative */
136 	 0,				  /* bitpos */
137 	 complain_overflow_bitfield,	  /* complain_on_overflow */
138 	 bfd_elf_generic_reloc,		  /* special_function */
139 	 "R_LARCH_COPY",		  /* name */
140 	 false,				  /* partial_inplace */
141 	 0,				  /* src_mask */
142 	 0,				  /* dst_mask */
143 	 false,				  /* pcrel_offset */
144 	 BFD_RELOC_NONE,			  /* undefined?  */
145 	 NULL),				  /* adjust_reloc_bits */
146 
147   LOONGARCH_HOWTO (R_LARCH_JUMP_SLOT,	  /* type (5).  */
148 	 0,				  /* rightshift */
149 	 8,				  /* size */
150 	 64,				  /* bitsize */
151 	 false,				  /* pc_relative */
152 	 0,				  /* bitpos */
153 	 complain_overflow_bitfield,	  /* complain_on_overflow */
154 	 bfd_elf_generic_reloc,		  /* special_function */
155 	 "R_LARCH_JUMP_SLOT",		  /* name */
156 	 false,				  /* partial_inplace */
157 	 0,				  /* src_mask */
158 	 0,				  /* dst_mask */
159 	 false,				  /* pcrel_offset */
160 	 BFD_RELOC_NONE,			  /* undefined?  */
161 	 NULL),				  /* adjust_reloc_bits */
162 
163   /* Dynamic TLS relocations.  */
164   LOONGARCH_HOWTO (R_LARCH_TLS_DTPMOD32,  /* type (6).  */
165 	 0,				  /* rightshift */
166 	 4,				  /* size */
167 	 32,				  /* bitsize */
168 	 false,				  /* pc_relative */
169 	 0,				  /* bitpos */
170 	 complain_overflow_dont,	  /* complain_on_overflow */
171 	 bfd_elf_generic_reloc,		  /* special_function */
172 	 "R_LARCH_TLS_DTPMOD32",	  /* name */
173 	 false,				  /* partial_inplace */
174 	 0,				  /* src_mask */
175 	 ALL_ONES,			  /* dst_mask */
176 	 false,				  /* pcrel_offset */
177 	 BFD_RELOC_LARCH_TLS_DTPMOD32,	  /* bfd_reloc_code_real_type */
178 	 NULL),				  /* adjust_reloc_bits */
179 
180   LOONGARCH_HOWTO (R_LARCH_TLS_DTPMOD64,  /* type (7).  */
181 	 0,				  /* rightshift */
182 	 8,				  /* size */
183 	 64,				  /* bitsize */
184 	 false,				  /* pc_relative */
185 	 0,				  /* bitpos */
186 	 complain_overflow_dont,	  /* complain_on_overflow */
187 	 bfd_elf_generic_reloc,		  /* special_function */
188 	 "R_LARCH_TLS_DTPMOD64",	  /* name */
189 	 false,				  /* partial_inplace */
190 	 0,				  /* src_mask */
191 	 ALL_ONES,			  /* dst_mask */
192 	 false,				  /* pcrel_offset */
193 	 BFD_RELOC_LARCH_TLS_DTPMOD64,	  /* bfd_reloc_code_real_type */
194 	 NULL),				  /* adjust_reloc_bits */
195 
196   LOONGARCH_HOWTO (R_LARCH_TLS_DTPREL32,  /* type (8). */
197 	 0,				  /* rightshift */
198 	 4,				  /* size */
199 	 32,				  /* bitsize */
200 	 false,				  /* pc_relative */
201 	 0,				  /* bitpos */
202 	 complain_overflow_dont,	  /* complain_on_overflow */
203 	 bfd_elf_generic_reloc,		  /* special_function */
204 	 "R_LARCH_TLS_DTPREL32",	  /* name */
205 	 true,				  /* partial_inplace */
206 	 0,				  /* src_mask */
207 	 ALL_ONES,			  /* dst_mask */
208 	 false,				  /* pcrel_offset */
209 	 BFD_RELOC_LARCH_TLS_DTPREL32,	  /* bfd_reloc_code_real_type */
210 	 NULL),				  /* adjust_reloc_bits */
211 
212   LOONGARCH_HOWTO (R_LARCH_TLS_DTPREL64,  /* type (9).  */
213 	 0,				  /* rightshift */
214 	 8,				  /* size */
215 	 64,				  /* bitsize */
216 	 false,				  /* pc_relative */
217 	 0,				  /* bitpos */
218 	 complain_overflow_dont,	  /* complain_on_overflow */
219 	 bfd_elf_generic_reloc,		  /* special_function */
220 	 "R_LARCH_TLS_DTPREL64",	  /* name */
221 	 true,				  /* partial_inplace */
222 	 0,				  /* src_mask */
223 	 ALL_ONES,			  /* dst_mask */
224 	 false,				  /* pcrel_offset */
225 	 BFD_RELOC_LARCH_TLS_DTPREL64,	  /* bfd_reloc_code_real_type */
226 	 NULL),				  /* adjust_reloc_bits */
227 
228   LOONGARCH_HOWTO (R_LARCH_TLS_TPREL32,	  /* type (10).  */
229 	 0,				  /* rightshift */
230 	 4,				  /* size */
231 	 32,				  /* bitsize */
232 	 false,				  /* pc_relative */
233 	 0,				  /* bitpos */
234 	 complain_overflow_dont,	  /* complain_on_overflow */
235 	 bfd_elf_generic_reloc,		  /* special_function */
236 	 "R_LARCH_TLS_TPREL32",		  /* name */
237 	 false,				  /* partial_inplace */
238 	 0,				  /* src_mask */
239 	 ALL_ONES,			  /* dst_mask */
240 	 false,				  /* pcrel_offset */
241 	 BFD_RELOC_LARCH_TLS_TPREL32,	  /* bfd_reloc_code_real_type */
242 	 NULL),				  /* adjust_reloc_bits */
243 
244   LOONGARCH_HOWTO (R_LARCH_TLS_TPREL64,	  /* type (11).  */
245 	 0,				  /* rightshift */
246 	 8,				  /* size */
247 	 64,				  /* bitsize */
248 	 false,				  /* pc_relative */
249 	 0,				  /* bitpos */
250 	 complain_overflow_dont,	  /* complain_on_overflow */
251 	 bfd_elf_generic_reloc,		  /* special_function */
252 	 "R_LARCH_TLS_TPREL64",		  /* name */
253 	 false,				  /* partial_inplace */
254 	 0,				  /* src_mask */
255 	 ALL_ONES,			  /* dst_mask */
256 	 false,				  /* pcrel_offset */
257 	 BFD_RELOC_LARCH_TLS_TPREL64,	  /* bfd_reloc_code_real_type */
258 	 NULL),				  /* adjust_reloc_bits */
259 
260   LOONGARCH_HOWTO (R_LARCH_IRELATIVE,	  /* type (12).  */
261 	 0,				  /* rightshift */
262 	 4,				  /* size */
263 	 32,				  /* bitsize */
264 	 false,				  /* pc_relative */
265 	 0,				  /* bitpos */
266 	 complain_overflow_dont,	  /* complain_on_overflow */
267 	 bfd_elf_generic_reloc,		  /* special_function */
268 	 "R_LARCH_IRELATIVE",		  /* name */
269 	 false,				  /* partial_inplace */
270 	 0,				  /* src_mask */
271 	 ALL_ONES,			  /* dst_mask */
272 	 false,				  /* pcrel_offset */
273 	 BFD_RELOC_NONE,		  /* undefined?  */
274 	 NULL),				  /* adjust_reloc_bits */
275 
276   LOONGARCH_EMPTY_HOWTO(13),
277   LOONGARCH_EMPTY_HOWTO(14),
278   LOONGARCH_EMPTY_HOWTO(15),
279   LOONGARCH_EMPTY_HOWTO(16),
280   LOONGARCH_EMPTY_HOWTO(17),
281   LOONGARCH_EMPTY_HOWTO(18),
282   LOONGARCH_EMPTY_HOWTO(19),
283 
284   LOONGARCH_HOWTO (R_LARCH_MARK_LA,		/* type (20).  */
285 	 0,				   	/* rightshift.  */
286 	 0,				   	/* size.  */
287 	 0,				  	/* bitsize.  */
288 	 false,					/* pc_relative.  */
289 	 0,				   	/* bitpos.  */
290 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
291 	 bfd_elf_generic_reloc,	       		/* special_function.  */
292 	 "R_LARCH_MARK_LA",			/* name.  */
293 	 false,			       		/* partial_inplace.  */
294 	 0,					/* src_mask.  */
295 	 0,					/* dst_mask.  */
296 	 false,					/* pcrel_offset */
297 	 BFD_RELOC_LARCH_MARK_LA,		/* bfd_reloc_code_real_type */
298 	 NULL),					/* adjust_reloc_bits */
299 
300   LOONGARCH_HOWTO (R_LARCH_MARK_PCREL,		/* type (21).  */
301 	 0,				   	/* rightshift.  */
302 	 0,				   	/* size.  */
303 	 0,				  	/* bitsize.  */
304 	 false,					/* pc_relative.  */
305 	 0,				   	/* bitpos.  */
306 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
307 	 bfd_elf_generic_reloc,	       		/* special_function.  */
308 	 "R_LARCH_MARK_PCREL",			/* name.  */
309 	 false,			       		/* partial_inplace.  */
310 	 0,					/* src_mask.  */
311 	 0,					/* dst_mask.  */
312 	 false,					/* pcrel_offset */
313 	 BFD_RELOC_LARCH_MARK_PCREL,		/* bfd_reloc_code_real_type */
314 	 NULL),					/* adjust_reloc_bits */
315 
316   LOONGARCH_HOWTO (R_LARCH_SOP_PUSH_PCREL,	/* type (22).  */
317 	 2,				   	/* rightshift.  */
318 	 4,				   	/* size.  */
319 	 32,				  	/* bitsize.  */
320 	 true /* FIXME: somewhat use this.  */,	/* pc_relative.  */
321 	 0,				   	/* bitpos.  */
322 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
323 	 bfd_elf_generic_reloc,	       		/* special_function.  */
324 	 "R_LARCH_SOP_PUSH_PCREL",	    	/* name.  */
325 	 false,			       		/* partial_inplace.  */
326 	 0x03ffffff,				/* src_mask.  */
327 	 0x03ffffff,				/* dst_mask.  */
328 	 false,					/* pcrel_offset */
329 	 BFD_RELOC_LARCH_SOP_PUSH_PCREL,	/* bfd_reloc_code_real_type */
330 	 NULL),					/* adjust_reloc_bits */
331 
332   /* type 23-37.  */
333   LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_ABSOLUTE),
334   LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_DUP),
335   LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_GPREL),
336   LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_TLS_TPREL),
337   LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_TLS_GOT),
338   LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_TLS_GD),
339   LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_PLT_PCREL),
340   LOONGARCH_DEFAULT_HOWTO (SOP_ASSERT),
341   LOONGARCH_DEFAULT_HOWTO (SOP_NOT),
342   LOONGARCH_DEFAULT_HOWTO (SOP_SUB),
343   LOONGARCH_DEFAULT_HOWTO (SOP_SL),
344   LOONGARCH_DEFAULT_HOWTO (SOP_SR),
345   LOONGARCH_DEFAULT_HOWTO (SOP_ADD),
346   LOONGARCH_DEFAULT_HOWTO (SOP_AND),
347   LOONGARCH_DEFAULT_HOWTO (SOP_IF_ELSE),
348 
349   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_5,	  /* type (38).  */
350 	 0,				   	  /* rightshift.  */
351 	 4,				   	  /* size.  */
352 	 5,				  	  /* bitsize.  */
353 	 false,					  /* pc_relative.  */
354 	 10,				   	  /* bitpos.  */
355 	 complain_overflow_signed,	    	  /* complain_on_overflow.  */
356 	 bfd_elf_generic_reloc,	       		  /* special_function.  */
357 	 "R_LARCH_SOP_POP_32_S_10_5",	    	  /* name.  */
358 	 false,			       		  /* partial_inplace.  */
359 	 0,					  /* src_mask */
360 	 0x7c00,				  /* dst_mask */
361 	 false,					  /* pcrel_offset */
362 	 BFD_RELOC_LARCH_SOP_POP_32_S_10_5,	  /* bfd_reloc_code_real_type */
363 	 loongarch_gen_adjust_reloc_bits),	  /* adjust_reloc_bits */
364 
365   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_U_10_12,	  /* type (39).  */
366 	 0,				   	  /* rightshift.  */
367 	 4,				   	  /* size.  */
368 	 12,				  	  /* bitsize.  */
369 	 false,					  /* pc_relative.  */
370 	 10,				   	  /* bitpos.  */
371 	 complain_overflow_unsigned,	    	  /* complain_on_overflow.  */
372 	 bfd_elf_generic_reloc,	       		  /* special_function.  */
373 	 "R_LARCH_SOP_POP_32_U_10_12",	    	  /* name.  */
374 	 false,			       		  /* partial_inplace.  */
375 	 0,					  /* src_mask */
376 	 0x3ffc00,				  /* dst_mask */
377 	 false,					  /* pcrel_offset */
378 	 BFD_RELOC_LARCH_SOP_POP_32_U_10_12,	  /* bfd_reloc_code_real_type */
379 	 loongarch_gen_adjust_reloc_bits),	  /* adjust_reloc_bits */
380 
381   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_12,	  /* type (40).  */
382 	 0,				   	  /* rightshift.  */
383 	 4,				   	  /* size.  */
384 	 12,				  	  /* bitsize.  */
385 	 false,					  /* pc_relative.  */
386 	 10,				   	  /* bitpos.  */
387 	 complain_overflow_signed,	    	  /* complain_on_overflow.  */
388 	 bfd_elf_generic_reloc,	       		  /* special_function.  */
389 	 "R_LARCH_SOP_POP_32_S_10_12",	    	  /* name.  */
390 	 false,			       		  /* partial_inplace.  */
391 	 0,					  /* src_mask */
392 	 0x3ffc00,				  /* dst_mask */
393 	 false,					  /* pcrel_offset */
394 	 BFD_RELOC_LARCH_SOP_POP_32_S_10_12,	  /* bfd_reloc_code_real_type */
395 	 loongarch_gen_adjust_reloc_bits),	  /* adjust_reloc_bits */
396 
397   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_16,	  /* type (41).  */
398 	 0,				   	  /* rightshift.  */
399 	 4,				   	  /* size.  */
400 	 16,				  	  /* bitsize.  */
401 	 false,					  /* pc_relative.  */
402 	 10,				   	  /* bitpos.  */
403 	 complain_overflow_signed,	    	  /* complain_on_overflow.  */
404 	 bfd_elf_generic_reloc,	       		  /* special_function.  */
405 	 "R_LARCH_SOP_POP_32_S_10_16",	    	  /* name.  */
406 	 false,			       		  /* partial_inplace.  */
407 	 0,					  /* src_mask */
408 	 0x3fffc00,				  /* dst_mask */
409 	 false,					  /* pcrel_offset */
410 	 BFD_RELOC_LARCH_SOP_POP_32_S_10_16,	  /* bfd_reloc_code_real_type */
411 	 loongarch_gen_adjust_reloc_bits),	  /* adjust_reloc_bits */
412 
413   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_16_S2, /* type (42).  */
414 	 2,					  /* rightshift.  */
415 	 4,				   	  /* size.  */
416 	 16,				  	  /* bitsize.  */
417 	 false,					  /* pc_relative.  */
418 	 10,				   	  /* bitpos.  */
419 	 complain_overflow_signed,	    	  /* complain_on_overflow.  */
420 	 bfd_elf_generic_reloc,	       		  /* special_function.  */
421 	 "R_LARCH_SOP_POP_32_S_10_16_S2",    	  /* name.  */
422 	 false,			       		  /* partial_inplace.  */
423 	 0,					  /* src_mask */
424 	 0x3fffc00,				  /* dst_mask */
425 	 false,					  /* pcrel_offset */
426 	 BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2,	  /* bfd_reloc_code_real_type */
427 	 loongarch_gen_adjust_reloc_bits),	  /* adjust_reloc_bits */
428 
429   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_5_20,	  /* type (43).  */
430 	 0,				   	  /* rightshift.  */
431 	 4,				   	  /* size.  */
432 	 20,				  	  /* bitsize.  */
433 	 false,					  /* pc_relative.  */
434 	 5,				   	  /* bitpos.  */
435 	 complain_overflow_signed,	    	  /* complain_on_overflow.  */
436 	 bfd_elf_generic_reloc,	       		  /* special_function.  */
437 	 "R_LARCH_SOP_POP_32_S_5_20",    	  /* name.  */
438 	 false,			       		  /* partial_inplace.  */
439 	 0,					  /* src_mask */
440 	 0x1ffffe0,				  /* dst_mask */
441 	 false,					  /* pcrel_offset */
442 	 BFD_RELOC_LARCH_SOP_POP_32_S_5_20,	  /* bfd_reloc_code_real_type */
443 	 loongarch_gen_adjust_reloc_bits),        /* adjust_reloc_bits */
444 
445   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_0_5_10_16_S2,
446 						  /* type (44).  */
447 	 2,					  /* rightshift.  */
448 	 4,					  /* size.  */
449 	 21,				  	  /* bitsize.  */
450 	 false,					  /* pc_relative.  */
451 	 0,				   	  /* bitpos.  */
452 	 complain_overflow_signed,	    	  /* complain_on_overflow.  */
453 	 bfd_elf_generic_reloc,	       		  /* special_function.  */
454 	 "R_LARCH_SOP_POP_32_S_0_5_10_16_S2",  	  /* name.  */
455 	 false,			       		  /* partial_inplace.  */
456 	 0xfc0003e0,				  /* src_mask */
457 	 0xfc0003e0,				  /* dst_mask */
458 	 false,					  /* pcrel_offset */
459 	 BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2,
460 						  /* bfd_reloc_code_real_type */
461 	 loongarch_adjust_reloc_bits_l16_xx5_h5), /* adjust_reloc_bits */
462 
463   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_0_10_10_16_S2,	/* type (45).  */
464 	 2,				   	/* rightshift.  */
465 	 4,				   	/* size.  */
466 	 26,				  	/* bitsize.  */
467 	 false,					/* pc_relative.  */
468 	 0,				   	/* bitpos.  */
469 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
470 	 bfd_elf_generic_reloc,	       		/* special_function.  */
471 	 "R_LARCH_SOP_POP_32_S_0_10_10_16_S2", 	/* name.  */
472 	 false,			       		/* partial_inplace.  */
473 	 0xfc000000,				/* src_mask */
474 	 0xfc000000,				/* dst_mask */
475 	 false,					/* pcrel_offset */
476 	 BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2,
477 						/* bfd_reloc_code_real_type */
478 	 loongarch_adjust_reloc_bits_l16_h10),	/* adjust_reloc_bits */
479 
480   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_U,	/* type (46).  */
481 	 0,				   	/* rightshift.  */
482 	 4,				   	/* size.  */
483 	 32,				  	/* bitsize.  */
484 	 false,					/* pc_relative.  */
485 	 0,				   	/* bitpos.  */
486 	 complain_overflow_unsigned,	    	/* complain_on_overflow.  */
487 	 bfd_elf_generic_reloc,	       		/* special_function.  */
488 	 "R_LARCH_SOP_POP_32_S_U",    		/* name.  */
489 	 false,			       		/* partial_inplace.  */
490 	 0xffffffff00000000,			/* src_mask */
491 	 0x00000000ffffffff,			/* dst_mask */
492 	 false,					/* pcrel_offset */
493 	 BFD_RELOC_LARCH_SOP_POP_32_U,		/* bfd_reloc_code_real_type */
494 	 loongarch_gen_adjust_reloc_bits),	/* adjust_reloc_bits */
495 
496   LOONGARCH_HOWTO (R_LARCH_ADD8,	      	/* type (47).  */
497 	 0,				   	/* rightshift.  */
498 	 4,				   	/* size.  */
499 	 8,				  	/* bitsize.  */
500 	 false,					/* pc_relative.  */
501 	 0,				   	/* bitpos.  */
502 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
503 	 bfd_elf_generic_reloc,	       		/* special_function.  */
504 	 "R_LARCH_ADD8",    			/* name.  */
505 	 false,			       		/* partial_inplace.  */
506 	 0,					/* src_mask */
507 	 ALL_ONES,				/* dst_mask */
508 	 false,					/* pcrel_offset */
509 	 BFD_RELOC_LARCH_ADD8,			/* bfd_reloc_code_real_type */
510 	 NULL),					/* adjust_reloc_bits */
511 
512   LOONGARCH_HOWTO (R_LARCH_ADD16,	      	/* type (48).  */
513 	 0,				   	/* rightshift.  */
514 	 4,				   	/* size.  */
515 	 16,				  	/* bitsize.  */
516 	 false,					/* pc_relative.  */
517 	 0,				   	/* bitpos.  */
518 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
519 	 bfd_elf_generic_reloc,	       		/* special_function.  */
520 	 "R_LARCH_ADD16",    			/* name.  */
521 	 false,			       		/* partial_inplace.  */
522 	 0,					/* src_mask */
523 	 ALL_ONES,				/* dst_mask */
524 	 false,					/* pcrel_offset */
525 	 BFD_RELOC_LARCH_ADD16,			/* bfd_reloc_code_real_type */
526 	 NULL),					/* adjust_reloc_bits */
527 
528   LOONGARCH_HOWTO (R_LARCH_ADD24,	      	/* type (49).  */
529 	 0,				   	/* rightshift.  */
530 	 4,				   	/* size.  */
531 	 24,				  	/* bitsize.  */
532 	 false,					/* pc_relative.  */
533 	 0,				   	/* bitpos.  */
534 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
535 	 bfd_elf_generic_reloc,	       		/* special_function.  */
536 	 "R_LARCH_ADD24",    			/* name.  */
537 	 false,			       		/* partial_inplace.  */
538 	 0,					/* src_mask */
539 	 ALL_ONES,				/* dst_mask */
540 	 false,					/* pcrel_offset */
541 	 BFD_RELOC_LARCH_ADD24,			/* bfd_reloc_code_real_type */
542 	 NULL),					/* adjust_reloc_bits */
543 
544   LOONGARCH_HOWTO (R_LARCH_ADD32,	      	/* type (50).  */
545 	 0,				   	/* rightshift.  */
546 	 4,				   	/* size.  */
547 	 32,				  	/* bitsize.  */
548 	 false,					/* pc_relative.  */
549 	 0,				   	/* bitpos.  */
550 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
551 	 bfd_elf_generic_reloc,	       		/* special_function.  */
552 	 "R_LARCH_ADD32",    			/* name.  */
553 	 false,			       		/* partial_inplace.  */
554 	 0,					/* src_mask */
555 	 ALL_ONES,				/* dst_mask */
556 	 false,					/* pcrel_offset */
557 	 BFD_RELOC_LARCH_ADD32,			/* bfd_reloc_code_real_type */
558 	 NULL),					/* adjust_reloc_bits */
559 
560   LOONGARCH_HOWTO (R_LARCH_ADD64,	      	/* type (51).  */
561 	 0,				   	/* rightshift.  */
562 	 8,				   	/* size.  */
563 	 64,				  	/* bitsize.  */
564 	 false,					/* pc_relative.  */
565 	 0,				   	/* bitpos.  */
566 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
567 	 bfd_elf_generic_reloc,	       		/* special_function.  */
568 	 "R_LARCH_ADD64",    			/* name.  */
569 	 false,			       		/* partial_inplace.  */
570 	 0,					/* src_mask */
571 	 ALL_ONES,				/* dst_mask */
572 	 false,					/* pcrel_offset */
573 	 BFD_RELOC_LARCH_ADD64,			/* bfd_reloc_code_real_type */
574 	 NULL),					/* adjust_reloc_bits */
575 
576   LOONGARCH_HOWTO (R_LARCH_SUB8,	      	/* type (52).  */
577 	 0,				   	/* rightshift.  */
578 	 4,				   	/* size.  */
579 	 8,				  	/* bitsize.  */
580 	 false,					/* pc_relative.  */
581 	 0,				   	/* bitpos.  */
582 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
583 	 bfd_elf_generic_reloc,	       		/* special_function.  */
584 	 "R_LARCH_SUB8",    			/* name.  */
585 	 false,			       		/* partial_inplace.  */
586 	 0,					/* src_mask */
587 	 ALL_ONES,				/* dst_mask */
588 	 false,					/* pcrel_offset */
589 	 BFD_RELOC_LARCH_SUB8,			/* bfd_reloc_code_real_type */
590 	 NULL),					/* adjust_reloc_bits */
591 
592   LOONGARCH_HOWTO (R_LARCH_SUB16,	      	/* type (53).  */
593 	 0,				   	/* rightshift.  */
594 	 4,				   	/* size.  */
595 	 16,				  	/* bitsize.  */
596 	 false,					/* pc_relative.  */
597 	 0,				   	/* bitpos.  */
598 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
599 	 bfd_elf_generic_reloc,	       		/* special_function.  */
600 	 "R_LARCH_SUB16",    			/* name.  */
601 	 false,			       		/* partial_inplace.  */
602 	 0,					/* src_mask */
603 	 ALL_ONES,				/* dst_mask */
604 	 false,					/* pcrel_offset */
605 	 BFD_RELOC_LARCH_SUB16,			/* bfd_reloc_code_real_type */
606 	 NULL),					/* adjust_reloc_bits */
607 
608   LOONGARCH_HOWTO (R_LARCH_SUB24,	      	/* type (54).  */
609 	 0,				   	/* rightshift.  */
610 	 4,				   	/* size.  */
611 	 24,				  	/* bitsize.  */
612 	 false,					/* pc_relative.  */
613 	 0,				   	/* bitpos.  */
614 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
615 	 bfd_elf_generic_reloc,	       		/* special_function.  */
616 	 "R_LARCH_SUB24",    			/* name.  */
617 	 false,			       		/* partial_inplace.  */
618 	 0,					/* src_mask */
619 	 ALL_ONES,				/* dst_mask */
620 	 false,					/* pcrel_offset */
621 	 BFD_RELOC_LARCH_SUB24,			/* bfd_reloc_code_real_type */
622 	 NULL),					/* adjust_reloc_bits */
623 
624   LOONGARCH_HOWTO (R_LARCH_SUB32,	      	/* type (55).  */
625 	 0,				   	/* rightshift.  */
626 	 4,				   	/* size.  */
627 	 32,				  	/* bitsize.  */
628 	 false,					/* pc_relative.  */
629 	 0,				   	/* bitpos.  */
630 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
631 	 bfd_elf_generic_reloc,	       		/* special_function.  */
632 	 "R_LARCH_SUB32",    			/* name.  */
633 	 false,			       		/* partial_inplace.  */
634 	 0,					/* src_mask */
635 	 ALL_ONES,				/* dst_mask */
636 	 false,					/* pcrel_offset */
637 	 BFD_RELOC_LARCH_SUB32,			/* bfd_reloc_code_real_type */
638 	 NULL),					/* adjust_reloc_bits */
639 
640   LOONGARCH_HOWTO (R_LARCH_SUB64,	      	/* type (56).  */
641 	 0,				   	/* rightshift.  */
642 	 8,				   	/* size.  */
643 	 64,				  	/* bitsize.  */
644 	 false,					/* pc_relative.  */
645 	 0,				   	/* bitpos.  */
646 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
647 	 bfd_elf_generic_reloc,	       		/* special_function.  */
648 	 "R_LARCH_SUB64",    			/* name.  */
649 	 false,			       		/* partial_inplace.  */
650 	 0,					/* src_mask */
651 	 ALL_ONES,				/* dst_mask */
652 	 false,					/* pcrel_offset */
653 	 BFD_RELOC_LARCH_SUB64,			/* bfd_reloc_code_real_type */
654 	 NULL),					/* adjust_reloc_bits */
655 
656   LOONGARCH_HOWTO (R_LARCH_GNU_VTINHERIT,      	/* type (57).  */
657 	 0,				   	/* rightshift.  */
658 	 0,				   	/* size.  */
659 	 0,				  	/* bitsize.  */
660 	 false,					/* pc_relative.  */
661 	 0,				   	/* bitpos.  */
662 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
663 	 bfd_elf_generic_reloc,	       		/* special_function.  */
664 	 "R_LARCH_GNU_VTINHERIT",  		/* name.  */
665 	 false,			       		/* partial_inplace.  */
666 	 0,					/* src_mask */
667 	 0,					/* dst_mask */
668 	 false,					/* pcrel_offset */
669 	 BFD_RELOC_NONE,			/* bfd_reloc_code_real_type */
670 	 NULL),					/* adjust_reloc_bits */
671 
672   LOONGARCH_HOWTO (R_LARCH_GNU_VTENTRY,      	/* type (58).  */
673 	 0,				   	/* rightshift.  */
674 	 0,				   	/* size.  */
675 	 0,				  	/* bitsize.  */
676 	 false,					/* pc_relative.  */
677 	 0,				   	/* bitpos.  */
678 	 complain_overflow_signed,	    	/* complain_on_overflow.  */
679 	 NULL,					/* special_function.  */
680 	 "R_LARCH_GNU_VTENTRY",  		/* name.  */
681 	 false,			       		/* partial_inplace.  */
682 	 0,					/* src_mask */
683 	 0,					/* dst_mask */
684 	 false,					/* pcrel_offset */
685 	 BFD_RELOC_NONE,			/* bfd_reloc_code_real_type */
686 	 NULL),					/* adjust_reloc_bits */
687 };
688 
689 reloc_howto_type *
loongarch_elf_rtype_to_howto(bfd * abfd,unsigned int r_type)690 loongarch_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
691 {
692   if(r_type < R_LARCH_count)
693     {
694       /* For search table fast.  */
695       BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count);
696 
697       if (loongarch_howto_table[r_type].howto.type == r_type)
698 	return (reloc_howto_type *)&loongarch_howto_table[r_type];
699 
700       BFD_ASSERT (loongarch_howto_table[r_type].howto.type == r_type);
701 
702       for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
703 	if (loongarch_howto_table[i].howto.type == r_type)
704 	  return (reloc_howto_type *)&loongarch_howto_table[i];
705     }
706 
707   (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"),
708 			 abfd, r_type);
709   bfd_set_error (bfd_error_bad_value);
710   return NULL;
711 }
712 
713 reloc_howto_type *
loongarch_reloc_name_lookup(bfd * abfd ATTRIBUTE_UNUSED,const char * r_name)714 loongarch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
715 {
716   BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count);
717 
718   for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
719     if (loongarch_howto_table[i].howto.name
720 	&& strcasecmp (loongarch_howto_table[i].howto.name, r_name) == 0)
721       return (reloc_howto_type *)&loongarch_howto_table[i];
722 
723   (*_bfd_error_handler) (_("%pB: unsupported relocation type %s"),
724 			 abfd, r_name);
725   bfd_set_error (bfd_error_bad_value);
726 
727   return NULL;
728 }
729 
730 /* Cost so much.  */
731 reloc_howto_type *
loongarch_reloc_type_lookup(bfd * abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code)732 loongarch_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
733 			     bfd_reloc_code_real_type code)
734 {
735   BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count);
736 
737   for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
738     if (loongarch_howto_table[i].bfd_type == code)
739       return (reloc_howto_type *)&loongarch_howto_table[i];
740 
741   (*_bfd_error_handler) (_("%pB: unsupported bfd relocation type %#x"),
742 			 abfd, code);
743   bfd_set_error (bfd_error_bad_value);
744 
745   return NULL;
746 }
747 
748 #define LARCH_RELOC_BFD_VMA_BIT_MASK(bitsize) \
749   (~((((bfd_vma)0x1) << (bitsize)) - 1))
750 
751 /* Adjust val to perform insn
752  * BFD_RELOC_LARCH_SOP_POP_32_S_10_5
753  * BFD_RELOC_LARCH_SOP_POP_32_S_10_12
754  * BFD_RELOC_LARCH_SOP_POP_32_U_10_12
755  * BFD_RELOC_LARCH_SOP_POP_32_S_10_16
756  * BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2
757  * BFD_RELOC_LARCH_SOP_POP_32_S_5_20
758  * BFD_RELOC_LARCH_SOP_POP_32_U.
759 */
760 
loongarch_gen_adjust_reloc_bits(reloc_howto_type * howto,bfd_vma * fix_val)761 bool loongarch_gen_adjust_reloc_bits (reloc_howto_type *howto, bfd_vma *fix_val)
762 {
763   bfd_vma val = *fix_val;
764   /* Check val low bits if rightshift != 0, before rightshift  */
765   if (howto->rightshift
766       && (((0x1UL << howto->rightshift) - 1) & val))
767     return false;
768 
769   int bitsize = howto->bitsize + howto->rightshift;
770 
771   /* Return false if overflow.  */
772   if (howto->complain_on_overflow == complain_overflow_signed)
773     {
774       bfd_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
775       /* If val < 0.  */
776       if (sig_bit)
777 	{
778 	  if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
779 	      != LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1))
780 	    return false;
781 	}
782       else
783 	{
784 	  if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
785 	    return false;
786 	}
787     }
788   else if (howto->complain_on_overflow == complain_overflow_unsigned)
789     {
790       if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val)
791 	return false;
792     }
793   else
794     return false;
795 
796   /* Perform insn bits field.  */
797   val = (val & ((0x1U << bitsize) - 1)) >> howto->rightshift;
798   val <<= howto->bitpos;
799 
800   *fix_val = val;
801 
802   return true;
803 }
804 
805 /* Reloc type R_LARCH_SOP_POP_32_S_0_5_10_16_S2.  */
loongarch_adjust_reloc_bits_l16_xx5_h5(reloc_howto_type * howto,bfd_vma * fix_val)806 bool loongarch_adjust_reloc_bits_l16_xx5_h5 (reloc_howto_type *howto,
807 					     bfd_vma *fix_val)
808 {
809   bfd_vma val = *fix_val;
810   /* Check val low bits if rightshift != 0, before rightshift  */
811   if (howto->rightshift
812       && (((0x1UL << howto->rightshift) - 1) & val))
813     return false;
814 
815   /* Return false if overflow.  */
816   if (howto->complain_on_overflow != complain_overflow_signed)
817     return false;
818 
819   int bitsize = howto->bitsize + howto->rightshift;
820   bfd_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
821   /* If val < 0.  */
822   if (sig_bit)
823     {
824       if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
825 	  != LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1))
826 	return false;
827     }
828   else
829     {
830       if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
831 	return false;
832     }
833 
834   /* Perform insn bits field.  */
835   val = (val & ((0x1U << bitsize) - 1)) >> howto->rightshift;
836 
837   /* Perform insn bits field. 20:16>>16, 15:0<<10 */
838   val = ((val & 0xffff) << 10) | ((val >> 16) & 0x1f);
839 
840   *fix_val = val;
841 
842   return true;
843 }
844 
845 /* Reloc type R_LARCH_SOP_POP_32_S_0_10_10_16_S2.  */
loongarch_adjust_reloc_bits_l16_h10(reloc_howto_type * howto,bfd_vma * fix_val)846 bool loongarch_adjust_reloc_bits_l16_h10 (reloc_howto_type *howto,
847 					  bfd_vma *fix_val)
848 {
849   bfd_vma val = *fix_val;
850   /* Check val low bits if rightshift != 0, before rightshift  */
851   if (howto->rightshift
852       && (((0x1UL << howto->rightshift) - 1) & val))
853     return false;
854 
855   /* Return false if overflow.  */
856   if (howto->complain_on_overflow != complain_overflow_signed)
857     return false;
858 
859   int bitsize = howto->bitsize + howto->rightshift;
860   bfd_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
861   /* If val < 0.  */
862   if (sig_bit)
863     {
864       if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
865 	  != LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1))
866 	return false;
867     }
868   else
869     {
870       if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
871 	return false;
872     }
873 
874   /* Perform insn bits field.  */
875   val = (val & ((0x1U << bitsize) - 1)) >> howto->rightshift;
876 
877   /* Perform insn bits field. 25:16>>16, 15:0<<10 */
878   val = ((val & 0xffff) << 10) | ((val >> 16) & 0x3ff);
879 
880   *fix_val = val;
881 
882   return true;
883 }
884 
loongarch_adjust_reloc_bitsfield(reloc_howto_type * howto,bfd_vma * fix_val)885 bool loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto,
886 				       bfd_vma *fix_val)
887 {
888   BFD_ASSERT (((loongarch_reloc_howto_type *)howto)->adjust_reloc_bits);
889   return ((loongarch_reloc_howto_type *)
890 	  howto)->adjust_reloc_bits(howto, fix_val);
891 }
892