diff options
author | mengqinggang <mengqinggang@loongson.cn> | 2023-09-28 16:41:15 +0800 |
---|---|---|
committer | liuzhensong <liuzhensong@loongson.cn> | 2023-12-18 18:36:21 +0800 |
commit | dc5f359ed6a36d2c895d89c3e4886f3a2b6d9232 (patch) | |
tree | ca60c74de15fdc76c54e8eb3a7d881078f3585d7 | |
parent | d51cd0f64c6d3bd235f140ed71cc2c3e0b87a5ff (diff) | |
download | gdb-dc5f359ed6a36d2c895d89c3e4886f3a2b6d9232.zip gdb-dc5f359ed6a36d2c895d89c3e4886f3a2b6d9232.tar.gz gdb-dc5f359ed6a36d2c895d89c3e4886f3a2b6d9232.tar.bz2 |
LoongArch: Add new relocation R_LARCH_CALL36
R_LARCH_CALL36 is used for medium code model function call pcaddu18i+jirl, and
these two instructions must adjacent.
The LoongArch ABI v2.20 at here: https://github.com/loongson/la-abi-specs.
-rw-r--r-- | bfd/bfd-in2.h | 1 | ||||
-rw-r--r-- | bfd/elfnn-loongarch.c | 19 | ||||
-rw-r--r-- | bfd/elfxx-loongarch.c | 24 | ||||
-rw-r--r-- | bfd/libbfd.h | 1 | ||||
-rw-r--r-- | bfd/reloc.c | 3 | ||||
-rw-r--r-- | gas/config/tc-loongarch.c | 6 | ||||
-rw-r--r-- | gas/testsuite/gas/loongarch/medium-call.d | 15 | ||||
-rw-r--r-- | gas/testsuite/gas/loongarch/medium-call.s | 6 | ||||
-rw-r--r-- | include/elf/loongarch.h | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp | 12 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/medium-call.s | 7 |
11 files changed, 89 insertions, 7 deletions
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 2807e69..53c40ec 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -7460,6 +7460,7 @@ enum bfd_reloc_code_real BFD_RELOC_LARCH_ADD_ULEB128, BFD_RELOC_LARCH_SUB_ULEB128, BFD_RELOC_LARCH_64_PCREL, + BFD_RELOC_LARCH_CALL36, BFD_RELOC_UNUSED }; typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c index 024c5d4..aa88ee8 100644 --- a/bfd/elfnn-loongarch.c +++ b/bfd/elfnn-loongarch.c @@ -780,6 +780,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_LARCH_B16: case R_LARCH_B21: case R_LARCH_B26: + case R_LARCH_CALL36: if (h != NULL) { h->needs_plt = 1; @@ -1884,20 +1885,24 @@ loongarch_check_offset (const Elf_Internal_Rela *rel, ret; \ }) +/* Write immediate to instructions. */ + static bfd_reloc_status_type loongarch_reloc_rewrite_imm_insn (const Elf_Internal_Rela *rel, const asection *input_section ATTRIBUTE_UNUSED, reloc_howto_type *howto, bfd *input_bfd, bfd_byte *contents, bfd_vma reloc_val) { - int bits = bfd_get_reloc_size (howto) * 8; - uint32_t insn = bfd_get (bits, input_bfd, contents + rel->r_offset); - + /* Adjust the immediate based on alignment and + its position in the instruction. */ if (!loongarch_adjust_reloc_bitsfield (input_bfd, howto, &reloc_val)) return bfd_reloc_overflow; - insn = (insn & (uint32_t)howto->src_mask) - | ((insn & (~(uint32_t)howto->dst_mask)) | reloc_val); + int bits = bfd_get_reloc_size (howto) * 8; + uint64_t insn = bfd_get (bits, input_bfd, contents + rel->r_offset); + + /* Write immediate to instruction. */ + insn = (insn & ~howto->dst_mask) | (reloc_val & howto->dst_mask); bfd_put (bits, input_bfd, insn, contents + rel->r_offset); @@ -2120,6 +2125,7 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section, case R_LARCH_TLS_GD_PC_HI20: case R_LARCH_TLS_GD_HI20: case R_LARCH_PCREL20_S2: + case R_LARCH_CALL36: r = loongarch_check_offset (rel, input_section); if (r != bfd_reloc_ok) break; @@ -3127,9 +3133,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, break; /* New reloc types. */ + case R_LARCH_B16: case R_LARCH_B21: case R_LARCH_B26: - case R_LARCH_B16: + case R_LARCH_CALL36: unresolved_reloc = false; if (is_undefweak) { diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c index 7f298c0..d93b790 100644 --- a/bfd/elfxx-loongarch.c +++ b/bfd/elfxx-loongarch.c @@ -1547,6 +1547,24 @@ static loongarch_reloc_howto_type loongarch_howto_table[] = NULL, /* adjust_reloc_bits */ NULL), /* larch_reloc_type_name */ + /* Used for medium code model function call pcaddu18i+jirl, + these two instructions must adjacent. */ + LOONGARCH_HOWTO (R_LARCH_CALL36, /* type (110). */ + 2, /* rightshift. */ + 8, /* size. */ + 36, /* bitsize. */ + true, /* pc_relative. */ + 0, /* bitpos. */ + complain_overflow_signed, /* complain_on_overflow. */ + bfd_elf_generic_reloc, /* special_function. */ + "R_LARCH_CALL36", /* name. */ + false, /* partial_inplace. */ + 0, /* src_mask. */ + 0x03fffc0001ffffe0, /* dst_mask. */ + false, /* pcrel_offset. */ + BFD_RELOC_LARCH_CALL36, /* bfd_reloc_code_real_type. */ + reloc_sign_bits, /* adjust_reloc_bits. */ + "call36"), /* larch_reloc_type_name. */ }; reloc_howto_type * @@ -1726,6 +1744,12 @@ reloc_sign_bits (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val) /* Perform insn bits field. 15:0<<10, 20:16>>16. */ val = ((val & 0xffff) << 10) | ((val >> 16) & 0x1f); break; + case R_LARCH_CALL36: + /* 0x8000: If low 16-bit immediate greater than 0x7fff, + it become to a negative number due to sign-extended, + so the high part need to add 0x8000. */ + val = (((val + 0x8000) >> 16) << 5) | (((val & 0xffff) << 10) << 32); + break; default: val <<= howto->bitpos; break; diff --git a/bfd/libbfd.h b/bfd/libbfd.h index cc43267..399b1f6 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -3599,6 +3599,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_LARCH_ADD_ULEB128", "BFD_RELOC_LARCH_SUB_ULEB128", "BFD_RELOC_LARCH_64_PCREL", + "BFD_RELOC_LARCH_CALL36", "@@overflow: BFD_RELOC_UNUSED@@", }; #endif diff --git a/bfd/reloc.c b/bfd/reloc.c index 93ebad8..4d3ac4c 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -8292,6 +8292,9 @@ ENUMX ENUMX BFD_RELOC_LARCH_64_PCREL +ENUMX + BFD_RELOC_LARCH_CALL36 + ENUMDOC LARCH relocations. diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c index 5923283..367a0b6 100644 --- a/gas/config/tc-loongarch.c +++ b/gas/config/tc-loongarch.c @@ -682,7 +682,7 @@ loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2, esc_ch1, esc_ch2, bit_field, arg); if (ip->reloc_info[0].type >= BFD_RELOC_LARCH_B16 - && ip->reloc_info[0].type < BFD_RELOC_LARCH_64_PCREL) + && ip->reloc_info[0].type < BFD_RELOC_UNUSED) { /* As we compact stack-relocs, it is no need for pop operation. But break out until here in order to check the imm field. @@ -956,6 +956,10 @@ move_insn (struct loongarch_cl_insn *insn, fragS *frag, long where) static void append_fixed_insn (struct loongarch_cl_insn *insn) { + /* Ensure the jirl is emitted to the same frag as the pcaddu18i. */ + if (BFD_RELOC_LARCH_CALL36 == insn->reloc_info[0].type) + frag_grow (8); + char *f = frag_more (insn->insn_length); move_insn (insn, frag_now, f - frag_now->fr_literal); } diff --git a/gas/testsuite/gas/loongarch/medium-call.d b/gas/testsuite/gas/loongarch/medium-call.d new file mode 100644 index 0000000..4183818 --- /dev/null +++ b/gas/testsuite/gas/loongarch/medium-call.d @@ -0,0 +1,15 @@ +#as: +#objdump: -dr + +.*:[ ]+file format .* + + +Disassembly of section .text: + +.* <.text>: +[ ]+0:[ ]+1e000001[ ]+pcaddu18i[ ]+\$ra, 0 +[ ]+0: R_LARCH_CALL36[ ]+a +[ ]+4:[ ]+4c000021[ ]+jirl[ ]+\$ra, \$ra, 0 +[ ]+8:[ ]+1e00000c[ ]+pcaddu18i[ ]+\$t0, 0 +[ ]+8: R_LARCH_CALL36[ ]+a +[ ]+c:[ ]+4c000180[ ]+jr[ ]+\$t0 diff --git a/gas/testsuite/gas/loongarch/medium-call.s b/gas/testsuite/gas/loongarch/medium-call.s new file mode 100644 index 0000000..f2977d1 --- /dev/null +++ b/gas/testsuite/gas/loongarch/medium-call.s @@ -0,0 +1,6 @@ + # call .L1, r1(ra) temp register, r1(ra) return register. + pcaddu18i $r1, %call36(a) + jirl $r1, $r1, 0 + # tail .L1, r12(t0) temp register, r0(zero) return register. + pcaddu18i $r12, %call36(a) + jirl $r0, $r12, 0 diff --git a/include/elf/loongarch.h b/include/elf/loongarch.h index e31395e..34719ee 100644 --- a/include/elf/loongarch.h +++ b/include/elf/loongarch.h @@ -251,6 +251,8 @@ RELOC_NUMBER (R_LARCH_SUB_ULEB128, 108) RELOC_NUMBER (R_LARCH_64_PCREL, 109) +RELOC_NUMBER (R_LARCH_CALL36, 110) + END_RELOC_NUMBERS (R_LARCH_count) /* Processor specific flags for the ELF header e_flags field. */ diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp index b95cc53..1fc70d0 100644 --- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp +++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp @@ -55,4 +55,16 @@ if [istarget "loongarch64-*-*"] { "64_pcrel" \ ] \ ] + + run_ld_link_tests \ + [list \ + [list \ + "medium code model call" \ + "-e 0x0" "" \ + "" \ + {medium-call.s} \ + {} \ + "medium-call" \ + ] \ + ] } diff --git a/ld/testsuite/ld-loongarch-elf/medium-call.s b/ld/testsuite/ld-loongarch-elf/medium-call.s new file mode 100644 index 0000000..4d1888b --- /dev/null +++ b/ld/testsuite/ld-loongarch-elf/medium-call.s @@ -0,0 +1,7 @@ +.L1: + # call .L1, r1(ra) temp register, r1(ra) return register. + pcaddu18i $r1, %call36(.L1) + jirl $r1, $r1, 0 + # tail .L1, r12(t0) temp register, r0(zero) return register. + pcaddu18i $r12, %call36(.L1) + jirl $r0, $r12, 0 |