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.
This commit is contained in:
mengqinggang 2023-09-28 16:41:15 +08:00 committed by liuzhensong
parent d51cd0f64c
commit dc5f359ed6
11 changed files with 89 additions and 7 deletions

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -8292,6 +8292,9 @@ ENUMX
ENUMX
BFD_RELOC_LARCH_64_PCREL
ENUMX
BFD_RELOC_LARCH_CALL36
ENUMDOC
LARCH relocations.

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

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

View File

@ -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" \
] \
]
}

View File

@ -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