diff options
author | Alan Modra <amodra@gmail.com> | 2002-02-18 12:40:28 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2002-02-18 12:40:28 +0000 |
commit | 82bd7b59c94c3fbb5ee9186e7c08b350ea073375 (patch) | |
tree | fd3983450f22f7a64cc4b633df0bfd1e026ebd5f /bfd | |
parent | ef1355e8a09a27ef162dad8852e6e65f8890f29f (diff) | |
download | gdb-82bd7b59c94c3fbb5ee9186e7c08b350ea073375.zip gdb-82bd7b59c94c3fbb5ee9186e7c08b350ea073375.tar.gz gdb-82bd7b59c94c3fbb5ee9186e7c08b350ea073375.tar.bz2 |
* 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.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 15 | ||||
-rw-r--r-- | bfd/elf64-ppc.c | 182 |
2 files changed, 166 insertions, 31 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 8dfccdd..ff86ca3 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -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> * configure.in: Bump version number post 2.12 branching. diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index cca9b7f..08232a3 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -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) transfer + 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; } |