1 /* LoongArch-specific support for ELF.
2 Copyright (C) 2021 Free Software Foundation, Inc.
3 Contributed by Loongson Ltd.
5 Based on RISC-V target.
7 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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/>. */
27 #include "elf/loongarch.h"
28 #include "elfxx-loongarch.h"
30 #define ALL_ONES (~ (bfd_vma) 0)
32 /* This does not include any relocation information, but should be
33 good enough for GDB or objdump to read the file. */
35 static reloc_howto_type howto_table
[] =
37 #define LOONGARCH_HOWTO(r_name) \
38 HOWTO (R_LARCH_##r_name, 0, 2, 32, false, 0, complain_overflow_signed, \
39 bfd_elf_generic_reloc, "R_LARCH_" #r_name, false, 0, 0xffffffff, false)
42 HOWTO (R_LARCH_NONE
, /* type (0). */
46 false, /* pc_relative */
48 complain_overflow_dont
, /* complain_on_overflow */
49 bfd_elf_generic_reloc
, /* special_function */
50 "R_LARCH_NONE", /* name */
51 false, /* partial_inplace */
54 false), /* pcrel_offset */
56 /* 32 bit relocation. */
57 HOWTO (R_LARCH_32
, /* type (1). */
61 false, /* pc_relative */
63 complain_overflow_dont
, /* complain_on_overflow */
64 bfd_elf_generic_reloc
, /* special_function */
65 "R_LARCH_32", /* name */
66 false, /* partial_inplace */
68 0xffffffff, /* dst_mask */
69 false), /* pcrel_offset */
71 /* 64 bit relocation. */
72 HOWTO (R_LARCH_64
, /* type (2). */
76 false, /* pc_relative */
78 complain_overflow_dont
, /* complain_on_overflow */
79 bfd_elf_generic_reloc
, /* special_function */
80 "R_LARCH_64", /* name */
81 false, /* partial_inplace */
83 ALL_ONES
, /* dst_mask */
84 false), /* pcrel_offset */
86 HOWTO (R_LARCH_RELATIVE
, /* type (3). */
90 false, /* pc_relative */
92 complain_overflow_dont
, /* complain_on_overflow */
93 bfd_elf_generic_reloc
, /* special_function */
94 "R_LARCH_RELATIVE", /* name */
95 false, /* partial_inplace */
97 0xffffffff, /* dst_mask */
98 false), /* pcrel_offset */
100 HOWTO (R_LARCH_COPY
, /* type (4). */
102 0, /* this one is variable size */
104 false, /* pc_relative */
106 complain_overflow_bitfield
, /* complain_on_overflow */
107 bfd_elf_generic_reloc
, /* special_function */
108 "R_LARCH_COPY", /* name */
109 false, /* partial_inplace */
112 false), /* pcrel_offset */
114 HOWTO (R_LARCH_JUMP_SLOT
, /* type (5). */
118 false, /* pc_relative */
120 complain_overflow_bitfield
, /* complain_on_overflow */
121 bfd_elf_generic_reloc
, /* special_function */
122 "R_LARCH_JUMP_SLOT", /* name */
123 false, /* partial_inplace */
126 false), /* pcrel_offset */
128 /* Dynamic TLS relocations. */
129 HOWTO (R_LARCH_TLS_DTPMOD32
, /* type (6). */
133 false, /* pc_relative */
135 complain_overflow_dont
, /* complain_on_overflow */
136 bfd_elf_generic_reloc
, /* special_function */
137 "R_LARCH_TLS_DTPMOD32", /* name */
138 false, /* partial_inplace */
140 0xffffffff, /* dst_mask */
141 false), /* pcrel_offset */
143 HOWTO (R_LARCH_TLS_DTPMOD64
, /* type (7). */
147 false, /* pc_relative */
149 complain_overflow_dont
, /* complain_on_overflow */
150 bfd_elf_generic_reloc
, /* special_function */
151 "R_LARCH_TLS_DTPMOD64", /* name */
152 false, /* partial_inplace */
154 ALL_ONES
, /* dst_mask */
155 false), /* pcrel_offset */
157 HOWTO (R_LARCH_TLS_DTPREL32
, /* type (8). */
161 false, /* pc_relative */
163 complain_overflow_dont
, /* complain_on_overflow */
164 bfd_elf_generic_reloc
, /* special_function */
165 "R_LARCH_TLS_DTPREL32", /* name */
166 true, /* partial_inplace */
168 0xffffffff, /* dst_mask */
169 false), /* pcrel_offset */
171 HOWTO (R_LARCH_TLS_DTPREL64
, /* type (9). */
175 false, /* pc_relative */
177 complain_overflow_dont
, /* complain_on_overflow */
178 bfd_elf_generic_reloc
, /* special_function */
179 "R_LARCH_TLS_DTPREL64", /* name */
180 true, /* partial_inplace */
182 ALL_ONES
, /* dst_mask */
183 false), /* pcrel_offset */
185 HOWTO (R_LARCH_TLS_TPREL32
, /* type (10). */
189 false, /* pc_relative */
191 complain_overflow_dont
, /* complain_on_overflow */
192 bfd_elf_generic_reloc
, /* special_function */
193 "R_LARCH_TLS_TPREL32", /* name */
194 false, /* partial_inplace */
196 0xffffffff, /* dst_mask */
197 false), /* pcrel_offset */
199 HOWTO (R_LARCH_TLS_TPREL64
, /* type (11). */
203 false, /* pc_relative */
205 complain_overflow_dont
, /* complain_on_overflow */
206 bfd_elf_generic_reloc
, /* special_function */
207 "R_LARCH_TLS_TPREL64", /* name */
208 false, /* partial_inplace */
210 ALL_ONES
, /* dst_mask */
211 false), /* pcrel_offset */
213 HOWTO (R_LARCH_IRELATIVE
, /* type (12). */
217 false, /* pc_relative */
219 complain_overflow_dont
, /* complain_on_overflow */
220 bfd_elf_generic_reloc
, /* special_function */
221 "R_LARCH_IRELATIVE", /* name */
222 false, /* partial_inplace */
224 0xffffffff, /* dst_mask */
225 false), /* pcrel_offset */
235 HOWTO (R_LARCH_MARK_LA
, /* type (20). */
239 false, /* pc_relative. */
241 complain_overflow_signed
, /* complain_on_overflow. */
242 bfd_elf_generic_reloc
, /* special_function. */
243 "R_LARCH_MARK_LA", /* name. */
244 false, /* partial_inplace. */
247 false), /* pcrel_offset. */
249 HOWTO (R_LARCH_MARK_PCREL
, /* type (21). */
253 false, /* pc_relative. */
255 complain_overflow_signed
, /* complain_on_overflow. */
256 bfd_elf_generic_reloc
, /* special_function. */
257 "R_LARCH_MARK_PCREL", /* name. */
258 false, /* partial_inplace. */
261 false), /* pcrel_offset. */
263 HOWTO (R_LARCH_SOP_PUSH_PCREL
, /* type (22). */
267 true /* FIXME: somewhat use this. */, /* pc_relative. */
269 complain_overflow_signed
, /* complain_on_overflow. */
270 bfd_elf_generic_reloc
, /* special_function. */
271 "R_LARCH_SOP_PUSH_PCREL", /* name. */
272 false, /* partial_inplace. */
273 0x03ffffff, /* src_mask. */
274 0x03ffffff, /* dst_mask. */
275 false), /* pcrel_offset. */
278 LOONGARCH_HOWTO (SOP_PUSH_ABSOLUTE
),
279 LOONGARCH_HOWTO (SOP_PUSH_DUP
),
280 LOONGARCH_HOWTO (SOP_PUSH_GPREL
),
281 LOONGARCH_HOWTO (SOP_PUSH_TLS_TPREL
),
282 LOONGARCH_HOWTO (SOP_PUSH_TLS_GOT
),
283 LOONGARCH_HOWTO (SOP_PUSH_TLS_GD
),
284 LOONGARCH_HOWTO (SOP_PUSH_PLT_PCREL
),
285 LOONGARCH_HOWTO (SOP_ASSERT
),
286 LOONGARCH_HOWTO (SOP_NOT
),
287 LOONGARCH_HOWTO (SOP_SUB
),
288 LOONGARCH_HOWTO (SOP_SL
),
289 LOONGARCH_HOWTO (SOP_SR
),
290 LOONGARCH_HOWTO (SOP_ADD
),
291 LOONGARCH_HOWTO (SOP_AND
),
292 LOONGARCH_HOWTO (SOP_IF_ELSE
),
294 HOWTO (R_LARCH_SOP_POP_32_S_10_5
, /* type (38). */
298 false, /* pc_relative. */
300 complain_overflow_signed
, /* complain_on_overflow. */
301 bfd_elf_generic_reloc
, /* special_function. */
302 "R_LARCH_SOP_POP_32_S_10_5", /* name. */
303 false, /* partial_inplace. */
305 0x7c00, /* dst_mask */
306 false), /* pcrel_offset. */
308 HOWTO (R_LARCH_SOP_POP_32_U_10_12
, /* type (39). */
312 false, /* pc_relative. */
314 complain_overflow_signed
, /* complain_on_overflow. */
315 bfd_elf_generic_reloc
, /* special_function. */
316 "R_LARCH_SOP_POP_32_U_10_12", /* name. */
317 false, /* partial_inplace. */
319 0x3ffc00, /* dst_mask */
320 false), /* pcrel_offset. */
322 HOWTO (R_LARCH_SOP_POP_32_S_10_12
, /* type (40). */
326 false, /* pc_relative. */
328 complain_overflow_signed
, /* complain_on_overflow. */
329 bfd_elf_generic_reloc
, /* special_function. */
330 "R_LARCH_SOP_POP_32_S_10_12", /* name. */
331 false, /* partial_inplace. */
333 0x3ffc00, /* dst_mask */
334 false), /* pcrel_offset. */
336 HOWTO (R_LARCH_SOP_POP_32_S_10_16
, /* type (41). */
340 false, /* pc_relative. */
342 complain_overflow_signed
, /* complain_on_overflow. */
343 bfd_elf_generic_reloc
, /* special_function. */
344 "R_LARCH_SOP_POP_32_S_10_16", /* name. */
345 false, /* partial_inplace. */
347 0x3fffc00, /* dst_mask */
348 false), /* pcrel_offset. */
350 HOWTO (R_LARCH_SOP_POP_32_S_10_16_S2
, /* type (42). */
354 false, /* pc_relative. */
356 complain_overflow_signed
, /* complain_on_overflow. */
357 bfd_elf_generic_reloc
, /* special_function. */
358 "R_LARCH_SOP_POP_32_S_10_16_S2", /* name. */
359 false, /* partial_inplace. */
361 0x3fffc00, /* dst_mask */
362 false), /* pcrel_offset. */
364 HOWTO (R_LARCH_SOP_POP_32_S_5_20
, /* type (43). */
368 false, /* pc_relative. */
370 complain_overflow_signed
, /* complain_on_overflow. */
371 bfd_elf_generic_reloc
, /* special_function. */
372 "R_LARCH_SOP_POP_32_S_5_20", /* name. */
373 false, /* partial_inplace. */
375 0x1fffe0, /* dst_mask */
376 false), /* pcrel_offset. */
378 HOWTO (R_LARCH_SOP_POP_32_S_0_5_10_16_S2
, /* type (44). */
382 false, /* pc_relative. */
384 complain_overflow_signed
, /* complain_on_overflow. */
385 bfd_elf_generic_reloc
, /* special_function. */
386 "R_LARCH_SOP_POP_32_S_0_5_10_16_S2", /* name. */
387 false, /* partial_inplace. */
388 0xfc0003e0, /* src_mask */
389 0xfc0003e0, /* dst_mask */
390 false), /* pcrel_offset. */
392 HOWTO (R_LARCH_SOP_POP_32_S_0_10_10_16_S2
, /* type (45). */
396 false, /* pc_relative. */
398 complain_overflow_signed
, /* complain_on_overflow. */
399 bfd_elf_generic_reloc
, /* special_function. */
400 "R_LARCH_SOP_POP_32_S_0_10_10_16_S2", /* name. */
401 false, /* partial_inplace. */
402 0xfc000000, /* src_mask */
403 0xfc000000, /* dst_mask */
404 false), /* pcrel_offset. */
406 HOWTO (R_LARCH_SOP_POP_32_U
, /* type (46). */
410 false, /* pc_relative. */
412 complain_overflow_signed
, /* complain_on_overflow. */
413 bfd_elf_generic_reloc
, /* special_function. */
414 "R_LARCH_SOP_POP_32_S_U", /* name. */
415 false, /* partial_inplace. */
418 false), /* pcrel_offset. */
420 HOWTO (R_LARCH_ADD8
, /* type (47). */
424 false, /* pc_relative. */
426 complain_overflow_signed
, /* complain_on_overflow. */
427 bfd_elf_generic_reloc
, /* special_function. */
428 "R_LARCH_ADD8", /* name. */
429 false, /* partial_inplace. */
431 0xffffffff, /* dst_mask */
432 false), /* pcrel_offset. */
434 HOWTO (R_LARCH_ADD16
, /* type (48). */
438 false, /* pc_relative. */
440 complain_overflow_signed
, /* complain_on_overflow. */
441 bfd_elf_generic_reloc
, /* special_function. */
442 "R_LARCH_ADD16", /* name. */
443 false, /* partial_inplace. */
445 0xffffffff, /* dst_mask */
446 false), /* pcrel_offset. */
448 HOWTO (R_LARCH_ADD24
, /* type (49). */
452 false, /* pc_relative. */
454 complain_overflow_signed
, /* complain_on_overflow. */
455 bfd_elf_generic_reloc
, /* special_function. */
456 "R_LARCH_ADD24", /* name. */
457 false, /* partial_inplace. */
459 0xffffffff, /* dst_mask */
460 false), /* pcrel_offset. */
462 HOWTO (R_LARCH_ADD32
, /* type (50). */
466 false, /* pc_relative. */
468 complain_overflow_signed
, /* complain_on_overflow. */
469 bfd_elf_generic_reloc
, /* special_function. */
470 "R_LARCH_ADD32", /* name. */
471 false, /* partial_inplace. */
473 0xffffffff, /* dst_mask */
474 false), /* pcrel_offset. */
476 HOWTO (R_LARCH_ADD64
, /* type (51). */
480 false, /* pc_relative. */
482 complain_overflow_signed
, /* complain_on_overflow. */
483 bfd_elf_generic_reloc
, /* special_function. */
484 "R_LARCH_ADD64", /* name. */
485 false, /* partial_inplace. */
487 ALL_ONES
, /* dst_mask */
488 false), /* pcrel_offset. */
490 HOWTO (R_LARCH_SUB8
, /* type (52). */
494 false, /* pc_relative. */
496 complain_overflow_signed
, /* complain_on_overflow. */
497 bfd_elf_generic_reloc
, /* special_function. */
498 "R_LARCH_SUB8", /* name. */
499 false, /* partial_inplace. */
501 0xffffffff, /* dst_mask */
502 false), /* pcrel_offset. */
504 HOWTO (R_LARCH_SUB16
, /* type (53). */
508 false, /* pc_relative. */
510 complain_overflow_signed
, /* complain_on_overflow. */
511 bfd_elf_generic_reloc
, /* special_function. */
512 "R_LARCH_SUB16", /* name. */
513 false, /* partial_inplace. */
515 0xffffffff, /* dst_mask */
516 false), /* pcrel_offset. */
518 HOWTO (R_LARCH_SUB24
, /* type (54). */
522 false, /* pc_relative. */
524 complain_overflow_signed
, /* complain_on_overflow. */
525 bfd_elf_generic_reloc
, /* special_function. */
526 "R_LARCH_SUB24", /* name. */
527 false, /* partial_inplace. */
529 0xffffffff, /* dst_mask */
530 false), /* pcrel_offset. */
532 HOWTO (R_LARCH_SUB32
, /* type (55). */
536 false, /* pc_relative. */
538 complain_overflow_signed
, /* complain_on_overflow. */
539 bfd_elf_generic_reloc
, /* special_function. */
540 "R_LARCH_SUB32", /* name. */
541 false, /* partial_inplace. */
543 0xffffffff, /* dst_mask */
544 false), /* pcrel_offset. */
546 HOWTO (R_LARCH_SUB64
, /* type (56). */
550 false, /* pc_relative. */
552 complain_overflow_signed
, /* complain_on_overflow. */
553 bfd_elf_generic_reloc
, /* special_function. */
554 "R_LARCH_SUB64", /* name. */
555 false, /* partial_inplace. */
557 ALL_ONES
, /* dst_mask */
558 false), /* pcrel_offset. */
564 bfd_reloc_code_real_type bfd_val
;
565 enum elf_loongarch_reloc_type elf_val
;
568 static const struct elf_reloc_map larch_reloc_map
[] =
570 { BFD_RELOC_NONE
, R_LARCH_NONE
},
571 { BFD_RELOC_32
, R_LARCH_32
},
572 { BFD_RELOC_64
, R_LARCH_64
},
574 #define LOONGARCH_reloc_map(r_name) \
576 BFD_RELOC_LARCH_##r_name, R_LARCH_##r_name \
578 LOONGARCH_reloc_map (TLS_DTPMOD32
),
579 LOONGARCH_reloc_map (TLS_DTPMOD64
),
580 LOONGARCH_reloc_map (TLS_DTPREL32
),
581 LOONGARCH_reloc_map (TLS_DTPREL64
),
582 LOONGARCH_reloc_map (TLS_TPREL32
),
583 LOONGARCH_reloc_map (TLS_TPREL64
),
585 LOONGARCH_reloc_map (MARK_LA
),
586 LOONGARCH_reloc_map (MARK_PCREL
),
587 LOONGARCH_reloc_map (SOP_PUSH_PCREL
),
588 LOONGARCH_reloc_map (SOP_PUSH_ABSOLUTE
),
589 LOONGARCH_reloc_map (SOP_PUSH_DUP
),
590 LOONGARCH_reloc_map (SOP_PUSH_GPREL
),
591 LOONGARCH_reloc_map (SOP_PUSH_TLS_TPREL
),
592 LOONGARCH_reloc_map (SOP_PUSH_TLS_GOT
),
593 LOONGARCH_reloc_map (SOP_PUSH_TLS_GD
),
594 LOONGARCH_reloc_map (SOP_PUSH_PLT_PCREL
),
595 LOONGARCH_reloc_map (SOP_ASSERT
),
596 LOONGARCH_reloc_map (SOP_NOT
),
597 LOONGARCH_reloc_map (SOP_SUB
),
598 LOONGARCH_reloc_map (SOP_SL
),
599 LOONGARCH_reloc_map (SOP_SR
),
600 LOONGARCH_reloc_map (SOP_ADD
),
601 LOONGARCH_reloc_map (SOP_AND
),
602 LOONGARCH_reloc_map (SOP_IF_ELSE
),
603 LOONGARCH_reloc_map (SOP_POP_32_S_10_5
),
604 LOONGARCH_reloc_map (SOP_POP_32_U_10_12
),
605 LOONGARCH_reloc_map (SOP_POP_32_S_10_12
),
606 LOONGARCH_reloc_map (SOP_POP_32_S_10_16
),
607 LOONGARCH_reloc_map (SOP_POP_32_S_10_16_S2
),
608 LOONGARCH_reloc_map (SOP_POP_32_S_5_20
),
609 LOONGARCH_reloc_map (SOP_POP_32_S_0_5_10_16_S2
),
610 LOONGARCH_reloc_map (SOP_POP_32_S_0_10_10_16_S2
),
611 LOONGARCH_reloc_map (SOP_POP_32_U
),
612 LOONGARCH_reloc_map (ADD8
),
613 LOONGARCH_reloc_map (ADD16
),
614 LOONGARCH_reloc_map (ADD24
),
615 LOONGARCH_reloc_map (ADD32
),
616 LOONGARCH_reloc_map (ADD64
),
617 LOONGARCH_reloc_map (SUB8
),
618 LOONGARCH_reloc_map (SUB16
),
619 LOONGARCH_reloc_map (SUB24
),
620 LOONGARCH_reloc_map (SUB32
),
621 LOONGARCH_reloc_map (SUB64
),
625 loongarch_elf_rtype_to_howto (bfd
*abfd
, unsigned int r_type
)
628 for (i
= 0; i
< ARRAY_SIZE (howto_table
); i
++)
629 if (howto_table
[i
].type
== r_type
)
630 return &howto_table
[i
];
632 (*_bfd_error_handler
) (_("%pB: unsupported relocation type %#x"),
634 bfd_set_error (bfd_error_bad_value
);
639 loongarch_reloc_type_lookup (bfd
*abfd ATTRIBUTE_UNUSED
,
640 bfd_reloc_code_real_type code
)
643 for (i
= 0; i
< ARRAY_SIZE (larch_reloc_map
); i
++)
644 if (larch_reloc_map
[i
].bfd_val
== code
)
645 return loongarch_elf_rtype_to_howto (abfd
,
646 (int) larch_reloc_map
[i
].elf_val
);
652 loongarch_reloc_name_lookup (bfd
*abfd ATTRIBUTE_UNUSED
, const char *r_name
)
656 for (i
= 0; i
< ARRAY_SIZE (howto_table
); i
++)
657 if (howto_table
[i
].name
&& strcasecmp (howto_table
[i
].name
, r_name
) == 0)
658 return &howto_table
[i
];