Jakub Jelinek <jj@ultra.linux.cz>

* 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.
This commit is contained in:
Richard Henderson 1999-07-30 21:34:44 +00:00
parent d512aa072e
commit 587ff49e9a
6 changed files with 462 additions and 12 deletions

View File

@ -1,3 +1,21 @@
1999-07-30 Jakub Jelinek <jj@ultra.linux.cz>
* 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 <clm@cygnus.com>
* elf32-arm.h (elf32_arm_check_relocs): Use r_offset for

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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));
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);
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);
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;

View File

@ -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,