Made libbfd read and understand our a.out dynamic symbols.

Solves PR bin/7576 from Mike Neuman.
This commit is contained in:
kristerw 2000-01-06 21:50:05 +00:00
parent 81a78604bf
commit f59fc24c1e
1 changed files with 359 additions and 1 deletions

360
gnu/dist/bfd/netbsd.h vendored
View File

@ -35,7 +35,7 @@ USA. */
#define N_PIC(exec) ((exec).a_info & 0x40000000)
/* Determine if this is a shared library using the flags. */
#define N_SHARED_LIB(x) (N_DYNAMIC(x))
#define N_SHARED_LIB(x) (N_DYNAMIC(x) && N_PIC(x))
/* We have 6 bits of flags and 10 bits of machine ID. */
#define N_MACHTYPE(exec) \
@ -55,6 +55,7 @@ USA. */
((exec).a_info & 0x03ffffff) | ((flags & 0x03f) << 26))
#define BIND_WEAK 2
#define EXTERNAL_NZLIST_SIZE 16
#include "bfd.h"
#include "sysdep.h"
@ -78,9 +79,14 @@ static boolean MY(write_object_contents) PARAMS ((bfd *abfd));
_bfd_archive_bsd44_construct_extended_name_table
#define MY_translate_from_native_sym_flags netbsd_translate_from_native_sym_flags
#define MY_translate_to_native_sym_flags netbsd_translate_to_native_sym_flags
#define MY_get_dynamic_symtab_upper_bound netbsd_get_dynamic_symtab_upper_bound
#define MY_canonicalize_dynamic_symtab netbsd_canonicalize_dynamic_symtab
static boolean netbsd_translate_from_native_sym_flags PARAMS ((bfd *, aout_symbol_type *));
static boolean netbsd_translate_to_native_sym_flags PARAMS ((bfd *, asymbol *, struct external_nlist *));
static long netbsd_get_dynamic_symtab_upper_bound PARAMS ((bfd *));
static long netbsd_canonicalize_dynamic_symtab PARAMS ((bfd *, asymbol **));
static boolean netbsd_slurp_dynamic_symtab PARAMS ((bfd *));
#define SET_ARCH_MACH(ABFD, EXEC) \
bfd_default_set_arch_mach(abfd, DEFAULT_ARCH, 0); \
@ -431,3 +437,355 @@ netbsd_translate_to_native_sym_flags (abfd, cache_ptr, sym_pointer)
return true;
}
/* NetBSD shared library support. We store a pointer to this structure
in obj_aout_dynamic_info (abfd). */
struct netbsd_dynamic_info
{
/* Whether we found any dynamic information. */
boolean valid;
/* Dynamic information. */
struct internal_section_dispatch_table dyninfo;
/* Number of dynamic symbols. */
unsigned long dynsym_count;
/* Read in nlists for dynamic symbols. */
struct external_nlist *dynsym;
/* asymbol structures for dynamic symbols. */
aout_symbol_type *canonical_dynsym;
/* Read in dynamic string table. */
char *dynstr;
/* Number of dynamic relocs. */
unsigned long dynrel_count;
/* Read in dynamic relocs. This may be reloc_std_external or
reloc_ext_external. */
PTR dynrel;
/* arelent structures for dynamic relocs. */
arelent *canonical_dynrel;
};
struct external_nzlist {
bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */
bfd_byte e_type[1]; /* type of symbol */
bfd_byte e_other[1]; /* misc info */
bfd_byte e_desc[2]; /* description field */
bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */
bfd_byte e_size[4];
};
static boolean netbsd_translate_symbol_table PARAMS ((bfd *, aout_symbol_type *, struct external_nzlist *, bfd_size_type, char *, bfd_size_type, boolean));
/* Read in the basic dynamic information. This locates the __DYNAMIC
structure and uses it to find the dynamic_link structure. It
creates and saves a sunos_dynamic_info structure. If it can't find
__DYNAMIC, it sets the valid field of the sunos_dynamic_info
structure to false to avoid doing this work again. */
static boolean
netbsd_read_dynamic_info (abfd)
bfd *abfd;
{
struct netbsd_dynamic_info *info;
asection *dynsec;
bfd_vma dynoff;
struct external_netbsd_dynamic dyninfo;
unsigned long dynver;
struct external_netbsd_dynamic_link linkinfo;
if (obj_aout_dynamic_info (abfd) != (PTR) NULL)
return true;
if ((abfd->flags & DYNAMIC) == 0)
{
bfd_set_error (bfd_error_invalid_operation);
return false;
}
info = ((struct netbsd_dynamic_info *)
bfd_zalloc (abfd, sizeof (struct netbsd_dynamic_info)));
if (!info)
return false;
info->valid = false;
info->dynsym = NULL;
info->dynstr = NULL;
info->canonical_dynsym = NULL;
info->dynrel = NULL;
info->canonical_dynrel = NULL;
obj_aout_dynamic_info (abfd) = (PTR) info;
/* This code used to look for the __DYNAMIC symbol to locate the dynamic
linking information.
However this inhibits recovering the dynamic symbols from a
stripped object file, so blindly assume that the dynamic linking
information is located at the start of the data section.
We could verify this assumption later by looking through the dynamic
symbols for the __DYNAMIC symbol. */
if ((abfd->flags & DYNAMIC) == 0)
return true;
if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (PTR) &dyninfo,
(file_ptr) 0, sizeof dyninfo))
return true;
dynver = GET_WORD (abfd, dyninfo.d_version);
if (dynver != 8)
return true;
dynoff = GET_WORD (abfd, dyninfo.d_un);
/* dynoff is a virtual address. It is probably always in the .data
section, but this code should work even if it moves. */
if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd)))
dynsec = obj_textsec (abfd);
else
dynsec = obj_datasec (abfd);
dynoff -= bfd_get_section_vma (abfd, dynsec);
if (dynoff > bfd_section_size (abfd, dynsec))
return true;
/* This executable appears to be dynamically linked in a way that we
can understand. */
if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, dynoff,
(bfd_size_type) sizeof linkinfo))
return true;
/* Swap in the dynamic link information. */
info->dyninfo.sdt_loaded = GET_WORD (abfd, linkinfo.sdt_loaded);
info->dyninfo.sdt_sods = GET_WORD (abfd, linkinfo.sdt_sods);
info->dyninfo.sdt_paths = GET_WORD (abfd, linkinfo.sdt_paths);
info->dyninfo.sdt_got = GET_WORD (abfd, linkinfo.sdt_got);
info->dyninfo.sdt_plt = GET_WORD (abfd, linkinfo.sdt_plt);
info->dyninfo.sdt_rel = GET_WORD (abfd, linkinfo.sdt_rel);
info->dyninfo.sdt_hash = GET_WORD (abfd, linkinfo.sdt_hash);
info->dyninfo.sdt_nzlist = GET_WORD (abfd, linkinfo.sdt_nzlist);
info->dyninfo.sdt_filler2 = GET_WORD (abfd, linkinfo.sdt_filler2);
info->dyninfo.sdt_buckets = GET_WORD (abfd, linkinfo.sdt_buckets);
info->dyninfo.sdt_strings = GET_WORD (abfd, linkinfo.sdt_strings);
info->dyninfo.sdt_str_sz = GET_WORD (abfd, linkinfo.sdt_str_sz);
info->dyninfo.sdt_text_sz = GET_WORD (abfd, linkinfo.sdt_text_sz);
info->dyninfo.sdt_plt_sz = GET_WORD (abfd, linkinfo.sdt_plt_sz);
/* Transform values into file offsets. */
{
struct internal_exec *execp = exec_hdr (abfd);
unsigned long text_addr;
text_addr = N_TXTADDR(*execp) - N_TXTOFF(*execp);
info->dyninfo.sdt_sods -= text_addr;
info->dyninfo.sdt_paths -= text_addr;
info->dyninfo.sdt_got -= text_addr;
info->dyninfo.sdt_plt -= text_addr;
info->dyninfo.sdt_rel -= text_addr;
info->dyninfo.sdt_hash -= text_addr;
info->dyninfo.sdt_nzlist -= text_addr;
info->dyninfo.sdt_strings -= text_addr;
}
/* The only way to get the size of the symbol information appears to
be to determine the distance between it and the string table. */
info->dynsym_count = ((info->dyninfo.sdt_strings - info->dyninfo.sdt_nzlist)
/ EXTERNAL_NZLIST_SIZE);
BFD_ASSERT (info->dynsym_count * EXTERNAL_NZLIST_SIZE
== (unsigned long) (info->dyninfo.sdt_strings
- info->dyninfo.sdt_nzlist));
/* Similarly, the relocs end at the hash table. */
info->dynrel_count = ((info->dyninfo.sdt_hash - info->dyninfo.sdt_rel)
/ obj_reloc_entry_size (abfd));
BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd)
== (unsigned long) (info->dyninfo.sdt_hash
- info->dyninfo.sdt_rel));
info->valid = true;
return true;
}
/* Return the amount of memory required for the dynamic symbols. */
static long
netbsd_get_dynamic_symtab_upper_bound (abfd)
bfd *abfd;
{
struct netbsd_dynamic_info *info;
if (! netbsd_read_dynamic_info (abfd))
return -1;
info = (struct netbsd_dynamic_info *) obj_aout_dynamic_info (abfd);
if (! info->valid)
{
bfd_set_error (bfd_error_no_symbols);
return -1;
}
return (info->dynsym_count + 1) * sizeof (asymbol *);
}
/* Read in the dynamic symbols. */
static long
netbsd_canonicalize_dynamic_symtab (abfd, storage)
bfd *abfd;
asymbol **storage;
{
struct netbsd_dynamic_info *info;
unsigned long i;
if (! netbsd_slurp_dynamic_symtab (abfd))
return -1;
info = (struct netbsd_dynamic_info *) obj_aout_dynamic_info (abfd);
/* Get the asymbol structures corresponding to the dynamic nlist
structures. */
if (info->canonical_dynsym == (aout_symbol_type *) NULL)
{
info->canonical_dynsym = ((aout_symbol_type *)
bfd_alloc (abfd,
(info->dynsym_count
* sizeof (aout_symbol_type))));
if (info->canonical_dynsym == NULL && info->dynsym_count != 0)
return -1;
if (! netbsd_translate_symbol_table (abfd, info->canonical_dynsym,
(struct external_nzlist *)info->dynsym,
info->dynsym_count,
info->dynstr,
info->dyninfo.sdt_str_sz,
true))
{
if (info->canonical_dynsym != NULL)
{
bfd_release (abfd, info->canonical_dynsym);
info->canonical_dynsym = NULL;
}
return -1;
}
}
/* Return pointers to the dynamic asymbol structures. */
for (i = 0; i < info->dynsym_count; i++)
*storage++ = (asymbol *) (info->canonical_dynsym + i);
*storage = NULL;
return info->dynsym_count;
}
/* Read the external dynamic symbols. */
static boolean
netbsd_slurp_dynamic_symtab (abfd)
bfd *abfd;
{
struct netbsd_dynamic_info *info;
/* Get the general dynamic information. */
if (obj_aout_dynamic_info (abfd) == NULL)
{
if (! netbsd_read_dynamic_info (abfd))
return false;
}
info = (struct netbsd_dynamic_info *) obj_aout_dynamic_info (abfd);
if (! info->valid)
{
bfd_set_error (bfd_error_no_symbols);
return false;
}
/* Get the dynamic nlist structures. */
if (info->dynsym == (struct external_nlist *) NULL)
{
info->dynsym = ((struct external_nlist *)
bfd_alloc (abfd,
(info->dynsym_count
* EXTERNAL_NZLIST_SIZE)));
if (info->dynsym == NULL && info->dynsym_count != 0)
return false;
if (bfd_seek (abfd, info->dyninfo.sdt_nzlist, SEEK_SET) != 0
|| (bfd_read ((PTR) info->dynsym, info->dynsym_count,
EXTERNAL_NZLIST_SIZE, abfd)
!= info->dynsym_count * EXTERNAL_NZLIST_SIZE))
{
if (info->dynsym != NULL)
{
bfd_release (abfd, info->dynsym);
info->dynsym = NULL;
}
return false;
}
}
/* Get the dynamic strings. */
if (info->dynstr == (char *) NULL)
{
info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.sdt_str_sz);
if (info->dynstr == NULL && info->dyninfo.sdt_str_sz != 0)
return false;
if (bfd_seek (abfd, info->dyninfo.sdt_strings, SEEK_SET) != 0
|| (bfd_read ((PTR) info->dynstr, 1, info->dyninfo.sdt_str_sz,
abfd)
!= info->dyninfo.sdt_str_sz))
{
if (info->dynstr != NULL)
{
bfd_release (abfd, info->dynstr);
info->dynstr = NULL;
}
return false;
}
}
return true;
}
static boolean
netbsd_translate_symbol_table (abfd, in, ext, count, str, strsize, dynamic)
bfd *abfd;
aout_symbol_type *in;
struct external_nzlist *ext;
bfd_size_type count;
char *str;
bfd_size_type strsize;
boolean dynamic;
{
struct external_nzlist *ext_end;
ext_end = ext + count;
for (; ext < ext_end; ext++, in++)
{
bfd_vma x;
x = GET_WORD (abfd, ext->e_strx);
in->symbol.the_bfd = abfd;
/* For the normal symbols, the zero index points at the number
of bytes in the string table but is to be interpreted as the
null string. For the dynamic symbols, the number of bytes in
the string table is stored in the __DYNAMIC structure and the
zero index points at an actual string. */
if (x == 0 && ! dynamic)
in->symbol.name = "";
else if (x < strsize)
in->symbol.name = str + x;
else
return false;
in->symbol.value = GET_SWORD (abfd, ext->e_value);
in->desc = bfd_h_get_16 (abfd, ext->e_desc);
in->other = bfd_h_get_8 (abfd, ext->e_other);
in->type = bfd_h_get_8 (abfd, ext->e_type);
in->symbol.udata.p = NULL;
if (! netbsd_translate_from_native_sym_flags (abfd, in))
return false;
if (dynamic)
in->symbol.flags |= BSF_DYNAMIC;
}
return true;
}