@ -163,6 +163,7 @@ struct riscv_elf_link_hash_entry
# define GOT_TLS_GD 2
# define GOT_TLS_GD 2
# define GOT_TLS_IE 4
# define GOT_TLS_IE 4
# define GOT_TLS_LE 8
# define GOT_TLS_LE 8
# define GOT_TLSDESC 16
char tls_type ;
char tls_type ;
} ;
} ;
@ -300,6 +301,7 @@ riscv_is_insn_reloc (const reloc_howto_type *howto)
# define GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
# define GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
# define TLS_GD_GOT_ENTRY_SIZE (RISCV_ELF_WORD_BYTES * 2)
# define TLS_GD_GOT_ENTRY_SIZE (RISCV_ELF_WORD_BYTES * 2)
# define TLS_IE_GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
# define TLS_IE_GOT_ENTRY_SIZE RISCV_ELF_WORD_BYTES
# define TLSDESC_GOT_ENTRY_SIZE (RISCV_ELF_WORD_BYTES * 2)
/* Reserve two entries of GOTPLT for ld.so, one is used for PLT resolver,
/* Reserve two entries of GOTPLT for ld.so, one is used for PLT resolver,
the other is used for link map . Other targets also reserve one more
the other is used for link map . Other targets also reserve one more
entry used for runtime profile ? */
entry used for runtime profile ? */
@ -855,6 +857,12 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
return false ;
return false ;
break ;
break ;
case R_RISCV_TLSDESC_HI20 :
if ( ! riscv_elf_record_got_reference ( abfd , info , h , r_symndx )
| | ! riscv_elf_record_tls_type ( abfd , h , r_symndx , GOT_TLSDESC ) )
return false ;
break ;
case R_RISCV_CALL :
case R_RISCV_CALL :
case R_RISCV_CALL_PLT :
case R_RISCV_CALL_PLT :
/* These symbol requires a procedure linkage table entry.
/* These symbol requires a procedure linkage table entry.
@ -1313,7 +1321,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
s = htab - > elf . sgot ;
s = htab - > elf . sgot ;
h - > got . offset = s - > size ;
h - > got . offset = s - > size ;
dyn = htab - > elf . dynamic_sections_created ;
dyn = htab - > elf . dynamic_sections_created ;
if ( tls_type & ( GOT_TLS_GD | GOT_TLS_IE ) )
if ( tls_type & ( GOT_TLS_GD | GOT_TLS_IE | GOT_TLSDESC ) )
{
{
int indx = 0 ;
int indx = 0 ;
bool need_reloc = false ;
bool need_reloc = false ;
@ -1334,6 +1342,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if ( need_reloc )
if ( need_reloc )
htab - > elf . srelgot - > size + = sizeof ( ElfNN_External_Rela ) ;
htab - > elf . srelgot - > size + = sizeof ( ElfNN_External_Rela ) ;
}
}
/* TLSDESC needs one dynamic reloc and two GOT slots. */
if ( tls_type & GOT_TLSDESC )
{
s - > size + = TLSDESC_GOT_ENTRY_SIZE ;
/* TLSDESC always use dynamic relocs. */
htab - > elf . srelgot - > size + = sizeof ( ElfNN_External_Rela ) ;
}
}
}
else
else
{
{
@ -1561,7 +1577,7 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
if ( * local_got > 0 )
if ( * local_got > 0 )
{
{
* local_got = s - > size ;
* local_got = s - > size ;
if ( * local_tls_type & ( GOT_TLS_GD | GOT_TLS_IE ) )
if ( * local_tls_type & ( GOT_TLS_GD | GOT_TLS_IE | GOT_TLSDESC ) )
{
{
if ( * local_tls_type & GOT_TLS_GD )
if ( * local_tls_type & GOT_TLS_GD )
{
{
@ -1575,6 +1591,11 @@ riscv_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
if ( bfd_link_dll ( info ) )
if ( bfd_link_dll ( info ) )
srel - > size + = sizeof ( ElfNN_External_Rela ) ;
srel - > size + = sizeof ( ElfNN_External_Rela ) ;
}
}
if ( * local_tls_type & GOT_TLSDESC )
{
s - > size + = TLSDESC_GOT_ENTRY_SIZE ;
srel - > size + = sizeof ( ElfNN_External_Rela ) ;
}
}
}
else
else
{
{
@ -1725,6 +1746,17 @@ tpoff (struct bfd_link_info *info, bfd_vma address)
return address - elf_hash_table ( info ) - > tls_sec - > vma - TP_OFFSET ;
return address - elf_hash_table ( info ) - > tls_sec - > vma - TP_OFFSET ;
}
}
/* Return the relocation value for a static TLSDESC relocation. */
static bfd_vma
tlsdescoff ( struct bfd_link_info * info , bfd_vma address )
{
/* If tls_sec is NULL, we should have signalled an error already. */
if ( elf_hash_table ( info ) - > tls_sec = = NULL )
return 0 ;
return address - elf_hash_table ( info ) - > tls_sec - > vma ;
}
/* Return the global pointer's value, or 0 if it is not in use. */
/* Return the global pointer's value, or 0 if it is not in use. */
static bfd_vma
static bfd_vma
@ -1764,6 +1796,7 @@ perform_relocation (const reloc_howto_type *howto,
case R_RISCV_GOT_HI20 :
case R_RISCV_GOT_HI20 :
case R_RISCV_TLS_GOT_HI20 :
case R_RISCV_TLS_GOT_HI20 :
case R_RISCV_TLS_GD_HI20 :
case R_RISCV_TLS_GD_HI20 :
case R_RISCV_TLSDESC_HI20 :
if ( ARCH_SIZE > 32 & & ! VALID_UTYPE_IMM ( RISCV_CONST_HIGH_PART ( value ) ) )
if ( ARCH_SIZE > 32 & & ! VALID_UTYPE_IMM ( RISCV_CONST_HIGH_PART ( value ) ) )
return bfd_reloc_overflow ;
return bfd_reloc_overflow ;
value = ENCODE_UTYPE_IMM ( RISCV_CONST_HIGH_PART ( value ) ) ;
value = ENCODE_UTYPE_IMM ( RISCV_CONST_HIGH_PART ( value ) ) ;
@ -1774,6 +1807,8 @@ perform_relocation (const reloc_howto_type *howto,
case R_RISCV_TPREL_LO12_I :
case R_RISCV_TPREL_LO12_I :
case R_RISCV_TPREL_I :
case R_RISCV_TPREL_I :
case R_RISCV_PCREL_LO12_I :
case R_RISCV_PCREL_LO12_I :
case R_RISCV_TLSDESC_LOAD_LO12 :
case R_RISCV_TLSDESC_ADD_LO12 :
value = ENCODE_ITYPE_IMM ( value ) ;
value = ENCODE_ITYPE_IMM ( value ) ;
break ;
break ;
@ -2192,8 +2227,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
bfd_vma relocation ;
bfd_vma relocation ;
bfd_reloc_status_type r = bfd_reloc_ok ;
bfd_reloc_status_type r = bfd_reloc_ok ;
const char * name = NULL ;
const char * name = NULL ;
bfd_vma off , ie_off ;
bfd_vma off , ie_off , desc_off ;
bool unresolved_reloc , is_ie = false ;
bool unresolved_reloc , is_ie = false , is_desc = false ;
bfd_vma pc = sec_addr ( input_section ) + rel - > r_offset ;
bfd_vma pc = sec_addr ( input_section ) + rel - > r_offset ;
int r_type = ELFNN_R_TYPE ( rel - > r_info ) , tls_type ;
int r_type = ELFNN_R_TYPE ( rel - > r_info ) , tls_type ;
reloc_howto_type * howto = riscv_elf_rtype_to_howto ( input_bfd , r_type ) ;
reloc_howto_type * howto = riscv_elf_rtype_to_howto ( input_bfd , r_type ) ;
@ -2496,6 +2531,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
case R_RISCV_NONE :
case R_RISCV_NONE :
case R_RISCV_RELAX :
case R_RISCV_RELAX :
case R_RISCV_TPREL_ADD :
case R_RISCV_TPREL_ADD :
case R_RISCV_TLSDESC_CALL :
case R_RISCV_COPY :
case R_RISCV_COPY :
case R_RISCV_JUMP_SLOT :
case R_RISCV_JUMP_SLOT :
case R_RISCV_RELATIVE :
case R_RISCV_RELATIVE :
@ -2843,6 +2879,22 @@ riscv_elf_relocate_section (bfd *output_bfd,
relocation = dtpoff ( info , relocation ) ;
relocation = dtpoff ( info , relocation ) ;
break ;
break ;
case R_RISCV_TLSDESC_LOAD_LO12 :
case R_RISCV_TLSDESC_ADD_LO12 :
if ( rel - > r_addend )
{
msg = _ ( " %tlsdesc_lo with addend " ) ;
r = bfd_reloc_dangerous ;
break ;
}
if ( riscv_record_pcrel_lo_reloc ( & pcrel_relocs , relocation , rel ,
input_section , info , howto ,
contents ) )
continue ;
r = bfd_reloc_overflow ;
break ;
case R_RISCV_32 :
case R_RISCV_32 :
/* Non ABS symbol should be blocked in check_relocs. */
/* Non ABS symbol should be blocked in check_relocs. */
if ( ARCH_SIZE > 32 )
if ( ARCH_SIZE > 32 )
@ -2908,11 +2960,16 @@ riscv_elf_relocate_section (bfd *output_bfd,
}
}
break ;
break ;
case R_RISCV_TLSDESC_HI20 :
is_desc = true ;
goto tls ;
case R_RISCV_TLS_GOT_HI20 :
case R_RISCV_TLS_GOT_HI20 :
is_ie = true ;
is_ie = true ;
/* Fall through. */
goto tls ;
case R_RISCV_TLS_GD_HI20 :
case R_RISCV_TLS_GD_HI20 :
tls :
if ( h ! = NULL )
if ( h ! = NULL )
{
{
off = h - > got . offset ;
off = h - > got . offset ;
@ -2925,12 +2982,16 @@ riscv_elf_relocate_section (bfd *output_bfd,
}
}
tls_type = _bfd_riscv_elf_tls_type ( input_bfd , h , r_symndx ) ;
tls_type = _bfd_riscv_elf_tls_type ( input_bfd , h , r_symndx ) ;
BFD_ASSERT ( tls_type & ( GOT_TLS_IE | GOT_TLS_GD ) ) ;
BFD_ASSERT ( tls_type & ( GOT_TLS_IE | GOT_TLS_GD | GOT_TLSDESC ) ) ;
/* If this symbol is referenced by both GD and IE TLS, the IE
/* When more than one TLS type is used, the GD slot comes first,
reference ' s GOT slot follows the GD reference ' s slots . */
then IE , then finally TLSDESC . */
ie_off = 0 ;
ie_off = 0 ;
if ( ( tls_type & GOT_TLS_GD ) & & ( tls_type & GOT_TLS_IE ) )
if ( tls_type & GOT_TLS_GD )
ie_off = TLS_GD_GOT_ENTRY_SIZE ;
ie_off + = TLS_GD_GOT_ENTRY_SIZE ;
desc_off = ie_off ;
if ( tls_type & GOT_TLS_IE )
desc_off + = TLS_IE_GOT_ENTRY_SIZE ;
if ( ( off & 1 ) ! = 0 )
if ( ( off & 1 ) ! = 0 )
off & = ~ 1 ;
off & = ~ 1 ;
@ -3012,10 +3073,29 @@ riscv_elf_relocate_section (bfd *output_bfd,
htab - > elf . sgot - > contents + off + ie_off ) ;
htab - > elf . sgot - > contents + off + ie_off ) ;
}
}
}
}
if ( tls_type & GOT_TLSDESC )
{
/* TLSDESC is always handled by the dynamic linker and always need
* a relocation . */
bfd_put_NN ( output_bfd , 0 ,
htab - > elf . sgot - > contents + off + desc_off ) ;
outrel . r_offset = sec_addr ( htab - > elf . sgot )
+ off + desc_off ;
outrel . r_addend = 0 ;
if ( indx = = 0 )
outrel . r_addend = tlsdescoff ( info , relocation ) ;
outrel . r_info = ELFNN_R_INFO ( indx , R_RISCV_TLSDESC ) ;
riscv_elf_append_rela ( output_bfd , htab - > elf . srelgot , & outrel ) ;
}
}
}
BFD_ASSERT ( off < ( bfd_vma ) - 2 ) ;
BFD_ASSERT ( off < ( bfd_vma ) - 2 ) ;
relocation = sec_addr ( htab - > elf . sgot ) + off + ( is_ie ? ie_off : 0 ) ;
relocation = sec_addr ( htab - > elf . sgot ) + off ;
if ( is_ie )
relocation + = ie_off ;
else if ( is_desc )
relocation + = desc_off ;
if ( ! riscv_record_pcrel_hi_reloc ( & pcrel_relocs , pc ,
if ( ! riscv_record_pcrel_hi_reloc ( & pcrel_relocs , pc ,
relocation , r_type ,
relocation , r_type ,
false ) )
false ) )
@ -3235,7 +3315,7 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
}
}
if ( h - > got . offset ! = ( bfd_vma ) - 1
if ( h - > got . offset ! = ( bfd_vma ) - 1
& & ! ( riscv_elf_hash_entry ( h ) - > tls_type & ( GOT_TLS_GD | GOT_TLS_IE ) )
& & ! ( riscv_elf_hash_entry ( h ) - > tls_type & ( GOT_TLS_GD | GOT_TLS_IE | GOT_TLSDESC ) )
& & ! UNDEFWEAK_NO_DYNAMIC_RELOC ( info , h ) )
& & ! UNDEFWEAK_NO_DYNAMIC_RELOC ( info , h ) )
{
{
asection * sgot ;
asection * sgot ;