X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf.c;h=6c29ca762e98a1969f0acc50d9cacd7575e55184;hb=bc6b39f5f5186513c2ed28da36c14746b145d26d;hp=ba00bc8d0ce6dd3cfb4b1ea5e7a93928c5fe988c;hpb=44ef8897daee098e361b279406693bc6849c61e5;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf.c b/bfd/elf.c index ba00bc8d0c..6c29ca762e 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1,5 +1,5 @@ /* 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. @@ -39,12 +39,164 @@ SECTION #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 @@ -82,10 +234,7 @@ elf_read (abfd, offset, size) 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) @@ -98,7 +247,7 @@ elf_read (abfd, offset, size) } boolean -elf_mkobject (abfd) +bfd_elf_mkobject (abfd) bfd * abfd; { /* this just does initialization */ @@ -106,10 +255,7 @@ elf_mkobject (abfd) 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? */ @@ -159,6 +305,18 @@ bfd_elf_string_from_elf_section (abfd, shindex, strindex) && 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; } @@ -216,6 +374,15 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name) || 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; @@ -229,9 +396,14 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name) for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) { if (phdr->p_type == PT_LOAD + && phdr->p_paddr != 0 && phdr->p_vaddr != phdr->p_paddr && phdr->p_vaddr <= hdr->sh_addr - && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size) + && 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; @@ -339,56 +511,212 @@ _bfd_elf_print_private_bfd_data (abfd, farg) { 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; - c = elf_elfheader (abfd)->e_phnum; - for (i = 0; i < c; i++, p++) + (*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"); + } + } + } + + 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; @@ -418,6 +746,64 @@ bfd_elf_print_symbol (ignore_abfd, filep, symbol, 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; @@ -440,10 +826,7 @@ _bfd_elf_link_hash_newfunc (entry, table, string) 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 *) @@ -459,8 +842,15 @@ _bfd_elf_link_hash_newfunc (entry, table, string) 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; @@ -483,6 +873,8 @@ _bfd_elf_link_hash_table_init (table, abfd, newfunc) 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); } @@ -497,10 +889,7 @@ _bfd_elf_link_hash_table_create (abfd) 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)) { @@ -521,11 +910,13 @@ bfd_elf_set_dt_needed_name (abfd, name) 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) @@ -536,6 +927,20 @@ 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; +} /* Allocate an ELF string table--force the first byte to be zero. */ @@ -586,6 +991,7 @@ bfd_section_from_shdr (abfd, shindex) 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 */ @@ -685,7 +1091,6 @@ bfd_section_from_shdr (abfd, shindex) { 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 @@ -730,30 +1135,24 @@ bfd_section_from_shdr (abfd, shindex) 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; @@ -762,7 +1161,22 @@ bfd_section_from_shdr (abfd, shindex) } 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: @@ -803,10 +1217,7 @@ _bfd_elf_new_section_hook (abfd, sec) sdata = (struct bfd_elf_section_data *) bfd_alloc (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)); return true; @@ -851,10 +1262,7 @@ bfd_section_from_phdr (abfd, hdr, index) sprintf (namebuf, split ? "segment%da" : "segment%d", 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) @@ -885,10 +1293,7 @@ bfd_section_from_phdr (abfd, hdr, index) sprintf (namebuf, "segment%db", 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) @@ -942,7 +1347,8 @@ elf_fake_sections (abfd, asect, failedptrarg) 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; @@ -987,11 +1393,42 @@ elf_fake_sections (abfd, asect, failedptrarg) 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; @@ -1031,7 +1468,6 @@ elf_fake_sections (abfd, asect, failedptrarg) name = bfd_alloc (abfd, sizeof ".rela" + strlen (asect->name)); if (name == NULL) { - bfd_set_error (bfd_error_no_memory); *failedptr = true; return; } @@ -1100,17 +1536,13 @@ assign_section_numbers (abfd) 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)); @@ -1182,12 +1614,9 @@ assign_section_numbers (abfd) 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); @@ -1205,16 +1634,20 @@ assign_section_numbers (abfd) 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; @@ -1276,10 +1709,7 @@ elf_map_symbols (abfd) 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++) @@ -1356,10 +1786,7 @@ elf_map_symbols (abfd) 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++) { @@ -1520,11 +1947,12 @@ _bfd_elf_compute_section_file_positions (abfd, link_info) /* 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; @@ -1535,16 +1963,20 @@ make_mapping (abfd, sections, from, to) (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; } @@ -1565,6 +1997,9 @@ map_sections_to_segments (abfd) 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; @@ -1574,13 +2009,10 @@ map_sections_to_segments (abfd) /* 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) @@ -1610,15 +2042,13 @@ map_sections_to_segments (abfd) 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; @@ -1626,10 +2056,7 @@ map_sections_to_segments (abfd) 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; @@ -1645,43 +2072,124 @@ map_sections_to_segments (abfd) 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) + < hdr->lma) + { + /* 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 ((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 ((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 (! 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; @@ -1690,30 +2198,50 @@ map_sections_to_segments (abfd) } /* 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; } - free (sections); - sections = NULL; - - elf_tdata (abfd)->segment_map = mfirst; - return true; + /* 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; + + elf_tdata (abfd)->segment_map = mfirst; + return true; error_return: if (sections != NULL) @@ -1736,6 +2264,13 @@ elf_sort_sections (arg1, arg2) 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) @@ -1775,8 +2310,9 @@ assign_file_positions_for_segments (abfd) 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) @@ -1785,6 +2321,12 @@ assign_file_positions_for_segments (abfd) 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; @@ -1796,11 +2338,6 @@ assign_file_positions_for_segments (abfd) 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. */ @@ -1820,15 +2357,15 @@ assign_file_positions_for_segments (abfd) 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++) @@ -1836,13 +2373,29 @@ assign_file_positions_for_segments (abfd) 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; 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; @@ -1856,59 +2409,86 @@ assign_file_positions_for_segments (abfd) 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) { - p->p_offset = off; + 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); + 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 (! found_load) + if (m->includes_phdrs) + { + if (! m->p_flags_valid) + p->p_flags |= PF_R; + if (m->includes_filehdr) { - struct elf_segment_map *mi; - Elf_Internal_Phdr *pi; - 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; - p->p_paddr -= off; - } - if (mi->p_type == PT_PHDR) - pi_phdr = pi; + phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr; + phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr; } - - /* Set up the PT_PHDR addresses. */ - if (pi_phdr != NULL) + } + else + { + p->p_offset = bed->s->sizeof_ehdr; + if (m->count > 0) { - pi_phdr->p_vaddr = p->p_vaddr + bed->s->sizeof_ehdr; - pi_phdr->p_paddr = p->p_paddr + bed->s->sizeof_ehdr; + 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; } + if (p->p_type == PT_LOAD) + { + phdrs_vaddr = p->p_vaddr; + phdrs_paddr = p->p_paddr; + } + } + p->p_filesz += alloc * bed->s->sizeof_phdr; + p->p_memsz += alloc * bed->s->sizeof_phdr; + } - found_load = true; + if (p->p_type == PT_LOAD) + { + 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; @@ -1917,6 +2497,7 @@ assign_file_positions_for_segments (abfd) sec = *secpp; flags = sec->flags; + align = 1 << bfd_get_section_alignment (abfd, sec); if (p->p_type == PT_LOAD) { @@ -1924,21 +2505,30 @@ assign_file_positions_for_segments (abfd) /* The section VMA must equal the file position modulo the page size. */ - adjust = (sec->vma - off) % bed->maxpagesize; - if (adjust != 0) + if ((flags & SEC_ALLOC) != 0) { - if (i == 0) - abort (); - p->p_memsz += adjust; - if ((flags & SEC_LOAD) != 0) - p->p_filesz += adjust; - off += adjust; + 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; + } } sec->filepos = off; if ((flags & SEC_LOAD) != 0) off += sec->_raw_size; + if ((flags & SEC_ALLOC) != 0) + voff += sec->_raw_size; } p->p_memsz += sec->_raw_size; @@ -1946,12 +2536,12 @@ assign_file_positions_for_segments (abfd) 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) @@ -1967,20 +2557,27 @@ assign_file_positions_for_segments (abfd) 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++) { @@ -2023,6 +2620,17 @@ get_program_header_size (abfd) 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; @@ -2043,10 +2651,26 @@ get_program_header_size (abfd) ++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; @@ -2133,7 +2757,10 @@ assign_file_positions_except_relocs (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); } @@ -2184,7 +2811,7 @@ prep_headers (abfd) 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++) @@ -2229,11 +2856,39 @@ prep_headers (abfd) case bfd_arch_powerpc: i_ehdrp->e_machine = EM_PPC; break; + 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 */ +/* start-sanitize-v850 */ + case bfd_arch_v850: + i_ehdrp->e_machine = EM_CYGNUS_V850; + break; +/* end-sanitize-v850 */ /* start-sanitize-arc */ 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; /* also note that EM_M32, AT&T WE32100 is unknown to bfd */ default: i_ehdrp->e_machine = EM_NONE; @@ -2407,13 +3062,15 @@ _bfd_elf_section_from_bfd_section (abfd, asect) 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; @@ -2437,13 +3094,24 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) } 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 @@ -2451,6 +3119,111 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) return idx; } +/* Copy private BFD data. This copies any program header information. */ + +static boolean +copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + Elf_Internal_Ehdr *iehdr; + struct elf_segment_map *mfirst; + struct elf_segment_map **pm; + Elf_Internal_Phdr *p; + unsigned int i, c; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return true; + + 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++) + { + unsigned int csecs; + asection *s; + struct elf_segment_map *m; + unsigned int isec; + + csecs = 0; + + /* The complicated case when p_vaddr is 0 is to handle the + Solaris linker, which generates a PT_INTERP section with + p_vaddr and p_memsz set to 0. */ + for (s = ibfd->sections; s != NULL; s = s->next) + if (((s->vma >= p->p_vaddr + && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz + || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz)) + || (p->p_vaddr == 0 + && p->p_filesz > 0 + && (s->flags & SEC_HAS_CONTENTS) != 0 + && (bfd_vma) s->filepos >= p->p_offset + && ((bfd_vma) s->filepos + s->_raw_size + <= p->p_offset + p->p_filesz))) + && (s->flags & SEC_ALLOC) != 0 + && s->output_section != NULL) + ++csecs; + + m = ((struct elf_segment_map *) + bfd_alloc (obfd, + (sizeof (struct elf_segment_map) + + ((size_t) csecs - 1) * sizeof (asection *)))); + if (m == NULL) + return false; + + m->next = NULL; + m->p_type = p->p_type; + m->p_flags = p->p_flags; + m->p_flags_valid = 1; + m->p_paddr = p->p_paddr; + m->p_paddr_valid = 1; + + m->includes_filehdr = (p->p_offset == 0 + && p->p_filesz >= iehdr->e_ehsize); + + m->includes_phdrs = (p->p_offset <= (bfd_vma) iehdr->e_phoff + && (p->p_offset + p->p_filesz + >= ((bfd_vma) iehdr->e_phoff + + iehdr->e_phnum * iehdr->e_phentsize))); + + isec = 0; + for (s = ibfd->sections; s != NULL; s = s->next) + { + if (((s->vma >= p->p_vaddr + && (s->vma + s->_raw_size <= p->p_vaddr + p->p_memsz + || s->vma + s->_raw_size <= p->p_vaddr + p->p_filesz)) + || (p->p_vaddr == 0 + && p->p_filesz > 0 + && (s->flags & SEC_HAS_CONTENTS) != 0 + && (bfd_vma) s->filepos >= p->p_offset + && ((bfd_vma) s->filepos + s->_raw_size + <= p->p_offset + p->p_filesz))) + && (s->flags & SEC_ALLOC) != 0 + && s->output_section != NULL) + { + m->sections[isec] = s->output_section; + ++isec; + } + } + BFD_ASSERT (isec == csecs); + m->count = csecs; + + *pm = m; + pm = &m->next; + } + + elf_tdata (obfd)->segment_map = mfirst; + + return true; +} + /* Copy private section information. This copies over the entsize field, and sometimes the info field. */ @@ -2467,13 +3240,37 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec) || obfd->xvec->flavour != bfd_target_elf_flavour) return true; + /* Copy over private BFD data if it has not already been copied. + This must be done here, rather than in the copy_private_bfd_data + entry point, because the latter is called after the section + contents have been set, which means that the program headers have + already been worked out. */ + if (elf_tdata (obfd)->segment_map == NULL + && elf_tdata (ibfd)->phdr != NULL) + { + 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) + break; + if (s == NULL) + { + if (! copy_private_bfd_data (ibfd, obfd)) + return false; + } + } + ihdr = &elf_section_data (isec)->this_hdr; ohdr = &elf_section_data (osec)->this_hdr; 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; @@ -2499,6 +3296,10 @@ _bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg) { 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); @@ -2562,10 +3363,7 @@ swap_out_syms (abfd, sttp) 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") */ @@ -2587,6 +3385,7 @@ swap_out_syms (abfd, sttp) 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. */ @@ -2681,15 +3480,20 @@ swap_out_syms (abfd, sttp) 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) @@ -2697,7 +3501,6 @@ swap_out_syms (abfd, sttp) else { int bind = STB_LOCAL; - int type = STT_OBJECT; if (flags & BSF_LOCAL) bind = STB_LOCAL; @@ -2706,13 +3509,14 @@ swap_out_syms (abfd, sttp) 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; } @@ -2792,7 +3596,10 @@ _bfd_elf_canonicalize_reloc (abfd, section, relptr, symbols) 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; @@ -2824,6 +3631,264 @@ _bfd_elf_canonicalize_dynamic_symtab (abfd, alocation) 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; +} + +/* 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; +} + asymbol * _bfd_elf_make_empty_symbol (abfd) bfd *abfd; @@ -2832,10 +3897,7 @@ _bfd_elf_make_empty_symbol (abfd) newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (elf_symbol_type)); if (!newsym) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } + return NULL; else { newsym->symbol.the_bfd = abfd; @@ -2852,6 +3914,36 @@ _bfd_elf_get_symbol_info (ignore_abfd, symbol, 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; + 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; @@ -2896,15 +3988,26 @@ _bfd_elf_find_nearest_line (abfd, CONST char **functionname_ptr; unsigned int *line_ptr; { + boolean found; const char *filename; asymbol *func; + bfd_vma low_func; asymbol **p; + 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++) { @@ -2923,9 +4026,13 @@ _bfd_elf_find_nearest_line (abfd, 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; } } @@ -2996,3 +4103,101 @@ _bfd_elf_no_info_to_howto_rel (abfd, cache_ptr, dst) 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; +}