/* ELF executable support for BFD.
- Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
static INLINE struct elf_segment_map *make_mapping
PARAMS ((bfd *, asection **, unsigned int, unsigned int, boolean));
+static boolean map_sections_to_segments PARAMS ((bfd *));
static int elf_sort_sections PARAMS ((const PTR, const PTR));
static boolean assign_file_positions_for_segments PARAMS ((bfd *));
static boolean assign_file_positions_except_relocs PARAMS ((bfd *));
static boolean prep_headers PARAMS ((bfd *));
-static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **));
+static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int));
static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
+static char *elf_read PARAMS ((bfd *, long, unsigned int));
+static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
+static boolean assign_section_numbers PARAMS ((bfd *));
+static INLINE int sym_is_global PARAMS ((bfd *, asymbol *));
+static boolean elf_map_symbols PARAMS ((bfd *));
+static bfd_size_type get_program_header_size PARAMS ((bfd *));
+
+/* Swap version information in and out. The version information is
+ currently size independent. If that ever changes, this code will
+ need to move into elfcode.h. */
+
+/* Swap in a Verdef structure. */
+
+void
+_bfd_elf_swap_verdef_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Verdef *src;
+ Elf_Internal_Verdef *dst;
+{
+ dst->vd_version = bfd_h_get_16 (abfd, src->vd_version);
+ dst->vd_flags = bfd_h_get_16 (abfd, src->vd_flags);
+ dst->vd_ndx = bfd_h_get_16 (abfd, src->vd_ndx);
+ dst->vd_cnt = bfd_h_get_16 (abfd, src->vd_cnt);
+ dst->vd_hash = bfd_h_get_32 (abfd, src->vd_hash);
+ dst->vd_aux = bfd_h_get_32 (abfd, src->vd_aux);
+ dst->vd_next = bfd_h_get_32 (abfd, src->vd_next);
+}
+
+/* Swap out a Verdef structure. */
+
+void
+_bfd_elf_swap_verdef_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Verdef *src;
+ Elf_External_Verdef *dst;
+{
+ bfd_h_put_16 (abfd, src->vd_version, dst->vd_version);
+ bfd_h_put_16 (abfd, src->vd_flags, dst->vd_flags);
+ bfd_h_put_16 (abfd, src->vd_ndx, dst->vd_ndx);
+ bfd_h_put_16 (abfd, src->vd_cnt, dst->vd_cnt);
+ bfd_h_put_32 (abfd, src->vd_hash, dst->vd_hash);
+ bfd_h_put_32 (abfd, src->vd_aux, dst->vd_aux);
+ bfd_h_put_32 (abfd, src->vd_next, dst->vd_next);
+}
+
+/* Swap in a Verdaux structure. */
+
+void
+_bfd_elf_swap_verdaux_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Verdaux *src;
+ Elf_Internal_Verdaux *dst;
+{
+ dst->vda_name = bfd_h_get_32 (abfd, src->vda_name);
+ dst->vda_next = bfd_h_get_32 (abfd, src->vda_next);
+}
+
+/* Swap out a Verdaux structure. */
+
+void
+_bfd_elf_swap_verdaux_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Verdaux *src;
+ Elf_External_Verdaux *dst;
+{
+ bfd_h_put_32 (abfd, src->vda_name, dst->vda_name);
+ bfd_h_put_32 (abfd, src->vda_next, dst->vda_next);
+}
+
+/* Swap in a Verneed structure. */
+
+void
+_bfd_elf_swap_verneed_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Verneed *src;
+ Elf_Internal_Verneed *dst;
+{
+ dst->vn_version = bfd_h_get_16 (abfd, src->vn_version);
+ dst->vn_cnt = bfd_h_get_16 (abfd, src->vn_cnt);
+ dst->vn_file = bfd_h_get_32 (abfd, src->vn_file);
+ dst->vn_aux = bfd_h_get_32 (abfd, src->vn_aux);
+ dst->vn_next = bfd_h_get_32 (abfd, src->vn_next);
+}
+
+/* Swap out a Verneed structure. */
+
+void
+_bfd_elf_swap_verneed_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Verneed *src;
+ Elf_External_Verneed *dst;
+{
+ bfd_h_put_16 (abfd, src->vn_version, dst->vn_version);
+ bfd_h_put_16 (abfd, src->vn_cnt, dst->vn_cnt);
+ bfd_h_put_32 (abfd, src->vn_file, dst->vn_file);
+ bfd_h_put_32 (abfd, src->vn_aux, dst->vn_aux);
+ bfd_h_put_32 (abfd, src->vn_next, dst->vn_next);
+}
+
+/* Swap in a Vernaux structure. */
+
+void
+_bfd_elf_swap_vernaux_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Vernaux *src;
+ Elf_Internal_Vernaux *dst;
+{
+ dst->vna_hash = bfd_h_get_32 (abfd, src->vna_hash);
+ dst->vna_flags = bfd_h_get_16 (abfd, src->vna_flags);
+ dst->vna_other = bfd_h_get_16 (abfd, src->vna_other);
+ dst->vna_name = bfd_h_get_32 (abfd, src->vna_name);
+ dst->vna_next = bfd_h_get_32 (abfd, src->vna_next);
+}
+
+/* Swap out a Vernaux structure. */
+
+void
+_bfd_elf_swap_vernaux_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Vernaux *src;
+ Elf_External_Vernaux *dst;
+{
+ bfd_h_put_32 (abfd, src->vna_hash, dst->vna_hash);
+ bfd_h_put_16 (abfd, src->vna_flags, dst->vna_flags);
+ bfd_h_put_16 (abfd, src->vna_other, dst->vna_other);
+ bfd_h_put_32 (abfd, src->vna_name, dst->vna_name);
+ bfd_h_put_32 (abfd, src->vna_next, dst->vna_next);
+}
+
+/* Swap in a Versym structure. */
+
+void
+_bfd_elf_swap_versym_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Versym *src;
+ Elf_Internal_Versym *dst;
+{
+ dst->vs_vers = bfd_h_get_16 (abfd, src->vs_vers);
+}
+
+/* Swap out a Versym structure. */
+
+void
+_bfd_elf_swap_versym_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Versym *src;
+ Elf_External_Versym *dst;
+{
+ bfd_h_put_16 (abfd, src->vs_vers, dst->vs_vers);
+}
/* Standard ELF hash function. Do not change this function; you will
- cause invalid hash tables to be generated. (Well, you would if this
- were being used yet.) */
+ cause invalid hash tables to be generated. */
unsigned long
bfd_elf_hash (name)
CONST unsigned char *name;
if ((g = (h & 0xf0000000)) != 0)
{
h ^= g >> 24;
- h &= ~g;
+ /* The ELF ABI says `h &= ~g', but this is equivalent in
+ this case and on some machines one insn instead of two. */
+ h ^= g;
}
}
return h;
}
boolean
-elf_mkobject (abfd)
+bfd_elf_mkobject (abfd)
bfd * abfd;
{
/* this just does initialization */
return true;
}
+boolean
+bfd_elf_mkcorefile (abfd)
+ bfd * abfd;
+{
+ /* I think this can be done just like an object file. */
+ return bfd_elf_mkobject (abfd);
+}
+
char *
bfd_elf_get_str_section (abfd, shindex)
bfd * abfd;
&& bfd_elf_get_str_section (abfd, shindex) == NULL)
return NULL;
+ if (strindex >= hdr->sh_size)
+ {
+ (*_bfd_error_handler)
+ (_("%s: invalid string offset %u >= %lu for section `%s'"),
+ bfd_get_filename (abfd), strindex, (unsigned long) hdr->sh_size,
+ ((shindex == elf_elfheader(abfd)->e_shstrndx
+ && strindex == hdr->sh_name)
+ ? ".shstrtab"
+ : elf_string_from_elf_strtab (abfd, hdr->sh_name)));
+ return "";
+ }
+
return ((char *) hdr->contents) + strindex;
}
|| strncmp (name, ".stab", sizeof ".stab" - 1) == 0)
flags |= SEC_DEBUGGING;
+ /* As a GNU extension, if the name begins with .gnu.linkonce, we
+ only link a single copy of the section. This is used to support
+ g++. g++ will emit each template expansion in its own section.
+ The symbols will be defined as weak, so that multiple definitions
+ are permitted. The GNU linker extension is to actually discard
+ all but one of the sections. */
+ if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+ flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
if (! bfd_set_section_flags (abfd, newsect, flags))
return false;
Elf_Internal_Phdr *phdr;
unsigned int i;
- /* Look through the phdrs to see if we need to adjust the lma. */
+ /* Look through the phdrs to see if we need to adjust the lma.
+ If all the p_paddr fields are zero, we ignore them, since
+ some ELF linkers produce such output. */
phdr = elf_tdata (abfd)->phdr;
for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
{
- if (phdr->p_type == PT_LOAD
- && phdr->p_paddr != 0
- && phdr->p_vaddr != phdr->p_paddr
- && phdr->p_vaddr <= hdr->sh_addr
- && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size)
+ if (phdr->p_paddr != 0)
+ break;
+ }
+ if (i < elf_elfheader (abfd)->e_phnum)
+ {
+ phdr = elf_tdata (abfd)->phdr;
+ for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
{
- newsect->lma += phdr->p_paddr - phdr->p_vaddr;
- break;
+ if (phdr->p_type == PT_LOAD
+ && phdr->p_vaddr != phdr->p_paddr
+ && phdr->p_vaddr <= hdr->sh_addr
+ && (phdr->p_vaddr + phdr->p_memsz
+ >= hdr->sh_addr + hdr->sh_size)
+ && ((flags & SEC_LOAD) == 0
+ || (phdr->p_offset <= (bfd_vma) hdr->sh_offset
+ && (phdr->p_offset + phdr->p_filesz
+ >= hdr->sh_offset + hdr->sh_size))))
+ {
+ newsect->lma += phdr->p_paddr - phdr->p_vaddr;
+ break;
+ }
}
}
}
i_shdrp = elf_elfsections (abfd);
if (i_shdrp != NULL)
{
- shstrtab = bfd_elf_get_str_section (abfd, elf_elfheader (abfd)->e_shstrndx);
+ shstrtab = bfd_elf_get_str_section
+ (abfd, elf_elfheader (abfd)->e_shstrndx);
if (shstrtab != NULL)
{
max = elf_elfheader (abfd)->e_shnum;
{
unsigned int i, c;
- fprintf (f, "\nProgram Header:\n");
+ fprintf (f, _("\nProgram Header:\n"));
c = elf_elfheader (abfd)->e_phnum;
for (i = 0; i < c; i++, p++)
{
size_t extdynsize;
void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *));
- fprintf (f, "\nDynamic Section:\n");
+ fprintf (f, _("\nDynamic Section:\n"));
dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size);
if (dynbuf == NULL)
case DT_DEBUG: name = "DEBUG"; break;
case DT_TEXTREL: name = "TEXTREL"; break;
case DT_JMPREL: name = "JMPREL"; break;
+ case DT_AUXILIARY: name = "AUXILIARY"; stringp = true; break;
+ case DT_FILTER: name = "FILTER"; stringp = true; break;
+ case DT_VERSYM: name = "VERSYM"; break;
+ case DT_VERDEF: name = "VERDEF"; break;
+ case DT_VERDEFNUM: name = "VERDEFNUM"; break;
+ case DT_VERNEED: name = "VERNEED"; break;
+ case DT_VERNEEDNUM: name = "VERNEEDNUM"; break;
}
fprintf (f, " %-11s ", name);
dynbuf = NULL;
}
+ if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL)
+ || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL))
+ {
+ if (! _bfd_elf_slurp_version_tables (abfd))
+ return false;
+ }
+
+ if (elf_dynverdef (abfd) != 0)
+ {
+ Elf_Internal_Verdef *t;
+
+ fprintf (f, _("\nVersion definitions:\n"));
+ for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef)
+ {
+ fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx,
+ t->vd_flags, t->vd_hash, t->vd_nodename);
+ if (t->vd_auxptr->vda_nextptr != NULL)
+ {
+ Elf_Internal_Verdaux *a;
+
+ fprintf (f, "\t");
+ for (a = t->vd_auxptr->vda_nextptr;
+ a != NULL;
+ a = a->vda_nextptr)
+ fprintf (f, "%s ", a->vda_nodename);
+ fprintf (f, "\n");
+ }
+ }
+ }
+
+ if (elf_dynverref (abfd) != 0)
+ {
+ Elf_Internal_Verneed *t;
+
+ fprintf (f, _("\nVersion References:\n"));
+ for (t = elf_tdata (abfd)->verref; t != NULL; t = t->vn_nextref)
+ {
+ Elf_Internal_Vernaux *a;
+
+ fprintf (f, _(" required from %s:\n"), t->vn_filename);
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ fprintf (f, " 0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash,
+ a->vna_flags, a->vna_other, a->vna_nodename);
+ }
+ }
+
return true;
error_return:
}
/* Display ELF-specific fields of a symbol. */
+
void
-bfd_elf_print_symbol (ignore_abfd, filep, symbol, how)
- bfd *ignore_abfd;
+bfd_elf_print_symbol (abfd, filep, symbol, how)
+ bfd *abfd;
PTR filep;
asymbol *symbol;
bfd_print_symbol_type how;
(bfd_is_com_section (symbol->section)
? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value
: ((elf_symbol_type *) symbol)->internal_elf_sym.st_size));
+
+ /* If we have version information, print it. */
+ if (elf_tdata (abfd)->dynversym_section != 0
+ && (elf_tdata (abfd)->dynverdef_section != 0
+ || elf_tdata (abfd)->dynverref_section != 0))
+ {
+ unsigned int vernum;
+ const char *version_string;
+
+ vernum = ((elf_symbol_type *) symbol)->version & VERSYM_VERSION;
+
+ if (vernum == 0)
+ version_string = "";
+ else if (vernum == 1)
+ version_string = "Base";
+ else if (vernum <= elf_tdata (abfd)->cverdefs)
+ version_string =
+ elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+ else
+ {
+ Elf_Internal_Verneed *t;
+
+ version_string = "";
+ for (t = elf_tdata (abfd)->verref;
+ t != NULL;
+ t = t->vn_nextref)
+ {
+ Elf_Internal_Vernaux *a;
+
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ {
+ if (a->vna_other == vernum)
+ {
+ version_string = a->vna_nodename;
+ break;
+ }
+ }
+ }
+ }
+
+ if ((((elf_symbol_type *) symbol)->version & VERSYM_HIDDEN) == 0)
+ fprintf (file, " %-11s", version_string);
+ else
+ {
+ int i;
+
+ fprintf (file, " (%s)", version_string);
+ for (i = 10 - strlen (version_string); i > 0; --i)
+ putc (' ', file);
+ }
+ }
+
+ /* If the st_other field is not zero, print it. */
+ if (((elf_symbol_type *) symbol)->internal_elf_sym.st_other != 0)
+ fprintf (file, " 0x%02x",
+ ((unsigned int)
+ ((elf_symbol_type *) symbol)->internal_elf_sym.st_other));
+
fprintf (file, " %s", symbol->name);
}
break;
ret->dynindx = -1;
ret->dynstr_index = 0;
ret->weakdef = NULL;
- ret->got_offset = (bfd_vma) -1;
- ret->plt_offset = (bfd_vma) -1;
+ ret->got.offset = (bfd_vma) -1;
+ ret->plt.offset = (bfd_vma) -1;
ret->linker_section_pointer = (elf_linker_section_pointers_t *)0;
+ ret->verinfo.verdef = NULL;
+ ret->vtable_entries_used = NULL;
+ ret->vtable_parent = NULL;
ret->type = STT_NOTYPE;
+ ret->other = 0;
/* Assume that we have been called by a non-ELF symbol reader.
This flag is then reset by the code which reads an ELF input
file. This ensures that a symbol created by a non-ELF symbol
table->bucketcount = 0;
table->needed = NULL;
table->hgot = NULL;
+ table->stab_info = NULL;
return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
}
}
/* Get the list of DT_NEEDED entries for a link. This is a hook for
- the ELF emulation code. */
+ the linker ELF emulation code. */
struct bfd_link_needed_list *
bfd_elf_get_needed_list (abfd, info)
return elf_dt_name (abfd);
return NULL;
}
+
+/* Get the list of DT_NEEDED entries from a BFD. This is a hook for
+ the ELF linker emulation code. */
+
+boolean
+bfd_elf_get_bfd_needed_list (abfd, pneeded)
+ bfd *abfd;
+ struct bfd_link_needed_list **pneeded;
+{
+ asection *s;
+ bfd_byte *dynbuf = NULL;
+ int elfsec;
+ unsigned long link;
+ bfd_byte *extdyn, *extdynend;
+ size_t extdynsize;
+ void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *));
+
+ *pneeded = NULL;
+
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour
+ || bfd_get_format (abfd) != bfd_object)
+ return true;
+
+ s = bfd_get_section_by_name (abfd, ".dynamic");
+ if (s == NULL || s->_raw_size == 0)
+ return true;
+
+ dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size);
+ if (dynbuf == NULL)
+ goto error_return;
+
+ if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, (file_ptr) 0,
+ s->_raw_size))
+ goto error_return;
+
+ elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+ if (elfsec == -1)
+ goto error_return;
+
+ link = elf_elfsections (abfd)[elfsec]->sh_link;
+
+ extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
+ swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
+
+ extdyn = dynbuf;
+ extdynend = extdyn + s->_raw_size;
+ for (; extdyn < extdynend; extdyn += extdynsize)
+ {
+ Elf_Internal_Dyn dyn;
+
+ (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn);
+
+ if (dyn.d_tag == DT_NULL)
+ break;
+
+ if (dyn.d_tag == DT_NEEDED)
+ {
+ const char *string;
+ struct bfd_link_needed_list *l;
+
+ string = bfd_elf_string_from_elf_section (abfd, link,
+ dyn.d_un.d_val);
+ if (string == NULL)
+ goto error_return;
+
+ l = (struct bfd_link_needed_list *) bfd_alloc (abfd, sizeof *l);
+ if (l == NULL)
+ goto error_return;
+
+ l->by = abfd;
+ l->name = string;
+ l->next = *pneeded;
+ *pneeded = l;
+ }
+ }
+
+ free (dynbuf);
+
+ return true;
+
+ error_return:
+ if (dynbuf != NULL)
+ free (dynbuf);
+ return false;
+}
\f
/* Allocate an ELF string table--force the first byte to be zero. */
{
asection *target_sect;
Elf_Internal_Shdr *hdr2;
- int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
/* For some incomprehensible reason Oracle distributes
libraries for Solaris in which some of the objects have
if (hdr->sh_link != elf_onesymtab (abfd))
return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
- /* Don't allow REL relocations on a machine that uses RELA and
- vice versa. */
- /* @@ Actually, the generic ABI does suggest that both might be
- used in one file. But the four ABI Processor Supplements I
- have access to right now all specify that only one is used on
- each of those architectures. It's conceivable that, e.g., a
- bunch of absolute 32-bit relocs might be more compact in REL
- form even on a RELA machine... */
- BFD_ASSERT (use_rela_p
- ? (hdr->sh_type == SHT_RELA
- && hdr->sh_entsize == bed->s->sizeof_rela)
- : (hdr->sh_type == SHT_REL
- && hdr->sh_entsize == bed->s->sizeof_rel));
-
if (! bfd_section_from_shdr (abfd, hdr->sh_info))
return false;
target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info);
if (target_sect == NULL)
return false;
- hdr2 = &elf_section_data (target_sect)->rel_hdr;
+ if ((target_sect->flags & SEC_RELOC) == 0
+ || target_sect->reloc_count == 0)
+ hdr2 = &elf_section_data (target_sect)->rel_hdr;
+ else
+ {
+ BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL);
+ hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
+ elf_section_data (target_sect)->rel_hdr2 = hdr2;
+ }
*hdr2 = *hdr;
elf_elfsections (abfd)[shindex] = hdr2;
- target_sect->reloc_count = hdr->sh_size / hdr->sh_entsize;
+ target_sect->reloc_count += hdr->sh_size / hdr->sh_entsize;
target_sect->flags |= SEC_RELOC;
target_sect->relocation = NULL;
target_sect->rel_filepos = hdr->sh_offset;
}
break;
+ case SHT_GNU_verdef:
+ elf_dynverdef (abfd) = shindex;
+ elf_tdata (abfd)->dynverdef_hdr = *hdr;
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+ break;
+
+ case SHT_GNU_versym:
+ elf_dynversym (abfd) = shindex;
+ elf_tdata (abfd)->dynversym_hdr = *hdr;
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+ break;
+
+ case SHT_GNU_verneed:
+ elf_dynverref (abfd) = shindex;
+ elf_tdata (abfd)->dynverref_hdr = *hdr;
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+ break;
+
case SHT_SHLIB:
return true;
char namebuf[64];
int split;
- split = ((hdr->p_memsz > 0) &&
- (hdr->p_filesz > 0) &&
- (hdr->p_memsz > hdr->p_filesz));
+ split = ((hdr->p_memsz > 0)
+ && (hdr->p_filesz > 0)
+ && (hdr->p_memsz > hdr->p_filesz));
sprintf (namebuf, split ? "segment%da" : "segment%d", index);
name = bfd_alloc (abfd, strlen (namebuf) + 1);
if (!name)
this_hdr->sh_flags = 0;
- if ((asect->flags & SEC_ALLOC) != 0)
+ if ((asect->flags & SEC_ALLOC) != 0
+ || asect->user_set_vma)
this_hdr->sh_addr = asect->vma;
else
this_hdr->sh_addr = 0;
this_hdr->sh_type = SHT_REL;
this_hdr->sh_entsize = bed->s->sizeof_rel;
}
- else if (strcmp (asect->name, ".note") == 0)
+ else if (strncmp (asect->name, ".note", 5) == 0)
this_hdr->sh_type = SHT_NOTE;
else if (strncmp (asect->name, ".stab", 5) == 0
&& strcmp (asect->name + strlen (asect->name) - 3, "str") == 0)
this_hdr->sh_type = SHT_STRTAB;
+ else if (strcmp (asect->name, ".gnu.version") == 0)
+ {
+ this_hdr->sh_type = SHT_GNU_versym;
+ this_hdr->sh_entsize = sizeof (Elf_External_Versym);
+ }
+ else if (strcmp (asect->name, ".gnu.version_d") == 0)
+ {
+ this_hdr->sh_type = SHT_GNU_verdef;
+ this_hdr->sh_entsize = 0;
+ /* objcopy or strip will copy over sh_info, but may not set
+ cverdefs. The linker will set cverdefs, but sh_info will be
+ zero. */
+ if (this_hdr->sh_info == 0)
+ this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->cverdefs == 0
+ || this_hdr->sh_info == elf_tdata (abfd)->cverdefs);
+ }
+ else if (strcmp (asect->name, ".gnu.version_r") == 0)
+ {
+ this_hdr->sh_type = SHT_GNU_verneed;
+ this_hdr->sh_entsize = 0;
+ /* objcopy or strip will copy over sh_info, but may not set
+ cverrefs. The linker will set cverrefs, but sh_info will be
+ zero. */
+ if (this_hdr->sh_info == 0)
+ this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0
+ || this_hdr->sh_info == elf_tdata (abfd)->cverrefs);
+ }
else if ((asect->flags & SEC_ALLOC) != 0
&& (asect->flags & SEC_LOAD) != 0)
this_hdr->sh_type = SHT_PROGBITS;
case SHT_DYNAMIC:
case SHT_DYNSYM:
+ case SHT_GNU_verneed:
+ case SHT_GNU_verdef:
/* sh_link is the section header index of the string table
- used for the dynamic entries or symbol table. */
+ used for the dynamic entries, or the symbol table, or the
+ version strings. */
s = bfd_get_section_by_name (abfd, ".dynstr");
if (s != NULL)
d->this_hdr.sh_link = elf_section_data (s)->this_idx;
break;
case SHT_HASH:
+ case SHT_GNU_versym:
/* sh_link is the section header index of the symbol table
- this hash table is for. */
+ this hash table or version table is for. */
s = bfd_get_section_by_name (abfd, ".dynsym");
if (s != NULL)
d->this_hdr.sh_link = elf_section_data (s)->this_idx;
for (idx = 0; idx < symcount; idx++)
{
if ((syms[idx]->flags & BSF_SECTION_SYM) != 0
- && (syms[idx]->value + syms[idx]->section->vma) == 0)
+ && syms[idx]->value == 0)
{
asection *sec;
num_sections++;
#ifdef DEBUG
fprintf (stderr,
- "creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n",
+ _("creating section symbol, name = %s, value = 0x%.8lx, index = %d, section = 0x%.8lx\n"),
asect->name, (long) asect->vma, asect->index, (long) asect);
#endif
}
/* The backend linker builds symbol table information itself. */
if (link_info == NULL && abfd->symcount > 0)
{
- if (! swap_out_syms (abfd, &strtab))
+ /* Non-zero if doing a relocatable link. */
+ int relocatable_p = ! (abfd->flags & (EXEC_P | DYNAMIC));
+
+ if (! swap_out_syms (abfd, &strtab, relocatable_p))
return false;
}
unsigned int phdr_index;
bfd_vma maxpagesize;
asection **hdrpp;
- boolean phdr_in_section = true;
+ boolean phdr_in_segment = true;
boolean writable;
asection *dynsec;
&& (dynsec->flags & SEC_LOAD) == 0)
dynsec = NULL;
- /* Deal with -Ttext or something similar such that the
- first section is not adjacent to the program headers. */
- if (count
- && ((sections[0]->lma % maxpagesize) <
- (elf_tdata (abfd)->program_header_size % maxpagesize)))
- phdr_in_section = false;
+ /* Deal with -Ttext or something similar such that the first section
+ is not adjacent to the program headers. This is an
+ approximation, since at this point we don't know exactly how many
+ program headers we will need. */
+ if (count > 0)
+ {
+ bfd_size_type phdr_size;
+
+ phdr_size = elf_tdata (abfd)->program_header_size;
+ if (phdr_size == 0)
+ phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr;
+ if ((abfd->flags & D_PAGED) == 0
+ || sections[0]->lma < phdr_size
+ || sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
+ phdr_in_segment = false;
+ }
for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
{
asection *hdr;
+ boolean new_segment;
hdr = *hdrpp;
/* See if this section and the last one will fit in the same
- segment. Don't put a loadable section after a non-loadable
- section. If we are building a dynamic executable, don't put
- a writable section in a read only segment (we don't do this
- for a non-dynamic executable because some people prefer to
- have only one program segment; anybody can use PHDRS in their
- linker script to control what happens anyhow). */
- if (last_hdr == NULL
- || ((BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
- >= hdr->lma)
- && ((last_hdr->flags & SEC_LOAD) != 0
- || (hdr->flags & SEC_LOAD) == 0)
- && (dynsec == NULL
- || writable
- || (hdr->flags & SEC_READONLY) != 0)))
+ segment. */
+
+ if (last_hdr == NULL)
+ {
+ /* If we don't have a segment yet, then we don't need a new
+ one (we build the last one after this loop). */
+ new_segment = false;
+ }
+ else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma)
+ {
+ /* If this section has a different relation between the
+ virtual address and the load address, then we need a new
+ segment. */
+ new_segment = true;
+ }
+ else if (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
+ < BFD_ALIGN (hdr->lma, maxpagesize))
+ {
+ /* If putting this section in this segment would force us to
+ skip a page in the segment, then we need a new segment. */
+ new_segment = true;
+ }
+ else if ((last_hdr->flags & SEC_LOAD) == 0
+ && (hdr->flags & SEC_LOAD) != 0)
+ {
+ /* We don't want to put a loadable section after a
+ nonloadable section in the same segment. */
+ new_segment = true;
+ }
+ else if ((abfd->flags & D_PAGED) == 0)
+ {
+ /* If the file is not demand paged, which means that we
+ don't require the sections to be correctly aligned in the
+ file, then there is no other reason for a new segment. */
+ new_segment = false;
+ }
+ else if (! writable
+ && (hdr->flags & SEC_READONLY) == 0
+ && (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize)
+ == hdr->lma))
+ {
+ /* We don't want to put a writable section in a read only
+ segment, unless they are on the same page in memory
+ anyhow. We already know that the last section does not
+ bring us past the current section on the page, so the
+ only case in which the new section is not on the same
+ page as the previous section is when the previous section
+ ends precisely on a page boundary. */
+ new_segment = true;
+ }
+ else
{
+ /* Otherwise, we can use the same segment. */
+ new_segment = false;
+ }
+
+ if (! new_segment)
+ {
+ if ((hdr->flags & SEC_READONLY) == 0)
+ writable = true;
last_hdr = hdr;
continue;
}
- /* This section won't fit in the program segment. We must
- create a new program header holding all the sections from
- phdr_index until hdr. */
+ /* We need a new program segment. We must create a new program
+ header holding all the sections from phdr_index until hdr. */
- m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section);
+ m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
if (m == NULL)
goto error_return;
if ((hdr->flags & SEC_READONLY) == 0)
writable = true;
+ else
+ writable = false;
last_hdr = hdr;
phdr_index = i;
- phdr_in_section = false;
+ phdr_in_segment = false;
}
/* Create a final PT_LOAD program segment. */
if (last_hdr != NULL)
{
- m = make_mapping (abfd, sections, phdr_index, i, phdr_in_section);
+ m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
if (m == NULL)
goto error_return;
pm = &m->next;
}
+ /* For each loadable .note section, add a PT_NOTE segment. We don't
+ use bfd_get_section_by_name, because if we link together
+ nonloadable .note sections and loadable .note sections, we will
+ generate two .note sections in the output file. FIXME: Using
+ names for section types is bogus anyhow. */
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) != 0
+ && strncmp (s->name, ".note", 5) == 0)
+ {
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_NOTE;
+ m->count = 1;
+ m->sections[0] = s;
+
+ *pm = m;
+ pm = &m->next;
+ }
+ }
+
free (sections);
sections = NULL;
return false;
}
-/* Sort sections by VMA. */
+/* Sort sections by address. */
static int
elf_sort_sections (arg1, arg2)
const asection *sec1 = *(const asection **) arg1;
const asection *sec2 = *(const asection **) arg2;
+ /* Sort by LMA first, since this is the address used to
+ place the section into a segment. */
+ if (sec1->lma < sec2->lma)
+ return -1;
+ else if (sec1->lma > sec2->lma)
+ return 1;
+
+ /* Then sort by VMA. Normally the LMA and the VMA will be
+ the same, and this will do nothing. */
if (sec1->vma < sec2->vma)
return -1;
else if (sec1->vma > sec2->vma)
#define TOEND(x) (((x)->flags & SEC_LOAD) == 0)
if (TOEND (sec1))
- if (TOEND (sec2))
- return sec1->target_index - sec2->target_index;
- else
- return 1;
+ {
+ if (TOEND (sec2))
+ return sec1->target_index - sec2->target_index;
+ else
+ return 1;
+ }
if (TOEND (sec2))
return -1;
struct elf_segment_map *m;
unsigned int alloc;
Elf_Internal_Phdr *phdrs;
- file_ptr off;
+ file_ptr off, voff;
bfd_vma filehdr_vaddr, filehdr_paddr;
bfd_vma phdrs_vaddr, phdrs_paddr;
Elf_Internal_Phdr *p;
if (alloc != 0 && count > alloc)
{
((*_bfd_error_handler)
- ("%s: Not enough room for program headers (allocated %u, need %u)",
+ (_("%s: Not enough room for program headers (allocated %u, need %u)"),
bfd_get_filename (abfd), alloc, count));
bfd_set_error (bfd_error_bad_value);
return false;
filehdr_paddr = 0;
phdrs_vaddr = 0;
phdrs_paddr = 0;
+
for (m = elf_tdata (abfd)->segment_map, p = phdrs;
m != NULL;
m = m->next, p++)
if (p->p_type == PT_LOAD
&& m->count > 0
- && (m->sections[0]->flags & SEC_LOAD) != 0)
- off += (m->sections[0]->vma - off) % bed->maxpagesize;
+ && (m->sections[0]->flags & SEC_ALLOC) != 0)
+ {
+ if ((abfd->flags & D_PAGED) != 0)
+ off += (m->sections[0]->vma - off) % bed->maxpagesize;
+ else
+ off += ((m->sections[0]->vma - off)
+ % (1 << bfd_get_section_alignment (abfd, m->sections[0])));
+ }
if (m->count == 0)
p->p_vaddr = 0;
else
p->p_paddr = m->sections[0]->lma;
- if (p->p_type == PT_LOAD)
+ if (p->p_type == PT_LOAD
+ && (abfd->flags & D_PAGED) != 0)
p->p_align = bed->maxpagesize;
else if (m->count == 0)
p->p_align = bed->s->file_align;
if (m->count > 0)
{
BFD_ASSERT (p->p_type == PT_LOAD);
+
+ if (p->p_vaddr < (bfd_vma) off)
+ {
+ _bfd_error_handler (_("%s: Not enough room for program headers, try linking with -N"),
+ bfd_get_filename (abfd));
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
p->p_vaddr -= off;
if (! m->p_paddr_valid)
p->p_paddr -= off;
{
if (! m->p_flags_valid)
p->p_flags |= PF_R;
+
if (m->includes_filehdr)
{
if (p->p_type == PT_LOAD)
else
{
p->p_offset = bed->s->sizeof_ehdr;
+
if (m->count > 0)
{
BFD_ASSERT (p->p_type == PT_LOAD);
if (! m->p_paddr_valid)
p->p_paddr -= off - p->p_offset;
}
+
if (p->p_type == PT_LOAD)
{
phdrs_vaddr = p->p_vaddr;
phdrs_paddr = p->p_paddr;
}
+ else
+ phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
}
+
p->p_filesz += alloc * bed->s->sizeof_phdr;
p->p_memsz += alloc * bed->s->sizeof_phdr;
}
- if (p->p_type == PT_LOAD)
+ if (p->p_type == PT_LOAD
+ || (p->p_type == PT_NOTE && abfd->format == bfd_core))
{
if (! m->includes_filehdr && ! m->includes_phdrs)
p->p_offset = off;
}
}
+ voff = off;
+
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
{
asection *sec;
sec = *secpp;
flags = sec->flags;
+ align = 1 << bfd_get_section_alignment (abfd, sec);
+
+ /* The section may have artificial alignment forced by a
+ link script. Notice this case by the gap between the
+ cumulative phdr vma and the section's vma. */
+ if (p->p_vaddr + p->p_memsz < sec->vma)
+ {
+ bfd_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz);
+
+ p->p_memsz += adjust;
+ off += adjust;
+ voff += adjust;
+ if ((flags & SEC_LOAD) != 0)
+ p->p_filesz += adjust;
+ }
if (p->p_type == PT_LOAD)
{
- bfd_vma adjust;
+ bfd_signed_vma adjust;
- /* The section VMA must equal the file position modulo
- the page size. */
- if ((flags & SEC_ALLOC) != 0)
+ if ((flags & SEC_LOAD) != 0)
+ {
+ adjust = sec->lma - (p->p_paddr + p->p_memsz);
+ if (adjust < 0)
+ adjust = 0;
+ }
+ else if ((flags & SEC_ALLOC) != 0)
{
- adjust = (sec->vma - off) % bed->maxpagesize;
- if (adjust != 0)
+ /* The section VMA must equal the file position
+ modulo the page size. FIXME: I'm not sure if
+ this adjustment is really necessary. We used to
+ not have the SEC_LOAD case just above, and then
+ this was necessary, but now I'm not sure. */
+ if ((abfd->flags & D_PAGED) != 0)
+ adjust = (sec->vma - voff) % bed->maxpagesize;
+ else
+ adjust = (sec->vma - voff) % align;
+ }
+ else
+ adjust = 0;
+
+ if (adjust != 0)
+ {
+ if (i == 0)
{
- if (i == 0)
- abort ();
- p->p_memsz += adjust;
- off += adjust;
- if ((flags & SEC_LOAD) != 0)
- p->p_filesz += adjust;
+ (* _bfd_error_handler)
+ (_("Error: First section in segment (%s) starts at 0x%x"),
+ bfd_section_name (abfd, sec), sec->lma);
+ (* _bfd_error_handler)
+ (_(" whereas segment starts at 0x%x"),
+ p->p_paddr);
+
+ return false;
}
+ p->p_memsz += adjust;
+ off += adjust;
+ voff += adjust;
+ if ((flags & SEC_LOAD) != 0)
+ p->p_filesz += adjust;
}
sec->filepos = off;
- if ((flags & SEC_LOAD) != 0)
+ /* We check SEC_HAS_CONTENTS here because if NOLOAD is
+ used in a linker script we may have a section with
+ SEC_LOAD clear but which is supposed to have
+ contents. */
+ if ((flags & SEC_LOAD) != 0
+ || (flags & SEC_HAS_CONTENTS) != 0)
off += sec->_raw_size;
+
+ if ((flags & SEC_ALLOC) != 0)
+ voff += sec->_raw_size;
}
- p->p_memsz += sec->_raw_size;
+ if (p->p_type == PT_NOTE && abfd->format == bfd_core)
+ {
+ if (i == 0) /* the actual "note" segment */
+ { /* this one actually contains everything. */
+ sec->filepos = off;
+ p->p_filesz = sec->_raw_size;
+ off += sec->_raw_size;
+ voff = off;
+ }
+ else /* fake sections -- don't need to be written */
+ {
+ sec->filepos = 0;
+ sec->_raw_size = 0;
+ flags = sec->flags = 0; /* no contents */
+ }
+ p->p_memsz = 0;
+ p->p_align = 1;
+ }
+ else
+ {
+ p->p_memsz += sec->_raw_size;
- if ((flags & SEC_LOAD) != 0)
- p->p_filesz += sec->_raw_size;
+ if ((flags & SEC_LOAD) != 0)
+ p->p_filesz += sec->_raw_size;
- align = 1 << bfd_get_section_alignment (abfd, sec);
- if (align > p->p_align)
- p->p_align = align;
+ if (align > p->p_align)
+ p->p_align = align;
+ }
if (! m->p_flags_valid)
{
++segs;
}
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) != 0
+ && strncmp (s->name, ".note", 5) == 0)
+ {
+ /* We need a PT_NOTE segment. */
+ ++segs;
+ }
+ }
+
/* Let the backend count up any program headers it might need. */
if (bed->elf_backend_additional_program_headers)
{
file_ptr off;
struct elf_backend_data *bed = get_elf_backend_data (abfd);
- if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0
+ && abfd->format != bfd_core)
{
Elf_Internal_Shdr **hdrpp;
unsigned int i;
hdr->sh_offset = -1;
continue;
}
-
+
off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
}
}
else if ((hdr->sh_flags & SHF_ALLOC) != 0)
{
((*_bfd_error_handler)
- ("%s: warning: allocated section `%s' not in segment",
+ (_("%s: warning: allocated section `%s' not in segment"),
bfd_get_filename (abfd),
(hdr->bfd_section == NULL
? "*unknown*"
: hdr->bfd_section->name)));
- off += (hdr->sh_addr - off) % bed->maxpagesize;
+ if ((abfd->flags & D_PAGED) != 0)
+ off += (hdr->sh_addr - off) % bed->maxpagesize;
+ else
+ off += (hdr->sh_addr - off) % hdr->sh_addralign;
off = _bfd_elf_assign_file_position_for_section (hdr, off,
false);
}
hdr->sh_offset = -1;
else
off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
- }
+ }
}
/* Place the section headers. */
bfd *abfd;
{
Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
- Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
+ Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
int count;
struct bfd_strtab_hash *shstrtab;
i_ehdrp->e_type = ET_DYN;
else if ((abfd->flags & EXEC_P) != 0)
i_ehdrp->e_type = ET_EXEC;
+ else if (bfd_get_format (abfd) == bfd_core)
+ i_ehdrp->e_type = ET_CORE;
else
i_ehdrp->e_type = ET_REL;
break;
case bfd_arch_sparc:
if (bed->s->arch_size == 64)
- i_ehdrp->e_machine = EM_SPARC64;
+ i_ehdrp->e_machine = EM_SPARCV9;
else
i_ehdrp->e_machine = EM_SPARC;
break;
case bfd_arch_powerpc:
i_ehdrp->e_machine = EM_PPC;
break;
-/* start-sanitize-arc */
- case bfd_arch_arc:
+ case bfd_arch_alpha:
+ i_ehdrp->e_machine = EM_ALPHA;
+ break;
+ case bfd_arch_sh:
+ i_ehdrp->e_machine = EM_SH;
+ break;
+ case bfd_arch_d10v:
+ i_ehdrp->e_machine = EM_CYGNUS_D10V;
+ break;
+ case bfd_arch_d30v:
+ i_ehdrp->e_machine = EM_CYGNUS_D30V;
+ break;
+ case bfd_arch_fr30:
+ i_ehdrp->e_machine = EM_CYGNUS_FR30;
+ break;
+ case bfd_arch_v850:
+ switch (bfd_get_mach (abfd))
+ {
+ default:
+ case 0: i_ehdrp->e_machine = EM_CYGNUS_V850; break;
+ }
+ break;
+ case bfd_arch_arc:
i_ehdrp->e_machine = EM_CYGNUS_ARC;
break;
-/* end-sanitize-arc */
+ case bfd_arch_arm:
+ i_ehdrp->e_machine = EM_ARM;
+ break;
+ case bfd_arch_m32r:
+ i_ehdrp->e_machine = EM_CYGNUS_M32R;
+ break;
+ case bfd_arch_mn10200:
+ i_ehdrp->e_machine = EM_CYGNUS_MN10200;
+ break;
+ case bfd_arch_mn10300:
+ i_ehdrp->e_machine = EM_CYGNUS_MN10300;
+ break;
/* also note that EM_M32, AT&T WE32100 is unknown to bfd */
default:
i_ehdrp->e_machine = EM_NONE;
unsigned int count;
if (! abfd->output_has_begun
- && ! _bfd_elf_compute_section_file_positions (abfd,
- (struct bfd_link_info *) NULL))
+ && ! _bfd_elf_compute_section_file_positions
+ (abfd, (struct bfd_link_info *) NULL))
return false;
i_shdrp = elf_elfsections (abfd);
bfd_map_over_sections (abfd, bed->s->write_relocs, &failed);
if (failed)
return false;
+
_bfd_elf_assign_file_positions_for_relocs (abfd);
/* After writing the headers, we need to write the sections too... */
return bed->s->write_shdrs_and_ehdr (abfd);
}
+boolean
+_bfd_elf_write_corefile_contents (abfd)
+ bfd *abfd;
+{
+ /* Hopefully this can be done just like an object file. */
+ return _bfd_elf_write_object_contents (abfd);
+}
/* given a section, search the header to find them... */
int
_bfd_elf_section_from_bfd_section (abfd, asect)
if (bfd_is_und_section (asect))
return SHN_UNDEF;
+ bfd_set_error (bfd_error_nonrepresentable_section);
+
return -1;
}
int
_bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
bfd *abfd;
- struct symbol_cache_entry **asym_ptr_ptr;
+ asymbol **asym_ptr_ptr;
{
- struct symbol_cache_entry *asym_ptr = *asym_ptr_ptr;
+ asymbol *asym_ptr = *asym_ptr_ptr;
int idx;
flagword flags = asym_ptr->flags;
/* This case can occur when using --strip-symbol on a symbol
which is used in a relocation entry. */
(*_bfd_error_handler)
- ("%s: symbol `%s' required but not present",
+ (_("%s: symbol `%s' required but not present"),
bfd_get_filename (abfd), bfd_asymbol_name (asym_ptr));
bfd_set_error (bfd_error_no_symbols);
return -1;
#if DEBUG & 4
{
fprintf (stderr,
- "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n",
+ _("elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n"),
(long) asym_ptr, asym_ptr->name, idx, flags,
elf_symbol_flags (flags));
fflush (stderr);
Elf_Internal_Ehdr *iehdr;
struct elf_segment_map *mfirst;
struct elf_segment_map **pm;
+ struct elf_segment_map *m;
Elf_Internal_Phdr *p;
- unsigned int i, c;
+ unsigned int i;
+ unsigned int num_segments;
+ boolean phdr_included = false;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
mfirst = NULL;
pm = &mfirst;
- c = elf_elfheader (ibfd)->e_phnum;
- for (i = 0, p = elf_tdata (ibfd)->phdr; i < c; i++, p++)
+ num_segments = elf_elfheader (ibfd)->e_phnum;
+
+#define IS_CONTAINED_BY(addr, len, bottom, phdr) \
+ ((addr) >= (bottom) \
+ && ( ((addr) + (len)) <= ((bottom) + (phdr)->p_memsz) \
+ || ((addr) + (len)) <= ((bottom) + (phdr)->p_filesz)))
+
+ /* Special case: corefile "NOTE" section containing regs, prpsinfo etc. */
+
+#define IS_COREFILE_NOTE(p, s) \
+ (p->p_type == PT_NOTE \
+ && ibfd->format == bfd_core \
+ && s->vma == 0 && s->lma == 0 \
+ && (bfd_vma) s->filepos >= p->p_offset \
+ && (bfd_vma) s->filepos + s->_raw_size \
+ <= p->p_offset + p->p_filesz)
+
+ /* The complicated case when p_vaddr is 0 is to handle the Solaris
+ linker, which generates a PT_INTERP section with p_vaddr and
+ p_memsz set to 0. */
+
+#define IS_SOLARIS_PT_INTERP(p, s) \
+ (p->p_vaddr == 0 \
+ && p->p_filesz > 0 \
+ && (s->flags & SEC_HAS_CONTENTS) != 0 \
+ && s->_raw_size > 0 \
+ && (bfd_vma) s->filepos >= p->p_offset \
+ && ((bfd_vma) s->filepos + s->_raw_size \
+ <= p->p_offset + p->p_filesz))
+
+ /* Scan through the segments specified in the program header
+ of the input BFD. */
+ for (i = 0, p = elf_tdata (ibfd)->phdr; i < num_segments; i++, p++)
{
unsigned int csecs;
asection *s;
- struct elf_segment_map *m;
+ asection **sections;
+ asection *os;
unsigned int isec;
-
+ bfd_vma matching_lma;
+ bfd_vma suggested_lma;
+ unsigned int j;
+
+ /* For each section in the input BFD, decide if it should be
+ included in the current segment. A section will be included
+ if it is within the address space of the segment, and it is
+ an allocated segment, and there is an output section
+ associated with it. */
csecs = 0;
-
- /* The complicated case when p_vaddr is 0 is to handle the
- Solaris linker, which generates a PT_INTERP section with
- p_vaddr and p_memsz set to 0. */
for (s = ibfd->sections; s != NULL; s = s->next)
- if (((s->vma >= p->p_vaddr
- && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz
- || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz))
- || (p->p_vaddr == 0
- && p->p_filesz > 0
- && (s->flags & SEC_HAS_CONTENTS) != 0
- && (bfd_vma) s->filepos >= p->p_offset
- && ((bfd_vma) s->filepos + s->_raw_size
- <= p->p_offset + p->p_filesz)))
- && (s->flags & SEC_ALLOC) != 0
- && s->output_section != NULL)
- ++csecs;
+ if (s->output_section != NULL)
+ {
+ if ((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
+ || IS_SOLARIS_PT_INTERP (p, s))
+ && (s->flags & SEC_ALLOC) != 0)
+ ++csecs;
+ else if (IS_COREFILE_NOTE (p, s))
+ ++csecs;
+ }
+ /* Allocate a segment map big enough to contain all of the
+ sections we have selected. */
m = ((struct elf_segment_map *)
bfd_alloc (obfd,
(sizeof (struct elf_segment_map)
- + (csecs - 1) * sizeof (asection *))));
+ + ((size_t) csecs - 1) * sizeof (asection *))));
if (m == NULL)
return false;
- m->next = NULL;
- m->p_type = p->p_type;
- m->p_flags = p->p_flags;
+ /* Initialise the fields of the segment map. Default to
+ using the physical address of the segment in the input BFD. */
+ m->next = NULL;
+ m->p_type = p->p_type;
+ m->p_flags = p->p_flags;
m->p_flags_valid = 1;
- m->p_paddr = p->p_paddr;
+ m->p_paddr = p->p_paddr;
m->p_paddr_valid = 1;
+ /* Determine if this segment contains the ELF file header
+ and if it contains the program headers themselves. */
m->includes_filehdr = (p->p_offset == 0
&& p->p_filesz >= iehdr->e_ehsize);
- m->includes_phdrs = (p->p_offset <= (bfd_vma) iehdr->e_phoff
- && (p->p_offset + p->p_filesz
- >= ((bfd_vma) iehdr->e_phoff
- + iehdr->e_phnum * iehdr->e_phentsize)));
+ if (! phdr_included || p->p_type != PT_LOAD)
+ {
+ m->includes_phdrs =
+ (p->p_offset <= (bfd_vma) iehdr->e_phoff
+ && (p->p_offset + p->p_filesz
+ >= ((bfd_vma) iehdr->e_phoff
+ + iehdr->e_phnum * iehdr->e_phentsize)));
+ if (p->p_type == PT_LOAD && m->includes_phdrs)
+ phdr_included = true;
+ }
+
+ if (csecs == 0)
+ {
+ /* Special segments, such as the PT_PHDR segment, may contain
+ no sections, but ordinary, loadable segments should contain
+ something. */
+
+ if (p->p_type == PT_LOAD)
+ _bfd_error_handler
+ (_("%s: warning: Empty loadable segment detected\n"),
+ bfd_get_filename (ibfd));
+
+ m->count = 0;
+ *pm = m;
+ pm = &m->next;
+
+ continue;
+ }
+
+ /* Now scan the sections in the input BFD again and attempt
+ to add their corresponding output sections to the segment map.
+ The problem here is how to handle an output section which has
+ been moved (ie had its LMA changed). There are four possibilities:
+
+ 1. None of the sections have been moved.
+ In this case we can continue to use the segment LMA from the
+ input BFD.
+
+ 2. All of the sections have been moved by the same amount.
+ In this case we can change the segment's LMA to match the LMA
+ of the first section.
+
+ 3. Some of the sections have been moved, others have not.
+ In this case those sections which have not been moved can be
+ placed in the current segment which will have to have its size,
+ and possibly its LMA changed, and a new segment or segments will
+ have to be created to contain the other sections.
+
+ 4. The sections have been moved, but not be the same amount.
+ In this case we can change the segment's LMA to match the LMA
+ of the first section and we will have to create a new segment
+ or segments to contain the other sections.
+
+ In order to save time, we allocate an array to hold the section
+ pointers that we are interested in. As these sections get assigned
+ to a segment, they are removed from this array. */
+
+ sections = (asection **) bfd_malloc (sizeof (asection *) * csecs);
+ if (sections == NULL)
+ return false;
+
+ /* Step One: Scan for segment vs section LMA conflicts.
+ Also add the sections to the section array allocated above.
+ Also add the sections to the current segment. In the common
+ case, where the sections have not been moved, this means that
+ we have completely filled the segment, and there is nothing
+ more to do. */
isec = 0;
- for (s = ibfd->sections; s != NULL; s = s->next)
+ matching_lma = false;
+ suggested_lma = 0;
+
+ for (j = 0, s = ibfd->sections; s != NULL; s = s->next)
{
- if (((s->vma >= p->p_vaddr
- && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz
- || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz))
- || (p->p_vaddr == 0
- && p->p_filesz > 0
- && (s->flags & SEC_HAS_CONTENTS) != 0
- && (bfd_vma) s->filepos >= p->p_offset
- && ((bfd_vma) s->filepos + s->_raw_size
- <= p->p_offset + p->p_filesz)))
- && (s->flags & SEC_ALLOC) != 0
- && s->output_section != NULL)
+ os = s->output_section;
+
+ if ((((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
+ || IS_SOLARIS_PT_INTERP (p, s))
+ && (s->flags & SEC_ALLOC) != 0)
+ || IS_COREFILE_NOTE (p, s))
+ && os != NULL)
{
- m->sections[isec] = s->output_section;
- ++isec;
+ sections[j++] = s;
+
+ /* The Solaris native linker always sets p_paddr to 0.
+ We try to catch that case here, and set it to the
+ correct value. */
+ if (p->p_paddr == 0
+ && p->p_vaddr != 0
+ && isec == 0
+ && os->lma != 0
+ && (os->vma == (p->p_vaddr
+ + (m->includes_filehdr
+ ? iehdr->e_ehsize
+ : 0)
+ + (m->includes_phdrs
+ ? iehdr->e_phnum * iehdr->e_phentsize
+ : 0))))
+ m->p_paddr = p->p_vaddr;
+
+ /* Match up the physical address of the segment with the
+ LMA address of the output section. */
+ if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p)
+ || IS_COREFILE_NOTE (p, s))
+ {
+ if (matching_lma == 0)
+ matching_lma = os->lma;
+
+ /* We assume that if the section fits within the segment
+ that it does not overlap any other section within that
+ segment. */
+ m->sections[isec++] = os;
+ }
+ else if (suggested_lma == 0)
+ suggested_lma = os->lma;
}
}
- BFD_ASSERT (isec == csecs);
- m->count = csecs;
- *pm = m;
- pm = &m->next;
+ BFD_ASSERT (j == csecs);
+
+ /* Step Two: Adjust the physical address of the current segment,
+ if necessary. */
+ if (isec == csecs)
+ {
+ /* All of the sections fitted within the segment as currently
+ specified. This is the default case. Add the segment to
+ the list of built segments and carry on to process the next
+ program header in the input BFD. */
+ m->count = csecs;
+ *pm = m;
+ pm = &m->next;
+
+ free (sections);
+ continue;
+ }
+ else if (matching_lma != 0)
+ {
+ /* At least one section fits inside the current segment.
+ Keep it, but modify its physical address to match the
+ LMA of the first section that fitted. */
+
+ m->p_paddr = matching_lma;
+ }
+ else
+ {
+ /* None of the sections fitted inside the current segment.
+ Change the current segment's physical address to match
+ the LMA of the first section. */
+
+ m->p_paddr = suggested_lma;
+ }
+
+ /* Step Three: Loop over the sections again, this time assigning
+ those that fit to the current segment and remvoing them from the
+ sections array; but making sure not to leave large gaps. Once all
+ possible sections have been assigned to the current segment it is
+ added to the list of built segments and if sections still remain
+ to be assigned, a new segment is constructed before repeating
+ the loop. */
+ isec = 0;
+ do
+ {
+ m->count = 0;
+ suggested_lma = 0;
+
+ /* Fill the current segment with sections that fit. */
+ for (j = 0; j < csecs; j++)
+ {
+ s = sections[j];
+
+ if (s == NULL)
+ continue;
+
+ os = s->output_section;
+
+ if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p)
+ || IS_COREFILE_NOTE (p, s))
+ {
+ if (m->count == 0)
+ {
+ /* If the first section in a segment does not start at
+ the beginning of the segment, then something is wrong. */
+ if (os->lma != m->p_paddr)
+ abort ();
+ }
+ else
+ {
+ asection * prev_sec;
+ bfd_vma maxpagesize;
+
+ prev_sec = m->sections[m->count - 1];
+ maxpagesize = get_elf_backend_data (obfd)->maxpagesize;
+
+ /* If the gap between the end of the previous section
+ and the start of this section is more than maxpagesize
+ then we need to start a new segment. */
+ if (BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size, maxpagesize)
+ < BFD_ALIGN (os->lma, maxpagesize))
+ {
+ if (suggested_lma == 0)
+ suggested_lma = os->lma;
+
+ continue;
+ }
+ }
+
+ m->sections[m->count++] = os;
+ ++isec;
+ sections[j] = NULL;
+ }
+ else if (suggested_lma == 0)
+ suggested_lma = os->lma;
+ }
+
+ BFD_ASSERT (m->count > 0);
+
+ /* Add the current segment to the list of built segments. */
+ *pm = m;
+ pm = &m->next;
+
+ if (isec < csecs)
+ {
+ /* We still have not allocated all of the sections to
+ segments. Create a new segment here, initialise it
+ and carry on looping. */
+
+ m = ((struct elf_segment_map *)
+ bfd_alloc (obfd,
+ (sizeof (struct elf_segment_map)
+ + ((size_t) csecs - 1) * sizeof (asection *))));
+ if (m == NULL)
+ return false;
+
+ /* Initialise the fields of the segment map. Set the physical
+ physical address to the LMA of the first section that has
+ not yet been assigned. */
+
+ m->next = NULL;
+ m->p_type = p->p_type;
+ m->p_flags = p->p_flags;
+ m->p_flags_valid = 1;
+ m->p_paddr = suggested_lma;
+ m->p_paddr_valid = 1;
+ m->includes_filehdr = 0;
+ m->includes_phdrs = 0;
+ }
+ }
+ while (isec < csecs);
+
+ free (sections);
+ }
+
+ /* The Solaris linker creates program headers in which all the
+ p_paddr fields are zero. When we try to objcopy or strip such a
+ file, we get confused. Check for this case, and if we find it
+ reset the p_paddr_valid fields. */
+ for (m = mfirst; m != NULL; m = m->next)
+ if (m->p_paddr != 0)
+ break;
+ if (m == NULL)
+ {
+ for (m = mfirst; m != NULL; m = m->next)
+ m->p_paddr_valid = 0;
}
elf_tdata (obfd)->segment_map = mfirst;
+#if 0
+ /* Final Step: Sort the segments into ascending order of physical address. */
+ if (mfirst != NULL)
+ {
+ struct elf_segment_map* prev;
+
+ prev = mfirst;
+ for (m = mfirst->next; m != NULL; prev = m, m = m->next)
+ {
+ /* Yes I know - its a bubble sort....*/
+ if (m->next != NULL && (m->next->p_paddr < m->p_paddr))
+ {
+ /* swap m and m->next */
+ prev->next = m->next;
+ m->next = m->next->next;
+ prev->next->next = m;
+
+ /* restart loop. */
+ m = mfirst;
+ }
+ }
+ }
+#endif
+
+#undef IS_CONTAINED_BY
+#undef IS_SOLARIS_PT_INTERP
+#undef IS_COREFILE_NOTE
return true;
}
{
asection *s;
- /* Only set up the segments when all the sections have been set
- up. */
- for (s = ibfd->sections; s != NULL; s = s->next)
- if (s->output_section == NULL)
+ /* Only set up the segments if there are no more SEC_ALLOC
+ sections. FIXME: This won't do the right thing if objcopy is
+ used to remove the last SEC_ALLOC section, since objcopy
+ won't call this routine in that case. */
+ for (s = isec->next; s != NULL; s = s->next)
+ if ((s->flags & SEC_ALLOC) != 0)
break;
if (s == NULL)
{
ohdr->sh_entsize = ihdr->sh_entsize;
if (ihdr->sh_type == SHT_SYMTAB
- || ihdr->sh_type == SHT_DYNSYM)
+ || ihdr->sh_type == SHT_DYNSYM
+ || ihdr->sh_type == SHT_GNU_verneed
+ || ihdr->sh_type == SHT_GNU_verdef)
ohdr->sh_info = ihdr->sh_info;
return true;
{
elf_symbol_type *isym, *osym;
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
isym = elf_symbol_from (ibfd, isymarg);
osym = elf_symbol_from (obfd, osymarg);
/* Swap out the symbols. */
static boolean
-swap_out_syms (abfd, sttp)
+swap_out_syms (abfd, sttp, relocatable_p)
bfd *abfd;
struct bfd_strtab_hash **sttp;
+ int relocatable_p;
{
struct elf_backend_data *bed = get_elf_backend_data (abfd);
type_ptr = elf_symbol_from (abfd, syms[idx]);
- if (bfd_is_com_section (syms[idx]->section))
+ if ((flags & BSF_SECTION_SYM) == 0
+ && bfd_is_com_section (syms[idx]->section))
{
/* ELF common symbols put the alignment into the `value' field,
and the size into the `size' field. This is backwards from
sym.st_value = value >= 16 ? 16 : (1 << bfd_log2 (value));
else
sym.st_value = type_ptr->internal_elf_sym.st_value;
- sym.st_shndx = _bfd_elf_section_from_bfd_section (abfd,
- syms[idx]->section);
+ sym.st_shndx = _bfd_elf_section_from_bfd_section
+ (abfd, syms[idx]->section);
}
else
{
value += sec->output_offset;
sec = sec->output_section;
}
- value += sec->vma;
+ /* Don't add in the section vma for relocatable output. */
+ if (! relocatable_p)
+ value += sec->vma;
sym.st_value = value;
sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0;
else
type = STT_NOTYPE;
- if (bfd_is_com_section (syms[idx]->section))
+ /* Processor-specific types */
+ if (bed->elf_backend_get_symbol_type)
+ type = (*bed->elf_backend_get_symbol_type) (&type_ptr->internal_elf_sym, type);
+
+ if (flags & BSF_SECTION_SYM)
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+ else if (bfd_is_com_section (syms[idx]->section))
sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
else if (bfd_is_und_section (syms[idx]->section))
sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
? STB_WEAK
: STB_GLOBAL),
type);
- else if (flags & BSF_SECTION_SYM)
- sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
else if (flags & BSF_FILE)
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
else
sym.st_info = ELF_ST_INFO (bind, type);
}
- sym.st_other = 0;
+ if (type_ptr != NULL)
+ sym.st_other = type_ptr->internal_elf_sym.st_other;
+ else
+ sym.st_other = 0;
+
bed->s->swap_symbol_out (abfd, &sym, (PTR) outbound_syms);
outbound_syms += bed->s->sizeof_sym;
}
arelent *tblptr;
unsigned int i;
- if (! get_elf_backend_data (abfd)->s->slurp_reloc_table (abfd, section, symbols))
+ if (! get_elf_backend_data (abfd)->s->slurp_reloc_table (abfd,
+ section,
+ symbols,
+ false))
return -1;
tblptr = section->relocation;
bfd *abfd;
asymbol **alocation;
{
- long symcount = get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, false);
+ long symcount = get_elf_backend_data (abfd)->s->slurp_symbol_table
+ (abfd, alocation, false);
if (symcount >= 0)
bfd_get_symcount (abfd) = symcount;
bfd *abfd;
asymbol **alocation;
{
- return get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, true);
+ return get_elf_backend_data (abfd)->s->slurp_symbol_table
+ (abfd, alocation, true);
+}
+
+/* Return the size required for the dynamic reloc entries. Any
+ section that was actually installed in the BFD, and has type
+ SHT_REL or SHT_RELA, and uses the dynamic symbol table, is
+ considered to be a dynamic reloc section. */
+
+long
+_bfd_elf_get_dynamic_reloc_upper_bound (abfd)
+ bfd *abfd;
+{
+ long ret;
+ asection *s;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ ret = sizeof (arelent *);
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ ret += ((s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize)
+ * sizeof (arelent *));
+
+ return ret;
+}
+
+/* Canonicalize the dynamic relocation entries. Note that we return
+ the dynamic relocations as a single block, although they are
+ actually associated with particular sections; the interface, which
+ was designed for SunOS style shared libraries, expects that there
+ is only one set of dynamic relocs. Any section that was actually
+ installed in the BFD, and has type SHT_REL or SHT_RELA, and uses
+ the dynamic symbol table, is considered to be a dynamic reloc
+ section. */
+
+long
+_bfd_elf_canonicalize_dynamic_reloc (abfd, storage, syms)
+ bfd *abfd;
+ arelent **storage;
+ asymbol **syms;
+{
+ boolean (*slurp_relocs) PARAMS ((bfd *, asection *, asymbol **, boolean));
+ asection *s;
+ long ret;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+ ret = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ {
+ arelent *p;
+ long count, i;
+
+ if (! (*slurp_relocs) (abfd, s, syms, true))
+ return -1;
+ count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize;
+ p = s->relocation;
+ for (i = 0; i < count; i++)
+ *storage++ = p++;
+ ret += count;
+ }
+ }
+
+ *storage = NULL;
+
+ return ret;
}
+\f
+/* Read in the version information. */
+
+boolean
+_bfd_elf_slurp_version_tables (abfd)
+ bfd *abfd;
+{
+ bfd_byte *contents = NULL;
+
+ if (elf_dynverdef (abfd) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+ Elf_External_Verdef *everdef;
+ Elf_Internal_Verdef *iverdef;
+ unsigned int i;
+
+ hdr = &elf_tdata (abfd)->dynverdef_hdr;
+
+ elf_tdata (abfd)->verdef =
+ ((Elf_Internal_Verdef *)
+ bfd_zalloc (abfd, hdr->sh_info * sizeof (Elf_Internal_Verdef)));
+ if (elf_tdata (abfd)->verdef == NULL)
+ goto error_return;
+
+ elf_tdata (abfd)->cverdefs = hdr->sh_info;
+
+ contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ goto error_return;
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+ || bfd_read ((PTR) contents, 1, hdr->sh_size, abfd) != hdr->sh_size)
+ goto error_return;
+
+ everdef = (Elf_External_Verdef *) contents;
+ iverdef = elf_tdata (abfd)->verdef;
+ for (i = 0; i < hdr->sh_info; i++, iverdef++)
+ {
+ Elf_External_Verdaux *everdaux;
+ Elf_Internal_Verdaux *iverdaux;
+ unsigned int j;
+
+ _bfd_elf_swap_verdef_in (abfd, everdef, iverdef);
+
+ iverdef->vd_bfd = abfd;
+
+ iverdef->vd_auxptr = ((Elf_Internal_Verdaux *)
+ bfd_alloc (abfd,
+ (iverdef->vd_cnt
+ * sizeof (Elf_Internal_Verdaux))));
+ if (iverdef->vd_auxptr == NULL)
+ goto error_return;
+
+ everdaux = ((Elf_External_Verdaux *)
+ ((bfd_byte *) everdef + iverdef->vd_aux));
+ iverdaux = iverdef->vd_auxptr;
+ for (j = 0; j < iverdef->vd_cnt; j++, iverdaux++)
+ {
+ _bfd_elf_swap_verdaux_in (abfd, everdaux, iverdaux);
+
+ iverdaux->vda_nodename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ iverdaux->vda_name);
+ if (iverdaux->vda_nodename == NULL)
+ goto error_return;
+
+ if (j + 1 < iverdef->vd_cnt)
+ iverdaux->vda_nextptr = iverdaux + 1;
+ else
+ iverdaux->vda_nextptr = NULL;
+
+ everdaux = ((Elf_External_Verdaux *)
+ ((bfd_byte *) everdaux + iverdaux->vda_next));
+ }
+
+ iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
+
+ if (i + 1 < hdr->sh_info)
+ iverdef->vd_nextdef = iverdef + 1;
+ else
+ iverdef->vd_nextdef = NULL;
+
+ everdef = ((Elf_External_Verdef *)
+ ((bfd_byte *) everdef + iverdef->vd_next));
+ }
+
+ free (contents);
+ contents = NULL;
+ }
+
+ if (elf_dynverref (abfd) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+ Elf_External_Verneed *everneed;
+ Elf_Internal_Verneed *iverneed;
+ unsigned int i;
+
+ hdr = &elf_tdata (abfd)->dynverref_hdr;
+
+ elf_tdata (abfd)->verref =
+ ((Elf_Internal_Verneed *)
+ bfd_zalloc (abfd, hdr->sh_info * sizeof (Elf_Internal_Verneed)));
+ if (elf_tdata (abfd)->verref == NULL)
+ goto error_return;
+
+ elf_tdata (abfd)->cverrefs = hdr->sh_info;
+
+ contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ goto error_return;
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+ || bfd_read ((PTR) contents, 1, hdr->sh_size, abfd) != hdr->sh_size)
+ goto error_return;
+
+ everneed = (Elf_External_Verneed *) contents;
+ iverneed = elf_tdata (abfd)->verref;
+ for (i = 0; i < hdr->sh_info; i++, iverneed++)
+ {
+ Elf_External_Vernaux *evernaux;
+ Elf_Internal_Vernaux *ivernaux;
+ unsigned int j;
+
+ _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
+
+ iverneed->vn_bfd = abfd;
+
+ iverneed->vn_filename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ iverneed->vn_file);
+ if (iverneed->vn_filename == NULL)
+ goto error_return;
+
+ iverneed->vn_auxptr =
+ ((Elf_Internal_Vernaux *)
+ bfd_alloc (abfd,
+ iverneed->vn_cnt * sizeof (Elf_Internal_Vernaux)));
+
+ evernaux = ((Elf_External_Vernaux *)
+ ((bfd_byte *) everneed + iverneed->vn_aux));
+ ivernaux = iverneed->vn_auxptr;
+ for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
+ {
+ _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+
+ ivernaux->vna_nodename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ ivernaux->vna_name);
+ if (ivernaux->vna_nodename == NULL)
+ goto error_return;
+
+ if (j + 1 < iverneed->vn_cnt)
+ ivernaux->vna_nextptr = ivernaux + 1;
+ else
+ ivernaux->vna_nextptr = NULL;
+
+ evernaux = ((Elf_External_Vernaux *)
+ ((bfd_byte *) evernaux + ivernaux->vna_next));
+ }
+
+ if (i + 1 < hdr->sh_info)
+ iverneed->vn_nextref = iverneed + 1;
+ else
+ iverneed->vn_nextref = NULL;
+
+ everneed = ((Elf_External_Verneed *)
+ ((bfd_byte *) everneed + iverneed->vn_next));
+ }
+ free (contents);
+ contents = NULL;
+ }
+
+ return true;
+
+ error_return:
+ if (contents == NULL)
+ free (contents);
+ return false;
+}
+\f
asymbol *
_bfd_elf_make_empty_symbol (abfd)
bfd *abfd;
bfd_symbol_info (symbol, ret);
}
+/* Return whether a symbol name implies a local symbol. Most targets
+ use this function for the is_local_label_name entry point, but some
+ override it. */
+
+boolean
+_bfd_elf_is_local_label_name (abfd, name)
+ bfd *abfd;
+ const char *name;
+{
+ /* Normal local symbols start with ``.L''. */
+ if (name[0] == '.' && name[1] == 'L')
+ return true;
+
+ /* At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate
+ DWARF debugging symbols starting with ``..''. */
+ if (name[0] == '.' && name[1] == '.')
+ return true;
+
+ /* gcc will sometimes generate symbols beginning with ``_.L_'' when
+ emitting DWARF debugging output. I suspect this is actually a
+ small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call
+ ASM_GENERATE_INTERNAL_LABEL, and this causes the leading
+ underscore to be emitted on some ELF targets). For ease of use,
+ we treat such symbols as local. */
+ if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
+ return true;
+
+ return false;
+}
+
alent *
_bfd_elf_get_lineno (ignore_abfd, symbol)
bfd *ignore_abfd;
bfd_vma low_func;
asymbol **p;
- if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
- &found, filename_ptr,
+ if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset,
+ filename_ptr, functionname_ptr,
+ line_ptr))
+ return true;
+
+ if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+ filename_ptr, functionname_ptr,
+ line_ptr))
+ return true;
+
+ if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
+ &found, filename_ptr,
functionname_ptr, line_ptr,
&elf_tdata (abfd)->line_info))
return false;
case STT_FILE:
filename = bfd_asymbol_name (&q->symbol);
break;
+ case STT_NOTYPE:
case STT_FUNC:
if (q->symbol.section == section
&& q->symbol.value >= low_func
Elf_Internal_Shdr *hdr;
if (! abfd->output_has_begun
- && ! _bfd_elf_compute_section_file_positions (abfd,
- (struct bfd_link_info *) NULL))
+ && ! _bfd_elf_compute_section_file_positions
+ (abfd, (struct bfd_link_info *) NULL))
return false;
hdr = &elf_section_data (section)->this_hdr;
abort ();
}
#endif
+
+/* Try to convert a non-ELF reloc into an ELF one. */
+
+boolean
+_bfd_elf_validate_reloc (abfd, areloc)
+ bfd *abfd;
+ arelent *areloc;
+{
+ /* Check whether we really have an ELF howto. */
+
+ if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec)
+ {
+ bfd_reloc_code_real_type code;
+ reloc_howto_type *howto;
+
+ /* Alien reloc: Try to determine its type to replace it with an
+ equivalent ELF reloc. */
+
+ if (areloc->howto->pc_relative)
+ {
+ switch (areloc->howto->bitsize)
+ {
+ case 8:
+ code = BFD_RELOC_8_PCREL;
+ break;
+ case 12:
+ code = BFD_RELOC_12_PCREL;
+ break;
+ case 16:
+ code = BFD_RELOC_16_PCREL;
+ break;
+ case 24:
+ code = BFD_RELOC_24_PCREL;
+ break;
+ case 32:
+ code = BFD_RELOC_32_PCREL;
+ break;
+ case 64:
+ code = BFD_RELOC_64_PCREL;
+ break;
+ default:
+ goto fail;
+ }
+
+ howto = bfd_reloc_type_lookup (abfd, code);
+
+ if (areloc->howto->pcrel_offset != howto->pcrel_offset)
+ {
+ if (howto->pcrel_offset)
+ areloc->addend += areloc->address;
+ else
+ areloc->addend -= areloc->address; /* addend is unsigned!! */
+ }
+ }
+ else
+ {
+ switch (areloc->howto->bitsize)
+ {
+ case 8:
+ code = BFD_RELOC_8;
+ break;
+ case 14:
+ code = BFD_RELOC_14;
+ break;
+ case 16:
+ code = BFD_RELOC_16;
+ break;
+ case 26:
+ code = BFD_RELOC_26;
+ break;
+ case 32:
+ code = BFD_RELOC_32;
+ break;
+ case 64:
+ code = BFD_RELOC_64;
+ break;
+ default:
+ goto fail;
+ }
+
+ howto = bfd_reloc_type_lookup (abfd, code);
+ }
+
+ if (howto)
+ areloc->howto = howto;
+ else
+ goto fail;
+ }
+
+ return true;
+
+ fail:
+ (*_bfd_error_handler)
+ (_("%s: unsupported relocation type %s"),
+ bfd_get_filename (abfd), areloc->howto->name);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+}
+
+boolean
+_bfd_elf_close_and_cleanup (abfd)
+ bfd *abfd;
+{
+ if (bfd_get_format (abfd) == bfd_object)
+ {
+ if (elf_shstrtab (abfd) != NULL)
+ _bfd_stringtab_free (elf_shstrtab (abfd));
+ }
+
+ return _bfd_generic_close_and_cleanup (abfd);
+}
+
+/* For Rel targets, we encode meaningful data for BFD_RELOC_VTABLE_ENTRY
+ in the relocation's offset. Thus we cannot allow any sort of sanity
+ range-checking to interfere. There is nothing else to do in processing
+ this reloc. */
+
+bfd_reloc_status_type
+_bfd_elf_rel_vtable_reloc_fn (abfd, re, symbol, data, is, obfd, errmsg)
+ bfd *abfd;
+ arelent *re;
+ struct symbol_cache_entry *symbol;
+ PTR data;
+ asection *is;
+ bfd *obfd;
+ char **errmsg;
+{
+ return bfd_reloc_ok;
+}
+
+\f
+/* Elf core file support. Much of this only works on native
+ toolchains, since we rely on knowing the
+ machine-dependent procfs structure in order to pick
+ out details about the corefile. */
+
+#ifdef HAVE_SYS_PROCFS_H
+# include <sys/procfs.h>
+#endif
+
+
+/* Define offsetof for those systems which lack it. */
+
+#ifndef offsetof
+# define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+
+/* FIXME: this is kinda wrong, but it's what gdb wants. */
+
+static int
+elfcore_make_pid (abfd)
+ bfd* abfd;
+{
+ return ((elf_tdata (abfd)->core_lwpid << 16)
+ + (elf_tdata (abfd)->core_pid));
+}
+
+
+/* If there isn't a section called NAME, make one, using
+ data from SECT. Note, this function will generate a
+ reference to NAME, so you shouldn't deallocate or
+ overwrite it. */
+
+static boolean
+elfcore_maybe_make_sect (abfd, name, sect)
+ bfd* abfd;
+ char* name;
+ asection* sect;
+{
+ asection* sect2;
+
+ if (bfd_get_section_by_name (abfd, name) != NULL)
+ return true;
+
+ sect2 = bfd_make_section (abfd, name);
+ if (sect2 == NULL)
+ return false;
+
+ sect2->_raw_size = sect->_raw_size;
+ sect2->filepos = sect->filepos;
+ sect2->flags = sect->flags;
+ sect2->alignment_power = sect->alignment_power;
+ return true;
+}
+
+
+/* prstatus_t exists on:
+ solaris 2.[567]
+ linux 2.[01] + glibc
+ unixware 4.2
+*/
+
+#if defined (HAVE_PRSTATUS_T)
+static boolean
+elfcore_grok_prstatus (abfd, note)
+ bfd* abfd;
+ Elf_Internal_Note* note;
+{
+ prstatus_t prstat;
+ char buf[100];
+ char* name;
+ asection* sect;
+
+ if (note->descsz != sizeof (prstat))
+ return true;
+
+ memcpy (&prstat, note->descdata, sizeof (prstat));
+
+ elf_tdata (abfd)->core_signal = prstat.pr_cursig;
+ elf_tdata (abfd)->core_pid = prstat.pr_pid;
+
+ /* pr_who exists on:
+ solaris 2.[567]
+ unixware 4.2
+ pr_who doesn't exist on:
+ linux 2.[01]
+ */
+#if defined (HAVE_PRSTATUS_T_PR_WHO)
+ elf_tdata (abfd)->core_lwpid = prstat.pr_who;
+#endif
+
+ /* Make a ".reg/999" section. */
+
+ sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
+ name = bfd_alloc (abfd, strlen (buf) + 1);
+ if (name == NULL)
+ return false;
+ strcpy (name, buf);
+
+ sect = bfd_make_section (abfd, name);
+ if (sect == NULL)
+ return false;
+ sect->_raw_size = sizeof (prstat.pr_reg);
+ sect->filepos = note->descpos + offsetof (prstatus_t, pr_reg);
+ sect->flags = SEC_HAS_CONTENTS;
+ sect->alignment_power = 2;
+
+ if (! elfcore_maybe_make_sect (abfd, ".reg", sect))
+ return false;
+
+ return true;
+}
+#endif /* defined (HAVE_PRSTATUS_T) */
+
+
+/* There isn't a consistent prfpregset_t across platforms,
+ but it doesn't matter, because we don't have to pick this
+ data structure apart. */
+
+static boolean
+elfcore_grok_prfpreg (abfd, note)
+ bfd* abfd;
+ Elf_Internal_Note* note;
+{
+ char buf[100];
+ char* name;
+ asection* sect;
+
+ /* Make a ".reg2/999" section. */
+
+ sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
+ name = bfd_alloc (abfd, strlen (buf) + 1);
+ if (name == NULL)
+ return false;
+ strcpy (name, buf);
+
+ sect = bfd_make_section (abfd, name);
+ if (sect == NULL)
+ return false;
+ sect->_raw_size = note->descsz;
+ sect->filepos = note->descpos;
+ sect->flags = SEC_HAS_CONTENTS;
+ sect->alignment_power = 2;
+
+ if (! elfcore_maybe_make_sect (abfd, ".reg2", sect))
+ return false;
+
+ return true;
+}
+
+
+/* return a malloc'ed copy of a string at START which is at
+ most MAX bytes long, possibly without a terminating '\0'.
+ the copy will always have a terminating '\0'. */
+
+static char*
+elfcore_strndup (abfd, start, max)
+ bfd* abfd;
+ char* start;
+ int max;
+{
+ char* dup;
+ char* end = memchr (start, '\0', max);
+ int len;
+
+ if (end == NULL)
+ len = max;
+ else
+ len = end - start;
+
+ dup = bfd_alloc (abfd, len + 1);
+ if (dup == NULL)
+ return NULL;
+
+ memcpy (dup, start, len);
+ dup[len] = '\0';
+
+ return dup;
+}
+
+
+#if defined (HAVE_PRPSINFO_T)
+# define elfcore_psinfo_t prpsinfo_t
+#endif
+
+#if defined (HAVE_PSINFO_T)
+# define elfcore_psinfo_t psinfo_t
+#endif
+
+
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+static boolean
+elfcore_grok_psinfo (abfd, note)
+ bfd* abfd;
+ Elf_Internal_Note* note;
+{
+ elfcore_psinfo_t psinfo;
+
+ if (note->descsz != sizeof (elfcore_psinfo_t))
+ return true;
+
+ memcpy (&psinfo, note->descdata, note->descsz);
+
+ elf_tdata (abfd)->core_program
+ = elfcore_strndup (abfd, psinfo.pr_fname, sizeof (psinfo.pr_fname));
+
+ elf_tdata (abfd)->core_command
+ = elfcore_strndup (abfd, psinfo.pr_psargs, sizeof (psinfo.pr_psargs));
+
+ /* Note that for some reason, a spurious space is tacked
+ onto the end of the args in some (at least one anyway)
+ implementations, so strip it off if it exists. */
+
+ {
+ char* command = elf_tdata (abfd)->core_command;
+ int n = strlen (command);
+
+ if (0 < n && command[n - 1] == ' ')
+ command[n - 1] = '\0';
+ }
+
+ return true;
+}
+#endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */
+
+
+#if defined (HAVE_PSTATUS_T)
+static boolean
+elfcore_grok_pstatus (abfd, note)
+ bfd* abfd;
+ Elf_Internal_Note* note;
+{
+ pstatus_t pstat;
+
+ if (note->descsz != sizeof (pstat))
+ return true;
+
+ memcpy (&pstat, note->descdata, sizeof (pstat));
+
+ elf_tdata (abfd)->core_pid = pstat.pr_pid;
+
+ /* Could grab some more details from the "representative"
+ lwpstatus_t in pstat.pr_lwp, but we'll catch it all in an
+ NT_LWPSTATUS note, presumably. */
+
+ return true;
+}
+#endif /* defined (HAVE_PSTATUS_T) */
+
+
+#if defined (HAVE_LWPSTATUS_T)
+static boolean
+elfcore_grok_lwpstatus (abfd, note)
+ bfd* abfd;
+ Elf_Internal_Note* note;
+{
+ lwpstatus_t lwpstat;
+ char buf[100];
+ char* name;
+ asection* sect;
+
+ if (note->descsz != sizeof (lwpstat))
+ return true;
+
+ memcpy (&lwpstat, note->descdata, sizeof (lwpstat));
+
+ elf_tdata (abfd)->core_lwpid = lwpstat.pr_lwpid;
+ elf_tdata (abfd)->core_signal = lwpstat.pr_cursig;
+
+ /* Make a ".reg/999" section. */
+
+ sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
+ name = bfd_alloc (abfd, strlen (buf) + 1);
+ if (name == NULL)
+ return false;
+ strcpy (name, buf);
+
+ sect = bfd_make_section (abfd, name);
+ if (sect == NULL)
+ return false;
+
+#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+ sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.gregs);
+ sect->filepos = note->descpos
+ + offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T_PR_REG)
+ sect->_raw_size = sizeof (lwpstat.pr_reg);
+ sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg);
+#endif
+
+ sect->flags = SEC_HAS_CONTENTS;
+ sect->alignment_power = 2;
+
+ if (!elfcore_maybe_make_sect (abfd, ".reg", sect))
+ return false;
+
+ /* Make a ".reg2/999" section */
+
+ sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
+ name = bfd_alloc (abfd, strlen (buf) + 1);
+ if (name == NULL)
+ return false;
+ strcpy (name, buf);
+
+ sect = bfd_make_section (abfd, name);
+ if (sect == NULL)
+ return false;
+
+#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+ sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs);
+ sect->filepos = note->descpos
+ + offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T_PR_FPREG)
+ sect->_raw_size = sizeof (lwpstat.pr_fpreg);
+ sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg);
+#endif
+
+ sect->flags = SEC_HAS_CONTENTS;
+ sect->alignment_power = 2;
+
+ if (!elfcore_maybe_make_sect (abfd, ".reg2", sect))
+ return false;
+
+ return true;
+}
+#endif /* defined (HAVE_LWPSTATUS_T) */
+
+
+
+static boolean
+elfcore_grok_note (abfd, note)
+ bfd* abfd;
+ Elf_Internal_Note* note;
+{
+ switch (note->type)
+ {
+ default:
+ return true;
+
+#if defined (HAVE_PRSTATUS_T)
+ case NT_PRSTATUS:
+ return elfcore_grok_prstatus (abfd, note);
+#endif
+
+#if defined (HAVE_PSTATUS_T)
+ case NT_PSTATUS:
+ return elfcore_grok_pstatus (abfd, note);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T)
+ case NT_LWPSTATUS:
+ return elfcore_grok_lwpstatus (abfd, note);
+#endif
+
+ case NT_FPREGSET: /* FIXME: rename to NT_PRFPREG */
+ return elfcore_grok_prfpreg (abfd, note);
+
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+ case NT_PRPSINFO:
+ case NT_PSINFO:
+ return elfcore_grok_psinfo (abfd, note);
+#endif
+ }
+}
+
+
+static boolean
+elfcore_read_notes (abfd, offset, size)
+ bfd* abfd;
+ bfd_vma offset;
+ bfd_vma size;
+{
+ char* buf;
+ char* p;
+
+ if (size <= 0)
+ return true;
+
+ if (bfd_seek (abfd, offset, SEEK_SET) == -1)
+ return false;
+
+ buf = bfd_malloc ((size_t) size);
+ if (buf == NULL)
+ return false;
+
+ if (bfd_read (buf, size, 1, abfd) != size)
+ {
+ error:
+ free (buf);
+ return false;
+ }
+
+ p = buf;
+ while (p < buf + size)
+ {
+ /* FIXME: bad alignment assumption. */
+ Elf_External_Note* xnp = (Elf_External_Note*) p;
+ Elf_Internal_Note in;
+
+ in.type = bfd_h_get_32 (abfd, (bfd_byte *) xnp->type);
+
+ in.namesz = bfd_h_get_32 (abfd, (bfd_byte *) xnp->namesz);
+ in.namedata = xnp->name;
+
+ in.descsz = bfd_h_get_32 (abfd, (bfd_byte *) xnp->descsz);
+ in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
+ in.descpos = offset + (in.descdata - buf);
+
+ if (! elfcore_grok_note (abfd, &in))
+ goto error;
+
+ p = in.descdata + BFD_ALIGN (in.descsz, 4);
+ }
+
+ free (buf);
+ return true;
+}
+
+
+
+boolean
+_bfd_elfcore_section_from_phdr (abfd, phdr, sec_num)
+ bfd* abfd;
+ Elf_Internal_Phdr* phdr;
+ int sec_num;
+{
+ if (! bfd_section_from_phdr (abfd, phdr, sec_num))
+ return false;
+
+ if (phdr->p_type == PT_NOTE
+ && ! elfcore_read_notes (abfd, phdr->p_offset, phdr->p_filesz))
+ return false;
+
+ return true;
+}
+