@ -51,6 +51,8 @@ static struct bfd_hash_entry *link_hash_newfunc
PARAMS ( ( struct bfd_hash_entry * , struct bfd_hash_table * , const char * ) ) ;
static struct bfd_link_hash_table * ppc64_elf_link_hash_table_create
PARAMS ( ( bfd * ) ) ;
static boolean create_linkage_sections
PARAMS ( ( bfd * , struct bfd_link_info * ) ) ;
static boolean create_got_section
PARAMS ( ( bfd * , struct bfd_link_info * ) ) ;
static boolean ppc64_elf_create_dynamic_sections
@ -153,6 +155,11 @@ static boolean ppc64_elf_finish_dynamic_sections
# define LIS_R0_0 0x3c000000 /* lis %r0,0 */
# define ORI_R0_R0_0 0x60000000 /* ori %r0,%r0,0 */
/* Instructions to save and restore floating point regs. */
# define STFD_FR0_0R1 0xd8010000 /* stfd %fr0,0(%r1) */
# define LFD_FR0_0R1 0xc8010000 /* lfd %fr0,0(%r1) */
# define BLR 0x4e800020 /* blr */
/* Since .opd is an array of descriptors and each entry will end up
with identical R_PPC64_RELATIVE relocs , there is really no need to
propagate . opd relocs ; The dynamic linker should be taught to
@ -1719,6 +1726,7 @@ struct ppc_link_hash_table
asection * srelbss ;
asection * sstub ;
asection * sglink ;
asection * sfpr ;
/* Set on error. */
int plt_overflow ;
@ -1790,12 +1798,49 @@ ppc64_elf_link_hash_table_create (abfd)
htab - > srelbss = NULL ;
htab - > sstub = NULL ;
htab - > sglink = NULL ;
htab - > sfpr = NULL ;
htab - > plt_overflow = 0 ;
htab - > sym_sec . abfd = NULL ;
return & htab - > elf . root ;
}
/* Create sections for linker generated code. */
static boolean
create_linkage_sections ( dynobj , info )
bfd * dynobj ;
struct bfd_link_info * info ;
{
struct ppc_link_hash_table * htab ;
flagword flags ;
htab = ppc_hash_table ( info ) ;
/* Create .sfpr for code to save and restore fp regs. */
flags = ( SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED ) ;
htab - > sfpr = bfd_make_section ( dynobj , " .sfpr " ) ;
if ( htab - > sfpr = = NULL
| | ! bfd_set_section_flags ( dynobj , htab - > sfpr , flags )
| | ! bfd_set_section_alignment ( dynobj , htab - > sfpr , 2 ) )
return false ;
/* Create .stub and .glink for global linkage functions. */
htab - > sstub = bfd_make_section ( dynobj , " .stub " ) ;
if ( htab - > sstub = = NULL
| | ! bfd_set_section_flags ( dynobj , htab - > sstub , flags )
| | ! bfd_set_section_alignment ( dynobj , htab - > sstub , 2 ) )
return false ;
htab - > sglink = bfd_make_section ( dynobj , " .glink " ) ;
if ( htab - > sglink = = NULL
| | ! bfd_set_section_flags ( dynobj , htab - > sglink , flags )
| | ! bfd_set_section_alignment ( dynobj , htab - > sglink , 2 ) )
return false ;
return true ;
}
/* Create .got and .rela.got sections in DYNOBJ, and set up
shortcuts to them in our hash table . */
@ -1825,8 +1870,7 @@ create_got_section (dynobj, info)
return true ;
}
/* Create the .stub and .glink sections as well as the ordinary
dynamic sections . */
/* Create the dynamic sections, and set up shortcuts. */
static boolean
ppc64_elf_create_dynamic_sections ( dynobj , info )
@ -1834,7 +1878,6 @@ ppc64_elf_create_dynamic_sections (dynobj, info)
struct bfd_link_info * info ;
{
struct ppc_link_hash_table * htab ;
flagword flags ;
htab = ppc_hash_table ( info ) ;
if ( ! htab - > sgot & & ! create_got_section ( dynobj , info ) )
@ -1853,20 +1896,6 @@ ppc64_elf_create_dynamic_sections (dynobj, info)
| | ( ! info - > shared & & ! htab - > srelbss ) )
abort ( ) ;
/* Create .stub and .glink for global linkage functions. */
flags = ( SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED ) ;
htab - > sstub = bfd_make_section ( dynobj , " .stub " ) ;
if ( htab - > sstub = = NULL
| | ! bfd_set_section_flags ( dynobj , htab - > sstub , flags )
| | ! bfd_set_section_alignment ( dynobj , htab - > sstub , 2 ) )
return false ;
htab - > sglink = bfd_make_section ( dynobj , " .glink " ) ;
if ( htab - > sglink = = NULL
| | ! bfd_set_section_flags ( dynobj , htab - > sglink , flags )
| | ! bfd_set_section_alignment ( dynobj , htab - > sglink , 3 ) )
return false ;
return true ;
}
@ -1955,6 +1984,12 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
sreloc = NULL ;
is_opd = strcmp ( bfd_get_section_name ( abfd , sec ) , " .opd " ) = = 0 ;
if ( htab - > elf . dynobj = = NULL )
htab - > elf . dynobj = abfd ;
if ( htab - > sfpr = = NULL
& & ! create_linkage_sections ( htab - > elf . dynobj , info ) )
return false ;
rel_end = relocs + sec - > reloc_count ;
for ( rel = relocs ; rel < rel_end ; rel + + )
{
@ -1980,13 +2015,9 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
case R_PPC64_GOT16_LO_DS :
/* This symbol requires a global offset table entry. */
if ( htab - > sgot = = NULL )
{
if ( htab - > elf . dynobj = = NULL )
htab - > elf . dynobj = abfd ;
if ( ! create_got_section ( htab - > elf . dynobj , info ) )
return false ;
}
if ( htab - > sgot = = NULL
& & ! create_got_section ( htab - > elf . dynobj , info ) )
return false ;
if ( h ! = NULL )
{
@ -2197,9 +2228,6 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
bfd_set_error ( bfd_error_bad_value ) ;
}
if ( htab - > elf . dynobj = = NULL )
htab - > elf . dynobj = abfd ;
dynobj = htab - > elf . dynobj ;
sreloc = bfd_get_section_by_name ( dynobj , name ) ;
if ( sreloc = = NULL )
@ -2554,25 +2582,117 @@ func_desc_adjust (h, inf)
been imported from another library . Function code syms that
are really in the library we must leave global to prevent the
linker dragging in a definition from a static library . */
force_local = ( h - > elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR ) = = 0 ;
force_local = ( ( h - > elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR ) = = 0
& & info - > shared ) ;
_bfd_elf_link_hash_hide_symbol ( info , h , force_local ) ;
}
return true ;
}
# define MIN_SAVE_FPR 14
# define MAX_SAVE_FPR 31
/* Called near the start of bfd_elf_size_dynamic_sections. We use
this hook to transfer dynamic linking information gathered so far
on function code symbol entries , to their corresponding function
descriptor symbol entries . */
this hook to a ) provide some gcc support functions , and b ) transfe r
dynamic linking information gathered so far on function code symbol
entries , to their corresponding function descriptor symbol entries . */
static boolean
ppc64_elf_func_desc_adjust ( obfd , info )
bfd * obfd ATTRIBUTE_UNUSED ;
struct bfd_link_info * info ;
{
struct ppc_link_hash_table * htab ;
unsigned int lowest_savef = MAX_SAVE_FPR + 2 ;
unsigned int lowest_restf = MAX_SAVE_FPR + 2 ;
unsigned int i ;
struct elf_link_hash_entry * h ;
char sym [ 10 ] ;
htab = ppc_hash_table ( info ) ;
if ( htab - > sfpr = = NULL )
/* We don't have any relocs. */
return true ;
/* First provide any missing ._savef* and ._restf* functions. */
memcpy ( sym , " ._savef14 " , 10 ) ;
for ( i = MIN_SAVE_FPR ; i < = MAX_SAVE_FPR ; i + + )
{
sym [ 7 ] = i / 10 + ' 0 ' ;
sym [ 8 ] = i % 10 + ' 0 ' ;
h = elf_link_hash_lookup ( & htab - > elf , sym , false , false , true ) ;
if ( h ! = NULL
& & h - > root . type = = bfd_link_hash_undefined )
{
if ( lowest_savef > i )
lowest_savef = i ;
h - > root . type = bfd_link_hash_defined ;
h - > root . u . def . section = htab - > sfpr ;
h - > root . u . def . value = ( i - lowest_savef ) * 4 ;
h - > type = STT_FUNC ;
h - > elf_link_hash_flags | = ELF_LINK_HASH_DEF_REGULAR ;
_bfd_elf_link_hash_hide_symbol ( info , h , info - > shared ) ;
}
}
memcpy ( sym , " ._restf14 " , 10 ) ;
for ( i = MIN_SAVE_FPR ; i < = MAX_SAVE_FPR ; i + + )
{
sym [ 7 ] = i / 10 + ' 0 ' ;
sym [ 8 ] = i % 10 + ' 0 ' ;
h = elf_link_hash_lookup ( & htab - > elf , sym , false , false , true ) ;
if ( h ! = NULL
& & h - > root . type = = bfd_link_hash_undefined )
{
if ( lowest_restf > i )
lowest_restf = i ;
h - > root . type = bfd_link_hash_defined ;
h - > root . u . def . section = htab - > sfpr ;
h - > root . u . def . value = ( ( MAX_SAVE_FPR + 2 - lowest_savef ) * 4
+ ( i - lowest_restf ) * 4 ) ;
h - > type = STT_FUNC ;
h - > elf_link_hash_flags | = ELF_LINK_HASH_DEF_REGULAR ;
_bfd_elf_link_hash_hide_symbol ( info , h , info - > shared ) ;
}
}
htab - > sfpr - > _raw_size = ( ( MAX_SAVE_FPR + 2 - lowest_savef ) * 4
+ ( MAX_SAVE_FPR + 2 - lowest_restf ) * 4 ) ;
if ( htab - > sfpr - > _raw_size = = 0 )
{
_bfd_strip_section_from_output ( info , htab - > sfpr ) ;
}
else
{
bfd_byte * p = ( bfd_byte * ) bfd_alloc ( htab - > elf . dynobj ,
htab - > sfpr - > _raw_size ) ;
if ( p = = NULL )
return false ;
htab - > sfpr - > contents = p ;
for ( i = lowest_savef ; i < = MAX_SAVE_FPR ; i + + )
{
unsigned int fpr = i < < 21 ;
unsigned int stackoff = ( 1 < < 16 ) - ( MAX_SAVE_FPR + 1 - i ) * 8 ;
bfd_put_32 ( htab - > elf . dynobj , STFD_FR0_0R1 + fpr + stackoff , p ) ;
p + = 4 ;
}
bfd_put_32 ( htab - > elf . dynobj , BLR , p ) ;
p + = 4 ;
for ( i = lowest_restf ; i < = MAX_SAVE_FPR ; i + + )
{
unsigned int fpr = i < < 21 ;
unsigned int stackoff = ( 1 < < 16 ) - ( MAX_SAVE_FPR + 1 - i ) * 8 ;
bfd_put_32 ( htab - > elf . dynobj , LFD_FR0_0R1 + fpr + stackoff , p ) ;
p + = 4 ;
}
bfd_put_32 ( htab - > elf . dynobj , BLR , p ) ;
p + = 4 ;
}
elf_link_hash_traverse ( & htab - > elf , func_desc_adjust , ( PTR ) info ) ;
return true ;
}