@ -650,6 +650,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
power10_stubs_ ( false ) , plt_thread_safe_ ( false ) , plt_localentry0_ ( false ) ,
plt_localentry0_init_ ( false ) , has_localentry0_ ( false ) ,
has_tls_get_addr_opt_ ( false ) ,
tprel_opt_ ( parameters - > options ( ) . tls_optimize ( ) ) ,
relax_failed_ ( false ) , relax_fail_count_ ( 0 ) ,
stub_group_size_ ( 0 ) , savres_section_ ( 0 ) ,
tls_get_addr_ ( NULL ) , tls_get_addr_opt_ ( NULL ) ,
@ -1145,6 +1146,14 @@ class Target_powerpc : public Sized_target<size, big_endian>
return false ;
}
bool
tprel_opt ( ) const
{ return this - > tprel_opt_ ; }
void
set_tprel_opt ( bool val )
{ this - > tprel_opt_ = val ; }
// Remember any symbols seen with non-zero localentry, even those
// not providing a definition
bool
@ -1702,6 +1711,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
bool plt_localentry0_init_ ;
bool has_localentry0_ ;
bool has_tls_get_addr_opt_ ;
bool tprel_opt_ ;
bool relax_failed_ ;
int relax_fail_count_ ;
@ -8365,10 +8375,6 @@ Target_powerpc<size, big_endian>::Scan::local(
switch ( r_type )
{
case elfcpp : : R_POWERPC_TPREL16 :
case elfcpp : : R_POWERPC_TPREL16_LO :
case elfcpp : : R_POWERPC_TPREL16_HI :
case elfcpp : : R_POWERPC_TPREL16_HA :
case elfcpp : : R_PPC64_TPREL16_DS :
case elfcpp : : R_PPC64_TPREL16_LO_DS :
case elfcpp : : R_PPC64_TPREL16_HIGH :
@ -8378,12 +8384,55 @@ Target_powerpc<size, big_endian>::Scan::local(
case elfcpp : : R_PPC64_TPREL16_HIGHEST :
case elfcpp : : R_PPC64_TPREL16_HIGHESTA :
case elfcpp : : R_PPC64_TPREL34 :
if ( size ! = 64 )
break ;
// Fall through.
case elfcpp : : R_POWERPC_TPREL16 :
case elfcpp : : R_POWERPC_TPREL16_LO :
case elfcpp : : R_POWERPC_TPREL16_HI :
case elfcpp : : R_POWERPC_TPREL16_HA :
layout - > set_has_static_tls ( ) ;
break ;
default :
break ;
}
switch ( r_type )
{
case elfcpp : : R_POWERPC_TPREL16_HA :
if ( target - > tprel_opt ( ) )
{
section_size_type slen ;
const unsigned char * view = NULL ;
view = ppc_object - > section_contents ( data_shndx , & slen , false ) ;
section_size_type off
= convert_to_section_size_type ( reloc . get_r_offset ( ) ) & - 4 ;
if ( off < slen )
{
uint32_t insn = elfcpp : : Swap < 32 , big_endian > : : readval ( view + off ) ;
if ( ( insn & ( ( 0x3fu < < 26 ) | 0x1f < < 16 ) )
! = ( ( 15u < < 26 ) | ( ( size = = 32 ? 2 : 13 ) < < 16 ) ) )
target - > set_tprel_opt ( false ) ;
}
}
break ;
case elfcpp : : R_PPC64_TPREL16_HIGH :
case elfcpp : : R_PPC64_TPREL16_HIGHA :
case elfcpp : : R_PPC64_TPREL16_HIGHER :
case elfcpp : : R_PPC64_TPREL16_HIGHERA :
case elfcpp : : R_PPC64_TPREL16_HIGHEST :
case elfcpp : : R_PPC64_TPREL16_HIGHESTA :
if ( size ! = 64 )
break ;
// Fall through.
case elfcpp : : R_POWERPC_TPREL16_HI :
target - > set_tprel_opt ( false ) ;
break ;
default :
break ;
}
switch ( r_type )
{
case elfcpp : : R_PPC64_D34 :
@ -9123,10 +9172,6 @@ Target_powerpc<size, big_endian>::Scan::global(
switch ( r_type )
{
case elfcpp : : R_POWERPC_TPREL16 :
case elfcpp : : R_POWERPC_TPREL16_LO :
case elfcpp : : R_POWERPC_TPREL16_HI :
case elfcpp : : R_POWERPC_TPREL16_HA :
case elfcpp : : R_PPC64_TPREL16_DS :
case elfcpp : : R_PPC64_TPREL16_LO_DS :
case elfcpp : : R_PPC64_TPREL16_HIGH :
@ -9136,12 +9181,55 @@ Target_powerpc<size, big_endian>::Scan::global(
case elfcpp : : R_PPC64_TPREL16_HIGHEST :
case elfcpp : : R_PPC64_TPREL16_HIGHESTA :
case elfcpp : : R_PPC64_TPREL34 :
if ( size ! = 64 )
break ;
// Fall through.
case elfcpp : : R_POWERPC_TPREL16 :
case elfcpp : : R_POWERPC_TPREL16_LO :
case elfcpp : : R_POWERPC_TPREL16_HI :
case elfcpp : : R_POWERPC_TPREL16_HA :
layout - > set_has_static_tls ( ) ;
break ;
default :
break ;
}
switch ( r_type )
{
case elfcpp : : R_POWERPC_TPREL16_HA :
if ( target - > tprel_opt ( ) )
{
section_size_type slen ;
const unsigned char * view = NULL ;
view = ppc_object - > section_contents ( data_shndx , & slen , false ) ;
section_size_type off
= convert_to_section_size_type ( reloc . get_r_offset ( ) ) & - 4 ;
if ( off < slen )
{
uint32_t insn = elfcpp : : Swap < 32 , big_endian > : : readval ( view + off ) ;
if ( ( insn & ( ( 0x3fu < < 26 ) | 0x1f < < 16 ) )
! = ( ( 15u < < 26 ) | ( ( size = = 32 ? 2 : 13 ) < < 16 ) ) )
target - > set_tprel_opt ( false ) ;
}
}
break ;
case elfcpp : : R_PPC64_TPREL16_HIGH :
case elfcpp : : R_PPC64_TPREL16_HIGHA :
case elfcpp : : R_PPC64_TPREL16_HIGHER :
case elfcpp : : R_PPC64_TPREL16_HIGHERA :
case elfcpp : : R_PPC64_TPREL16_HIGHEST :
case elfcpp : : R_PPC64_TPREL16_HIGHESTA :
if ( size ! = 64 )
break ;
// Fall through.
case elfcpp : : R_POWERPC_TPREL16_HI :
target - > set_tprel_opt ( false ) ;
break ;
default :
break ;
}
switch ( r_type )
{
case elfcpp : : R_PPC64_D34 :
@ -11124,10 +11212,9 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
break ;
}
if ( size = = 64
& & ( gsym
? relative_value_is_known ( gsym )
: relative_value_is_known ( psymval ) ) )
if ( gsym
? relative_value_is_known ( gsym )
: relative_value_is_known ( psymval ) )
{
Insn * iview ;
Insn * iview2 ;
@ -11152,7 +11239,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
case elfcpp : : R_POWERPC_GOT_DTPREL16_HA :
case elfcpp : : R_POWERPC_GOT16_HA :
case elfcpp : : R_PPC64_TOC16_HA :
if ( parameters - > options ( ) . toc_optimize ( ) )
if ( size = = 64 & & parameters - > options ( ) . toc_optimize ( ) )
{
iview = reinterpret_cast < Insn * > ( view - d_offset ) ;
insn = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
@ -11184,7 +11271,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
case elfcpp : : R_PPC64_GOT16_LO_DS :
case elfcpp : : R_PPC64_TOC16_LO :
case elfcpp : : R_PPC64_TOC16_LO_DS :
if ( parameters - > options ( ) . toc_optimize ( ) )
if ( size = = 64 & & parameters - > options ( ) . toc_optimize ( ) )
{
iview = reinterpret_cast < Insn * > ( view - d_offset ) ;
insn = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
@ -11223,7 +11310,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
break ;
case elfcpp : : R_PPC64_GOT_PCREL34 :
if ( parameters - > options ( ) . toc_optimize ( ) )
if ( size = = 64 & & parameters - > options ( ) . toc_optimize ( ) )
{
iview = reinterpret_cast < Insn * > ( view ) ;
pinsn = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
@ -11249,63 +11336,57 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
break ;
case elfcpp : : R_PPC64_PCREL34 :
{
iview = reinterpret_cast < Insn * > ( view ) ;
pinsn = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
pinsn < < = 32 ;
pinsn | = elfcpp : : Swap < 32 , big_endian > : : readval ( iview + 1 ) ;
if ( ( pinsn & ( ( - 1ULL < < 50 ) | ( 63ULL < < 26 ) ) )
! = ( ( 1ULL < < 58 ) | ( 2ULL < < 56 ) | ( 1ULL < < 52 )
| ( 14ULL < < 26 ) /* paddi */ ) )
break ;
if ( size = = 64 )
{
iview = reinterpret_cast < Insn * > ( view ) ;
pinsn = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
pinsn < < = 32 ;
pinsn | = elfcpp : : Swap < 32 , big_endian > : : readval ( iview + 1 ) ;
if ( ( pinsn & ( ( - 1ULL < < 50 ) | ( 63ULL < < 26 ) ) )
! = ( ( 1ULL < < 58 ) | ( 2ULL < < 56 ) | ( 1ULL < < 52 )
| ( 14ULL < < 26 ) /* paddi */ ) )
break ;
pcrelopt :
const int reloc_size = elfcpp : : Elf_sizes < size > : : rela_size ;
elfcpp : : Shdr < size , big_endian > shdr ( relinfo - > reloc_shdr ) ;
size_t reloc_count = shdr . get_sh_size ( ) / reloc_size ;
if ( relnum > = reloc_count - 1 )
break ;
pcrelopt :
const int reloc_size = elfcpp : : Elf_sizes < size > : : rela_size ;
elfcpp : : Shdr < size , big_endian > shdr ( relinfo - > reloc_shdr ) ;
size_t reloc_count = shdr . get_sh_size ( ) / reloc_size ;
if ( relnum > = reloc_count - 1 )
break ;
Reltype next_rela ( preloc + reloc_size ) ;
if ( ( elfcpp : : elf_r_type < size > ( next_rela . get_r_info ( ) )
! = elfcpp : : R_PPC64_PCREL_OPT )
| | next_rela . get_r_offset ( ) ! = rela . get_r_offset ( ) )
break ;
Reltype next_rela ( preloc + reloc_size ) ;
if ( ( elfcpp : : elf_r_type < size > ( next_rela . get_r_info ( ) )
! = elfcpp : : R_PPC64_PCREL_OPT )
| | next_rela . get_r_offset ( ) ! = rela . get_r_offset ( ) )
break ;
Address off = next_rela . get_r_addend ( ) ;
if ( off = = 0 )
off = 8 ; // zero means next insn.
if ( off + rela . get_r_offset ( ) + 4 > view_size )
break ;
Address off = next_rela . get_r_addend ( ) ;
if ( off = = 0 )
off = 8 ; // zero means next insn.
if ( off + rela . get_r_offset ( ) + 4 > view_size )
break ;
iview2 = reinterpret_cast < Insn * > ( view + off ) ;
pinsn2 = elfcpp : : Swap < 32 , big_endian > : : readval ( iview2 ) ;
pinsn2 < < = 32 ;
if ( ( pinsn2 & ( 63ULL < < 58 ) ) = = 1ULL < < 58 )
break ;
if ( xlate_pcrel_opt ( & pinsn , & pinsn2 ) )
{
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview , pinsn > > 32 ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview + 1 ,
pinsn & 0xffffffff ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview2 , pinsn2 > > 32 ) ;
}
}
iview2 = reinterpret_cast < Insn * > ( view + off ) ;
pinsn2 = elfcpp : : Swap < 32 , big_endian > : : readval ( iview2 ) ;
pinsn2 < < = 32 ;
if ( ( pinsn2 & ( 63ULL < < 58 ) ) = = 1ULL < < 58 )
break ;
if ( xlate_pcrel_opt ( & pinsn , & pinsn2 ) )
{
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview , pinsn > > 32 ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview + 1 ,
pinsn & 0xffffffff ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview2 , pinsn2 > > 32 ) ;
}
}
break ;
case elfcpp : : R_POWERPC_TPREL16_HA :
if ( parameters - > options ( ) . tls_optimize ( ) & & value + 0x8000 < 0x10000 )
if ( target - > tprel_opt ( ) & & value + 0x8000 < 0x10000 )
{
Insn * iview = reinterpret_cast < Insn * > ( view - d_offset ) ;
Insn insn = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
if ( ( insn & ( ( 0x3f < < 26 ) | 0x1f < < 16 ) )
! = ( ( 15u < < 26 ) | ( ( size = = 32 ? 2 : 13 ) < < 16 ) ) )
;
else
{
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview , nop ) ;
return true ;
}
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview , nop ) ;
return true ;
}
break ;
@ -11315,7 +11396,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
break ;
// Fall through.
case elfcpp : : R_POWERPC_TPREL16_LO :
if ( parameters - > options ( ) . tls_optimize ( ) & & value + 0x8000 < 0x10000 )
if ( target - > tprel_opt ( ) & & value + 0x8000 < 0x10000 )
{
Insn * iview = reinterpret_cast < Insn * > ( view - d_offset ) ;
Insn insn = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
@ -11326,29 +11407,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
break ;
case elfcpp : : R_PPC64_ENTRY :
value = ( target - > got_section ( ) - > output_section ( ) - > address ( )
+ object - > toc_base_offset ( ) ) ;
if ( value + 0x80008000 < = 0xffffffff
& & ! parameters - > options ( ) . output_is_position_independent ( ) )
{
Insn * iview = reinterpret_cast < Insn * > ( view ) ;
Insn insn1 = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
Insn insn2 = elfcpp : : Swap < 32 , big_endian > : : readval ( iview + 1 ) ;
if ( ( insn1 & ~ 0xfffc ) = = ld_2_12
& & insn2 = = add_2_2_12 )
{
insn1 = lis_2 + ha ( value ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview , insn1 ) ;
insn2 = addi_2_2 + l ( value ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview + 1 , insn2 ) ;
return true ;
}
}
else
if ( size = = 64 )
{
value - = address ;
if ( value + 0x80008000 < = 0xffffffff )
value = ( target - > got_section ( ) - > output_section ( ) - > address ( )
+ object - > toc_base_offset ( ) ) ;
if ( value + 0x80008000 < = 0xffffffff
& & ! parameters - > options ( ) . output_is_position_independent ( ) )
{
Insn * iview = reinterpret_cast < Insn * > ( view ) ;
Insn insn1 = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
@ -11357,13 +11421,33 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
if ( ( insn1 & ~ 0xfffc ) = = ld_2_12
& & insn2 = = add_2_2_12 )
{
insn1 = addis_2_1 2 + ha ( value ) ;
insn1 = lis_ 2 + ha ( value ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview , insn1 ) ;
insn2 = addi_2_2 + l ( value ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview + 1 , insn2 ) ;
return true ;
}
}
else
{
value - = address ;
if ( value + 0x80008000 < = 0xffffffff )
{
Insn * iview = reinterpret_cast < Insn * > ( view ) ;
Insn insn1 = elfcpp : : Swap < 32 , big_endian > : : readval ( iview ) ;
Insn insn2 = elfcpp : : Swap < 32 , big_endian > : : readval ( iview + 1 ) ;
if ( ( insn1 & ~ 0xfffc ) = = ld_2_12
& & insn2 = = add_2_2_12 )
{
insn1 = addis_2_12 + ha ( value ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview , insn1 ) ;
insn2 = addi_2_2 + l ( value ) ;
elfcpp : : Swap < 32 , big_endian > : : writeval ( iview + 1 , insn2 ) ;
return true ;
}
}
}
}
break ;
@ -11375,7 +11459,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
// lis 2,.TOC.@ha
// addi 2,2,.TOC.@l
// if .TOC. is in range. */
if ( value + address - 4 + 0x80008000 < = 0xffffffff
if ( size = = 64
& & value + address - 4 + 0x80008000 < = 0xffffffff
& & relnum + 1 > 1
& & preloc ! = NULL
& & target - > abiversion ( ) > = 2