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 * 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 * 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 * 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 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. */ 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. */ 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 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