/* ELF executable support for BFD.
- Copyright 1993 Free Software Foundation, Inc.
+ Copyright 1993, 1994, 1995, 1996, 1997 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 copy_private_bfd_data PARAMS ((bfd *, bfd *));
+static char *elf_read PARAMS ((bfd *, long, unsigned int));
+static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
+static boolean assign_section_numbers PARAMS ((bfd *));
+static INLINE int sym_is_global PARAMS ((bfd *, asymbol *));
+static boolean elf_map_symbols PARAMS ((bfd *));
+static bfd_size_type get_program_header_size PARAMS ((bfd *));
+
+/* Swap version information in and out. The version information is
+ currently size independent. If that ever changes, this code will
+ need to move into elfcode.h. */
+
+/* Swap in a Verdef structure. */
+
+void
+_bfd_elf_swap_verdef_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Verdef *src;
+ Elf_Internal_Verdef *dst;
+{
+ dst->vd_version = bfd_h_get_16 (abfd, src->vd_version);
+ dst->vd_flags = bfd_h_get_16 (abfd, src->vd_flags);
+ dst->vd_ndx = bfd_h_get_16 (abfd, src->vd_ndx);
+ dst->vd_cnt = bfd_h_get_16 (abfd, src->vd_cnt);
+ dst->vd_hash = bfd_h_get_32 (abfd, src->vd_hash);
+ dst->vd_aux = bfd_h_get_32 (abfd, src->vd_aux);
+ dst->vd_next = bfd_h_get_32 (abfd, src->vd_next);
+}
+
+/* Swap out a Verdef structure. */
+
+void
+_bfd_elf_swap_verdef_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Verdef *src;
+ Elf_External_Verdef *dst;
+{
+ bfd_h_put_16 (abfd, src->vd_version, dst->vd_version);
+ bfd_h_put_16 (abfd, src->vd_flags, dst->vd_flags);
+ bfd_h_put_16 (abfd, src->vd_ndx, dst->vd_ndx);
+ bfd_h_put_16 (abfd, src->vd_cnt, dst->vd_cnt);
+ bfd_h_put_32 (abfd, src->vd_hash, dst->vd_hash);
+ bfd_h_put_32 (abfd, src->vd_aux, dst->vd_aux);
+ bfd_h_put_32 (abfd, src->vd_next, dst->vd_next);
+}
+
+/* Swap in a Verdaux structure. */
+
+void
+_bfd_elf_swap_verdaux_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Verdaux *src;
+ Elf_Internal_Verdaux *dst;
+{
+ dst->vda_name = bfd_h_get_32 (abfd, src->vda_name);
+ dst->vda_next = bfd_h_get_32 (abfd, src->vda_next);
+}
+
+/* Swap out a Verdaux structure. */
+
+void
+_bfd_elf_swap_verdaux_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Verdaux *src;
+ Elf_External_Verdaux *dst;
+{
+ bfd_h_put_32 (abfd, src->vda_name, dst->vda_name);
+ bfd_h_put_32 (abfd, src->vda_next, dst->vda_next);
+}
+
+/* Swap in a Verneed structure. */
+
+void
+_bfd_elf_swap_verneed_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Verneed *src;
+ Elf_Internal_Verneed *dst;
+{
+ dst->vn_version = bfd_h_get_16 (abfd, src->vn_version);
+ dst->vn_cnt = bfd_h_get_16 (abfd, src->vn_cnt);
+ dst->vn_file = bfd_h_get_32 (abfd, src->vn_file);
+ dst->vn_aux = bfd_h_get_32 (abfd, src->vn_aux);
+ dst->vn_next = bfd_h_get_32 (abfd, src->vn_next);
+}
+
+/* Swap out a Verneed structure. */
+
+void
+_bfd_elf_swap_verneed_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Verneed *src;
+ Elf_External_Verneed *dst;
+{
+ bfd_h_put_16 (abfd, src->vn_version, dst->vn_version);
+ bfd_h_put_16 (abfd, src->vn_cnt, dst->vn_cnt);
+ bfd_h_put_32 (abfd, src->vn_file, dst->vn_file);
+ bfd_h_put_32 (abfd, src->vn_aux, dst->vn_aux);
+ bfd_h_put_32 (abfd, src->vn_next, dst->vn_next);
+}
+
+/* Swap in a Vernaux structure. */
+
+void
+_bfd_elf_swap_vernaux_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Vernaux *src;
+ Elf_Internal_Vernaux *dst;
+{
+ dst->vna_hash = bfd_h_get_32 (abfd, src->vna_hash);
+ dst->vna_flags = bfd_h_get_16 (abfd, src->vna_flags);
+ dst->vna_other = bfd_h_get_16 (abfd, src->vna_other);
+ dst->vna_name = bfd_h_get_32 (abfd, src->vna_name);
+ dst->vna_next = bfd_h_get_32 (abfd, src->vna_next);
+}
+
+/* Swap out a Vernaux structure. */
+
+void
+_bfd_elf_swap_vernaux_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Vernaux *src;
+ Elf_External_Vernaux *dst;
+{
+ bfd_h_put_32 (abfd, src->vna_hash, dst->vna_hash);
+ bfd_h_put_16 (abfd, src->vna_flags, dst->vna_flags);
+ bfd_h_put_16 (abfd, src->vna_other, dst->vna_other);
+ bfd_h_put_32 (abfd, src->vna_name, dst->vna_name);
+ bfd_h_put_32 (abfd, src->vna_next, dst->vna_next);
+}
+
+/* Swap in a Versym structure. */
+
+void
+_bfd_elf_swap_versym_in (abfd, src, dst)
+ bfd *abfd;
+ const Elf_External_Versym *src;
+ Elf_Internal_Versym *dst;
+{
+ dst->vs_vers = bfd_h_get_16 (abfd, src->vs_vers);
+}
+
+/* Swap out a Versym structure. */
+
+void
+_bfd_elf_swap_versym_out (abfd, src, dst)
+ bfd *abfd;
+ const Elf_Internal_Versym *src;
+ Elf_External_Versym *dst;
+{
+ bfd_h_put_16 (abfd, src->vs_vers, dst->vs_vers);
+}
/* Standard ELF hash function. Do not change this function; you will
cause invalid hash tables to be generated. (Well, you would if this
}
boolean
-elf_mkobject (abfd)
+bfd_elf_mkobject (abfd)
bfd * abfd;
{
/* this just does initialization */
&& 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;
&& phdr->p_paddr != 0
&& phdr->p_vaddr != phdr->p_paddr
&& phdr->p_vaddr <= hdr->sh_addr
- && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size)
+ && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size
+ && ((flags & SEC_LOAD) == 0
+ || (phdr->p_offset <= hdr->sh_offset
+ && (phdr->p_offset + phdr->p_filesz
+ >= hdr->sh_offset + hdr->sh_size))))
{
newsect->lma += phdr->p_paddr - phdr->p_vaddr;
break;
{
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;
(bfd_is_com_section (symbol->section)
? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value
: ((elf_symbol_type *) symbol)->internal_elf_sym.st_size));
+
+ /* If we have version information, print it. */
+ if (elf_tdata (abfd)->dynversym_section != 0
+ && (elf_tdata (abfd)->dynverdef_section != 0
+ || elf_tdata (abfd)->dynverref_section != 0))
+ {
+ unsigned int vernum;
+ const char *version_string;
+
+ vernum = ((elf_symbol_type *) symbol)->version & VERSYM_VERSION;
+
+ if (vernum == 0)
+ version_string = "";
+ else if (vernum == 1)
+ version_string = "Base";
+ else if (vernum <= elf_tdata (abfd)->cverdefs)
+ version_string =
+ elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+ else
+ {
+ Elf_Internal_Verneed *t;
+
+ version_string = "";
+ for (t = elf_tdata (abfd)->verref;
+ t != NULL;
+ t = t->vn_nextref)
+ {
+ Elf_Internal_Vernaux *a;
+
+ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+ {
+ if (a->vna_other == vernum)
+ {
+ version_string = a->vna_nodename;
+ break;
+ }
+ }
+ }
+ }
+
+ if ((((elf_symbol_type *) symbol)->version & VERSYM_HIDDEN) == 0)
+ fprintf (file, " %-11s", version_string);
+ else
+ {
+ int i;
+
+ fprintf (file, " (%s)", version_string);
+ for (i = 10 - strlen (version_string); i > 0; --i)
+ putc (' ', file);
+ }
+ }
+
+ /* If the st_other field is not zero, print it. */
+ if (((elf_symbol_type *) symbol)->internal_elf_sym.st_other != 0)
+ fprintf (file, " 0x%02x",
+ ((unsigned int)
+ ((elf_symbol_type *) symbol)->internal_elf_sym.st_other));
+
fprintf (file, " %s", symbol->name);
}
break;
ret->weakdef = NULL;
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->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);
}
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 ELF emulation code. */
struct bfd_link_needed_list *
bfd_elf_get_needed_list (abfd, info)
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;
+}
\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;
/* For some incomprehensible reason Oracle distributes
libraries for Solaris in which some of the objects have
if (hdr->sh_link != elf_onesymtab (abfd))
return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
- /* Don't allow REL relocations on a machine that uses RELA and
- vice versa. */
- /* @@ Actually, the generic ABI does suggest that both might be
- used in one file. But the four ABI Processor Supplements I
- have access to right now all specify that only one is used on
- each of those architectures. It's conceivable that, e.g., a
- bunch of absolute 32-bit relocs might be more compact in REL
- form even on a RELA machine... */
- BFD_ASSERT (use_rela_p
- ? (hdr->sh_type == SHT_RELA
- && hdr->sh_entsize == bed->s->sizeof_rela)
- : (hdr->sh_type == SHT_REL
- && hdr->sh_entsize == bed->s->sizeof_rel));
-
if (! bfd_section_from_shdr (abfd, hdr->sh_info))
return false;
target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info);
if (target_sect == NULL)
return false;
- hdr2 = &elf_section_data (target_sect)->rel_hdr;
+ if ((target_sect->flags & SEC_RELOC) == 0
+ || target_sect->reloc_count == 0)
+ hdr2 = &elf_section_data (target_sect)->rel_hdr;
+ else
+ {
+ BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL);
+ hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
+ elf_section_data (target_sect)->rel_hdr2 = hdr2;
+ }
*hdr2 = *hdr;
elf_elfsections (abfd)[shindex] = hdr2;
- target_sect->reloc_count = hdr->sh_size / hdr->sh_entsize;
+ target_sect->reloc_count += hdr->sh_size / hdr->sh_entsize;
target_sect->flags |= SEC_RELOC;
target_sect->relocation = NULL;
target_sect->rel_filepos = hdr->sh_offset;
}
break;
- case SHT_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:
this_hdr->sh_flags = 0;
- if ((asect->flags & SEC_ALLOC) != 0)
+ if ((asect->flags & SEC_ALLOC) != 0
+ || asect->user_set_vma)
this_hdr->sh_addr = asect->vma;
else
this_hdr->sh_addr = 0;
this_hdr->sh_type = SHT_REL;
this_hdr->sh_entsize = bed->s->sizeof_rel;
}
- else if (strcmp (asect->name, ".note") == 0)
+ else if (strncmp (asect->name, ".note", 5) == 0)
this_hdr->sh_type = SHT_NOTE;
else if (strncmp (asect->name, ".stab", 5) == 0
&& strcmp (asect->name + strlen (asect->name) - 3, "str") == 0)
this_hdr->sh_type = SHT_STRTAB;
+ else if (strcmp (asect->name, ".gnu.version") == 0)
+ {
+ this_hdr->sh_type = SHT_GNU_versym;
+ this_hdr->sh_entsize = sizeof (Elf_External_Versym);
+ }
+ else if (strcmp (asect->name, ".gnu.version_d") == 0)
+ {
+ this_hdr->sh_type = SHT_GNU_verdef;
+ this_hdr->sh_entsize = 0;
+ /* objcopy or strip will copy over sh_info, but may not set
+ cverdefs. The linker will set cverdefs, but sh_info will be
+ zero. */
+ if (this_hdr->sh_info == 0)
+ this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->cverdefs == 0
+ || this_hdr->sh_info == elf_tdata (abfd)->cverdefs);
+ }
+ else if (strcmp (asect->name, ".gnu.version_r") == 0)
+ {
+ this_hdr->sh_type = SHT_GNU_verneed;
+ this_hdr->sh_entsize = 0;
+ /* objcopy or strip will copy over sh_info, but may not set
+ cverrefs. The linker will set cverrefs, but sh_info will be
+ zero. */
+ if (this_hdr->sh_info == 0)
+ this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0
+ || this_hdr->sh_info == elf_tdata (abfd)->cverrefs);
+ }
else if ((asect->flags & SEC_ALLOC) != 0
&& (asect->flags & SEC_LOAD) != 0)
this_hdr->sh_type = SHT_PROGBITS;
case SHT_DYNAMIC:
case SHT_DYNSYM:
+ case SHT_GNU_verneed:
+ case SHT_GNU_verdef:
/* sh_link is the section header index of the string table
- used for the dynamic entries or symbol table. */
+ used for the dynamic entries, or the symbol table, or the
+ version strings. */
s = bfd_get_section_by_name (abfd, ".dynstr");
if (s != NULL)
d->this_hdr.sh_link = elf_section_data (s)->this_idx;
break;
case SHT_HASH:
+ case SHT_GNU_versym:
/* sh_link is the section header index of the symbol table
- this hash table is for. */
+ this hash table or version table is for. */
s = bfd_get_section_by_name (abfd, ".dynsym");
if (s != NULL)
d->this_hdr.sh_link = elf_section_data (s)->this_idx;
/* 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;
m->sections[i - from] = *hdrpp;
m->count = to - from;
- if (from == 0)
+ if (from == 0 && phdr)
{
/* Include the headers in the first PT_LOAD segment. */
m->includes_filehdr = 1;
unsigned int phdr_index;
bfd_vma maxpagesize;
asection **hdrpp;
+ boolean phdr_in_section = true;
+ boolean writable;
+ asection *dynsec;
if (elf_tdata (abfd)->segment_map != NULL)
return true;
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 % maxpagesize < phdr_size % maxpagesize)
+ phdr_in_section = 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_section);
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_section = 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_section);
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)));
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;
else if (sec1->vma > sec2->vma)
return 1;
+ /* Sort by LMA. Normally the LMA and the VMA will be the same, and
+ this will do nothing. */
+ if (sec1->lma < sec2->lma)
+ return -1;
+ else if (sec1->lma > sec2->lma)
+ return 1;
+
/* Put !SEC_LOAD sections after SEC_LOAD ones. */
#define TOEND(x) (((x)->flags & SEC_LOAD) == 0)
struct elf_segment_map *m;
unsigned int alloc;
Elf_Internal_Phdr *phdrs;
- file_ptr off;
+ file_ptr off, voff;
bfd_vma filehdr_vaddr, filehdr_paddr;
bfd_vma phdrs_vaddr, phdrs_paddr;
Elf_Internal_Phdr *p;
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 (m->p_flags_valid)
p->p_flags = m->p_flags;
+ else
+ p->p_flags = 0;
- if (p->p_type == PT_LOAD && m->count > 0)
- off += (m->sections[0]->vma - off) % bed->maxpagesize;
+ 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
+ off += ((m->sections[0]->vma - off)
+ % (1 << bfd_get_section_alignment (abfd, m->sections[0])));
+ }
if (m->count == 0)
p->p_vaddr = 0;
else
p->p_paddr = m->sections[0]->lma;
- if (p->p_type == PT_LOAD)
+ if (p->p_type == PT_LOAD
+ && (abfd->flags & D_PAGED) != 0)
p->p_align = bed->maxpagesize;
else if (m->count == 0)
p->p_align = bed->s->file_align;
if (m->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 < off)
+ {
+ _bfd_error_handler ("%s: Not enough room for program headers, try linking with -N",
+ bfd_get_filename (abfd));
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
p->p_vaddr -= off;
if (! m->p_paddr_valid)
p->p_paddr -= off;
if (m->includes_phdrs)
{
+ if (! m->p_flags_valid)
+ p->p_flags |= PF_R;
if (m->includes_filehdr)
{
if (p->p_type == PT_LOAD)
}
}
- 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);
if (p->p_type == PT_LOAD)
{
bfd_vma adjust;
- /* The section VMA must equal the file position modulo
- the page size. */
- adjust = (sec->vma - off) % bed->maxpagesize;
+ if ((flags & SEC_LOAD) != 0)
+ adjust = sec->lma - (p->p_paddr + p->p_memsz);
+ 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;
+ }
+
if (adjust != 0)
{
if (i == 0)
abort ();
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 ((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 (! m->p_flags_valid)
{
+ p->p_flags |= PF_R;
if ((flags & SEC_CODE) != 0)
p->p_flags |= PF_X;
if ((flags & SEC_READONLY) == 0)
}
}
- /* 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++)
{
++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;
(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);
}
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;
for (count = EI_PAD; count < EI_NIDENT; count++)
case bfd_arch_powerpc:
i_ehdrp->e_machine = EM_PPC;
break;
-/* start-sanitize-arc */
- case bfd_arch_arc:
+ case bfd_arch_alpha:
+ i_ehdrp->e_machine = EM_ALPHA;
+ break;
+ case bfd_arch_sh:
+ i_ehdrp->e_machine = EM_SH;
+ break;
+ case bfd_arch_d10v:
+ i_ehdrp->e_machine = EM_CYGNUS_D10V;
+ break;
+/* start-sanitize-d30v */
+ case bfd_arch_d30v:
+ i_ehdrp->e_machine = EM_CYGNUS_D30V;
+ break;
+/* end-sanitize-d30v */
+ case bfd_arch_v850:
+ switch (bfd_get_mach (abfd))
+ {
+ default:
+ case 0: i_ehdrp->e_machine = EM_CYGNUS_V850; break;
+ }
+ break;
+ case bfd_arch_arc:
i_ehdrp->e_machine = EM_CYGNUS_ARC;
break;
-/* end-sanitize-arc */
+ case bfd_arch_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;
+/* start-sanitize-sky */
+ case bfd_arch_txvu:
+ i_ehdrp->e_machine = EM_CYGNUS_TXVU;
+ break;
+/* end-sanitize-sky */
/* also note that EM_M32, AT&T WE32100 is unknown to bfd */
default:
i_ehdrp->e_machine = EM_NONE;
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));
+ (long) asym_ptr, asym_ptr->name, idx, flags,
+ elf_symbol_flags (flags));
fflush (stderr);
}
#endif
&& (bfd_vma) s->filepos >= p->p_offset
&& ((bfd_vma) s->filepos + s->_raw_size
<= p->p_offset + p->p_filesz)))
+ && (s->flags & SEC_ALLOC) != 0
&& s->output_section != NULL)
++csecs;
m = ((struct elf_segment_map *)
bfd_alloc (obfd,
(sizeof (struct elf_segment_map)
- + (csecs - 1) * sizeof (asection *))));
+ + ((size_t) csecs - 1) * sizeof (asection *))));
if (m == NULL)
return false;
&& (bfd_vma) s->filepos >= p->p_offset
&& ((bfd_vma) s->filepos + s->_raw_size
<= p->p_offset + p->p_filesz)))
+ && (s->flags & SEC_ALLOC) != 0
&& s->output_section != NULL)
{
m->sections[isec] = s->output_section;
ohdr->sh_entsize = ihdr->sh_entsize;
if (ihdr->sh_type == SHT_SYMTAB
- || ihdr->sh_type == SHT_DYNSYM)
+ || ihdr->sh_type == SHT_DYNSYM
+ || ihdr->sh_type == SHT_GNU_verneed
+ || ihdr->sh_type == SHT_GNU_verdef)
ohdr->sh_info = ihdr->sh_info;
return true;
{
elf_symbol_type *isym, *osym;
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return true;
+
isym = elf_symbol_from (ibfd, isymarg);
osym = elf_symbol_from (obfd, osymarg);
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. */
sym.st_shndx = shndx;
}
+ if ((flags & BSF_FUNCTION) != 0)
+ type = STT_FUNC;
+ else if ((flags & BSF_OBJECT) != 0)
+ type = STT_OBJECT;
+ else
+ type = STT_NOTYPE;
+
if (bfd_is_com_section (syms[idx]->section))
- sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT);
+ 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));
+ type);
else if (flags & BSF_SECTION_SYM)
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
else if (flags & BSF_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;
}
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;
return get_elf_backend_data (abfd)->s->slurp_symbol_table (abfd, alocation, true);
}
+/* Return the size required for the dynamic reloc entries. Any
+ section that was actually installed in the BFD, and has type
+ SHT_REL or SHT_RELA, and uses the dynamic symbol table, is
+ considered to be a dynamic reloc section. */
+
+long
+_bfd_elf_get_dynamic_reloc_upper_bound (abfd)
+ bfd *abfd;
+{
+ long ret;
+ asection *s;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ ret = sizeof (arelent *);
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ ret += ((s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize)
+ * sizeof (arelent *));
+
+ return ret;
+}
+
+/* Canonicalize the dynamic relocation entries. Note that we return
+ the dynamic relocations as a single block, although they are
+ actually associated with particular sections; the interface, which
+ was designed for SunOS style shared libraries, expects that there
+ is only one set of dynamic relocs. Any section that was actually
+ installed in the BFD, and has type SHT_REL or SHT_RELA, and uses
+ the dynamic symbol table, is considered to be a dynamic reloc
+ section. */
+
+long
+_bfd_elf_canonicalize_dynamic_reloc (abfd, storage, syms)
+ bfd *abfd;
+ arelent **storage;
+ asymbol **syms;
+{
+ boolean (*slurp_relocs) PARAMS ((bfd *, asection *, asymbol **, boolean));
+ asection *s;
+ long ret;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+ ret = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ {
+ arelent *p;
+ long count, i;
+
+ if (! (*slurp_relocs) (abfd, s, syms, true))
+ return -1;
+ count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize;
+ p = s->relocation;
+ for (i = 0; i < count; i++)
+ *storage++ = p++;
+ ret += count;
+ }
+ }
+
+ *storage = NULL;
+
+ return ret;
+}
+\f
+/* Read in the version information. */
+
+boolean
+_bfd_elf_slurp_version_tables (abfd)
+ bfd *abfd;
+{
+ bfd_byte *contents = NULL;
+
+ if (elf_dynverdef (abfd) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+ Elf_External_Verdef *everdef;
+ Elf_Internal_Verdef *iverdef;
+ unsigned int i;
+
+ hdr = &elf_tdata (abfd)->dynverdef_hdr;
+
+ elf_tdata (abfd)->verdef =
+ ((Elf_Internal_Verdef *)
+ bfd_zalloc (abfd, hdr->sh_info * sizeof (Elf_Internal_Verdef)));
+ if (elf_tdata (abfd)->verdef == NULL)
+ goto error_return;
+
+ elf_tdata (abfd)->cverdefs = hdr->sh_info;
+
+ contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ goto error_return;
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+ || bfd_read ((PTR) contents, 1, hdr->sh_size, abfd) != hdr->sh_size)
+ goto error_return;
+
+ everdef = (Elf_External_Verdef *) contents;
+ iverdef = elf_tdata (abfd)->verdef;
+ for (i = 0; i < hdr->sh_info; i++, iverdef++)
+ {
+ Elf_External_Verdaux *everdaux;
+ Elf_Internal_Verdaux *iverdaux;
+ unsigned int j;
+
+ _bfd_elf_swap_verdef_in (abfd, everdef, iverdef);
+
+ iverdef->vd_bfd = abfd;
+
+ iverdef->vd_auxptr = ((Elf_Internal_Verdaux *)
+ bfd_alloc (abfd,
+ (iverdef->vd_cnt
+ * sizeof (Elf_Internal_Verdaux))));
+ if (iverdef->vd_auxptr == NULL)
+ goto error_return;
+
+ everdaux = ((Elf_External_Verdaux *)
+ ((bfd_byte *) everdef + iverdef->vd_aux));
+ iverdaux = iverdef->vd_auxptr;
+ for (j = 0; j < iverdef->vd_cnt; j++, iverdaux++)
+ {
+ _bfd_elf_swap_verdaux_in (abfd, everdaux, iverdaux);
+
+ iverdaux->vda_nodename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ iverdaux->vda_name);
+ if (iverdaux->vda_nodename == NULL)
+ goto error_return;
+
+ if (j + 1 < iverdef->vd_cnt)
+ iverdaux->vda_nextptr = iverdaux + 1;
+ else
+ iverdaux->vda_nextptr = NULL;
+
+ everdaux = ((Elf_External_Verdaux *)
+ ((bfd_byte *) everdaux + iverdaux->vda_next));
+ }
+
+ iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
+
+ if (i + 1 < hdr->sh_info)
+ iverdef->vd_nextdef = iverdef + 1;
+ else
+ iverdef->vd_nextdef = NULL;
+
+ everdef = ((Elf_External_Verdef *)
+ ((bfd_byte *) everdef + iverdef->vd_next));
+ }
+
+ free (contents);
+ contents = NULL;
+ }
+
+ if (elf_dynverref (abfd) != 0)
+ {
+ Elf_Internal_Shdr *hdr;
+ Elf_External_Verneed *everneed;
+ Elf_Internal_Verneed *iverneed;
+ unsigned int i;
+
+ hdr = &elf_tdata (abfd)->dynverref_hdr;
+
+ elf_tdata (abfd)->verref =
+ ((Elf_Internal_Verneed *)
+ bfd_zalloc (abfd, hdr->sh_info * sizeof (Elf_Internal_Verneed)));
+ if (elf_tdata (abfd)->verref == NULL)
+ goto error_return;
+
+ elf_tdata (abfd)->cverrefs = hdr->sh_info;
+
+ contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ goto error_return;
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+ || bfd_read ((PTR) contents, 1, hdr->sh_size, abfd) != hdr->sh_size)
+ goto error_return;
+
+ everneed = (Elf_External_Verneed *) contents;
+ iverneed = elf_tdata (abfd)->verref;
+ for (i = 0; i < hdr->sh_info; i++, iverneed++)
+ {
+ Elf_External_Vernaux *evernaux;
+ Elf_Internal_Vernaux *ivernaux;
+ unsigned int j;
+
+ _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
+
+ iverneed->vn_bfd = abfd;
+
+ iverneed->vn_filename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ iverneed->vn_file);
+ if (iverneed->vn_filename == NULL)
+ goto error_return;
+
+ iverneed->vn_auxptr =
+ ((Elf_Internal_Vernaux *)
+ bfd_alloc (abfd,
+ iverneed->vn_cnt * sizeof (Elf_Internal_Vernaux)));
+
+ evernaux = ((Elf_External_Vernaux *)
+ ((bfd_byte *) everneed + iverneed->vn_aux));
+ ivernaux = iverneed->vn_auxptr;
+ for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
+ {
+ _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+
+ ivernaux->vna_nodename =
+ bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+ ivernaux->vna_name);
+ if (ivernaux->vna_nodename == NULL)
+ goto error_return;
+
+ if (j + 1 < iverneed->vn_cnt)
+ ivernaux->vna_nextptr = ivernaux + 1;
+ else
+ ivernaux->vna_nextptr = NULL;
+
+ evernaux = ((Elf_External_Vernaux *)
+ ((bfd_byte *) evernaux + ivernaux->vna_next));
+ }
+
+ if (i + 1 < hdr->sh_info)
+ iverneed->vn_nextref = iverneed + 1;
+ else
+ iverneed->vn_nextref = NULL;
+
+ everneed = ((Elf_External_Verneed *)
+ ((bfd_byte *) everneed + iverneed->vn_next));
+ }
+
+ free (contents);
+ contents = NULL;
+ }
+
+ return true;
+
+ error_return:
+ if (contents == NULL)
+ free (contents);
+ return false;
+}
+\f
asymbol *
_bfd_elf_make_empty_symbol (abfd)
bfd *abfd;
bfd_symbol_info (symbol, ret);
}
+/* Return whether a symbol name implies a local symbol. Most targets
+ use this function for the is_local_label_name entry point, but some
+ override it. */
+
+boolean
+_bfd_elf_is_local_label_name (abfd, name)
+ bfd *abfd;
+ const char *name;
+{
+ /* Normal local symbols start with ``.L''. */
+ if (name[0] == '.' && name[1] == 'L')
+ return true;
+
+ /* At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate
+ DWARF debugging symbols starting with ``..''. */
+ if (name[0] == '.' && name[1] == '.')
+ return true;
+
+ /* gcc will sometimes generate symbols beginning with ``_.L_'' when
+ emitting DWARF debugging output. I suspect this is actually a
+ small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call
+ ASM_GENERATE_INTERNAL_LABEL, and this causes the leading
+ underscore to be emitted on some ELF targets). For ease of use,
+ we treat such symbols as local. */
+ if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
+ return true;
+
+ return false;
+}
+
alent *
_bfd_elf_get_lineno (ignore_abfd, symbol)
bfd *ignore_abfd;
CONST char **functionname_ptr;
unsigned int *line_ptr;
{
+ boolean found;
const char *filename;
asymbol *func;
+ bfd_vma low_func;
asymbol **p;
+ if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+ filename_ptr, functionname_ptr,
+ line_ptr))
+ return true;
+
+ if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
+ &found, filename_ptr,
+ functionname_ptr, line_ptr,
+ &elf_tdata (abfd)->line_info))
+ return false;
+ if (found)
+ return true;
+
if (symbols == NULL)
return false;
filename = NULL;
func = NULL;
+ low_func = 0;
for (p = symbols; *p != NULL; p++)
{
filename = bfd_asymbol_name (&q->symbol);
break;
case STT_FUNC:
- if (func == NULL
- || q->symbol.value <= offset)
- func = (asymbol *) q;
+ if (q->symbol.section == section
+ && q->symbol.value >= low_func
+ && q->symbol.value <= offset)
+ {
+ func = (asymbol *) q;
+ low_func = q->symbol.value;
+ }
break;
}
}
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;
+}