/* ELF executable support for BFD.
- Copyright 1993 Free Software Foundation, Inc.
+ Copyright 1993, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "elf-bfd.h"
static INLINE struct elf_segment_map *make_mapping
- PARAMS ((bfd *, asection **, unsigned int, unsigned int));
+ 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 *));
+static boolean elfcore_read_notes PARAMS ((bfd *, bfd_vma, bfd_vma));
+
+/* 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;
+bfd_elf_hash (namearg)
+ const char *namearg;
{
+ const unsigned char *name = (const unsigned char *) namearg;
unsigned long h = 0;
unsigned long g;
int ch;
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;
char *buf;
if ((buf = bfd_alloc (abfd, size)) == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
if (bfd_seek (abfd, offset, SEEK_SET) == -1)
return NULL;
if (bfd_read ((PTR) buf, size, 1, abfd) != size)
}
boolean
-elf_mkobject (abfd)
+bfd_elf_mkobject (abfd)
bfd * abfd;
{
/* this just does initialization */
elf_tdata (abfd) = (struct elf_obj_tdata *)
bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
if (elf_tdata (abfd) == 0)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
/* since everything is done at close time, do we need any
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_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;
input_section,
output_bfd,
error_message)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry;
asymbol *symbol;
- PTR data;
+ PTR data ATTRIBUTE_UNUSED;
asection *input_section;
bfd *output_bfd;
- char **error_message;
+ char **error_message ATTRIBUTE_UNUSED;
{
if (output_bfd != (bfd *) NULL
&& (symbol->flags & BSF_SECTION_SYM) == 0
{
FILE *f = (FILE *) farg;
Elf_Internal_Phdr *p;
- unsigned int i, c;
+ asection *s;
+ bfd_byte *dynbuf = NULL;
p = elf_tdata (abfd)->phdr;
- if (p == NULL)
- return true;
+ if (p != NULL)
+ {
+ unsigned int i, c;
+
+ fprintf (f, _("\nProgram Header:\n"));
+ c = elf_elfheader (abfd)->e_phnum;
+ for (i = 0; i < c; i++, p++)
+ {
+ const char *s;
+ char buf[20];
+
+ switch (p->p_type)
+ {
+ case PT_NULL: s = "NULL"; break;
+ case PT_LOAD: s = "LOAD"; break;
+ case PT_DYNAMIC: s = "DYNAMIC"; break;
+ case PT_INTERP: s = "INTERP"; break;
+ case PT_NOTE: s = "NOTE"; break;
+ case PT_SHLIB: s = "SHLIB"; break;
+ case PT_PHDR: s = "PHDR"; break;
+ default: sprintf (buf, "0x%lx", p->p_type); s = buf; break;
+ }
+ fprintf (f, "%8s off 0x", s);
+ fprintf_vma (f, p->p_offset);
+ fprintf (f, " vaddr 0x");
+ fprintf_vma (f, p->p_vaddr);
+ fprintf (f, " paddr 0x");
+ fprintf_vma (f, p->p_paddr);
+ fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align));
+ fprintf (f, " filesz 0x");
+ fprintf_vma (f, p->p_filesz);
+ fprintf (f, " memsz 0x");
+ fprintf_vma (f, p->p_memsz);
+ fprintf (f, " flags %c%c%c",
+ (p->p_flags & PF_R) != 0 ? 'r' : '-',
+ (p->p_flags & PF_W) != 0 ? 'w' : '-',
+ (p->p_flags & PF_X) != 0 ? 'x' : '-');
+ if ((p->p_flags &~ (PF_R | PF_W | PF_X)) != 0)
+ fprintf (f, " %lx", p->p_flags &~ (PF_R | PF_W | PF_X));
+ fprintf (f, "\n");
+ }
+ }
+
+ s = bfd_get_section_by_name (abfd, ".dynamic");
+ if (s != NULL)
+ {
+ int elfsec;
+ unsigned long link;
+ bfd_byte *extdyn, *extdynend;
+ size_t extdynsize;
+ void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *));
+
+ fprintf (f, _("\nDynamic Section:\n"));
+
+ 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;
+ const char *name;
+ char ab[20];
+ boolean stringp;
+
+ (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn);
+
+ if (dyn.d_tag == DT_NULL)
+ break;
+
+ stringp = false;
+ switch (dyn.d_tag)
+ {
+ default:
+ sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag);
+ name = ab;
+ break;
+
+ case DT_NEEDED: name = "NEEDED"; stringp = true; break;
+ case DT_PLTRELSZ: name = "PLTRELSZ"; break;
+ case DT_PLTGOT: name = "PLTGOT"; break;
+ case DT_HASH: name = "HASH"; break;
+ case DT_STRTAB: name = "STRTAB"; break;
+ case DT_SYMTAB: name = "SYMTAB"; break;
+ case DT_RELA: name = "RELA"; break;
+ case DT_RELASZ: name = "RELASZ"; break;
+ case DT_RELAENT: name = "RELAENT"; break;
+ case DT_STRSZ: name = "STRSZ"; break;
+ case DT_SYMENT: name = "SYMENT"; break;
+ case DT_INIT: name = "INIT"; break;
+ case DT_FINI: name = "FINI"; break;
+ case DT_SONAME: name = "SONAME"; stringp = true; break;
+ case DT_RPATH: name = "RPATH"; stringp = true; break;
+ case DT_SYMBOLIC: name = "SYMBOLIC"; break;
+ case DT_REL: name = "REL"; break;
+ case DT_RELSZ: name = "RELSZ"; break;
+ case DT_RELENT: name = "RELENT"; break;
+ case DT_PLTREL: name = "PLTREL"; break;
+ 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);
+ if (! stringp)
+ fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val);
+ else
+ {
+ const char *string;
+
+ string = bfd_elf_string_from_elf_section (abfd, link,
+ dyn.d_un.d_val);
+ if (string == NULL)
+ goto error_return;
+ fprintf (f, "%s", string);
+ }
+ fprintf (f, "\n");
+ }
+
+ free (dynbuf);
+ 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");
+ }
+ }
+ }
- c = elf_elfheader (abfd)->e_phnum;
- for (i = 0; i < c; i++, p++)
+ if (elf_dynverref (abfd) != 0)
{
- const char *s;
- char buf[20];
+ Elf_Internal_Verneed *t;
- switch (p->p_type)
+ fprintf (f, _("\nVersion References:\n"));
+ for (t = elf_tdata (abfd)->verref; t != NULL; t = t->vn_nextref)
{
- case PT_NULL: s = "NULL"; break;
- case PT_LOAD: s = "LOAD"; break;
- case PT_DYNAMIC: s = "DYNAMIC"; break;
- case PT_INTERP: s = "INTERP"; break;
- case PT_NOTE: s = "NOTE"; break;
- case PT_SHLIB: s = "SHLIB"; break;
- case PT_PHDR: s = "PHDR"; break;
- default: sprintf (buf, "0x%lx", p->p_type); s = buf; break;
+ 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);
}
- fprintf (f, "%8s off 0x", s);
- fprintf_vma (f, p->p_offset);
- fprintf (f, " vaddr 0x");
- fprintf_vma (f, p->p_vaddr);
- fprintf (f, " paddr 0x");
- fprintf_vma (f, p->p_paddr);
- fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align));
- fprintf (f, " filesz 0x");
- fprintf_vma (f, p->p_filesz);
- fprintf (f, " memsz 0x");
- fprintf_vma (f, p->p_memsz);
- fprintf (f, " flags %c%c%c",
- (p->p_flags & PF_R) != 0 ? 'r' : '-',
- (p->p_flags & PF_W) != 0 ? 'w' : '-',
- (p->p_flags & PF_X) != 0 ? 'x' : '-');
- if ((p->p_flags &~ (PF_R | PF_W | PF_X)) != 0)
- fprintf (f, " %lx", p->p_flags &~ (PF_R | PF_W | PF_X));
- fprintf (f, "\n");
}
return true;
+
+ error_return:
+ if (dynbuf != NULL)
+ free (dynbuf);
+ return false;
}
/* 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;
case bfd_print_symbol_all:
{
CONST char *section_name;
+ CONST char *name = NULL;
+ struct elf_backend_data *bed;
+ unsigned char st_other;
+
section_name = symbol->section ? symbol->section->name : "(*none*)";
- bfd_print_symbol_vandf ((PTR) file, symbol);
+
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_print_symbol_all)
+ name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol);
+
+ if (name == NULL)
+ {
+ name = symbol->name;
+ bfd_print_symbol_vandf ((PTR) file, symbol);
+ }
+
fprintf (file, " %s\t", section_name);
/* Print the "other" value for a symbol. For common symbols,
we've already printed the size; now print the alignment.
(bfd_is_com_section (symbol->section)
? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value
: ((elf_symbol_type *) symbol)->internal_elf_sym.st_size));
- fprintf (file, " %s", symbol->name);
+
+ /* 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. */
+ st_other = ((elf_symbol_type *) symbol)->internal_elf_sym.st_other;
+
+ switch (st_other)
+ {
+ case 0: break;
+ case STV_INTERNAL: fprintf (file, " .internal"); break;
+ case STV_HIDDEN: fprintf (file, " .hidden"); break;
+ case STV_PROTECTED: fprintf (file, " .protected"); break;
+ default:
+ /* Some other non-defined flags are also present, so print
+ everything hex. */
+ fprintf (file, " 0x%02x", (unsigned int) st_other);
+ }
+
+ fprintf (file, " %s", name);
}
break;
}
ret = ((struct elf_link_hash_entry *)
bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)));
if (ret == (struct elf_link_hash_entry *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return (struct bfd_hash_entry *) ret;
- }
+ return (struct bfd_hash_entry *) ret;
/* Call the allocation method of the superclass. */
ret = ((struct elf_link_hash_entry *)
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_entries_size = 0;
+ ret->vtable_parent = NULL;
ret->type = STT_NOTYPE;
- ret->elf_link_hash_flags = 0;
+ 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
+ reader will have the flag set correctly. */
+ ret->elf_link_hash_flags = ELF_LINK_NON_ELF;
}
return (struct bfd_hash_entry *) ret;
table->dynstr = NULL;
table->bucketcount = 0;
table->needed = NULL;
+ table->hgot = NULL;
+ table->stab_info = NULL;
return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
}
ret = ((struct elf_link_hash_table *)
bfd_alloc (abfd, sizeof (struct elf_link_hash_table)));
if (ret == (struct elf_link_hash_table *) NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc))
{
bfd *abfd;
const char *name;
{
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
- elf_dt_needed_name (abfd) = name;
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && bfd_get_format (abfd) == bfd_object)
+ elf_dt_name (abfd) = name;
}
-/* Get the list of DT_NEEDED entries for a link. */
+/* Get the list of DT_NEEDED entries for a link. This is a hook for
+ the linker ELF emulation code. */
struct bfd_link_needed_list *
bfd_elf_get_needed_list (abfd, info)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
{
if (info->hash->creator->flavour != bfd_target_elf_flavour)
return NULL;
return elf_hash_table (info)->needed;
}
+
+/* Get the name actually used for a dynamic object for a link. This
+ is the SONAME entry if there is one. Otherwise, it is the string
+ passed to bfd_elf_set_dt_needed_name, or it is the filename. */
+
+const char *
+bfd_elf_get_dt_soname (abfd)
+ bfd *abfd;
+{
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && bfd_get_format (abfd) == bfd_object)
+ 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. */
case SHT_DYNAMIC: /* Dynamic linking information. */
case SHT_NOBITS: /* .bss section. */
case SHT_HASH: /* .hash section. */
+ case SHT_NOTE: /* .note section. */
return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
case SHT_SYMTAB: /* A symbol table */
{
asection *target_sect;
Elf_Internal_Shdr *hdr2;
- int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
+
+ /* Check for a bogus link to avoid crashing. */
+ if (hdr->sh_link >= ehdr->e_shnum)
+ {
+ ((*_bfd_error_handler)
+ (_("%s: invalid link %lu for reloc section %s (index %u)"),
+ bfd_get_filename (abfd), hdr->sh_link, name, shindex));
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+ }
/* 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;
+ /* In the section to which the relocations apply, mark whether
+ its relocations are of the REL or RELA variety. */
+ elf_section_data (target_sect)->use_rela_p
+ = (hdr->sh_type == SHT_RELA);
abfd->flags |= HAS_RELOC;
return true;
}
break;
- case SHT_NOTE:
+ 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:
{
struct bfd_elf_section_data *sdata;
- sdata = (struct bfd_elf_section_data *) bfd_alloc (abfd, sizeof (*sdata));
+ sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, sizeof (*sdata));
if (!sdata)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
sec->used_by_bfd = (PTR) sdata;
- memset (sdata, 0, sizeof (*sdata));
+
+ /* Indicate whether or not this section should use RELA relocations. */
+ sdata->use_rela_p
+ = get_elf_backend_data (abfd)->default_use_rela_p;
+
return true;
}
*/
boolean
-bfd_section_from_phdr (abfd, hdr, index)
+_bfd_elf_make_section_from_phdr (abfd, hdr, index, typename)
bfd *abfd;
Elf_Internal_Phdr *hdr;
int index;
+ const char *typename;
{
asection *newsect;
char *name;
char namebuf[64];
int split;
- split = ((hdr->p_memsz > 0) &&
- (hdr->p_filesz > 0) &&
- (hdr->p_memsz > hdr->p_filesz));
- sprintf (namebuf, split ? "segment%da" : "segment%d", index);
+ split = ((hdr->p_memsz > 0)
+ && (hdr->p_filesz > 0)
+ && (hdr->p_memsz > hdr->p_filesz));
+ sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
name = bfd_alloc (abfd, strlen (namebuf) + 1);
if (!name)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
strcpy (name, namebuf);
newsect = bfd_make_section (abfd, name);
if (newsect == NULL)
if (split)
{
- sprintf (namebuf, "segment%db", index);
+ sprintf (namebuf, "%s%db", typename, index);
name = bfd_alloc (abfd, strlen (namebuf) + 1);
if (!name)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
strcpy (name, namebuf);
newsect = bfd_make_section (abfd, name);
if (newsect == NULL)
return true;
}
-/* Set up an ELF internal section header for a section. */
-
-/*ARGSUSED*/
-static void
-elf_fake_sections (abfd, asect, failedptrarg)
+boolean
+bfd_section_from_phdr (abfd, hdr, index)
bfd *abfd;
- asection *asect;
- PTR failedptrarg;
+ Elf_Internal_Phdr *hdr;
+ int index;
{
- struct elf_backend_data *bed = get_elf_backend_data (abfd);
- boolean *failedptr = (boolean *) failedptrarg;
- Elf_Internal_Shdr *this_hdr;
+ struct elf_backend_data *bed;
- if (*failedptr)
+ switch (hdr->p_type)
+ {
+ case PT_NULL:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "null");
+
+ case PT_LOAD:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "load");
+
+ case PT_DYNAMIC:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "dynamic");
+
+ case PT_INTERP:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "interp");
+
+ case PT_NOTE:
+ if (! _bfd_elf_make_section_from_phdr (abfd, hdr, index, "note"))
+ return false;
+ if (! elfcore_read_notes (abfd, hdr->p_offset, hdr->p_filesz))
+ return false;
+ return true;
+
+ case PT_SHLIB:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "shlib");
+
+ case PT_PHDR:
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "phdr");
+
+ default:
+ /* Check for any processor-specific program segment types.
+ If no handler for them, default to making "segment" sections. */
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_section_from_phdr)
+ return (*bed->elf_backend_section_from_phdr) (abfd, hdr, index);
+ else
+ return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "segment");
+ }
+}
+
+/* Initialize REL_HDR, the section-header for new section, containing
+ relocations against ASECT. If USE_RELA_P is true, we use RELA
+ relocations; otherwise, we use REL relocations. */
+
+boolean
+_bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p)
+ bfd *abfd;
+ Elf_Internal_Shdr *rel_hdr;
+ asection *asect;
+ boolean use_rela_p;
+{
+ char *name;
+ struct elf_backend_data *bed;
+
+ bed = get_elf_backend_data (abfd);
+ name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name));
+ if (name == NULL)
+ return false;
+ sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
+ rel_hdr->sh_name =
+ (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
+ true, false);
+ if (rel_hdr->sh_name == (unsigned int) -1)
+ return false;
+ rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
+ rel_hdr->sh_entsize = (use_rela_p
+ ? bed->s->sizeof_rela
+ : bed->s->sizeof_rel);
+ rel_hdr->sh_addralign = bed->s->file_align;
+ rel_hdr->sh_flags = 0;
+ rel_hdr->sh_addr = 0;
+ rel_hdr->sh_size = 0;
+ rel_hdr->sh_offset = 0;
+
+ return true;
+}
+
+/* Set up an ELF internal section header for a section. */
+
+/*ARGSUSED*/
+static void
+elf_fake_sections (abfd, asect, failedptrarg)
+ bfd *abfd;
+ asection *asect;
+ PTR failedptrarg;
+{
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ boolean *failedptr = (boolean *) failedptrarg;
+ Elf_Internal_Shdr *this_hdr;
+
+ if (*failedptr)
{
/* We already failed; just get out of the bfd_map_over_sections
loop. */
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;
else if (strcmp (asect->name, ".hash") == 0)
{
this_hdr->sh_type = SHT_HASH;
- this_hdr->sh_entsize = bed->s->arch_size / 8;
+ this_hdr->sh_entsize = bed->s->sizeof_hash_entry;
}
else if (strcmp (asect->name, ".dynsym") == 0)
{
this_hdr->sh_entsize = bed->s->sizeof_dyn;
}
else if (strncmp (asect->name, ".rela", 5) == 0
- && get_elf_backend_data (abfd)->use_rela_p)
+ && get_elf_backend_data (abfd)->may_use_rela_p)
{
this_hdr->sh_type = SHT_RELA;
this_hdr->sh_entsize = bed->s->sizeof_rela;
}
else if (strncmp (asect->name, ".rel", 4) == 0
- && ! get_elf_backend_data (abfd)->use_rela_p)
+ && get_elf_backend_data (abfd)->may_use_rel_p)
{
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;
this_hdr->sh_flags |= SHF_EXECINSTR;
/* Check for processor-specific section types. */
- {
- struct elf_backend_data *bed = get_elf_backend_data (abfd);
-
- if (bed->elf_backend_fake_sections)
- (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect);
- }
+ if (bed->elf_backend_fake_sections)
+ (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect);
/* If the section has relocs, set up a section header for the
- SHT_REL[A] section. */
- if ((asect->flags & SEC_RELOC) != 0)
- {
- Elf_Internal_Shdr *rela_hdr;
- int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
- char *name;
-
- rela_hdr = &elf_section_data (asect)->rel_hdr;
- name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name));
- if (name == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- *failedptr = true;
- return;
- }
- sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
- rela_hdr->sh_name =
- (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
- true, false);
- if (rela_hdr->sh_name == (unsigned int) -1)
- {
- *failedptr = true;
- return;
- }
- rela_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
- rela_hdr->sh_entsize = (use_rela_p
- ? bed->s->sizeof_rela
- : bed->s->sizeof_rel);
- rela_hdr->sh_addralign = bed->s->file_align;
- rela_hdr->sh_flags = 0;
- rela_hdr->sh_addr = 0;
- rela_hdr->sh_size = 0;
- rela_hdr->sh_offset = 0;
- }
+ SHT_REL[A] section. If two relocation sections are required for
+ this section, it is up to the processor-specific back-end to
+ create the other. */
+ if ((asect->flags & SEC_RELOC) != 0
+ && !_bfd_elf_init_reloc_shdr (abfd,
+ &elf_section_data (asect)->rel_hdr,
+ asect,
+ elf_section_data (asect)->use_rela_p))
+ *failedptr = true;
}
/* Assign all ELF section numbers. The dummy first section is handled here
d->rel_idx = 0;
else
d->rel_idx = section_number++;
+
+ if (d->rel_hdr2)
+ d->rel_idx2 = section_number++;
+ else
+ d->rel_idx2 = 0;
}
t->shstrtab_section = section_number++;
elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
t->shstrtab_hdr.sh_size = _bfd_stringtab_size (elf_shstrtab (abfd));
- if (abfd->symcount > 0)
+ if (bfd_get_symcount (abfd) > 0)
{
t->symtab_section = section_number++;
t->strtab_section = section_number++;
i_shdrp = ((Elf_Internal_Shdr **)
bfd_alloc (abfd, section_number * sizeof (Elf_Internal_Shdr *)));
if (i_shdrp == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
i_shdrp[0] = ((Elf_Internal_Shdr *)
bfd_alloc (abfd, sizeof (Elf_Internal_Shdr)));
if (i_shdrp[0] == NULL)
{
bfd_release (abfd, i_shdrp);
- bfd_set_error (bfd_error_no_memory);
return false;
}
memset (i_shdrp[0], 0, sizeof (Elf_Internal_Shdr));
elf_elfsections (abfd) = i_shdrp;
i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr;
- if (abfd->symcount > 0)
+ if (bfd_get_symcount (abfd) > 0)
{
i_shdrp[t->symtab_section] = &t->symtab_hdr;
i_shdrp[t->strtab_section] = &t->strtab_hdr;
i_shdrp[d->this_idx] = &d->this_hdr;
if (d->rel_idx != 0)
i_shdrp[d->rel_idx] = &d->rel_hdr;
+ if (d->rel_idx2 != 0)
+ i_shdrp[d->rel_idx2] = d->rel_hdr2;
/* Fill in the sh_link and sh_info fields while we're at it. */
d->rel_hdr.sh_link = t->symtab_section;
d->rel_hdr.sh_info = d->this_idx;
}
+ if (d->rel_idx2 != 0)
+ {
+ d->rel_hdr2->sh_link = t->symtab_section;
+ d->rel_hdr2->sh_info = d->this_idx;
+ }
switch (d->this_hdr.sh_type)
{
char *alc;
len = strlen (sec->name);
- alc = (char *) malloc (len - 2);
+ alc = (char *) bfd_malloc (len - 2);
if (alc == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
strncpy (alc, sec->name, len - 3);
alc[len - 3] = '\0';
s = bfd_get_section_by_name (abfd, alc);
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;
int idx;
asection *asect;
asymbol **new_syms;
+ asymbol *sym;
#ifdef DEBUG
fprintf (stderr, "elf_map_symbols\n");
max_index++;
sect_syms = (asymbol **) bfd_zalloc (abfd, max_index * sizeof (asymbol *));
if (sect_syms == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
elf_section_syms (abfd) = sect_syms;
for (idx = 0; idx < symcount; idx++)
{
- if ((syms[idx]->flags & BSF_SECTION_SYM) != 0
- && (syms[idx]->value + syms[idx]->section->vma) == 0)
+ sym = syms[idx];
+
+ if ((sym->flags & BSF_SECTION_SYM) != 0
+ && sym->value == 0)
{
asection *sec;
- sec = syms[idx]->section;
+ sec = sym->section;
+
if (sec->owner != NULL)
{
if (sec->owner != abfd)
{
if (sec->output_offset != 0)
continue;
+
sec = sec->output_section;
+
+ /* Empty sections in the input files may have had a section
+ symbol created for them. (See the comment near the end of
+ _bfd_generic_link_output_symbols in linker.c). If the linker
+ script discards such sections then we will reach this point.
+ Since we know that we cannot avoid this case, we detect it
+ and skip the abort and the assignment to the sect_syms array.
+ To reproduce this particular case try running the linker
+ testsuite test ld-scripts/weak.exp for an ELF port that uses
+ the generic linker. */
+ if (sec->owner == NULL)
+ continue;
+
BFD_ASSERT (sec->owner == abfd);
}
sect_syms[sec->index] = syms[idx];
for (asect = abfd->sections; asect; asect = asect->next)
{
- asymbol *sym;
-
if (sect_syms[asect->index] != NULL)
continue;
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
}
bfd_alloc (abfd,
(num_locals + num_globals) * sizeof (asymbol *)));
if (new_syms == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
for (idx = 0; idx < symcount; idx++)
{
if (! prep_headers (abfd))
return false;
+ /* Post process the headers if necessary. */
+ if (bed->elf_backend_post_process_headers)
+ (*bed->elf_backend_post_process_headers) (abfd, link_info);
+
failed = false;
bfd_map_over_sections (abfd, elf_fake_sections, &failed);
if (failed)
return false;
/* The backend linker builds symbol table information itself. */
- if (link_info == NULL && abfd->symcount > 0)
+ if (link_info == NULL && bfd_get_symcount (abfd) > 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;
}
if (!assign_file_positions_except_relocs (abfd))
return false;
- if (link_info == NULL && abfd->symcount > 0)
+ if (link_info == NULL && bfd_get_symcount (abfd) > 0)
{
file_ptr off;
Elf_Internal_Shdr *hdr;
/* Create a mapping from a set of sections to a program segment. */
static INLINE struct elf_segment_map *
-make_mapping (abfd, sections, from, to)
+make_mapping (abfd, sections, from, to, phdr)
bfd *abfd;
asection **sections;
unsigned int from;
unsigned int to;
+ boolean phdr;
{
struct elf_segment_map *m;
unsigned int i;
(sizeof (struct elf_segment_map)
+ (to - from - 1) * sizeof (asection *))));
if (m == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
+ return NULL;
m->next = NULL;
m->p_type = PT_LOAD;
for (i = from, hdrpp = sections + from; i < to; i++, hdrpp++)
m->sections[i - from] = *hdrpp;
m->count = to - from;
+ if (from == 0 && phdr)
+ {
+ /* Include the headers in the first PT_LOAD segment. */
+ m->includes_filehdr = 1;
+ m->includes_phdrs = 1;
+ }
+
return m;
}
unsigned int phdr_index;
bfd_vma maxpagesize;
asection **hdrpp;
+ boolean phdr_in_segment = true;
+ boolean writable;
+ asection *dynsec;
if (elf_tdata (abfd)->segment_map != NULL)
return true;
/* Select the allocated sections, and sort them. */
- sections = (asection **) malloc (bfd_count_sections (abfd)
- * sizeof (asection *));
+ sections = (asection **) bfd_malloc (bfd_count_sections (abfd)
+ * sizeof (asection *));
if (sections == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
+ goto error_return;
i = 0;
for (s = abfd->sections; s != NULL; s = s->next)
m = ((struct elf_segment_map *)
bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
if (m == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
+ goto error_return;
m->next = NULL;
m->p_type = PT_PHDR;
/* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */
m->p_flags = PF_R | PF_X;
m->p_flags_valid = 1;
+ m->includes_phdrs = 1;
*pm = m;
pm = &m->next;
m = ((struct elf_segment_map *)
bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
if (m == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
+ goto error_return;
m->next = NULL;
m->p_type = PT_INTERP;
m->count = 1;
last_hdr = NULL;
phdr_index = 0;
maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
+ writable = false;
+ dynsec = bfd_get_section_by_name (abfd, ".dynamic");
+ if (dynsec != NULL
+ && (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. 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. */
- 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)))
+
+ 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);
+ m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
if (m == NULL)
goto error_return;
*pm = m;
pm = &m->next;
+ if ((hdr->flags & SEC_READONLY) == 0)
+ writable = true;
+ else
+ writable = false;
+
last_hdr = hdr;
phdr_index = i;
+ phdr_in_segment = false;
}
/* Create a final PT_LOAD program segment. */
if (last_hdr != NULL)
{
- m = make_mapping (abfd, sections, phdr_index, i);
+ m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
if (m == NULL)
goto error_return;
}
/* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */
- s = bfd_get_section_by_name (abfd, ".dynamic");
- if (s != NULL && (s->flags & SEC_LOAD) != 0)
+ if (dynsec != NULL)
{
m = ((struct elf_segment_map *)
bfd_zalloc (abfd, sizeof (struct elf_segment_map)));
if (m == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
+ goto error_return;
m->next = NULL;
m->p_type = PT_DYNAMIC;
m->count = 1;
- m->sections[0] = s;
+ m->sections[0] = dynsec;
*pm = m;
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;
- boolean found_load;
+ file_ptr off, voff;
+ bfd_vma filehdr_vaddr, filehdr_paddr;
+ bfd_vma phdrs_vaddr, phdrs_paddr;
Elf_Internal_Phdr *p;
if (elf_tdata (abfd)->segment_map == NULL)
return false;
}
+ if (bed->elf_backend_modify_segment_map)
+ {
+ if (! (*bed->elf_backend_modify_segment_map) (abfd))
+ return false;
+ }
+
count = 0;
for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
++count;
if (count == 0)
return true;
- /* Let the backend count up any program headers it might need. */
- if (bed->elf_backend_create_program_headers)
- count = ((*bed->elf_backend_create_program_headers)
- (abfd, (Elf_Internal_Phdr *) NULL, count));
-
/* If we already counted the number of program segments, make sure
that we allocated enough space. This happens when SIZEOF_HEADERS
is used in a linker script. */
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;
phdrs = ((Elf_Internal_Phdr *)
bfd_alloc (abfd, alloc * sizeof (Elf_Internal_Phdr)));
if (phdrs == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
off = bed->s->sizeof_ehdr;
off += alloc * bed->s->sizeof_phdr;
- found_load = false;
+ filehdr_vaddr = 0;
+ filehdr_paddr = 0;
+ phdrs_vaddr = 0;
+ phdrs_paddr = 0;
+
for (m = elf_tdata (abfd)->segment_map, p = phdrs;
m != NULL;
m = m->next, p++)
unsigned int i;
asection **secpp;
+ /* If elf_segment_map is not from map_sections_to_segments, the
+ sections may not be correctly ordered. */
+ if (m->count > 0)
+ qsort (m->sections, (size_t) m->count, sizeof (asection *),
+ elf_sort_sections);
+
p->p_type = m->p_type;
+ p->p_flags = m->p_flags;
+
+ if (p->p_type == PT_LOAD
+ && m->count > 0
+ && (m->sections[0]->flags & SEC_ALLOC) != 0)
+ {
+ if ((abfd->flags & D_PAGED) != 0)
+ off += (m->sections[0]->vma - off) % bed->maxpagesize;
+ else
+ {
+ bfd_size_type align;
+
+ align = 0;
+ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+ {
+ bfd_size_type secalign;
- if (m->p_flags_valid)
- p->p_flags = m->p_flags;
+ secalign = bfd_get_section_alignment (abfd, *secpp);
+ if (secalign > align)
+ align = secalign;
+ }
- if (p->p_type == PT_LOAD && m->count > 0)
- off += (m->sections[0]->vma - off) % bed->maxpagesize;
+ off += (m->sections[0]->vma - off) % (1 << align);
+ }
+ }
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;
else
p->p_align = 0;
+ p->p_offset = 0;
p->p_filesz = 0;
p->p_memsz = 0;
- if (p->p_type == PT_LOAD)
+ if (m->includes_filehdr)
+ {
+ if (! m->p_flags_valid)
+ p->p_flags |= PF_R;
+ p->p_offset = 0;
+ p->p_filesz = bed->s->sizeof_ehdr;
+ p->p_memsz = bed->s->sizeof_ehdr;
+ 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 (p->p_type == PT_LOAD)
+ {
+ filehdr_vaddr = p->p_vaddr;
+ filehdr_paddr = p->p_paddr;
+ }
+ }
+
+ if (m->includes_phdrs)
{
- p->p_offset = off;
+ if (! m->p_flags_valid)
+ p->p_flags |= PF_R;
- if (! found_load)
+ if (m->includes_filehdr)
{
- struct elf_segment_map *mi;
- Elf_Internal_Phdr *pi;
- struct elf_segment_map *mi_phdr;
- Elf_Internal_Phdr *pi_phdr;
-
- /* This is the first PT_LOAD segment. If there is a
- PT_INTERP segment, adjust the offset of this segment
- to include the program headers and the file header. */
- pi_phdr = NULL;
- for (mi = elf_tdata (abfd)->segment_map, pi = phdrs;
- mi != NULL;
- mi = mi->next, pi++)
+ if (p->p_type == PT_LOAD)
{
- if (mi->p_type == PT_INTERP)
- {
- p->p_offset = 0;
- p->p_filesz = off;
- p->p_memsz = off;
- p->p_vaddr -= off;
- if (! m->p_paddr_valid)
- p->p_paddr -= off;
- }
- if (mi->p_type == PT_PHDR)
- {
- mi_phdr = mi;
- pi_phdr = pi;
- }
+ phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr;
+ phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr;
+ }
+ }
+ else
+ {
+ p->p_offset = bed->s->sizeof_ehdr;
+
+ if (m->count > 0)
+ {
+ BFD_ASSERT (p->p_type == PT_LOAD);
+ p->p_vaddr -= off - p->p_offset;
+ if (! m->p_paddr_valid)
+ p->p_paddr -= off - p->p_offset;
}
- /* Set up the PT_PHDR addresses. */
- if (pi_phdr != NULL)
+ if (p->p_type == PT_LOAD)
{
- pi_phdr->p_vaddr = p->p_vaddr + bed->s->sizeof_ehdr;
- if (! mi_phdr->p_paddr_valid)
- pi_phdr->p_paddr = p->p_paddr + bed->s->sizeof_ehdr;
+ phdrs_vaddr = p->p_vaddr;
+ phdrs_paddr = p->p_paddr;
}
+ else
+ phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
+ }
- found_load = true;
+ p->p_filesz += alloc * bed->s->sizeof_phdr;
+ p->p_memsz += alloc * bed->s->sizeof_phdr;
+ }
+
+ if (p->p_type == PT_LOAD
+ || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
+ {
+ if (! m->includes_filehdr && ! m->includes_phdrs)
+ p->p_offset = off;
+ else
+ {
+ file_ptr adjust;
+
+ adjust = off - (p->p_offset + p->p_filesz);
+ p->p_filesz += adjust;
+ p->p_memsz += adjust;
}
}
- if (! m->p_flags_valid)
- p->p_flags = PF_R;
+ 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;
+
+ 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)
+ {
+ /* 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;
- /* The section VMA must equal the file position modulo
- the page size. */
- adjust = (sec->vma - off) % bed->maxpagesize;
if (adjust != 0)
{
if (i == 0)
- abort ();
+ {
+ (* _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;
- off += 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 && bfd_get_format (abfd) == 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_type != PT_LOAD || (abfd->flags & D_PAGED) == 0))
+ p->p_align = align;
+ }
if (! m->p_flags_valid)
{
+ p->p_flags |= PF_R;
if ((flags & SEC_CODE) != 0)
p->p_flags |= PF_X;
if ((flags & SEC_READONLY) == 0)
m = m->next, p++)
{
if (p->p_type != PT_LOAD && m->count > 0)
- p->p_offset = m->sections[0]->filepos;
- if (p->p_type == PT_PHDR)
{
- p->p_offset = bed->s->sizeof_ehdr;
- p->p_filesz = count * bed->s->sizeof_phdr;
- p->p_memsz = p->p_filesz;
+ BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs);
+ p->p_offset = m->sections[0]->filepos;
+ }
+ if (m->count == 0)
+ {
+ if (m->includes_filehdr)
+ {
+ p->p_vaddr = filehdr_vaddr;
+ if (! m->p_paddr_valid)
+ p->p_paddr = filehdr_paddr;
+ }
+ else if (m->includes_phdrs)
+ {
+ p->p_vaddr = phdrs_vaddr;
+ if (! m->p_paddr_valid)
+ p->p_paddr = phdrs_paddr;
+ }
}
}
- /* Let the backend set up any program headers it might need. */
- if (bed->elf_backend_create_program_headers)
- count = ((*bed->elf_backend_create_program_headers)
- (abfd, phdrs, count));
-
/* Clear out any program headers we allocated but did not use. */
for (; count < alloc; count++, p++)
{
if (elf_tdata (abfd)->program_header_size != 0)
return elf_tdata (abfd)->program_header_size;
+ if (elf_tdata (abfd)->segment_map != NULL)
+ {
+ struct elf_segment_map *m;
+
+ segs = 0;
+ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ ++segs;
+ elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
+ return elf_tdata (abfd)->program_header_size;
+ }
+
/* Assume we will need exactly two PT_LOAD segments: one for text
and one for data. */
segs = 2;
++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_create_program_headers)
- segs = ((*bed->elf_backend_create_program_headers)
- (abfd, (Elf_Internal_Phdr *) NULL, segs));
+ if (bed->elf_backend_additional_program_headers)
+ {
+ int a;
+
+ a = (*bed->elf_backend_additional_program_headers) (abfd);
+ if (a == -1)
+ abort ();
+ segs += a;
+ }
elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
return elf_tdata (abfd)->program_header_size;
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
+ && bfd_get_format (abfd) != 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_ident[EI_CLASS] = bed->s->elfclass;
i_ehdrp->e_ident[EI_DATA] =
- abfd->xvec->byteorder_big_p ? ELFDATA2MSB : ELFDATA2LSB;
+ bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB;
i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current;
+ i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_SYSV;
+ i_ehdrp->e_ident[EI_ABIVERSION] = 0;
+
for (count = EI_PAD; count < EI_NIDENT; count++)
i_ehdrp->e_ident[count] = 0;
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_i860:
i_ehdrp->e_machine = EM_860;
break;
+ case bfd_arch_i960:
+ i_ehdrp->e_machine = EM_960;
+ break;
case bfd_arch_mips: /* MIPS Rxxxx */
i_ehdrp->e_machine = EM_MIPS; /* only MIPS R3000 */
break;
case bfd_arch_powerpc:
i_ehdrp->e_machine = EM_PPC;
break;
-/* start-sanitize-arc */
- case bfd_arch_arc:
- i_ehdrp->e_machine = EM_CYGNUS_ARC;
+ case bfd_arch_alpha:
+ i_ehdrp->e_machine = EM_ALPHA;
break;
-/* end-sanitize-arc */
- /* also note that EM_M32, AT&T WE32100 is unknown to bfd */
+ 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_mcore:
+ i_ehdrp->e_machine = EM_MCORE;
+ 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;
+ 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;
+ case bfd_arch_pj:
+ i_ehdrp->e_machine = EM_PJ;
+ 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;
}
-/* given a symbol, return the bfd index for that symbol. */
- int
+/* Given a BFD symbol, return the index in the ELF symbol table, or -1
+ on error. */
+
+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;
}
idx = asym_ptr->udata.i;
- BFD_ASSERT (idx != 0);
+
+ if (idx == 0)
+ {
+ /* 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"),
+ 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",
- (long) asym_ptr, asym_ptr->name, idx, flags, elf_symbol_flags (flags));
+ _("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);
}
#endif
bfd *ibfd;
bfd *obfd;
{
+ 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)
if (elf_tdata (ibfd)->phdr == NULL)
return true;
+ iehdr = elf_elfheader (ibfd);
+
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 \
+ && bfd_get_format (ibfd) == 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++)
{
- struct elf_segment_map *m;
unsigned int csecs;
-
+ asection *s;
+ 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;
- if (p->p_type != PT_PHDR)
- {
- asection *s;
-
- 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->output_section != NULL)
+ for (s = ibfd->sections; s != NULL; s = s->next)
+ 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)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ 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;
- if (p->p_type != PT_PHDR)
+ /* 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 = 0;
+
+ 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;
+ matching_lma = false;
+ suggested_lma = 0;
+
+ for (j = 0, s = ibfd->sections; s != NULL; s = s->next)
{
- asection *s;
- unsigned int isec;
+ os = s->output_section;
- isec = 0;
- for (s = ibfd->sections; s != NULL; s = s->next)
+ 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)
{
- if (s->vma >= p->p_vaddr
- && s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz
- && s->output_section != NULL)
+ 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))
{
- m->sections[isec] = s->output_section;
- ++isec;
+ 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;
}
- qsort (m->sections, (size_t) csecs, sizeof (asection *),
- elf_sort_sections);
+ }
+
+ 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. */
- *pm = m;
- pm = &m->next;
+ 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;
+ elf_section_data (osec)->use_rela_p
+ = elf_section_data (isec)->use_rela_p;
+
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);
outbound_syms = bfd_alloc (abfd,
(1 + symcount) * bed->s->sizeof_sym);
if (outbound_syms == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
symtab_hdr->contents = (PTR) outbound_syms;
/* now generate the data (for "contents") */
bfd_vma value = syms[idx]->value;
elf_symbol_type *type_ptr;
flagword flags = syms[idx]->flags;
+ int type;
if (flags & BSF_SECTION_SYM)
/* Section symbols have no names. */
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;
sym.st_shndx = shndx;
}
- if (bfd_is_com_section (syms[idx]->section))
- sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT);
+ if ((flags & BSF_FUNCTION) != 0)
+ type = STT_FUNC;
+ else if ((flags & BSF_OBJECT) != 0)
+ type = STT_OBJECT;
+ else
+ type = STT_NOTYPE;
+
+ /* 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),
- ((flags & BSF_FUNCTION)
- ? STT_FUNC
- : STT_NOTYPE));
- else if (flags & BSF_SECTION_SYM)
- sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+ type);
else if (flags & BSF_FILE)
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
else
{
int bind = STB_LOCAL;
- int type = STT_OBJECT;
if (flags & BSF_LOCAL)
bind = STB_LOCAL;
else if (flags & BSF_GLOBAL)
bind = STB_GLOBAL;
- if (flags & BSF_FUNCTION)
- type = STT_FUNC;
-
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;
}
long
_bfd_elf_get_reloc_upper_bound (abfd, asect)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
sec_ptr asect;
{
return (asect->reloc_count + 1) * sizeof (arelent *);
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);
}
-asymbol *
-_bfd_elf_make_empty_symbol (abfd)
+/* 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;
{
- elf_symbol_type *newsym;
+ long ret;
+ asection *s;
- newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type));
- if (!newsym)
- {
- bfd_set_error (bfd_error_no_memory);
- return NULL;
- }
- else
+ if (elf_dynsymtab (abfd) == 0)
{
- newsym->symbol.the_bfd = abfd;
- return &newsym->symbol;
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
}
-}
-void
-_bfd_elf_get_symbol_info (ignore_abfd, symbol, ret)
- bfd *ignore_abfd;
- asymbol *symbol;
- symbol_info *ret;
-{
- bfd_symbol_info (symbol, ret);
-}
+ 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 *));
-alent *
-_bfd_elf_get_lineno (ignore_abfd, symbol)
- bfd *ignore_abfd;
- asymbol *symbol;
-{
- abort ();
- return NULL;
+ return ret;
}
-boolean
-_bfd_elf_set_arch_mach (abfd, arch, machine)
+/* 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;
- enum bfd_architecture arch;
- unsigned long machine;
+ arelent **storage;
+ asymbol **syms;
{
- /* If this isn't the right architecture for this backend, and this
- isn't the generic backend, fail. */
- if (arch != get_elf_backend_data (abfd)->arch
- && arch != bfd_arch_unknown
- && get_elf_backend_data (abfd)->arch != bfd_arch_unknown)
- return false;
+ boolean (*slurp_relocs) PARAMS ((bfd *, asection *, asymbol **, boolean));
+ asection *s;
+ long ret;
- return bfd_default_set_arch_mach (abfd, arch, machine);
-}
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
-/* Find the nearest line to a particular section and offset, for error
- reporting. */
+ 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_find_nearest_line (abfd,
- section,
- symbols,
- offset,
- filename_ptr,
- functionname_ptr,
- line_ptr)
+_bfd_elf_slurp_version_tables (abfd)
bfd *abfd;
- asection *section;
- asymbol **symbols;
- bfd_vma offset;
- CONST char **filename_ptr;
- CONST char **functionname_ptr;
- unsigned int *line_ptr;
{
- const char *filename;
- asymbol *func;
- asymbol **p;
+ bfd_byte *contents = NULL;
- if (symbols == NULL)
- return false;
+ if (elf_dynverdef (abfd) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+ Elf_External_Verdef *everdef;
+ Elf_Internal_Verdef *iverdef;
+ unsigned int i;
- filename = NULL;
- func = NULL;
+ hdr = &elf_tdata (abfd)->dynverdef_hdr;
- for (p = symbols; *p != NULL; p++)
- {
- elf_symbol_type *q;
+ 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;
- q = (elf_symbol_type *) *p;
+ elf_tdata (abfd)->cverdefs = hdr->sh_info;
- if (bfd_get_section (&q->symbol) != section)
- continue;
+ 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;
- switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
+ everdef = (Elf_External_Verdef *) contents;
+ iverdef = elf_tdata (abfd)->verdef;
+ for (i = 0; i < hdr->sh_info; i++, iverdef++)
{
- default:
- break;
- case STT_FILE:
- filename = bfd_asymbol_name (&q->symbol);
- break;
- case STT_FUNC:
- if (func == NULL
- || q->symbol.value <= offset)
- func = (asymbol *) q;
- break;
- }
- }
+ Elf_External_Verdaux *everdaux;
+ Elf_Internal_Verdaux *iverdaux;
+ unsigned int j;
- if (func == NULL)
- return false;
+ _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;
+{
+ elf_symbol_type *newsym;
+
+ newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type));
+ if (!newsym)
+ return NULL;
+ else
+ {
+ newsym->symbol.the_bfd = abfd;
+ return &newsym->symbol;
+ }
+}
+
+void
+_bfd_elf_get_symbol_info (ignore_abfd, symbol, ret)
+ bfd *ignore_abfd ATTRIBUTE_UNUSED;
+ asymbol *symbol;
+ symbol_info *ret;
+{
+ 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 ATTRIBUTE_UNUSED;
+ 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 ATTRIBUTE_UNUSED;
+ asymbol *symbol ATTRIBUTE_UNUSED;
+{
+ abort ();
+ return NULL;
+}
+
+boolean
+_bfd_elf_set_arch_mach (abfd, arch, machine)
+ bfd *abfd;
+ enum bfd_architecture arch;
+ unsigned long machine;
+{
+ /* If this isn't the right architecture for this backend, and this
+ isn't the generic backend, fail. */
+ if (arch != get_elf_backend_data (abfd)->arch
+ && arch != bfd_arch_unknown
+ && get_elf_backend_data (abfd)->arch != bfd_arch_unknown)
+ return false;
+
+ return bfd_default_set_arch_mach (abfd, arch, machine);
+}
+
+/* Find the nearest line to a particular section and offset, for error
+ reporting. */
+
+boolean
+_bfd_elf_find_nearest_line (abfd,
+ section,
+ symbols,
+ offset,
+ filename_ptr,
+ functionname_ptr,
+ line_ptr)
+ bfd *abfd;
+ asection *section;
+ asymbol **symbols;
+ bfd_vma offset;
+ CONST char **filename_ptr;
+ CONST char **functionname_ptr;
+ unsigned int *line_ptr;
+{
+ boolean found;
+ const char *filename;
+ asymbol *func;
+ bfd_vma low_func;
+ asymbol **p;
+
+ 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, 0))
+ 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;
+ if (found)
+ return true;
+
+ if (symbols == NULL)
+ return false;
+
+ filename = NULL;
+ func = NULL;
+ low_func = 0;
+
+ for (p = symbols; *p != NULL; p++)
+ {
+ elf_symbol_type *q;
+
+ q = (elf_symbol_type *) *p;
+
+ if (bfd_get_section (&q->symbol) != section)
+ continue;
+
+ switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
+ {
+ default:
+ break;
+ 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
+ && q->symbol.value <= offset)
+ {
+ func = (asymbol *) q;
+ low_func = q->symbol.value;
+ }
+ break;
+ }
+ }
+
+ if (func == NULL)
+ return false;
*filename_ptr = filename;
*functionname_ptr = bfd_asymbol_name (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;
void
_bfd_elf_no_info_to_howto (abfd, cache_ptr, dst)
- bfd *abfd;
- arelent *cache_ptr;
- Elf_Internal_Rela *dst;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *cache_ptr ATTRIBUTE_UNUSED;
+ Elf_Internal_Rela *dst ATTRIBUTE_UNUSED;
{
abort ();
}
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 ATTRIBUTE_UNUSED;
+ arelent *re ATTRIBUTE_UNUSED;
+ struct symbol_cache_entry *symbol ATTRIBUTE_UNUSED;
+ PTR data ATTRIBUTE_UNUSED;
+ asection *is ATTRIBUTE_UNUSED;
+ bfd *obfd ATTRIBUTE_UNUSED;
+ char **errmsg ATTRIBUTE_UNUSED;
+{
+ 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) */
+
+
+/* Create a pseudosection containing the exact contents of NOTE. This
+ actually creates up to two pseudosections:
+ - For the single-threaded case, a section named NAME, unless
+ such a section already exists.
+ - For the multi-threaded case, a section named "NAME/PID", where
+ PID is elfcore_make_pid (abfd).
+ Both pseudosections have identical contents: the contents of NOTE. */
+
+static boolean
+elfcore_make_note_pseudosection (abfd, name, note)
+ bfd* abfd;
+ char *name;
+ Elf_Internal_Note* note;
+{
+ char buf[100];
+ char *threaded_name;
+ asection* sect;
+
+ /* Build the section name. */
+
+ sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd));
+ threaded_name = bfd_alloc (abfd, strlen (buf) + 1);
+ if (threaded_name == NULL)
+ return false;
+ strcpy (threaded_name, buf);
+
+ sect = bfd_make_section (abfd, threaded_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, name, sect))
+ return false;
+
+ return true;
+}
+
+
+/* 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;
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+}
+
+
+/* Linux dumps the Intel SSE regs in a note named "LINUX" with a note
+ type of 5 (NT_PRXFPREG). Just include the whole note's contents
+ literally. */
+static boolean
+elfcore_grok_prxfpreg (abfd, note)
+ bfd* abfd;
+ Elf_Internal_Note* note;
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note);
+}
+
+
+#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)
+
+/* 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;
+}
+
+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) */
+
+#if defined (HAVE_WIN32_PSTATUS_T)
+static boolean
+elfcore_grok_win32pstatus (abfd, note)
+ bfd * abfd;
+ Elf_Internal_Note * note;
+{
+ char buf[30];
+ char * name;
+ asection * sect;
+ win32_pstatus_t pstatus;
+
+ if (note->descsz < sizeof (pstatus))
+ return true;
+
+ memcpy (& pstatus, note->descdata, note->descsz);
+
+ switch (pstatus.data_type)
+ {
+ case NOTE_INFO_PROCESS:
+ /* FIXME: need to add ->core_command. */
+ elf_tdata (abfd)->core_signal = pstatus.data.process_info.signal;
+ elf_tdata (abfd)->core_pid = pstatus.data.process_info.pid;
+ break ;
+
+ case NOTE_INFO_THREAD:
+ /* Make a ".reg/999" section. */
+ sprintf (buf, ".reg/%d", pstatus.data.thread_info.tid);
+
+ 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 (pstatus.data.thread_info.thread_context);
+ sect->filepos = note->descpos + offsetof (struct win32_pstatus,
+ data.thread_info.thread_context);
+ sect->flags = SEC_HAS_CONTENTS;
+ sect->alignment_power = 2;
+
+ if (pstatus.data.thread_info.is_active_thread)
+ if (! elfcore_maybe_make_sect (abfd, ".reg", sect))
+ return false;
+ break;
+
+ case NOTE_INFO_MODULE:
+ /* Make a ".module/xxxxxxxx" section. */
+ sprintf (buf, ".module/%08x" , pstatus.data.module_info.base_address);
+
+ 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;
+ break;
+
+ default:
+ return true;
+ }
+
+ return true;
+}
+#endif /* HAVE_WIN32_PSTATUS_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_WIN32_PSTATUS_T)
+ case NT_WIN32PSTATUS:
+ return elfcore_grok_win32pstatus (abfd, note);
+#endif
+
+ case NT_PRXFPREG: /* Linux SSE extension */
+ if (note->namesz == 5
+ && ! strcmp (note->namedata, "LINUX"))
+ return elfcore_grok_prxfpreg (abfd, note);
+ else
+ return true;
+
+#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;
+}
+
+
+/* FIXME: This function is now unnecessary. Callers can just call
+ bfd_section_from_phdr directly. */
+
+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;
+
+ return true;
+}
+
+
+\f
+/* Providing external access to the ELF program header table. */
+
+/* Return an upper bound on the number of bytes required to store a
+ copy of ABFD's program header table entries. Return -1 if an error
+ occurs; bfd_get_error will return an appropriate code. */
+long
+bfd_get_elf_phdr_upper_bound (abfd)
+ bfd *abfd;
+{
+ if (abfd->xvec->flavour != bfd_target_elf_flavour)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return -1;
+ }
+
+ return (elf_elfheader (abfd)->e_phnum
+ * sizeof (Elf_Internal_Phdr));
+}
+
+
+/* Copy ABFD's program header table entries to *PHDRS. The entries
+ will be stored as an array of Elf_Internal_Phdr structures, as
+ defined in include/elf/internal.h. To find out how large the
+ buffer needs to be, call bfd_get_elf_phdr_upper_bound.
+
+ Return the number of program header table entries read, or -1 if an
+ error occurs; bfd_get_error will return an appropriate code. */
+int
+bfd_get_elf_phdrs (abfd, phdrs)
+ bfd *abfd;
+ void *phdrs;
+{
+ int num_phdrs;
+
+ if (abfd->xvec->flavour != bfd_target_elf_flavour)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return -1;
+ }
+
+ num_phdrs = elf_elfheader (abfd)->e_phnum;
+ memcpy (phdrs, elf_tdata (abfd)->phdr,
+ num_phdrs * sizeof (Elf_Internal_Phdr));
+
+ return num_phdrs;
+}