From 587ff49e9a50b61e86ea78ba3271f3ca24c1b0e8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 30 Jul 1999 21:34:44 +0000 Subject: [PATCH] Jakub Jelinek * elf-bfd.h (struct elf_backend_data): Add print_symbol_all and output_arch_syms backend methods. * elfxx-target.h: Likewise. * elf64-sparc.c (sparc64_elf_bfd_link_hash_table_create, sparc64_elf_add_symbol_hook, sparc64_elf_output_arch_syms, sparc64_elf_get_symbol_type, sparc64_elf_symbol_processing): New functions. (sparc64_elf_size_dynamic_sections): Leave space for STT_REGISTER symbols in .dynsym, add their names into .dynstr. Put those symbols into dynlocal. (sparc64_elf_finish_dynamic_sections): Fix up DT_SPARC_REGISTER pointers to STT_REGISTER symbols in dynsym section. (sparc64_elf_print_symbol_all): New function. * elf.c (bfd_elf_print_symbol): Allow special backend symbol printing using the print_symbol_all hook. --- bfd/ChangeLog | 18 +++ bfd/elf-bfd.h | 15 ++ bfd/elf.c | 17 ++- bfd/elf64-sparc.c | 374 +++++++++++++++++++++++++++++++++++++++++++++ bfd/elflink.h | 44 ++++-- bfd/elfxx-target.h | 8 + 6 files changed, 463 insertions(+), 13 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5ca7ca4020..a6ce27659d 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,21 @@ +1999-07-30 Jakub Jelinek + + * elf-bfd.h (struct elf_backend_data): Add + print_symbol_all and output_arch_syms backend methods. + * elfxx-target.h: Likewise. + * elf64-sparc.c (sparc64_elf_bfd_link_hash_table_create, + sparc64_elf_add_symbol_hook, sparc64_elf_output_arch_syms, + sparc64_elf_get_symbol_type, sparc64_elf_symbol_processing): New + functions. + (sparc64_elf_size_dynamic_sections): Leave space for STT_REGISTER + symbols in .dynsym, add their names into .dynstr. Put those symbols + into dynlocal. + (sparc64_elf_finish_dynamic_sections): Fix up DT_SPARC_REGISTER + pointers to STT_REGISTER symbols in dynsym section. + (sparc64_elf_print_symbol_all): New function. + * elf.c (bfd_elf_print_symbol): Allow special backend symbol + printing using the print_symbol_all hook. + 1999-07-30 Catherine Moore * elf32-arm.h (elf32_arm_check_relocs): Use r_offset for diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 577823b825..3fa25136fd 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -581,6 +581,21 @@ struct elf_backend_data void (*elf_backend_post_process_headers) PARAMS ((bfd *, struct bfd_link_info *)); + /* This function, if defined, prints a symbol to file and returns the + name of the symbol to be printed. It should return NULL to fall + back to default symbol printing. */ + const char *(*elf_backend_print_symbol_all) + PARAMS ((bfd *, PTR, asymbol *)); + + /* This function, if defined, is called after all local symbols and + global symbols converted to locals are emited into the symtab + section. It allows the backend to emit special global symbols + not handled in the hash table. */ + boolean (*elf_backend_output_arch_syms) + PARAMS ((bfd *, struct bfd_link_info *, PTR, + boolean (*) PARAMS ((PTR, const char *, + Elf_Internal_Sym *, asection *)))); + /* The swapping table to use when dealing with ECOFF information. Used for the MIPS ELF .mdebug section. */ const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap; diff --git a/bfd/elf.c b/bfd/elf.c index 9291b9887f..997408ce16 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -758,8 +758,21 @@ bfd_elf_print_symbol (abfd, filep, symbol, how) case bfd_print_symbol_all: { CONST char *section_name; + CONST char *name = NULL; + struct elf_backend_data *bed; + section_name = symbol->section ? symbol->section->name : "(*none*)"; - bfd_print_symbol_vandf ((PTR) file, symbol); + + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_print_symbol_all) + name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol); + + if (name == NULL) + { + name = symbol->name; + bfd_print_symbol_vandf ((PTR) file, symbol); + } + fprintf (file, " %s\t", section_name); /* Print the "other" value for a symbol. For common symbols, we've already printed the size; now print the alignment. @@ -827,7 +840,7 @@ bfd_elf_print_symbol (abfd, filep, symbol, how) ((unsigned int) ((elf_symbol_type *) symbol)->internal_elf_sym.st_other)); - fprintf (file, " %s", symbol->name); + fprintf (file, " %s", name); } break; } diff --git a/bfd/elf64-sparc.c b/bfd/elf64-sparc.c index 255713e3d7..107f371402 100644 --- a/bfd/elf64-sparc.c +++ b/bfd/elf64-sparc.c @@ -32,6 +32,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ #define MINUS_ONE (~ (bfd_vma) 0) +static struct bfd_link_hash_table * sparc64_elf_bfd_link_hash_table_create + PARAMS((bfd *)); static reloc_howto_type *sparc64_elf_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type)); static void sparc64_elf_info_to_howto @@ -51,6 +53,13 @@ static boolean sparc64_elf_adjust_dynamic_symbol PARAMS((struct bfd_link_info *, struct elf_link_hash_entry *)); static boolean sparc64_elf_size_dynamic_sections PARAMS((bfd *, struct bfd_link_info *)); +static int sparc64_elf_get_symbol_type + PARAMS (( Elf_Internal_Sym *, int)); +static boolean sparc64_elf_add_symbol_hook + PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, + const char **, flagword *, asection **, bfd_vma *)); +static void sparc64_elf_symbol_processing + PARAMS ((bfd *, asymbol *)); static boolean sparc64_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *)); @@ -595,6 +604,52 @@ sparc64_elf_write_relocs (abfd, sec, data) bfd_elf64_swap_reloca_out (abfd, &dst_rela, src_rela); } } + +/* Sparc64 ELF linker hash table. */ + +struct sparc64_elf_app_reg +{ + unsigned char bind; + unsigned short shndx; + bfd *abfd; + char *name; +}; + +struct sparc64_elf_link_hash_table +{ + struct elf_link_hash_table root; + + struct sparc64_elf_app_reg app_regs [4]; +}; + +/* Get the Sparc64 ELF linker hash table from a link_info structure. */ + +#define sparc64_elf_hash_table(p) \ + ((struct sparc64_elf_link_hash_table *) ((p)->hash)) + +/* Create a Sparc64 ELF linker hash table. */ + +static struct bfd_link_hash_table * +sparc64_elf_bfd_link_hash_table_create (abfd) + bfd *abfd; +{ + struct sparc64_elf_link_hash_table *ret; + + ret = ((struct sparc64_elf_link_hash_table *) + bfd_zalloc (abfd, sizeof (struct sparc64_elf_link_hash_table))); + if (ret == (struct sparc64_elf_link_hash_table *) NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (&ret->root, abfd, + _bfd_elf_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return NULL; + } + + return &ret->root.root; +} + /* Utility for performing the standard initial work of an instruction relocation. @@ -1196,6 +1251,221 @@ sparc64_elf_check_relocs (abfd, info, sec, relocs) return true; } +/* Hook called by the linker routine which adds symbols from an object + file. We use it for STT_REGISTER symbols. */ + +static boolean +sparc64_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) + bfd *abfd; + struct bfd_link_info *info; + const Elf_Internal_Sym *sym; + const char **namep; + flagword *flagsp; + asection **secp; + bfd_vma *valp; +{ + static char *stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" }; + + if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER) + { + int reg; + struct sparc64_elf_app_reg *p; + + reg = (int)sym->st_value; + switch (reg & ~1) + { + case 2: reg -= 2; break; + case 6: reg -= 4; break; + default: + (*_bfd_error_handler) + (_("%s: Only registers %%g[2367] can be declared using STT_REGISTER"), + bfd_get_filename (abfd)); + return false; + } + + if (info->hash->creator != abfd->xvec + || (abfd->flags & DYNAMIC) != 0) + { + /* STT_REGISTER only works when linking an elf64_sparc object. + If STT_REGISTER comes from a dynamic object, don't put it into + the output bfd. The dynamic linker will recheck it. */ + *namep = NULL; + return true; + } + + p = sparc64_elf_hash_table(info)->app_regs + reg; + + if (p->name != NULL && strcmp (p->name, *namep)) + { + (*_bfd_error_handler) + (_("Register %%g%d used incompatibly: " + "previously declared in %s to %s, in %s redefined to %s"), + (int)sym->st_value, + bfd_get_filename (p->abfd), *p->name ? p->name : "#scratch", + bfd_get_filename (abfd), **namep ? *namep : "#scratch"); + return false; + } + + if (p->name == NULL) + { + if (**namep) + { + struct elf_link_hash_entry *h; + + h = (struct elf_link_hash_entry *) + bfd_link_hash_lookup (info->hash, *namep, false, false, false); + + if (h != NULL) + { + unsigned char type = h->type; + + if (type > STT_FUNC) type = 0; + (*_bfd_error_handler) + (_("Symbol `%s' has differing types: " + "previously %s, REGISTER in %s"), + *namep, stt_types [type], bfd_get_filename (abfd)); + return false; + } + + p->name = bfd_hash_allocate (&info->hash->table, + strlen (*namep) + 1); + if (!p->name) + return false; + + strcpy (p->name, *namep); + } + else + p->name = ""; + p->bind = ELF_ST_BIND (sym->st_info); + p->abfd = abfd; + p->shndx = sym->st_shndx; + } + else + { + if (p->bind == STB_WEAK + && ELF_ST_BIND (sym->st_info) == STB_GLOBAL) + { + p->bind = STB_GLOBAL; + p->abfd = abfd; + } + } + *namep = NULL; + return true; + } + else if (! *namep || ! **namep) + return true; + else + { + int i; + struct sparc64_elf_app_reg *p; + + p = sparc64_elf_hash_table(info)->app_regs; + for (i = 0; i < 4; i++, p++) + if (p->name != NULL && ! strcmp (p->name, *namep)) + { + unsigned char type = ELF_ST_TYPE (sym->st_info); + + if (type > STT_FUNC) type = 0; + (*_bfd_error_handler) + (_("Symbol `%s' has differing types: " + "REGISTER in %s, %s in %s"), + *namep, bfd_get_filename (p->abfd), stt_types [type], + bfd_get_filename (abfd)); + return false; + } + } + return true; +} + +/* This function takes care of emiting STT_REGISTER symbols + which we cannot easily keep in the symbol hash table. */ + +static boolean +sparc64_elf_output_arch_syms (output_bfd, info, finfo, func) + bfd *output_bfd; + struct bfd_link_info *info; + PTR finfo; + boolean (*func) PARAMS ((PTR, const char *, + Elf_Internal_Sym *, asection *)); +{ + int reg; + struct sparc64_elf_app_reg *app_regs = + sparc64_elf_hash_table(info)->app_regs; + Elf_Internal_Sym sym; + + /* We arranged in size_dynamic_sections to put the STT_REGISTER entries + at the end of the dynlocal list, so they came at the end of the local + symbols in the symtab. Except that they aren't STB_LOCAL, so we need + to back up symtab->sh_info. */ + if (elf_hash_table (info)->dynlocal) + { + struct elf_link_local_dynamic_entry *e; + + for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) + if (e->input_indx == -1) + break; + if (e) + { + elf_section_data (dynsymsec->output_section)->this_hdr.sh_info + = e->dynindx; + } + } + + if (info->strip == strip_all) + return true; + + for (reg = 0; reg < 4; reg++) + if (app_regs [reg].name != NULL) + { + if (info->strip == strip_some + && bfd_hash_lookup (info->keep_hash, + app_regs [reg].name, + false, false) == NULL) + continue; + + sym.st_value = reg < 2 ? reg + 2 : reg + 4; + sym.st_size = 0; + sym.st_other = 0; + sym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER); + sym.st_shndx = app_regs [reg].shndx; + if (! (*func) (finfo, app_regs [reg].name, &sym, + sym.st_shndx == SHN_ABS + ? bfd_abs_section_ptr : bfd_und_section_ptr)) + return false; + } + + return true; +} + +static int +sparc64_elf_get_symbol_type (elf_sym, type) + Elf_Internal_Sym * elf_sym; + int type; +{ + if (ELF_ST_TYPE (elf_sym->st_info) == STT_REGISTER) + return STT_REGISTER; + else + return type; +} + +/* A STB_GLOBAL,STT_REGISTER symbol should be BSF_GLOBAL + even in SHN_UNDEF section. */ + +static void +sparc64_elf_symbol_processing (abfd, asym) + bfd *abfd; + asymbol *asym; +{ + elf_symbol_type *elfsym; + + elfsym = (elf_symbol_type *) asym; + if (elfsym->internal_elf_sym.st_info + == ELF_ST_INFO (STB_GLOBAL, STT_REGISTER)) + { + asym->flags |= BSF_GLOBAL; + } +} + /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -1495,6 +1765,11 @@ sparc64_elf_size_dynamic_sections (output_bfd, info) must add the entries now so that we get the correct size for the .dynamic section. The DT_DEBUG entry is filled in by the dynamic linker and used by the debugger. */ + int reg; + struct sparc64_elf_app_reg * app_regs; + struct bfd_strtab_hash *dynstr; + struct elf_link_hash_table *eht = elf_hash_table (info); + if (! info->shared) { if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0)) @@ -1521,6 +1796,53 @@ sparc64_elf_size_dynamic_sections (output_bfd, info) if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0)) return false; } + + /* Add dynamic STT_REGISTER symbols and corresponding DT_SPARC_REGISTER + entries if needed. */ + app_regs = sparc64_elf_hash_table (info)->app_regs; + dynstr = eht->dynstr; + + for (reg = 0; reg < 4; reg++) + if (app_regs [reg].name != NULL) + { + struct elf_link_local_dynamic_entry *entry, *e; + + if (! bfd_elf64_add_dynamic_entry (info, DT_SPARC_REGISTER, 0)) + return false; + + entry = (struct elf_link_local_dynamic_entry *) + bfd_hash_allocate (&info->hash->table, sizeof (*entry)); + if (entry == NULL) + return false; + + /* We cheat here a little bit: the symbol will not be local, so we + put it at the end of the dynlocal linked list. We will fix it + later on, as we have to fix other fields anyway. */ + entry->isym.st_value = reg < 2 ? reg + 2 : reg + 4; + entry->isym.st_size = 0; + if (*app_regs [reg].name != '\0') + entry->isym.st_name + = _bfd_stringtab_add (dynstr, app_regs[reg].name, true, false); + else + entry->isym.st_name = 0; + entry->isym.st_other = 0; + entry->isym.st_info = ELF_ST_INFO (app_regs [reg].bind, + STT_REGISTER); + entry->isym.st_shndx = app_regs [reg].shndx; + entry->next = NULL; + entry->input_bfd = output_bfd; + entry->input_indx = -1; + + if (eht->dynlocal == NULL) + eht->dynlocal = entry; + else + { + for (e = eht->dynlocal; e->next; e = e->next) + ; + e->next = entry; + } + eht->dynsymcount++; + } } return true; @@ -2346,6 +2668,7 @@ sparc64_elf_finish_dynamic_sections (output_bfd, info) struct bfd_link_info *info; { bfd *dynobj; + int stt_regidx = -1; asection *sdyn; asection *sgot; @@ -2376,6 +2699,17 @@ sparc64_elf_finish_dynamic_sections (output_bfd, info) case DT_PLTGOT: name = ".plt"; size = false; break; case DT_PLTRELSZ: name = ".rela.plt"; size = true; break; case DT_JMPREL: name = ".rela.plt"; size = false; break; + case DT_SPARC_REGISTER: + if (stt_regidx == -1) + { + stt_regidx = + _bfd_elf_link_lookup_local_dynindx (info, output_bfd, -1); + if (stt_regidx == -1) + return false; + } + dyn.d_un.d_val = stt_regidx++; + bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); + /* fallthrough */ default: name = NULL; size = false; break; } @@ -2505,7 +2839,34 @@ sparc64_elf_merge_private_bfd_data (ibfd, obfd) } return true; } + +/* Print a STT_REGISTER symbol to file FILE. */ +static const char * +sparc64_elf_print_symbol_all (abfd, filep, symbol) + bfd *abfd; + PTR filep; + asymbol *symbol; +{ + FILE *file = (FILE *) filep; + int reg, type; + + if (ELF_ST_TYPE (((elf_symbol_type *) symbol)->internal_elf_sym.st_info) + != STT_REGISTER) + return NULL; + + reg = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value; + type = symbol->flags; + fprintf (file, "REG_%c%c%11s%c%c R", "GOLI" [reg / 8], '0' + (reg & 7), "", + ((type & BSF_LOCAL) + ? (type & BSF_GLOBAL) ? '!' : 'l' + : (type & BSF_GLOBAL) ? 'g' : ' '), + (type & BSF_WEAK) ? 'w' : ' '); + if (symbol->name == NULL || symbol->name [0] == '\0') + return "#scratch"; + else + return symbol->name; +} /* Set the right machine number for a SPARC64 ELF file. */ @@ -2570,6 +2931,9 @@ const struct elf_size_info sparc64_elf_size_info = /* This is the value that we used before the ABI was released. */ #define ELF_MACHINE_ALT1 EM_OLD_SPARCV9 +#define bfd_elf64_bfd_link_hash_table_create \ + sparc64_elf_bfd_link_hash_table_create + #define elf_info_to_howto \ sparc64_elf_info_to_howto #define bfd_elf64_get_reloc_upper_bound \ @@ -2583,6 +2947,12 @@ const struct elf_size_info sparc64_elf_size_info = #define elf_backend_create_dynamic_sections \ _bfd_elf_create_dynamic_sections +#define elf_backend_add_symbol_hook \ + sparc64_elf_add_symbol_hook +#define elf_backend_get_symbol_type \ + sparc64_elf_get_symbol_type +#define elf_backend_symbol_processing \ + sparc64_elf_symbol_processing #define elf_backend_check_relocs \ sparc64_elf_check_relocs #define elf_backend_adjust_dynamic_symbol \ @@ -2595,6 +2965,10 @@ const struct elf_size_info sparc64_elf_size_info = sparc64_elf_finish_dynamic_symbol #define elf_backend_finish_dynamic_sections \ sparc64_elf_finish_dynamic_sections +#define elf_backend_print_symbol_all \ + sparc64_elf_print_symbol_all +#define elf_backend_output_arch_syms \ + sparc64_elf_output_arch_syms #define bfd_elf64_bfd_merge_private_bfd_data \ sparc64_elf_merge_private_bfd_data diff --git a/bfd/elflink.h b/bfd/elflink.h index 6fb9bbae8a..cfb4909882 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -2116,6 +2116,10 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx) entry->input_indx = input_indx; eht->dynsymcount++; + /* Whatever binding the symbol had before, it's now local. */ + entry->isym.st_info + = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info)); + /* The dynindx will be set at the end of size_dynamic_sections. */ return true; @@ -4253,16 +4257,22 @@ elf_bfd_final_link (abfd, info) the original st_name with the dynstr_index. */ sym.st_name = e->isym.st_name; - /* Whatever binding the symbol had before, it's now local. */ - sym.st_info = ELF_ST_INFO (STB_LOCAL, - ELF_ST_TYPE (e->isym.st_info)); - - s = bfd_section_from_elf_index (e->input_bfd, e->isym.st_shndx); - - sym.st_shndx = elf_section_data (s->output_section)->this_idx; - sym.st_value = (s->output_section->vma - + s->output_offset - + e->isym.st_value); + if (e->isym.st_shndx == 0 || e->isym.st_shndx >= SHN_LORESERVE) + { + sym.st_shndx = e->isym.st_shndx; + sym.st_value = e->isym.st_value; + } + else + { + s = bfd_section_from_elf_index (e->input_bfd, + e->isym.st_shndx); + + sym.st_shndx = + elf_section_data (s->output_section)->this_idx; + sym.st_value = (s->output_section->vma + + s->output_offset + + e->isym.st_value); + } if (last_local < e->dynindx) last_local = e->dynindx; @@ -4272,7 +4282,7 @@ elf_bfd_final_link (abfd, info) } elf_section_data (finfo.dynsym_sec->output_section) - ->this_hdr.sh_info = last_local; + ->this_hdr.sh_info = last_local + 1; } /* We get the global symbols from the hash table. */ @@ -4284,6 +4294,18 @@ elf_bfd_final_link (abfd, info) if (eoinfo.failed) return false; + /* If backend needs to output some symbols not present in the hash + table, do it now. */ + if (bed->elf_backend_output_arch_syms) + { + if (! (*bed->elf_backend_output_arch_syms) + (abfd, info, (PTR) &finfo, + (boolean (*) PARAMS ((PTR, const char *, + Elf_Internal_Sym *, asection *))) + elf_link_output_sym)) + return false; + } + /* Flush all symbols to the file. */ if (! elf_link_flush_output_syms (&finfo)) return false; diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index d40a870680..3a787a268d 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -297,6 +297,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef elf_backend_post_process_headers #define elf_backend_post_process_headers NULL #endif +#ifndef elf_backend_print_symbol_all +#define elf_backend_print_symbol_all NULL +#endif +#ifndef elf_backend_output_arch_syms +#define elf_backend_output_arch_syms NULL +#endif /* Previously, backends could only use SHT_REL or SHT_RELA relocation sections, but not both. They defined USE_REL to indicate SHT_REL @@ -369,6 +375,8 @@ static CONST struct elf_backend_data elfNN_bed = elf_backend_gc_mark_hook, elf_backend_gc_sweep_hook, elf_backend_post_process_headers, + elf_backend_print_symbol_all, + elf_backend_output_arch_syms, elf_backend_ecoff_debug_swap, ELF_MACHINE_ALT1, ELF_MACHINE_ALT2, -- 2.34.1