From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7867) id 1BE15385828D; Tue, 30 May 2023 12:03:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1BE15385828D Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: liu & zhensong To: bfd-cvs@sourceware.org Subject: [binutils-gdb] LoongArch: bfd: Add support for linker relaxation. X-Act-Checkin: binutils-gdb X-Git-Author: mengqinggang X-Git-Refname: refs/heads/master X-Git-Oldrev: 57a930e3bfe4b2c7fd6463ed39311e1938513138 X-Git-Newrev: 1b6fccd28db14fffe75ff6755307047ef932c81e Message-Id: <20230530120359.1BE15385828D@sourceware.org> Date: Tue, 30 May 2023 12:03:58 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 30 May 2023 12:03:59 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D1b6fccd28db1= 4fffe75ff6755307047ef932c81e commit 1b6fccd28db14fffe75ff6755307047ef932c81e Author: mengqinggang Date: Thu Dec 1 15:03:42 2022 +0800 LoongArch: bfd: Add support for linker relaxation. =20 Add relax support and related relocs in bfd. =20 bfd/ChangeLog: =20 * bfd-in2.h: Add relocs related to relax. * elfnn-loongarch.c (struct loongarch_elf_link_hash_table): New= integer pointer (data_segment_phase) to monitor the data segment phase. (loongarch_elf_check_relocs): Swap B21/B26 reloc sequence. (loongarch_elf_adjust_dynamic_symbol): Fix code format. (loongarch_reloc_rewrite_imm_insn): Fix function call. (perform_relocation): Handle new relocs related to relax. (RELOCATE_CALC_PC32_HI20): Fix code format. (RELOCATE_CALC_PC64_HI32): Likewise. (loongarch_elf_relocate_section): Handle new relocs related to = relax. (loongarch_relax_delete_bytes): New function. (loongarch_relax_pcala_addi): Likewise. (loongarch_relax_pcala_ld): Likewise. (bfd_elfNN_loongarch_set_data_segment_info): Likewise. (loongarch_relax_align): Likewise. (loongarch_elf_relax_section): Likewise. (bfd_elfNN_bfd_relax_section): New macro define. * elfxx-loongarch.c (reloc_bits): New bfd point parameter. (reloc_bits_b16): Likewise. (reloc_bits_b21): Likewise. (reloc_bits_b26): Likewise. (loongarch_adjust_reloc_bitsfield): Likewise. (reloc_bits_pcrel20_s2): New function. (loongarch_elf_add_sub_reloc): Likewise. (loongarch_elf_add_sub_reloc_uleb128): Likewise. (loongarch_write_unsigned_leb128): New function. * elfxx-loongarch.h (loongarch_adjust_reloc_bitsfield): New bfd= point parameter. (bfd_elf32_loongarch_set_data_segment_info): New declare. (bfd_elf64_loongarch_set_data_segment_info): Likewise. (loongarch_write_unsigned_leb128): Likewise. * libbfd.h: Add relocs related to relax. * reloc.c: Add relocs related to relax. Diff: --- bfd/bfd-in2.h | 8 + bfd/elfnn-loongarch.c | 582 +++++++++++++++++++++++++++++++++++++++---- bfd/elfxx-loongarch.c | 676 +++++++++++++++++++++++++++++++++++++---------= ---- bfd/elfxx-loongarch.h | 10 +- bfd/libbfd.h | 8 + bfd/reloc.c | 22 ++ 6 files changed, 1077 insertions(+), 229 deletions(-) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 363a6b35a5c..6f8a8fd114d 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -7334,6 +7334,14 @@ assembler and not (currently) written to any object = files. */ BFD_RELOC_LARCH_TLS_GD_HI20, BFD_RELOC_LARCH_32_PCREL, BFD_RELOC_LARCH_RELAX, + BFD_RELOC_LARCH_DELETE, + BFD_RELOC_LARCH_ALIGN, + BFD_RELOC_LARCH_PCREL20_S2, + BFD_RELOC_LARCH_CFA, + BFD_RELOC_LARCH_ADD6, + BFD_RELOC_LARCH_SUB6, + BFD_RELOC_LARCH_ADD_ULEB128, + BFD_RELOC_LARCH_SUB_ULEB128, BFD_RELOC_UNUSED }; typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; =20 diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c index 3fb74edb45c..d501991e4cf 100644 --- a/bfd/elfnn-loongarch.c +++ b/bfd/elfnn-loongarch.c @@ -27,6 +27,7 @@ #include "objalloc.h" #include "elf/loongarch.h" #include "elfxx-loongarch.h" +#include "opcode/loongarch.h" =20 static bool loongarch_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, @@ -93,6 +94,10 @@ struct loongarch_elf_link_hash_table =20 /* The max alignment of output sections. */ bfd_vma max_alignment; + + /* The data segment phase, don't relax the section + when it is exp_seg_relro_adjust. */ + int *data_segment_phase; }; =20 /* Get the LoongArch ELF linker hash table from a link_info structure. */ @@ -772,8 +777,8 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_= info *info, =20 break; =20 - case R_LARCH_B21: case R_LARCH_B16: + case R_LARCH_B21: case R_LARCH_B26: if (h !=3D NULL) { @@ -972,8 +977,12 @@ loongarch_elf_adjust_dynamic_symbol (struct bfd_link_i= nfo *info, =20 /* Make sure we know what is going on here. */ BFD_ASSERT (dynobj !=3D NULL - && (h->needs_plt || h->type =3D=3D STT_GNU_IFUNC || h->is_weakalias - || (h->def_dynamic && h->ref_regular && !h->def_regular))); + && (h->needs_plt + || h->type =3D=3D STT_GNU_IFUNC + || h->is_weakalias + || (h->def_dynamic + && h->ref_regular + && !h->def_regular))); =20 /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later @@ -1884,7 +1893,7 @@ loongarch_reloc_rewrite_imm_insn (const Elf_Internal_= Rela *rel, int bits =3D bfd_get_reloc_size (howto) * 8; uint32_t insn =3D bfd_get (bits, input_bfd, contents + rel->r_offset); =20 - if (!loongarch_adjust_reloc_bitsfield(howto, &reloc_val)) + if (!loongarch_adjust_reloc_bitsfield (input_bfd, howto, &reloc_val)) return bfd_reloc_overflow; =20 insn =3D (insn & (uint32_t)howto->src_mask) @@ -2004,42 +2013,73 @@ perform_relocation (const Elf_Internal_Rela *rel, a= section *input_section, bfd_put (bits, input_bfd, value, contents + rel->r_offset); break; =20 + /* LoongArch only has add/sub reloc pair, not has set/sub reloc pair. + Because set/sub reloc pair not support multi-thread. While add/sub + reloc pair process order not affect the final result. + + For add/sub reloc, the original value will be involved in the + calculation. In order not to add/sub extra value, we write 0 to sym= bol + address at assembly time. + + add/sub reloc bits determined by the value after symbol subtraction, + not symbol value. + + add/sub reloc save part of the symbol value, so we only need to + save howto->dst_mask bits. */ + case R_LARCH_ADD6: + case R_LARCH_SUB6: + { + bfd_vma word =3D bfd_get (howto->bitsize, input_bfd, + contents + rel->r_offset); + word =3D (word & ~howto->dst_mask) | (value & howto->dst_mask); + bfd_put (howto->bitsize, input_bfd, word, contents + rel->r_offset); + r =3D bfd_reloc_ok; + break; + } + + /* Not need to read the original value, just write the new value. */ case R_LARCH_ADD8: case R_LARCH_ADD16: case R_LARCH_ADD24: case R_LARCH_ADD32: case R_LARCH_ADD64: - r =3D loongarch_check_offset (rel, input_section); - if (r !=3D bfd_reloc_ok) - break; - - opr1 =3D bfd_get (bits, input_bfd, contents + rel->r_offset); - bfd_put (bits, input_bfd, opr1 + value, contents + rel->r_offset); - break; - case R_LARCH_SUB8: case R_LARCH_SUB16: case R_LARCH_SUB24: case R_LARCH_SUB32: case R_LARCH_SUB64: - r =3D loongarch_check_offset (rel, input_section); - if (r !=3D bfd_reloc_ok) + { + /* Because add/sub reloc is processed separately, + so the high bits is invalid. */ + bfd_vma word =3D value & howto->dst_mask; + bfd_put (howto->bitsize, input_bfd, word, contents + rel->r_offset); + r =3D bfd_reloc_ok; break; + } =20 - opr1 =3D bfd_get (bits, input_bfd, contents + rel->r_offset); - bfd_put (bits, input_bfd, opr1 - value, contents + rel->r_offset); - break; + case R_LARCH_ADD_ULEB128: + case R_LARCH_SUB_ULEB128: + { + unsigned int len =3D 0; + /* Before write uleb128, first read it to get it's length. */ + _bfd_read_unsigned_leb128 (input_bfd, contents + rel->r_offset, &len); + loongarch_write_unsigned_leb128 (contents + rel->r_offset, len, value); + r =3D bfd_reloc_ok; + break; + } =20 /* For eh_frame and debug info. */ case R_LARCH_32_PCREL: - value -=3D sec_addr (input_section) + rel->r_offset; - value +=3D rel->r_addend; - bfd_vma word =3D bfd_get (howto->bitsize, input_bfd, - contents + rel->r_offset); - word =3D (word & ~howto->dst_mask) | (value & howto->dst_mask); - bfd_put (howto->bitsize, input_bfd, word, contents + rel->r_offset); - r =3D bfd_reloc_ok; - break; + { + value -=3D sec_addr (input_section) + rel->r_offset; + value +=3D rel->r_addend; + bfd_vma word =3D bfd_get (howto->bitsize, input_bfd, + contents + rel->r_offset); + word =3D (word & ~howto->dst_mask) | (value & howto->dst_mask); + bfd_put (howto->bitsize, input_bfd, word, contents + rel->r_offset); + r =3D bfd_reloc_ok; + break; + } =20 /* New reloc type. R_LARCH_B16 ~ R_LARCH_TLS_GD_HI20. */ @@ -2078,6 +2118,7 @@ perform_relocation (const Elf_Internal_Rela *rel, ase= ction *input_section, case R_LARCH_TLS_LD_HI20: case R_LARCH_TLS_GD_PC_HI20: case R_LARCH_TLS_GD_HI20: + case R_LARCH_PCREL20_S2: r =3D loongarch_check_offset (rel, input_section); if (r !=3D bfd_reloc_ok) break; @@ -2244,9 +2285,9 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info, =20 #define RELOCATE_CALC_PC32_HI20(relocation, pc) \ ({ \ - bfd_vma lo =3D (relocation) & ((bfd_vma)0xfff); \ + bfd_vma __lo =3D (relocation) & ((bfd_vma)0xfff); \ pc =3D pc & (~(bfd_vma)0xfff); \ - if (lo > 0x7ff) \ + if (__lo > 0x7ff) \ { \ relocation +=3D 0x1000; \ } \ @@ -2256,8 +2297,8 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info, =20 #define RELOCATE_CALC_PC64_HI32(relocation, pc) \ ({ \ - bfd_vma lo =3D (relocation) & ((bfd_vma)0xfff); \ - if (lo > 0x7ff) \ + bfd_vma __lo =3D (relocation) & ((bfd_vma)0xfff); \ + if (__lo > 0x7ff) \ { \ relocation -=3D 0x100000000; \ } \ @@ -2522,29 +2563,49 @@ loongarch_elf_relocate_section (bfd *output_bfd, st= ruct bfd_link_info *info, relocation +=3D rel->r_addend; break; =20 + case R_LARCH_ADD6: case R_LARCH_ADD8: case R_LARCH_ADD16: case R_LARCH_ADD24: case R_LARCH_ADD32: case R_LARCH_ADD64: + { + bfd_vma old_value =3D bfd_get (howto->bitsize, input_bfd, + contents + rel->r_offset); + relocation =3D old_value + relocation + rel->r_addend; + break; + } + + case R_LARCH_SUB6: case R_LARCH_SUB8: case R_LARCH_SUB16: case R_LARCH_SUB24: case R_LARCH_SUB32: case R_LARCH_SUB64: - if (resolved_dynly) - fatal =3D (loongarch_reloc_is_fatal - (info, input_bfd, input_section, rel, howto, - bfd_reloc_undefined, is_undefweak, name, - "Can't be resolved dynamically. " - "If this procedure is hand-written assembly,\n" - "there must be something like '.dword sym1 - sym2' " - "to generate these relocs\n" - "and we can't get known link-time address of " - "these symbols.")); - else - relocation +=3D rel->r_addend; - break; + { + bfd_vma old_value =3D bfd_get (howto->bitsize, input_bfd, + contents + rel->r_offset); + relocation =3D old_value - relocation - rel->r_addend; + break; + } + + case R_LARCH_ADD_ULEB128: + case R_LARCH_SUB_ULEB128: + { + /* Get the value and length of the uleb128 data. */ + unsigned int len =3D 0; + bfd_vma old_value =3D _bfd_read_unsigned_leb128 (input_bfd, + contents + rel->r_offset, &len); + + if (R_LARCH_ADD_ULEB128 =3D=3D ELFNN_R_TYPE (rel->r_info)) + relocation =3D old_value + relocation + rel->r_addend; + else if (R_LARCH_SUB_ULEB128 =3D=3D ELFNN_R_TYPE (rel->r_info)) + relocation =3D old_value - relocation - rel->r_addend; + + bfd_vma mask =3D (1 << (7 * len)) - 1; + relocation &=3D mask; + break; + } =20 case R_LARCH_TLS_DTPREL32: case R_LARCH_TLS_DTPREL64: @@ -3084,6 +3145,15 @@ loongarch_elf_relocate_section (bfd *output_bfd, str= uct bfd_link_info *info, =20 break; =20 + case R_LARCH_PCREL20_S2: + unresolved_reloc =3D false; + if (h && h->plt.offset !=3D MINUS_ONE) + relocation =3D sec_addr (plt) + h->plt.offset; + else + relocation +=3D rel->r_addend; + relocation -=3D pc; + break; + case R_LARCH_PCALA_HI20: unresolved_reloc =3D false; if (h && h->plt.offset !=3D MINUS_ONE) @@ -3109,15 +3179,15 @@ loongarch_elf_relocate_section (bfd *output_bfd, st= ruct bfd_link_info *info, else relocation +=3D rel->r_addend; =20 - relocation &=3D 0xfff; - /* Signed extend. */ - relocation =3D (relocation ^ 0x800) - 0x800; - /* For 2G jump, generate pcalau12i, jirl. */ /* If use jirl, turns to R_LARCH_B16. */ uint32_t insn =3D bfd_get (32, input_bfd, contents + rel->r_offset); if ((insn & 0x4c000000) =3D=3D 0x4c000000) { + relocation &=3D 0xfff; + /* Signed extend. */ + relocation =3D (relocation ^ 0x800) - 0x800; + rel->r_info =3D ELFNN_R_INFO (r_symndx, R_LARCH_B16); howto =3D loongarch_elf_rtype_to_howto (input_bfd, R_LARCH_B16); } @@ -3253,13 +3323,12 @@ loongarch_elf_relocate_section (bfd *output_bfd, st= ruct bfd_link_info *info, + (idx * GOT_ENTRY_SIZE) - sec_addr (htab->elf.sgot); } + relocation =3D got_off + sec_addr (got); } =20 - if (r_type =3D=3D R_LARCH_GOT_PC_LO12) - relocation &=3D (bfd_vma)0xfff; - else if (r_type =3D=3D R_LARCH_GOT64_PC_LO20 - || r_type =3D=3D R_LARCH_GOT64_PC_HI12) + if (r_type =3D=3D R_LARCH_GOT64_PC_HI12 + || r_type =3D=3D R_LARCH_GOT64_PC_LO20) RELOCATE_CALC_PC64_HI32 (relocation, pc); =20 break; @@ -3417,15 +3486,16 @@ loongarch_elf_relocate_section (bfd *output_bfd, st= ruct bfd_link_info *info, if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE)) relocation +=3D 2 * GOT_ENTRY_SIZE; =20 - if (r_type =3D=3D R_LARCH_TLS_IE_PC_LO12) - relocation &=3D (bfd_vma)0xfff; - else if (r_type =3D=3D R_LARCH_TLS_IE64_PC_LO20 - || r_type =3D=3D R_LARCH_TLS_IE64_PC_HI12) + if (r_type =3D=3D R_LARCH_TLS_IE64_PC_LO20 + || r_type =3D=3D R_LARCH_TLS_IE64_PC_HI12) RELOCATE_CALC_PC64_HI32 (relocation, pc); =20 break; =20 case R_LARCH_RELAX: + case R_LARCH_ALIGN: + r =3D bfd_reloc_continue; + unresolved_reloc =3D false; break; =20 default: @@ -3516,6 +3586,409 @@ loongarch_elf_relocate_section (bfd *output_bfd, st= ruct bfd_link_info *info, return !fatal; } =20 +static bool +loongarch_relax_delete_bytes (bfd *abfd, + asection *sec, + bfd_vma addr, + size_t count, + struct bfd_link_info *link_info) +{ + unsigned int i, symcount; + bfd_vma toaddr =3D sec->size; + struct elf_link_hash_entry **sym_hashes =3D elf_sym_hashes (abfd); + Elf_Internal_Shdr *symtab_hdr =3D &elf_tdata (abfd)->symtab_hdr; + unsigned int sec_shndx =3D _bfd_elf_section_from_bfd_section (abfd, sec); + struct bfd_elf_section_data *data =3D elf_section_data (sec); + bfd_byte *contents =3D data->this_hdr.contents; + + /* Actually delete the bytes. */ + sec->size -=3D count; + memmove (contents + addr, contents + addr + count, toaddr - addr - count= ); + + /* Adjust the location of all of the relocs. Note that we need not + adjust the addends, since all PC-relative references must be against + symbols, which we will adjust below. */ + for (i =3D 0; i < sec->reloc_count; i++) + if (data->relocs[i].r_offset > addr && data->relocs[i].r_offset < toad= dr) + data->relocs[i].r_offset -=3D count; + + /* Adjust the local symbols defined in this section. */ + for (i =3D 0; i < symtab_hdr->sh_info; i++) + { + Elf_Internal_Sym *sym =3D (Elf_Internal_Sym *) symtab_hdr->contents = + i; + if (sym->st_shndx =3D=3D sec_shndx) + { + /* If the symbol is in the range of memory we just moved, we + have to adjust its value. */ + if (sym->st_value > addr && sym->st_value <=3D toaddr) + sym->st_value -=3D count; + + /* If the symbol *spans* the bytes we just deleted (i.e. its + *end* is in the moved bytes but its *start* isn't), then we + must adjust its size. + + This test needs to use the original value of st_value, otherwise + we might accidentally decrease size when deleting bytes right + before the symbol. But since deleted relocs can't span across + symbols, we can't have both a st_value and a st_size decrease, + so it is simpler to just use an else. */ + else if (sym->st_value <=3D addr + && sym->st_value + sym->st_size > addr + && sym->st_value + sym->st_size <=3D toaddr) + sym->st_size -=3D count; + } + } + + /* Now adjust the global symbols defined in this section. */ + symcount =3D ((symtab_hdr->sh_size / sizeof (ElfNN_External_Sym)) + - symtab_hdr->sh_info); + + for (i =3D 0; i < symcount; i++) + { + struct elf_link_hash_entry *sym_hash =3D sym_hashes[i]; + + /* The '--wrap SYMBOL' option is causing a pain when the object file, + containing the definition of __wrap_SYMBOL, includes a direct + call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference + the same symbol (which is __wrap_SYMBOL), but still exist as two + different symbols in 'sym_hashes', we don't want to adjust + the global symbol __wrap_SYMBOL twice. + + The same problem occurs with symbols that are versioned_hidden, as + foo becomes an alias for foo@BAR, and hence they need the same + treatment. */ + if (link_info->wrap_hash !=3D NULL + || sym_hash->versioned !=3D unversioned) + { + struct elf_link_hash_entry **cur_sym_hashes; + + /* Loop only over the symbols which have already been checked. */ + for (cur_sym_hashes =3D sym_hashes; cur_sym_hashes < &sym_hashes[i]; + cur_sym_hashes++) + { + /* If the current symbol is identical to 'sym_hash', that means + the symbol was already adjusted (or at least checked). */ + if (*cur_sym_hashes =3D=3D sym_hash) + break; + } + /* Don't adjust the symbol again. */ + if (cur_sym_hashes < &sym_hashes[i]) + continue; + } + + if ((sym_hash->root.type =3D=3D bfd_link_hash_defined + || sym_hash->root.type =3D=3D bfd_link_hash_defweak) + && sym_hash->root.u.def.section =3D=3D sec) + { + /* As above, adjust the value if needed. */ + if (sym_hash->root.u.def.value > addr + && sym_hash->root.u.def.value <=3D toaddr) + sym_hash->root.u.def.value -=3D count; + + /* As above, adjust the size if needed. */ + else if (sym_hash->root.u.def.value <=3D addr + && sym_hash->root.u.def.value + sym_hash->size > addr + && sym_hash->root.u.def.value + sym_hash->size <=3D toaddr) + sym_hash->size -=3D count; + } + } + + return true; +} + +/* Relax pcalau12i,addi.d =3D> pcaddi. */ +static bool +loongarch_relax_pcala_addi(bfd *abfd, asection *sec, + Elf_Internal_Rela *rel_hi, bfd_vma symval) +{ + bfd_byte *contents =3D elf_section_data (sec)->this_hdr.contents; + Elf_Internal_Rela *rel_lo =3D rel_hi + 2; + uint32_t pca =3D bfd_get (32, abfd, contents + rel_hi->r_offset); + uint32_t add =3D bfd_get (32, abfd, contents + rel_lo->r_offset); + uint32_t rd =3D pca & 0x1f; + bfd_vma pc =3D sec_addr (sec) + rel_hi->r_offset; + const uint32_t addi_d =3D 0x02c00000; + const uint32_t pcaddi =3D 0x18000000; + + /* Is pcalau12i + addi.d insns? */ + if ((ELFNN_R_TYPE (rel_lo->r_info) !=3D R_LARCH_PCALA_LO12) + || (ELFNN_R_TYPE ((rel_lo + 1)->r_info) !=3D R_LARCH_RELAX) + || (ELFNN_R_TYPE ((rel_hi + 1)->r_info) !=3D R_LARCH_RELAX) + || (rel_hi->r_offset + 4 !=3D rel_lo->r_offset) + || ((add & addi_d) !=3D addi_d) + /* Is pcalau12i $rd + addi.d $rd,$rd? */ + || ((add & 0x1f) !=3D rd) + || (((add >> 5) & 0x1f) !=3D rd) + /* Can be relaxed to pcaddi? */ + || (symval & 0x3) /* 4 bytes align. */ + || ((bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0xffe00= 000) + || ((bfd_signed_vma)(symval - pc) > (bfd_signed_vma)(int32_t)0x1ffff= c)) + return false; + + pca =3D pcaddi | rd; + bfd_put (32, abfd, pca, contents + rel_hi->r_offset); + + /* Adjust relocations. */ + rel_hi->r_info =3D ELFNN_R_INFO (ELFNN_R_SYM (rel_hi->r_info), + R_LARCH_PCREL20_S2); + rel_lo->r_info =3D ELFNN_R_INFO (ELFNN_R_SYM (rel_hi->r_info), + R_LARCH_DELETE); + + return true; +} + +/* Relax pcalau12i,ld.d =3D> pcalau12i,addi.d. */ +static bool +loongarch_relax_pcala_ld (bfd *abfd, asection *sec, + Elf_Internal_Rela *rel_hi) +{ + bfd_byte *contents =3D elf_section_data (sec)->this_hdr.contents; + Elf_Internal_Rela *rel_lo =3D rel_hi + 2; + uint32_t pca =3D bfd_get (32, abfd, contents + rel_hi->r_offset); + uint32_t ld =3D bfd_get (32, abfd, contents + rel_lo->r_offset); + uint32_t rd =3D pca & 0x1f; + const uint32_t ld_d =3D 0x28c00000; + uint32_t addi_d =3D 0x02c00000; + + if ((ELFNN_R_TYPE (rel_lo->r_info) !=3D R_LARCH_GOT_PC_LO12) + || (ELFNN_R_TYPE ((rel_lo + 1)->r_info) !=3D R_LARCH_RELAX) + || (ELFNN_R_TYPE ((rel_hi + 1)->r_info) !=3D R_LARCH_RELAX) + || (rel_hi->r_offset + 4 !=3D rel_lo->r_offset) + || ((ld & 0x1f) !=3D rd) + || (((ld >> 5) & 0x1f) !=3D rd) + || ((ld & ld_d) !=3D ld_d)) + return false; + + addi_d =3D addi_d | (rd << 5) | rd; + bfd_put (32, abfd, addi_d, contents + rel_lo->r_offset); + + rel_hi->r_info =3D ELFNN_R_INFO (ELFNN_R_SYM (rel_hi->r_info), + R_LARCH_PCALA_HI20); + rel_lo->r_info =3D ELFNN_R_INFO (ELFNN_R_SYM (rel_lo->r_info), + R_LARCH_PCALA_LO12); + return true; +} + +/* Called by after_allocation to set the information of data segment + before relaxing. */ + +void +bfd_elfNN_loongarch_set_data_segment_info (struct bfd_link_info *info, + int *data_segment_phase) +{ + struct loongarch_elf_link_hash_table *htab =3D loongarch_elf_hash_table = (info); + htab->data_segment_phase =3D data_segment_phase; +} + +/* Implement R_LARCH_ALIGN by deleting excess alignment NOPs. + Once we've handled an R_LARCH_ALIGN, we can't relax anything else. */ +static bool +loongarch_relax_align (bfd *abfd, asection *sec, + asection *sym_sec, + struct bfd_link_info *link_info, + Elf_Internal_Rela *rel, + bfd_vma symval) +{ + bfd_byte *contents =3D elf_section_data (sec)->this_hdr.contents; + bfd_vma alignment =3D 1, pos; + while (alignment <=3D rel->r_addend) + alignment *=3D 2; + + symval -=3D rel->r_addend; + bfd_vma aligned_addr =3D ((symval - 1) & ~(alignment - 1)) + alignment; + bfd_vma nop_bytes =3D aligned_addr - symval; + + /* Once we've handled an R_LARCH_ALIGN, we can't relax anything else. */ + sec->sec_flg0 =3D true; + + /* Make sure there are enough NOPs to actually achieve the alignment. */ + if (rel->r_addend < nop_bytes) + { + _bfd_error_handler + (_("%pB(%pA+%#" PRIx64 "): %" PRId64 " bytes required for alignment " + "to %" PRId64 "-byte boundary, but only %" PRId64 " present"), + abfd, sym_sec, (uint64_t) rel->r_offset, + (int64_t) nop_bytes, (int64_t) alignment, (int64_t) rel->r_addend); + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Delete the reloc. */ + rel->r_info =3D ELFNN_R_INFO (0, R_LARCH_NONE); + + /* If the number of NOPs is already correct, there's nothing to do. */ + if (nop_bytes =3D=3D rel->r_addend) + return true; + + /* Write as many LOONGARCH NOPs as we need. */ + for (pos =3D 0; pos < (nop_bytes & -4); pos +=3D 4) + bfd_putl32 (LARCH_NOP, contents + rel->r_offset + pos); + + /* Delete the excess NOPs. */ + return loongarch_relax_delete_bytes (abfd, sec, rel->r_offset + nop_byte= s, + rel->r_addend - nop_bytes, link_info); +} + +static bool +loongarch_elf_relax_section (bfd *abfd, asection *sec, + struct bfd_link_info *info, + bool *again) +{ + struct loongarch_elf_link_hash_table *htab =3D loongarch_elf_hash_table = (info); + Elf_Internal_Shdr *symtab_hdr =3D &elf_symtab_hdr (abfd); + struct bfd_elf_section_data *data =3D elf_section_data (sec); + Elf_Internal_Rela *relocs; + *again =3D false; + + if (bfd_link_relocatable (info) + || sec->sec_flg0 + || (sec->flags & SEC_RELOC) =3D=3D 0 + || sec->reloc_count =3D=3D 0 + || elf_seg_map (info->output_bfd) =3D=3D NULL + || (info->disable_target_specific_optimizations + && info->relax_pass =3D=3D 0) + /* The exp_seg_relro_adjust is enum phase_enum (0x4), + and defined in ld/ldexp.h. */ + || *(htab->data_segment_phase) =3D=3D 4) + return true; + + if (data->relocs) + relocs =3D data->relocs; + else if (!(relocs =3D _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, + info->keep_memory))) + return true; + + if (!data->this_hdr.contents + && !bfd_malloc_and_get_section (abfd, sec, &data->this_hdr.contents)) + return true; + + if (symtab_hdr->sh_info !=3D 0 + && !symtab_hdr->contents + && !(symtab_hdr->contents =3D + (unsigned char *) bfd_elf_get_elf_syms (abfd, symtab_hdr, + symtab_hdr->sh_info, + 0, NULL, NULL, NULL))) + return true; + + data->relocs =3D relocs; + + for (unsigned int i =3D 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *rel =3D relocs + i; + asection *sym_sec; + bfd_vma symval; + unsigned long r_symndx =3D ELFNN_R_SYM (rel->r_info); + bool local_got =3D false; + char symtype; + struct elf_link_hash_entry *h =3D NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + Elf_Internal_Sym *sym =3D (Elf_Internal_Sym *)symtab_hdr->contents + + r_symndx; + if (ELF_ST_TYPE (sym->st_info) =3D=3D STT_GNU_IFUNC) + continue; + + if (sym->st_shndx =3D=3D SHN_UNDEF) + { + sym_sec =3D sec; + symval =3D rel->r_offset; + } + else + { + sym_sec =3D elf_elfsections (abfd)[sym->st_shndx]->bfd_section; + symval =3D sym->st_value; + } + symtype =3D ELF_ST_TYPE (sym->st_info); + } + else + { + r_symndx =3D ELFNN_R_SYM (rel->r_info) - symtab_hdr->sh_info; + h =3D elf_sym_hashes (abfd)[r_symndx]; + + while (h->root.type =3D=3D bfd_link_hash_indirect + || h->root.type =3D=3D bfd_link_hash_warning) + h =3D (struct elf_link_hash_entry *) h->root.u.i.link; + + /* Disable the relaxation for ifunc. */ + if (h !=3D NULL && h->type =3D=3D STT_GNU_IFUNC) + continue; + + if ((h->root.type =3D=3D bfd_link_hash_defined + || h->root.type =3D=3D bfd_link_hash_defweak) + && h->root.u.def.section !=3D NULL + && h->root.u.def.section->output_section !=3D NULL) + { + symval =3D h->root.u.def.value; + sym_sec =3D h->root.u.def.section; + } + else + continue; + + if (h && bfd_link_executable (info) + && SYMBOL_REFERENCES_LOCAL (info, h)) + local_got =3D true; + symtype =3D h->type; + } + + if (sym_sec->sec_info_type =3D=3D SEC_INFO_TYPE_MERGE + && (sym_sec->flags & SEC_MERGE)) + { + if (symtype =3D=3D STT_SECTION) + symval +=3D rel->r_addend; + + symval =3D _bfd_merged_section_offset (abfd, &sym_sec, + elf_section_data (sym_sec)->sec_info, + symval); + + if (symtype !=3D STT_SECTION) + symval +=3D rel->r_addend; + } + else + symval +=3D rel->r_addend; + + symval +=3D sec_addr (sym_sec); + + switch (ELFNN_R_TYPE (rel->r_info)) + { + case R_LARCH_ALIGN: + if (2 =3D=3D info->relax_pass) + loongarch_relax_align (abfd, sec, sym_sec, info, rel, symval); + break; + case R_LARCH_DELETE: + if (info->relax_pass =3D=3D 1) + { + loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, info); + rel->r_info =3D ELFNN_R_INFO (0, R_LARCH_NONE); + } + break; + case R_LARCH_PCALA_HI20: + if (info->relax_pass =3D=3D 0) + { + if (i + 4 > sec->reloc_count) + break; + loongarch_relax_pcala_addi(abfd, sec, rel, symval); + } + break; + case R_LARCH_GOT_PC_HI20: + if (local_got) + { + if (i + 4 > sec->reloc_count) + break; + if (loongarch_relax_pcala_ld (abfd, sec, rel)) + { + loongarch_relax_pcala_addi(abfd, sec, rel, symval); + } + } + break; + default: + break; + } + } + + return true; +} + /* Finish up dynamic symbol handling. We set the contents of various dynamic sections here. */ =20 @@ -4149,5 +4622,6 @@ elf_loongarch64_hash_symbol (struct elf_link_hash_ent= ry *h) #define elf_backend_grok_prstatus loongarch_elf_grok_prstatus #define elf_backend_grok_psinfo loongarch_elf_grok_psinfo #define elf_backend_hash_symbol elf_loongarch64_hash_symbol +#define bfd_elfNN_bfd_relax_section loongarch_elf_relax_section =20 #include "elfNN-target.h" diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c index 1253e790512..9cfbef1431f 100644 --- a/bfd/elfxx-loongarch.c +++ b/bfd/elfxx-loongarch.c @@ -34,7 +34,7 @@ typedef struct loongarch_reloc_howto_type_struct /* The first must be reloc_howto_type! */ reloc_howto_type howto; bfd_reloc_code_real_type bfd_type; - bool (*adjust_reloc_bits)(reloc_howto_type *, bfd_vma *); + bool (*adjust_reloc_bits)(bfd *, reloc_howto_type *, bfd_vma *); const char *larch_reloc_type_name; } loongarch_reloc_howto_type; =20 @@ -52,13 +52,23 @@ typedef struct loongarch_reloc_howto_type_struct { EMPTY_HOWTO (C), BFD_RELOC_NONE, NULL, NULL } =20 static bool -reloc_bits (reloc_howto_type *howto, bfd_vma *val); +reloc_bits (bfd *abfd, reloc_howto_type *howto, bfd_vma *val); static bool -reloc_bits_b16 (reloc_howto_type *howto, bfd_vma *fix_val); +reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_va= l); static bool -reloc_bits_b21 (reloc_howto_type *howto, bfd_vma *fix_val); +reloc_bits_b16 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val); static bool -reloc_bits_b26 (reloc_howto_type *howto, bfd_vma *val); +reloc_bits_b21 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val); +static bool +reloc_bits_b26 (bfd *abfd, reloc_howto_type *howto, bfd_vma *val); + +static bfd_reloc_status_type +loongarch_elf_add_sub_reloc (bfd *, arelent *, asymbol *, void *, + asection *, bfd *, char **); + +static bfd_reloc_status_type +loongarch_elf_add_sub_reloc_uleb128 (bfd *, arelent *, asymbol *, void *, + asection *, bfd *, char **); =20 /* This does not include any relocation information, but should be good enough for GDB or objdump to read the file. */ @@ -521,175 +531,185 @@ static loongarch_reloc_howto_type loongarch_howto_t= able[] =3D reloc_bits, /* adjust_reloc_bits */ NULL), /* larch_reloc_type_name */ =20 + /* 8-bit in-place addition, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_ADD8, /* type (47). */ 0, /* rightshift. */ - 4, /* size. */ + 1, /* size. */ 8, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_ADD8", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_ADD8, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0xff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_ADD8, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 16-bit in-place addition, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_ADD16, /* type (48). */ 0, /* rightshift. */ - 4, /* size. */ + 2, /* size. */ 16, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_ADD16", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_ADD16, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0xffff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_ADD16, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 24-bit in-place addition, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_ADD24, /* type (49). */ 0, /* rightshift. */ - 4, /* size. */ + 3, /* size. */ 24, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_ADD24", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_ADD24, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0xffffff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_ADD24, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 32-bit in-place addition, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_ADD32, /* type (50). */ 0, /* rightshift. */ 4, /* size. */ 32, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_ADD32", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_ADD32, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0xffffffff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_ADD32, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 64-bit in-place addition, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_ADD64, /* type (51). */ 0, /* rightshift. */ 8, /* size. */ 64, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_ADD64", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_ADD64, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + ALL_ONES, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_ADD64, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 8-bit in-place subtraction, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_SUB8, /* type (52). */ 0, /* rightshift. */ - 4, /* size. */ + 1, /* size. */ 8, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_SUB8", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_SUB8, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0xff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_SUB8, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 16-bit in-place subtraction, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_SUB16, /* type (53). */ 0, /* rightshift. */ - 4, /* size. */ + 2, /* size. */ 16, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_SUB16", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_SUB16, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0xffff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_SUB16, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 24-bit in-place subtraction, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_SUB24, /* type (54). */ 0, /* rightshift. */ - 4, /* size. */ + 3, /* size. */ 24, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_SUB24", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_SUB24, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0xffffff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_SUB24, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 32-bit in-place subtraction, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_SUB32, /* type (55). */ 0, /* rightshift. */ 4, /* size. */ 32, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_SUB32", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_SUB32, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0xffffffff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_SUB32, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 + /* 64-bit in-place subtraction, for local label subtraction. */ LOONGARCH_HOWTO (R_LARCH_SUB64, /* type (56). */ 0, /* rightshift. */ 8, /* size. */ 64, /* bitsize. */ false, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ "R_LARCH_SUB64", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_SUB64, /* bfd_reloc_code_real_type */ - NULL, /* adjust_reloc_bits */ - NULL), /* larch_reloc_type_name */ + 0, /* src_mask. */ + ALL_ONES, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_SUB64, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ =20 LOONGARCH_HOWTO (R_LARCH_GNU_VTINHERIT, /* type (57). */ 0, /* rightshift. */ @@ -742,12 +762,12 @@ static loongarch_reloc_howto_type loongarch_howto_tab= le[] =3D bfd_elf_generic_reloc, /* special_function. */ "R_LARCH_B16", /* name. */ false, /* partial_inplace. */ - 0x3fffc00, /* src_mask */ - 0x3fffc00, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_B16, /* bfd_reloc_code_real_type */ - reloc_bits_b16, /* adjust_reloc_bits */ - "b16"), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0x3fffc00, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_B16, /* bfd_reloc_code_real_type. */ + reloc_bits_b16, /* adjust_reloc_bits. */ + "b16"), /* larch_reloc_type_name. */ =20 LOONGARCH_HOWTO (R_LARCH_B21, /* type (65). */ 2, /* rightshift. */ @@ -759,12 +779,12 @@ static loongarch_reloc_howto_type loongarch_howto_tab= le[] =3D bfd_elf_generic_reloc, /* special_function. */ "R_LARCH_B21", /* name. */ false, /* partial_inplace. */ - 0xfc0003e0, /* src_mask */ - 0xfc0003e0, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_B21, /* bfd_reloc_code_real_type */ - reloc_bits_b21, /* adjust_reloc_bits */ - "b21"), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0x3fffc1f, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_B21, /* bfd_reloc_code_real_type. */ + reloc_bits_b21, /* adjust_reloc_bits. */ + "b21"), /* larch_reloc_type_name. */ =20 LOONGARCH_HOWTO (R_LARCH_B26, /* type (66). */ 2, /* rightshift. */ @@ -776,12 +796,12 @@ static loongarch_reloc_howto_type loongarch_howto_tab= le[] =3D bfd_elf_generic_reloc, /* special_function. */ "R_LARCH_B26", /* name. */ false, /* partial_inplace. */ - 0, /* src_mask */ - 0x03ffffff, /* dst_mask */ - false, /* pcrel_offset */ - BFD_RELOC_LARCH_B26, /* bfd_reloc_code_real_type */ - reloc_bits_b26, /* adjust_reloc_bits */ - "b26"), /* larch_reloc_type_name */ + 0, /* src_mask. */ + 0x03ffffff, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_B26, /* bfd_reloc_code_real_type. */ + reloc_bits_b26, /* adjust_reloc_bits. */ + "b26"), /* larch_reloc_type_name. */ =20 LOONGARCH_HOWTO (R_LARCH_ABS_HI20, /* type (67). */ 12, /* rightshift. */ @@ -1078,7 +1098,7 @@ static loongarch_reloc_howto_type loongarch_howto_tab= le[] =3D 12, /* bitsize. */ false, /* pc_relative. */ 10, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ + complain_overflow_unsigned, /* complain_on_overflow. */ bfd_elf_generic_reloc, /* special_function. */ "R_LARCH_TLS_LE_LO12", /* name. */ false, /* partial_inplace. */ @@ -1146,7 +1166,7 @@ static loongarch_reloc_howto_type loongarch_howto_tab= le[] =3D 12, /* bitsize. */ false, /* pc_relative. */ 10, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ + complain_overflow_signed, /* complain_on_overflow. */ bfd_elf_generic_reloc, /* special_function. */ "R_LARCH_TLS_IE_PC_LO12", /* name. */ false, /* partial_inplace. */ @@ -1191,7 +1211,7 @@ static loongarch_reloc_howto_type loongarch_howto_tab= le[] =3D reloc_bits, /* adjust_reloc_bits */ "ie64_pc_hi12"), /* larch_reloc_type_name */ =20 - LOONGARCH_HOWTO (R_LARCH_TLS_IE_HI20, /* type (91). */ + LOONGARCH_HOWTO (R_LARCH_TLS_IE_HI20, /* type (91). */ 12, /* rightshift. */ 4, /* size. */ 20, /* bitsize. */ @@ -1327,13 +1347,14 @@ static loongarch_reloc_howto_type loongarch_howto_t= able[] =3D reloc_bits, /* adjust_reloc_bits */ "gd_hi20"), /* larch_reloc_type_name */ =20 + /* 32-bit PC relative. */ LOONGARCH_HOWTO (R_LARCH_32_PCREL, /* type (99). */ 0, /* rightshift. */ 4, /* size. */ 32, /* bitsize. */ true, /* pc_relative. */ 0, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ + complain_overflow_signed, /* complain_on_overflow. */ bfd_elf_generic_reloc, /* special_function. */ "R_LARCH_32_PCREL", /* name. */ false, /* partial_inplace. */ @@ -1344,6 +1365,7 @@ static loongarch_reloc_howto_type loongarch_howto_tab= le[] =3D NULL, /* adjust_reloc_bits */ NULL), /* larch_reloc_type_name */ =20 + /* The paired relocation may be relaxed. */ LOONGARCH_HOWTO (R_LARCH_RELAX, /* type (100). */ 0, /* rightshift */ 1, /* size */ @@ -1361,6 +1383,158 @@ static loongarch_reloc_howto_type loongarch_howto_t= able[] =3D NULL, /* adjust_reloc_bits */ NULL), /* larch_reloc_type_name */ =20 + /* Delete relaxed instruction. */ + LOONGARCH_HOWTO (R_LARCH_DELETE, /* type (101). */ + 0, /* rightshift. */ + 0, /* size. */ + 0, /* bitsize. */ + false, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_dont, /* complain_on_overflow. */ + bfd_elf_generic_reloc, /* special_function. */ + "R_LARCH_DELETE", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_DELETE, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ + + /* Indicates an alignment statement. The addend field encodes how many + bytes of NOPs follow the statement. The desired alignment is the + addend rounded up to the next power of two. */ + LOONGARCH_HOWTO (R_LARCH_ALIGN, /* type (102). */ + 0, /* rightshift. */ + 0, /* size. */ + 0, /* bitsize. */ + false, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_dont, /* complain_on_overflow. */ + bfd_elf_generic_reloc, /* special_function. */ + "R_LARCH_ALIGN", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_ALIGN, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ + + /* pcala_hi20 + pcala_lo12 relaxed to pcrel20_s2. */ + LOONGARCH_HOWTO (R_LARCH_PCREL20_S2, /* type (103). */ + 2, /* rightshift. */ + 4, /* size. */ + 20, /* bitsize. */ + false, /* pc_relative. */ + 5, /* bitpos. */ + complain_overflow_signed, /* complain_on_overflow. */ + bfd_elf_generic_reloc, /* special_function. */ + "R_LARCH_PCREL20_S2", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0x1ffffe0, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_PCREL20_S2, /* bfd_reloc_code_real_type. */ + reloc_bits_pcrel20_s2, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ + + /* Canonical Frame Address. */ + LOONGARCH_HOWTO (R_LARCH_CFA, /* type (104). */ + 0, /* rightshift. */ + 0, /* size. */ + 0, /* bitsize. */ + false, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_dont, /* complain_on_overflow. */ + bfd_elf_generic_reloc, /* special_function. */ + "R_LARCH_CFA", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_CFA, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ + + /* 6-bit in-place addition, for local label subtraction + to calculate DW_CFA_advance_loc. */ + LOONGARCH_HOWTO (R_LARCH_ADD6, /* type (105). */ + 0, /* rightshift. */ + 1, /* size. */ + 8, /* bitsize. */ + false, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ + "R_LARCH_ADD6", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0x3f, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_ADD6, /* bfd_reloc_code_real_type. */ + reloc_bits, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ + + /* 6-bit in-place subtraction, for local label subtraction + to calculate DW_CFA_advance_loc. */ + LOONGARCH_HOWTO (R_LARCH_SUB6, /* type (106). */ + 0, /* rightshift. */ + 1, /* size. */ + 8, /* bitsize. */ + false, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc, /* special_function. */ + "R_LARCH_SUB6", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0x3f, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_SUB6, /* bfd_reloc_code_real_type. */ + reloc_bits, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ + + /* The length of unsigned-leb128 is variable, just assume the + size is one byte here. + uleb128 in-place addition, for local label subtraction. */ + LOONGARCH_HOWTO (R_LARCH_ADD_ULEB128, /* type (107). */ + 0, /* rightshift. */ + 1, /* size. */ + 0, /* bitsize. */ + false, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc_uleb128, /* special_function. */ + "R_LARCH_ADD_ULEB128", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_ADD_ULEB128, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ + + /* The length of unsigned-leb128 is variable, just assume the + size is one byte here. + uleb128 in-place subtraction, for local label subtraction. */ + LOONGARCH_HOWTO (R_LARCH_SUB_ULEB128, /* type (108). */ + 0, /* rightshift. */ + 1, /* size. */ + 0, /* bitsize. */ + false, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_dont, /* complain_on_overflow. */ + loongarch_elf_add_sub_reloc_uleb128, /* special_function. */ + "R_LARCH_SUB_ULEB128", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_SUB_ULEB128, /* bfd_reloc_code_real_type. */ + NULL, /* adjust_reloc_bits. */ + NULL), /* larch_reloc_type_name. */ + }; =20 reloc_howto_type * @@ -1464,13 +1638,54 @@ loongarch_larch_reloc_name_lookup (bfd *abfd ATTRIB= UTE_UNUSED, BFD_RELOC_LARCH_SOP_POP_32_S_10_16 BFD_RELOC_LARCH_SOP_POP_32_S_5_20 BFD_RELOC_LARCH_SOP_POP_32_U. */ + +static bool +reloc_bits (bfd *abfd ATTRIBUTE_UNUSED, + reloc_howto_type *howto, + bfd_vma *fix_val) +{ + bfd_signed_vma val =3D (bfd_signed_vma)(*fix_val); + bfd_signed_vma mask =3D ((bfd_signed_vma)0x1 << howto->bitsize) - 1; + + val =3D val >> howto->rightshift; + + /* Perform insn bits field. */ + val =3D val & mask; + val <<=3D howto->bitpos; + + *fix_val =3D (bfd_vma)val; + + return true; +} + static bool -reloc_bits (reloc_howto_type *howto, bfd_vma *fix_val) +reloc_bits_pcrel20_s2 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_va= l) { - bfd_signed_vma val =3D ((bfd_signed_vma)(*fix_val)) >> howto->rightshift; + bfd_signed_vma val =3D (bfd_signed_vma)(*fix_val); + bfd_signed_vma mask =3D ((bfd_signed_vma)0x1 << howto->bitsize) - 1; + + /* Check rightshift. */ + if (howto->rightshift + && (val & ((((bfd_signed_vma) 1) << howto->rightshift) - 1))) + { + (*_bfd_error_handler) (_("%pB: relocation %s right shift %d error 0x= %lx"), + abfd, howto->name, howto->rightshift, val); + bfd_set_error (bfd_error_bad_value); + return false; + } + + val =3D val >> howto->rightshift; + + if ((val & ~mask) && ((val & ~mask) !=3D ~mask)) + { + (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"), + abfd, howto->name, val); + bfd_set_error (bfd_error_bad_value); + return false; + } =20 /* Perform insn bits field. */ - val =3D val & (((bfd_vma)0x1 << howto->bitsize) - 1); + val =3D val & mask; val <<=3D howto->bitpos; =20 *fix_val =3D (bfd_vma)val; @@ -1478,42 +1693,35 @@ reloc_bits (reloc_howto_type *howto, bfd_vma *fix_v= al) return true; } =20 + /* Adjust val to perform insn R_LARCH_SOP_POP_32_S_10_16_S2 R_LARCH_B16. */ static bool -reloc_bits_b16 (reloc_howto_type *howto, bfd_vma *fix_val) +reloc_bits_b16 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) { + bfd_signed_vma val =3D *fix_val; + bfd_signed_vma mask =3D ((bfd_signed_vma)0x1 << howto->bitsize) - 1; + if (howto->complain_on_overflow !=3D complain_overflow_signed) return false; =20 - bfd_signed_vma val =3D *fix_val; - /* Judge whether 4 bytes align. */ if (val & ((0x1UL << howto->rightshift) - 1)) return false; =20 - int bitsize =3D howto->bitsize + howto->rightshift; - bfd_signed_vma sig_bit =3D (val >> (bitsize - 1)) & 0x1; + val =3D val >> howto->rightshift; =20 - /* If val < 0, sign bit is 1. */ - if (sig_bit) - { - /* Signed bits is 1. */ - if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val) - !=3D LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1)) - return false; - } - else + if ((val & ~mask) && ((val & ~mask) !=3D ~mask)) { - /* Signed bits is 0. */ - if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val) - return false; + (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"), + abfd, howto->name, val); + bfd_set_error (bfd_error_bad_value); + return false; } =20 /* Perform insn bits field. */ - val >>=3D howto->rightshift; - val =3D val & (((bfd_vma)0x1 << howto->bitsize) - 1); + val =3D val & mask; val <<=3D howto->bitpos; =20 *fix_val =3D val; @@ -1525,36 +1733,30 @@ reloc_bits_b16 (reloc_howto_type *howto, bfd_vma *f= ix_val) R_LARCH_SOP_POP_32_S_0_5_10_16_S2 R_LARCH_B21. */ static bool -reloc_bits_b21 (reloc_howto_type *howto, - bfd_vma *fix_val) +reloc_bits_b21 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) { + bfd_signed_vma val =3D *fix_val; + bfd_signed_vma mask =3D ((bfd_signed_vma)0x1 << howto->bitsize) - 1; + if (howto->complain_on_overflow !=3D complain_overflow_signed) return false; =20 - bfd_signed_vma val =3D *fix_val; - + /* Judge whether 4 bytes align. */ if (val & ((0x1UL << howto->rightshift) - 1)) return false; =20 - int bitsize =3D howto->bitsize + howto->rightshift; - bfd_signed_vma sig_bit =3D (val >> (bitsize - 1)) & 0x1; + val =3D val >> howto->rightshift; =20 - /* If val < 0. */ - if (sig_bit) + if ((val & ~mask) && ((val & ~mask) !=3D ~mask)) { - if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val) - !=3D LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1)) - return false; - } - else - { - if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val) - return false; + (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"), + abfd, howto->name, val); + bfd_set_error (bfd_error_bad_value); + return false; } =20 /* Perform insn bits field. */ - val >>=3D howto->rightshift; - val =3D val & (((bfd_vma)0x1 << howto->bitsize) - 1); + val =3D val & mask; =20 /* Perform insn bits field. 15:0<<10, 20:16>>16. */ val =3D ((val & 0xffff) << 10) | ((val >> 16) & 0x1f); @@ -1568,37 +1770,31 @@ reloc_bits_b21 (reloc_howto_type *howto, R_LARCH_SOP_POP_32_S_0_10_10_16_S2 R_LARCH_B26. */ static bool -reloc_bits_b26 (reloc_howto_type *howto, - bfd_vma *fix_val) +reloc_bits_b26 (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) { - /* Return false if overflow. */ + bfd_signed_vma val =3D *fix_val; + bfd_signed_vma mask =3D ((bfd_signed_vma)0x1 << howto->bitsize) - 1; + if (howto->complain_on_overflow !=3D complain_overflow_signed) return false; =20 - bfd_signed_vma val =3D *fix_val; - + /* Judge whether 4 bytes align. */ if (val & ((0x1UL << howto->rightshift) - 1)) return false; =20 - int bitsize =3D howto->bitsize + howto->rightshift; - bfd_signed_vma sig_bit =3D (val >> (bitsize - 1)) & 0x1; + val =3D val >> howto->rightshift; =20 - /* If val < 0. */ - if (sig_bit) + if ((val & ~mask) && ((val & ~mask) !=3D ~mask)) { - if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val) - !=3D LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1)) - return false; - } - else - { - if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val) - return false; + (*_bfd_error_handler) (_("%pB: relocation %s overflow 0x%lx"), + abfd, howto->name, val); + bfd_set_error (bfd_error_bad_value); + return false; } =20 + /* Perform insn bits field. */ - val >>=3D howto->rightshift; - val =3D val & (((bfd_vma)0x1 << howto->bitsize) - 1); + val =3D val & mask; =20 /* Perform insn bits field. 25:16>>16, 15:0<<10. */ val =3D ((val & 0xffff) << 10) | ((val >> 16) & 0x3ff); @@ -1609,10 +1805,142 @@ reloc_bits_b26 (reloc_howto_type *howto, } =20 bool -loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto, +loongarch_adjust_reloc_bitsfield (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) { BFD_ASSERT (((loongarch_reloc_howto_type *)howto)->adjust_reloc_bits); return ((loongarch_reloc_howto_type *) - howto)->adjust_reloc_bits(howto, fix_val); + howto)->adjust_reloc_bits (abfd, howto, fix_val); +} + +static bfd_reloc_status_type +loongarch_elf_add_sub_reloc (bfd *abfd, + arelent *reloc_entry, + asymbol *symbol, + void *data, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + reloc_howto_type *howto =3D reloc_entry->howto; + bfd_vma relocation; + + if (output_bfd !=3D NULL + && (symbol->flags & BSF_SECTION_SYM) =3D=3D 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend =3D= =3D 0)) + { + reloc_entry->address +=3D input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd !=3D NULL) + return bfd_reloc_continue; + + relocation =3D symbol->value + symbol->section->output_section->vma + + symbol->section->output_offset + reloc_entry->addend; + + bfd_size_type octets =3D reloc_entry->address + * bfd_octets_per_byte (abfd, input_section); + if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, + input_section, octets)) + return bfd_reloc_outofrange; + + bfd_vma old_value =3D bfd_get (howto->bitsize, abfd, + data + reloc_entry->address); + + switch (howto->type) + { + case R_LARCH_ADD6: + case R_LARCH_ADD8: + case R_LARCH_ADD16: + case R_LARCH_ADD32: + case R_LARCH_ADD64: + relocation =3D old_value + relocation; + break; + + case R_LARCH_SUB6: + case R_LARCH_SUB8: + case R_LARCH_SUB16: + case R_LARCH_SUB32: + case R_LARCH_SUB64: + relocation =3D old_value - relocation; + break; + } + + bfd_put (howto->bitsize, abfd, relocation, data + reloc_entry->address); + + return bfd_reloc_ok; +} + +static bfd_reloc_status_type +loongarch_elf_add_sub_reloc_uleb128 (bfd *abfd, + arelent *reloc_entry, + asymbol *symbol, + void *data, + asection *input_section, + bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + reloc_howto_type *howto =3D reloc_entry->howto; + bfd_vma relocation; + + if (output_bfd !=3D NULL + && (symbol->flags & BSF_SECTION_SYM) =3D=3D 0 + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend =3D= =3D 0)) + { + reloc_entry->address +=3D input_section->output_offset; + return bfd_reloc_ok; + } + + if (output_bfd !=3D NULL) + return bfd_reloc_continue; + + relocation =3D symbol->value + symbol->section->output_section->vma + + symbol->section->output_offset + reloc_entry->addend; + + bfd_size_type octets =3D reloc_entry->address + * bfd_octets_per_byte (abfd, input_section); + if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, + input_section, octets)) + return bfd_reloc_outofrange; + + unsigned int len =3D 0; + bfd_byte *p =3D data + reloc_entry->address; + bfd_vma old_value =3D _bfd_read_unsigned_leb128 (abfd, p, &len); + + switch (howto->type) + { + case R_LARCH_ADD_ULEB128: + relocation =3D old_value + relocation; + break; + + case R_LARCH_SUB_ULEB128: + relocation =3D old_value - relocation; + break; + } + + bfd_vma mask =3D (1 << (7 * len)) - 1; + relocation =3D relocation & mask; + loongarch_write_unsigned_leb128 (p, len, relocation); + return bfd_reloc_ok; +} + +/* Write VALUE in uleb128 format to P. + LEN is the uleb128 value length. + Return a pointer to the byte following the last byte that was written. = */ +bfd_byte * +loongarch_write_unsigned_leb128 (bfd_byte *p, unsigned int len, bfd_vma va= lue) +{ + bfd_byte c; + do + { + c =3D value & 0x7f; + if (len > 1) + c |=3D 0x80; + *(p++) =3D c; + value >>=3D 7; + len--; + } + while (len); + return p; } diff --git a/bfd/elfxx-loongarch.h b/bfd/elfxx-loongarch.h index 1a6b6df18f8..cb02af4fe73 100644 --- a/bfd/elfxx-loongarch.h +++ b/bfd/elfxx-loongarch.h @@ -34,7 +34,15 @@ extern bfd_reloc_code_real_type loongarch_larch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *l_r_name); =20 -bool loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto, bfd_vma *f= ix_val); +bool +loongarch_adjust_reloc_bitsfield (bfd *, reloc_howto_type *, bfd_vma *); +void +bfd_elf32_loongarch_set_data_segment_info (struct bfd_link_info *, int *); +void +bfd_elf64_loongarch_set_data_segment_info (struct bfd_link_info *, int *); + +bfd_byte * +loongarch_write_unsigned_leb128 (bfd_byte *p, unsigned int len, bfd_vma va= lue); =20 /* TRUE if this is a PLT reference to a local IFUNC. */ #define PLT_LOCAL_IFUNC_P(INFO, H) \ diff --git a/bfd/libbfd.h b/bfd/libbfd.h index f29a65a4b22..4f082ac75d6 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -3509,6 +3509,14 @@ static const char *const bfd_reloc_code_real_names[]= =3D { "@@uninitialized@@", "BFD_RELOC_LARCH_TLS_GD_HI20", "BFD_RELOC_LARCH_32_PCREL", "BFD_RELOC_LARCH_RELAX", + "BFD_RELOC_LARCH_DELETE", + "BFD_RELOC_LARCH_ALIGN", + "BFD_RELOC_LARCH_PCREL20_S2", + "BFD_RELOC_LARCH_CFA", + "BFD_RELOC_LARCH_ADD6", + "BFD_RELOC_LARCH_SUB6", + "BFD_RELOC_LARCH_ADD_ULEB128", + "BFD_RELOC_LARCH_SUB_ULEB128", "@@overflow: BFD_RELOC_UNUSED@@", }; #endif diff --git a/bfd/reloc.c b/bfd/reloc.c index c7d11cf5f40..b38cb32a8c9 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -8131,6 +8131,28 @@ ENUMX ENUMX BFD_RELOC_LARCH_RELAX =20 +ENUMX + BFD_RELOC_LARCH_DELETE + +ENUMX + BFD_RELOC_LARCH_ALIGN + +ENUMX + BFD_RELOC_LARCH_PCREL20_S2 + +ENUMX + BFD_RELOC_LARCH_CFA + +ENUMX + BFD_RELOC_LARCH_ADD6 +ENUMX + BFD_RELOC_LARCH_SUB6 + +ENUMX + BFD_RELOC_LARCH_ADD_ULEB128 +ENUMX + BFD_RELOC_LARCH_SUB_ULEB128 + ENUMDOC LARCH relocations.