NetBSD/gnu/dist/bfd/netbsd.h
kristerw f59fc24c1e Made libbfd read and understand our a.out dynamic symbols.
Solves PR bin/7576 from Mike Neuman.
2000-01-06 21:50:05 +00:00

792 lines
24 KiB
C

/* BFD back-end definitions used by all NetBSD targets.
Copyright (C) 1990, 91, 92, 94, 95, 96, 97 1998
Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
/* Check for our machine type (part of magic number). */
/* If other MID values, define MACHTYPE_OK in xxxnetbsd.c */
#ifndef MACHTYPE_OK
#define MACHTYPE_OK(m) ((m) == DEFAULT_MID || (m) == M_UNKNOWN)
#endif
/* This is the normal load address for executables. */
#define TEXT_START_ADDR TARGET_PAGE_SIZE
/* NetBSD ZMAGIC has its header in the text segment. */
#define N_HEADER_IN_TEXT(x) 1
/* Determine if this file is compiled as pic code. */
#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) && N_PIC(x))
/* We have 6 bits of flags and 10 bits of machine ID. */
#define N_MACHTYPE(exec) \
((enum machine_type)(((exec).a_info >> 16) & 0x03ff))
#define N_FLAGS(exec) \
(((exec).a_info >> 26) & 0x3f)
#define N_SET_INFO(exec, magic, type, flags) \
((exec).a_info = ((magic) & 0xffff) \
| (((int)(type) & 0x3ff) << 16) \
| (((flags) & 0x3f) << 24))
#define N_SET_MACHTYPE(exec, machtype) \
((exec).a_info = \
((exec).a_info & 0xfb00ffff) | ((((int)(machtype))&0x3ff) << 16))
#define N_SET_FLAGS(exec, flags) \
((exec).a_info = \
((exec).a_info & 0x03ffffff) | ((flags & 0x03f) << 26))
#define BIND_WEAK 2
#define EXTERNAL_NZLIST_SIZE 16
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "libaout.h"
/* On NetBSD, the magic number is always in ntohl's "network" (big-endian)
format. */
#ifndef SWAP_MAGIC
#define SWAP_MAGIC(ext) bfd_getb32 (ext)
#endif
/* On NetBSD, the entry point may be taken to be the start of the text
section. */
#define MY_entry_is_text_address 1
#define MY_write_object_contents MY(write_object_contents)
static boolean MY(write_object_contents) PARAMS ((bfd *abfd));
#define MY_text_includes_header 1
#define MY_construct_extended_name_table \
_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); \
netbsd_choose_reloc_size(ABFD);
static void netbsd_choose_reloc_size (bfd *abfd);
#include "aout/netbsd.h"
#include "aout-target.h"
/* Write an object file.
Section contents have already been written. We write the
file header, symbols, and relocation. */
static boolean
MY(write_object_contents) (abfd)
bfd *abfd;
{
struct external_exec exec_bytes;
struct internal_exec *execp = exec_hdr (abfd);
/* We must make certain that the magic number has been set. This
will normally have been done by set_section_contents, but only if
there actually are some section contents. */
if (! abfd->output_has_begun)
{
bfd_size_type text_size;
file_ptr text_end;
NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end);
}
#ifdef CHOOSE_RELOC_SIZE
CHOOSE_RELOC_SIZE(abfd);
#else
obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
#endif
if ((abfd->flags & BFD_PIC) != 0)
execp->a_info |= 0x40000000;
if ((abfd->flags & DYNAMIC) != 0)
execp->a_info |= 0x80000000;
/* Magic number, maestro, please! */
switch (bfd_get_arch(abfd)) {
case DEFAULT_ARCH:
N_SET_MACHTYPE(*execp, DEFAULT_MID);
break;
default:
N_SET_MACHTYPE(*execp, M_UNKNOWN);
break;
}
WRITE_HEADERS(abfd, execp);
/* The NetBSD magic number is always big-endian */
#ifndef TARGET_IS_BIG_ENDIAN_P
/* XXX aren't there any macro to change byteorder of a word independent of
the host's or target's endianesses? */
execp->a_info
= (execp->a_info & 0xff) << 24 | (execp->a_info & 0xff00) << 8
| (execp->a_info & 0xff0000) >> 8 | (execp->a_info & 0xff000000) >> 24;
/* XXX Write a new header with the right endianess for the magic number.
We must do it this way, since the WRITE_HEADER macro is dependent on
having "wrong" endianess... */
NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes);
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) return false;
if (bfd_write ((PTR) &exec_bytes, 1, EXEC_BYTES_SIZE, abfd)
!= EXEC_BYTES_SIZE)
return false;
#endif
return true;
}
/* Determine the size of a relocation entry, based on the architecture */
static void
netbsd_choose_reloc_size (abfd)
bfd *abfd;
{
switch (bfd_get_arch (abfd))
{
case bfd_arch_mips:
case bfd_arch_sparc:
obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;
break;
default:
obj_reloc_entry_size (abfd) = RELOC_STD_SIZE;
break;
}
}
/* Translate an a.out symbol into a BFD symbol. The desc, other, type
and symbol->value fields of CACHE_PTR will be set from the a.out
nlist structure. This function is responsible for setting
symbol->flags and symbol->section, and adjusting symbol->value. */
static boolean
netbsd_translate_from_native_sym_flags (abfd, cache_ptr)
bfd *abfd;
aout_symbol_type *cache_ptr;
{
flagword visible;
if ((cache_ptr->type & N_STAB) != 0
|| cache_ptr->type == N_FN)
{
asection *sec;
/* This is a debugging symbol. */
cache_ptr->symbol.flags = BSF_DEBUGGING;
/* Work out the symbol section. */
switch (cache_ptr->type & N_TYPE)
{
case N_TEXT:
case N_FN:
sec = obj_textsec (abfd);
break;
case N_DATA:
sec = obj_datasec (abfd);
break;
case N_BSS:
sec = obj_bsssec (abfd);
break;
default:
case N_ABS:
sec = bfd_abs_section_ptr;
break;
}
cache_ptr->symbol.section = sec;
cache_ptr->symbol.value -= sec->vma;
return true;
}
/* Get the default visibility. This does not apply to all types, so
we just hold it in a local variable to use if wanted. */
if ((cache_ptr->type & N_EXT) == 0)
visible = BSF_LOCAL;
else
visible = BSF_GLOBAL;
switch (cache_ptr->type)
{
default:
case N_ABS: case N_ABS | N_EXT:
cache_ptr->symbol.section = bfd_abs_section_ptr;
cache_ptr->symbol.flags = visible;
break;
case N_UNDF | N_EXT:
if (cache_ptr->symbol.value != 0)
{
/* This is a common symbol. */
cache_ptr->symbol.flags = BSF_GLOBAL;
cache_ptr->symbol.section = bfd_com_section_ptr;
}
else
{
cache_ptr->symbol.flags = 0;
cache_ptr->symbol.section = bfd_und_section_ptr;
}
break;
case N_TEXT: case N_TEXT | N_EXT:
cache_ptr->symbol.section = obj_textsec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = visible;
break;
/* N_SETV symbols used to represent set vectors placed in the
data section. They are no longer generated. Theoretically,
it was possible to extract the entries and combine them with
new ones, although I don't know if that was ever actually
done. Unless that feature is restored, treat them as data
symbols. */
case N_SETV: case N_SETV | N_EXT:
case N_DATA: case N_DATA | N_EXT:
cache_ptr->symbol.section = obj_datasec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = visible;
break;
case N_BSS: case N_BSS | N_EXT:
cache_ptr->symbol.section = obj_bsssec (abfd);
cache_ptr->symbol.value -= cache_ptr->symbol.section->vma;
cache_ptr->symbol.flags = visible;
break;
case N_SIZE: case N_SIZE | N_EXT:
cache_ptr->symbol.section = bfd_abs_section_ptr;
/* Set BSF_DEBUGGING so we don't link against this symbol. */
cache_ptr->symbol.flags = BSF_DEBUGGING | visible;
break;
case N_SETA: case N_SETA | N_EXT:
case N_SETT: case N_SETT | N_EXT:
case N_SETD: case N_SETD | N_EXT:
case N_SETB: case N_SETB | N_EXT:
{
switch (cache_ptr->type & N_TYPE)
{
case N_SETA:
cache_ptr->symbol.section = bfd_abs_section_ptr;
break;
case N_SETT:
cache_ptr->symbol.section = obj_textsec (abfd);
break;
case N_SETD:
cache_ptr->symbol.section = obj_datasec (abfd);
break;
case N_SETB:
cache_ptr->symbol.section = obj_bsssec (abfd);
break;
}
cache_ptr->symbol.flags |= BSF_CONSTRUCTOR;
}
break;
case N_WARNING:
/* This symbol is the text of a warning message. The next
symbol is the symbol to associate the warning with. If a
reference is made to that symbol, a warning is issued. */
cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING;
cache_ptr->symbol.section = bfd_abs_section_ptr;
break;
case N_INDR: case N_INDR | N_EXT:
/* An indirect symbol. This consists of two symbols in a row.
The first symbol is the name of the indirection. The second
symbol is the name of the target. A reference to the first
symbol becomes a reference to the second. */
cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT | visible;
cache_ptr->symbol.section = bfd_ind_section_ptr;
break;
}
if (((cache_ptr->other >> 4) & 0xf) == BIND_WEAK)
cache_ptr->symbol.flags |= BSF_WEAK;
return true;
}
/* Set the fields of SYM_POINTER according to CACHE_PTR. */
static boolean
netbsd_translate_to_native_sym_flags (abfd, cache_ptr, sym_pointer)
bfd *abfd;
asymbol *cache_ptr;
struct external_nlist *sym_pointer;
{
bfd_vma value = cache_ptr->value;
asection *sec;
bfd_vma off;
boolean is_size_symbol;
is_size_symbol = (sym_pointer->e_type[0] & N_TYPE) == N_SIZE;
/* Mask out any existing type bits in case copying from one section
to another. */
sym_pointer->e_type[0] &= ~N_TYPE;
sec = bfd_get_section (cache_ptr);
off = 0;
if (sec == NULL)
{
/* This case occurs, e.g., for the *DEBUG* section of a COFF
file. */
(*_bfd_error_handler)
("%s: can not represent section for symbol `%s' in a.out object file format",
bfd_get_filename (abfd),
cache_ptr->name != NULL ? cache_ptr->name : "*unknown*");
bfd_set_error (bfd_error_nonrepresentable_section);
return false;
}
if (sec->output_section != NULL)
{
off = sec->output_offset;
sec = sec->output_section;
}
if (is_size_symbol)
sym_pointer->e_type[0] |= N_SIZE;
else if (bfd_is_abs_section (sec))
sym_pointer->e_type[0] |= N_ABS;
else if (sec == obj_textsec (abfd))
sym_pointer->e_type[0] |= N_TEXT;
else if (sec == obj_datasec (abfd))
sym_pointer->e_type[0] |= N_DATA;
else if (sec == obj_bsssec (abfd))
sym_pointer->e_type[0] |= N_BSS;
else if (bfd_is_und_section (sec))
sym_pointer->e_type[0] = N_UNDF | N_EXT;
else if (bfd_is_ind_section (sec))
sym_pointer->e_type[0] = N_INDR;
else if (bfd_is_com_section (sec))
sym_pointer->e_type[0] = N_UNDF | N_EXT;
else
{
(*_bfd_error_handler)
("%s: can not represent section `%s' in a.out object file format",
bfd_get_filename (abfd), bfd_get_section_name (abfd, sec));
bfd_set_error (bfd_error_nonrepresentable_section);
return false;
}
/* Turn the symbol from section relative to absolute again */
value += sec->vma + off;
if ((cache_ptr->flags & BSF_WARNING) != 0)
sym_pointer->e_type[0] = N_WARNING;
if ((cache_ptr->flags & BSF_DEBUGGING) != 0)
sym_pointer->e_type[0] = ((aout_symbol_type *) cache_ptr)->type;
else if ((cache_ptr->flags & BSF_GLOBAL) != 0)
sym_pointer->e_type[0] |= N_EXT;
if ((cache_ptr->flags & BSF_CONSTRUCTOR) != 0)
{
int type = ((aout_symbol_type *) cache_ptr)->type;
switch (type)
{
case N_ABS: type = N_SETA; break;
case N_TEXT: type = N_SETT; break;
case N_DATA: type = N_SETD; break;
case N_BSS: type = N_SETB; break;
}
sym_pointer->e_type[0] = type;
}
if ((cache_ptr->flags & BSF_WEAK) != 0)
{
sym_pointer->e_other[0] |= 0x20; /* BIND_WEAK */
/* Weak symbols are always extern. */
sym_pointer->e_type[0] |= N_EXT;
}
PUT_WORD(abfd, value, sym_pointer->e_value);
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;
}