* elf64-ppc.c (STFD_FR0_0R1, LFD_FR0_0R1, BLR): Define.

(struct ppc_link_hash_table): Add sfpr.
	(ppc64_elf_link_hash_table_create): Init it.
	(ppc64_elf_create_dynamic_sections): Split creation of .stub and
	.glink out to..
	(create_linkage_sections): ..here.  Make .sfpr too.
	(ppc64_elf_check_relocs): Call create_linkage_sections, and set
	dynobj early.
	(MIN_SAVE_FPR, MAX_SAVE_FPR): Define.
	(ppc64_elf_func_desc_adjust): Look for missing ._savef* and
	._restf* functions, and create as needed.
	(func_desc_adjust): Only force_local for shared libs.

	* emulparams/elf64ppc.sh (OTHER_TEXT_SECTIONS): Define.
This commit is contained in:
Alan Modra
2002-02-18 12:40:28 +00:00
parent ef1355e8a0
commit 82bd7b59c9
4 changed files with 171 additions and 31 deletions

View File

@ -1,3 +1,18 @@
2002-02-18 Alan Modra <amodra@bigpond.net.au>
* elf64-ppc.c (STFD_FR0_0R1, LFD_FR0_0R1, BLR): Define.
(struct ppc_link_hash_table): Add sfpr.
(ppc64_elf_link_hash_table_create): Init it.
(ppc64_elf_create_dynamic_sections): Split creation of .stub and
.glink out to..
(create_linkage_sections): ..here. Make .sfpr too.
(ppc64_elf_check_relocs): Call create_linkage_sections, and set
dynobj early.
(MIN_SAVE_FPR, MAX_SAVE_FPR): Define.
(ppc64_elf_func_desc_adjust): Look for missing ._savef* and
._restf* functions, and create as needed.
(func_desc_adjust): Only force_local for shared libs.
2002-02-18 David O'Brien <obrien@FreeBSD.org> 2002-02-18 David O'Brien <obrien@FreeBSD.org>
* configure.in: Bump version number post 2.12 branching. * configure.in: Bump version number post 2.12 branching.

View File

@ -51,6 +51,8 @@ static struct bfd_hash_entry *link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static struct bfd_link_hash_table *ppc64_elf_link_hash_table_create static struct bfd_link_hash_table *ppc64_elf_link_hash_table_create
PARAMS ((bfd *)); PARAMS ((bfd *));
static boolean create_linkage_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean create_got_section static boolean create_got_section
PARAMS ((bfd *, struct bfd_link_info *)); PARAMS ((bfd *, struct bfd_link_info *));
static boolean ppc64_elf_create_dynamic_sections 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 LIS_R0_0 0x3c000000 /* lis %r0,0 */
#define ORI_R0_R0_0 0x60000000 /* ori %r0,%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 /* 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 with identical R_PPC64_RELATIVE relocs, there is really no need to
propagate .opd relocs; The dynamic linker should be taught to propagate .opd relocs; The dynamic linker should be taught to
@ -1719,6 +1726,7 @@ struct ppc_link_hash_table
asection *srelbss; asection *srelbss;
asection *sstub; asection *sstub;
asection *sglink; asection *sglink;
asection *sfpr;
/* Set on error. */ /* Set on error. */
int plt_overflow; int plt_overflow;
@ -1790,12 +1798,49 @@ ppc64_elf_link_hash_table_create (abfd)
htab->srelbss = NULL; htab->srelbss = NULL;
htab->sstub = NULL; htab->sstub = NULL;
htab->sglink = NULL; htab->sglink = NULL;
htab->sfpr = NULL;
htab->plt_overflow = 0; htab->plt_overflow = 0;
htab->sym_sec.abfd = NULL; htab->sym_sec.abfd = NULL;
return &htab->elf.root; 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 /* Create .got and .rela.got sections in DYNOBJ, and set up
shortcuts to them in our hash table. */ shortcuts to them in our hash table. */
@ -1825,8 +1870,7 @@ create_got_section (dynobj, info)
return true; return true;
} }
/* Create the .stub and .glink sections as well as the ordinary /* Create the dynamic sections, and set up shortcuts. */
dynamic sections. */
static boolean static boolean
ppc64_elf_create_dynamic_sections (dynobj, info) ppc64_elf_create_dynamic_sections (dynobj, info)
@ -1834,7 +1878,6 @@ ppc64_elf_create_dynamic_sections (dynobj, info)
struct bfd_link_info *info; struct bfd_link_info *info;
{ {
struct ppc_link_hash_table *htab; struct ppc_link_hash_table *htab;
flagword flags;
htab = ppc_hash_table (info); htab = ppc_hash_table (info);
if (!htab->sgot && !create_got_section (dynobj, info)) if (!htab->sgot && !create_got_section (dynobj, info))
@ -1853,20 +1896,6 @@ ppc64_elf_create_dynamic_sections (dynobj, info)
|| (!info->shared && !htab->srelbss)) || (!info->shared && !htab->srelbss))
abort (); 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; return true;
} }
@ -1955,6 +1984,12 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
sreloc = NULL; sreloc = NULL;
is_opd = strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0; 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; rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++) 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: case R_PPC64_GOT16_LO_DS:
/* This symbol requires a global offset table entry. */ /* This symbol requires a global offset table entry. */
if (htab->sgot == NULL) if (htab->sgot == NULL
{ && !create_got_section (htab->elf.dynobj, info))
if (htab->elf.dynobj == NULL) return false;
htab->elf.dynobj = abfd;
if (!create_got_section (htab->elf.dynobj, info))
return false;
}
if (h != NULL) if (h != NULL)
{ {
@ -2197,9 +2228,6 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
bfd_set_error (bfd_error_bad_value); bfd_set_error (bfd_error_bad_value);
} }
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
dynobj = htab->elf.dynobj; dynobj = htab->elf.dynobj;
sreloc = bfd_get_section_by_name (dynobj, name); sreloc = bfd_get_section_by_name (dynobj, name);
if (sreloc == NULL) if (sreloc == NULL)
@ -2554,25 +2582,117 @@ func_desc_adjust (h, inf)
been imported from another library. Function code syms that been imported from another library. Function code syms that
are really in the library we must leave global to prevent the are really in the library we must leave global to prevent the
linker dragging in a definition from a static library. */ 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); _bfd_elf_link_hash_hide_symbol (info, h, force_local);
} }
return true; return true;
} }
#define MIN_SAVE_FPR 14
#define MAX_SAVE_FPR 31
/* Called near the start of bfd_elf_size_dynamic_sections. We use /* Called near the start of bfd_elf_size_dynamic_sections. We use
this hook to transfer dynamic linking information gathered so far this hook to a) provide some gcc support functions, and b) transfer
on function code symbol entries, to their corresponding function dynamic linking information gathered so far on function code symbol
descriptor symbol entries. */ entries, to their corresponding function descriptor symbol entries. */
static boolean static boolean
ppc64_elf_func_desc_adjust (obfd, info) ppc64_elf_func_desc_adjust (obfd, info)
bfd *obfd ATTRIBUTE_UNUSED; bfd *obfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info; struct bfd_link_info *info;
{ {
struct ppc_link_hash_table *htab; 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); 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); elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
return true; return true;
} }

View File

@ -1,3 +1,7 @@
2002-02-18 Alan Modra <amodra@bigpond.net.au>
* emulparams/elf64ppc.sh (OTHER_TEXT_SECTIONS): Define.
2002-02-18 David O'Brien <obrien@FreeBSD.org> 2002-02-18 David O'Brien <obrien@FreeBSD.org>
* Makefile.in: Add new files earmelf_fbsd, eelf32ppc_fbsd, * Makefile.in: Add new files earmelf_fbsd, eelf32ppc_fbsd,

View File

@ -15,6 +15,7 @@ CTOR_START='PROVIDE (__CTOR_LIST__ = .); PROVIDE (___CTOR_LIST__ = .);'
CTOR_END='PROVIDE (__CTOR_END__ = .); PROVIDE (___CTOR_END__ = .);' CTOR_END='PROVIDE (__CTOR_END__ = .); PROVIDE (___CTOR_END__ = .);'
DTOR_START='PROVIDE (__DTOR_LIST__ = .); PROVIDE (___DTOR_LIST__ = .);' DTOR_START='PROVIDE (__DTOR_LIST__ = .); PROVIDE (___DTOR_LIST__ = .);'
DTOR_END='PROVIDE (__DTOR_END__ = .); PROVIDE (___DTOR_END__ = .);' DTOR_END='PROVIDE (__DTOR_END__ = .); PROVIDE (___DTOR_END__ = .);'
OTHER_TEXT_SECTIONS="*(.sfpr .glink)"
BSS_PLT= BSS_PLT=
OTHER_BSS_SYMBOLS=" OTHER_BSS_SYMBOLS="
.tocbss ${RELOCATING-0}${RELOCATING+ALIGN(8)} : { *(.tocbss)}" .tocbss ${RELOCATING-0}${RELOCATING+ALIGN(8)} : { *(.tocbss)}"