X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf.c;h=24ca6df7c9e3cfef7883e933c37a30a49f8b0e86;hb=d270463e93aa77304932b1df0e2315ec3c0d3be8;hp=6ba2cb86f4906eb044a7ff5bd709d2eedbd2a22f;hpb=3496cb2af49b7fdc1ea5a085b87e1a6c0b26aea4;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf.c b/bfd/elf.c index 6ba2cb86f4..24ca6df7c9 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1,7 +1,7 @@ /* ELF executable support for BFD. Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -19,8 +19,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -/* SECTION - +/* +SECTION ELF backends BFD support for ELF formats is being worked on. @@ -206,38 +206,32 @@ bfd_elf_hash (const char *namearg) return h & 0xffffffff; } -/* Read a specified number of bytes at a specified offset in an ELF - file, into a newly allocated buffer, and return a pointer to the - buffer. */ +/* DT_GNU_HASH hash function. Do not change this function; you will + cause invalid hash tables to be generated. */ -static bfd_byte * -elf_read (bfd *abfd, file_ptr offset, bfd_size_type size) +unsigned long +bfd_elf_gnu_hash (const char *namearg) { - bfd_byte *buf; + const unsigned char *name = (const unsigned char *) namearg; + unsigned long h = 5381; + unsigned char ch; - if ((buf = bfd_alloc (abfd, size)) == NULL) - return NULL; - if (bfd_seek (abfd, offset, SEEK_SET) != 0) - return NULL; - if (bfd_bread (buf, size, abfd) != size) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_file_truncated); - return NULL; - } - return buf; + while ((ch = *name++) != '\0') + h = (h << 5) + h + ch; + return h & 0xffffffff; } bfd_boolean bfd_elf_mkobject (bfd *abfd) { - /* This just does initialization. */ - /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ - elf_tdata (abfd) = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); - if (elf_tdata (abfd) == 0) - return FALSE; - /* Since everything is done at close time, do we need any - initialization? */ + if (abfd->tdata.any == NULL) + { + abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + if (abfd->tdata.any == NULL) + return FALSE; + } + + elf_tdata (abfd)->program_header_size = (bfd_size_type) -1; return TRUE; } @@ -267,7 +261,21 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) /* No cached one, attempt to read, and cache what we read. */ offset = i_shdrp[shindex]->sh_offset; shstrtabsize = i_shdrp[shindex]->sh_size; - shstrtab = elf_read (abfd, offset, shstrtabsize); + + /* Allocate and clear an extra byte at the end, to prevent crashes + in case the string table is not terminated. */ + if (shstrtabsize + 1 == 0 + || (shstrtab = bfd_alloc (abfd, shstrtabsize + 1)) == NULL + || bfd_seek (abfd, offset, SEEK_SET) != 0) + shstrtab = NULL; + else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_file_truncated); + shstrtab = NULL; + } + else + shstrtab[shstrtabsize] = '\0'; i_shdrp[shindex]->contents = shstrtab; } return (char *) shstrtab; @@ -348,7 +356,7 @@ bfd_elf_get_elf_syms (bfd *ibfd, pos = symtab_hdr->sh_offset + symoffset * extsym_size; if (extsym_buf == NULL) { - alloc_ext = bfd_malloc (amt); + alloc_ext = bfd_malloc2 (symcount, extsym_size); extsym_buf = alloc_ext; } if (extsym_buf == NULL @@ -367,7 +375,8 @@ bfd_elf_get_elf_syms (bfd *ibfd, pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx); if (extshndx_buf == NULL) { - alloc_extshndx = bfd_malloc (amt); + alloc_extshndx = bfd_malloc2 (symcount, + sizeof (Elf_External_Sym_Shndx)); extshndx_buf = alloc_extshndx; } if (extshndx_buf == NULL @@ -381,8 +390,7 @@ bfd_elf_get_elf_syms (bfd *ibfd, if (intsym_buf == NULL) { - bfd_size_type amt = symcount * sizeof (Elf_Internal_Sym); - intsym_buf = bfd_malloc (amt); + intsym_buf = bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym)); if (intsym_buf == NULL) goto out; } @@ -392,7 +400,15 @@ bfd_elf_get_elf_syms (bfd *ibfd, for (esym = extsym_buf, isym = intsym_buf, shndx = extshndx_buf; isym < isymend; esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL) - (*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym); + if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym)) + { + symoffset += (esym - (bfd_byte *) extsym_buf) / extsym_size; + (*_bfd_error_handler) (_("%B symbol number %lu references " + "nonexistent SHT_SYMTAB_SHNDX section"), + ibfd, (unsigned long) symoffset); + intsym_buf = NULL; + goto out; + } out: if (alloc_ext != NULL) @@ -452,8 +468,11 @@ group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr) Elf_External_Sym_Shndx eshndx; Elf_Internal_Sym isym; - /* First we need to ensure the symbol table is available. */ - if (! bfd_section_from_shdr (abfd, ghdr->sh_link)) + /* First we need to ensure the symbol table is available. Make sure + that it is a symbol table section. */ + hdr = elf_elfsections (abfd) [ghdr->sh_link]; + if (hdr->sh_type != SHT_SYMTAB + || ! bfd_section_from_shdr (abfd, ghdr->sh_link)) return NULL; /* Go read the symbol. */ @@ -499,10 +518,10 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) /* We keep a list of elf section headers for group sections, so we can find them quickly. */ bfd_size_type amt; - + elf_tdata (abfd)->num_group = num_group; - amt = num_group * sizeof (Elf_Internal_Shdr *); - elf_tdata (abfd)->group_sect_ptr = bfd_alloc (abfd, amt); + elf_tdata (abfd)->group_sect_ptr + = bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *)); if (elf_tdata (abfd)->group_sect_ptr == NULL) return FALSE; @@ -522,7 +541,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) /* Read the raw contents. */ BFD_ASSERT (sizeof (*dest) >= 4); amt = shdr->sh_size * sizeof (*dest) / 4; - shdr->contents = bfd_alloc (abfd, amt); + shdr->contents = bfd_alloc2 (abfd, shdr->sh_size, + sizeof (*dest) / 4); if (shdr->contents == NULL || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 || (bfd_bread (shdr->contents, shdr->sh_size, abfd) @@ -630,12 +650,56 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) } bfd_boolean -_bfd_elf_setup_group_pointers (bfd *abfd) +_bfd_elf_setup_sections (bfd *abfd) { unsigned int i; unsigned int num_group = elf_tdata (abfd)->num_group; bfd_boolean result = TRUE; + asection *s; + + /* Process SHF_LINK_ORDER. */ + for (s = abfd->sections; s != NULL; s = s->next) + { + Elf_Internal_Shdr *this_hdr = &elf_section_data (s)->this_hdr; + if ((this_hdr->sh_flags & SHF_LINK_ORDER) != 0) + { + unsigned int elfsec = this_hdr->sh_link; + /* FIXME: The old Intel compiler and old strip/objcopy may + not set the sh_link or sh_info fields. Hence we could + get the situation where elfsec is 0. */ + if (elfsec == 0) + { + const struct elf_backend_data *bed + = get_elf_backend_data (abfd); + if (bed->link_order_error_handler) + bed->link_order_error_handler + (_("%B: warning: sh_link not set for section `%A'"), + abfd, s); + } + else + { + asection *link; + + this_hdr = elf_elfsections (abfd)[elfsec]; + + /* PR 1991, 2008: + Some strip/objcopy may leave an incorrect value in + sh_link. We don't want to proceed. */ + link = this_hdr->bfd_section; + if (link == NULL) + { + (*_bfd_error_handler) + (_("%B: sh_link [%d] in section `%A' is incorrect"), + s->owner, s, elfsec); + result = FALSE; + } + + elf_linked_to_section (s) = link; + } + } + } + /* Process section groups. */ if (num_group == (unsigned) -1) return result; @@ -750,25 +814,45 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, if ((hdr->sh_flags & SHF_TLS) != 0) flags |= SEC_THREAD_LOCAL; - /* The debugging sections appear to be recognized only by name, not - any sort of flag. */ - { - static const char *debug_sec_names [] = + if ((flags & SEC_ALLOC) == 0) { - ".debug", - ".gnu.linkonce.wi.", - ".line", - ".stab" - }; - int i; - - for (i = ARRAY_SIZE (debug_sec_names); i--;) - if (strncmp (name, debug_sec_names[i], strlen (debug_sec_names[i])) == 0) - break; - - if (i >= 0) - flags |= SEC_DEBUGGING; - } + /* The debugging sections appear to be recognized only by name, + not any sort of flag. Their SEC_ALLOC bits are cleared. */ + static const struct + { + const char *name; + int len; + } debug_sections [] = + { + { STRING_COMMA_LEN ("debug") }, /* 'd' */ + { NULL, 0 }, /* 'e' */ + { NULL, 0 }, /* 'f' */ + { STRING_COMMA_LEN ("gnu.linkonce.wi.") }, /* 'g' */ + { NULL, 0 }, /* 'h' */ + { NULL, 0 }, /* 'i' */ + { NULL, 0 }, /* 'j' */ + { NULL, 0 }, /* 'k' */ + { STRING_COMMA_LEN ("line") }, /* 'l' */ + { NULL, 0 }, /* 'm' */ + { NULL, 0 }, /* 'n' */ + { NULL, 0 }, /* 'o' */ + { NULL, 0 }, /* 'p' */ + { NULL, 0 }, /* 'q' */ + { NULL, 0 }, /* 'r' */ + { STRING_COMMA_LEN ("stab") } /* 's' */ + }; + + if (name [0] == '.') + { + int i = name [1] - 'd'; + if (i >= 0 + && i < (int) ARRAY_SIZE (debug_sections) + && debug_sections [i].name != NULL + && strncmp (&name [1], debug_sections [i].name, + debug_sections [i].len) == 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 @@ -776,7 +860,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, 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 + if (CONST_STRNEQ (name, ".gnu.linkonce") && elf_next_in_group (newsect) == NULL) flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; @@ -1008,6 +1092,28 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) return TRUE; } +static const char * +get_segment_type (unsigned int p_type) +{ + const char *pt; + switch (p_type) + { + case PT_NULL: pt = "NULL"; break; + case PT_LOAD: pt = "LOAD"; break; + case PT_DYNAMIC: pt = "DYNAMIC"; break; + case PT_INTERP: pt = "INTERP"; break; + case PT_NOTE: pt = "NOTE"; break; + case PT_SHLIB: pt = "SHLIB"; break; + case PT_PHDR: pt = "PHDR"; break; + case PT_TLS: pt = "TLS"; break; + case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break; + case PT_GNU_STACK: pt = "STACK"; break; + case PT_GNU_RELRO: pt = "RELRO"; break; + default: pt = NULL; break; + } + return pt; +} + /* Print out the program headers. */ bfd_boolean @@ -1027,23 +1133,13 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) c = elf_elfheader (abfd)->e_phnum; for (i = 0; i < c; i++, p++) { - const char *pt; + const char *pt = get_segment_type (p->p_type); char buf[20]; - switch (p->p_type) + if (pt == NULL) { - case PT_NULL: pt = "NULL"; break; - case PT_LOAD: pt = "LOAD"; break; - case PT_DYNAMIC: pt = "DYNAMIC"; break; - case PT_INTERP: pt = "INTERP"; break; - case PT_NOTE: pt = "NOTE"; break; - case PT_SHLIB: pt = "SHLIB"; break; - case PT_PHDR: pt = "PHDR"; break; - case PT_TLS: pt = "TLS"; break; - case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break; - case PT_GNU_STACK: pt = "STACK"; break; - case PT_GNU_RELRO: pt = "RELRO"; break; - default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break; + sprintf (buf, "0x%lx", p->p_type); + pt = buf; } fprintf (f, "%8s off 0x", pt); bfd_fprintf_vma (abfd, f, p->p_offset); @@ -1167,6 +1263,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break; case DT_USED: name = "USED"; break; case DT_FILTER: name = "FILTER"; stringp = TRUE; break; + case DT_GNU_HASH: name = "GNU_HASH"; break; } fprintf (f, " %-11s ", name); @@ -1204,8 +1301,9 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) 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) + t->vd_flags, t->vd_hash, + t->vd_nodename ? t->vd_nodename : ""); + if (t->vd_auxptr != NULL && t->vd_auxptr->vda_nextptr != NULL) { Elf_Internal_Verdaux *a; @@ -1213,7 +1311,8 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) for (a = t->vd_auxptr->vda_nextptr; a != NULL; a = a->vda_nextptr) - fprintf (f, "%s ", a->vda_nodename); + fprintf (f, "%s ", + a->vda_nodename ? a->vda_nodename : ""); fprintf (f, "\n"); } } @@ -1228,10 +1327,12 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) { Elf_Internal_Vernaux *a; - fprintf (f, _(" required from %s:\n"), t->vn_filename); + fprintf (f, _(" required from %s:\n"), + t->vn_filename ? 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); + a->vna_flags, a->vna_other, + a->vna_nodename ? a->vna_nodename : ""); } } @@ -1391,7 +1492,8 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, /* Set local fields. */ ret->indx = -1; ret->dynindx = -1; - ret->got = ret->plt = htab->init_refcount; + ret->got = htab->init_got_refcount; + ret->plt = htab->init_plt_refcount; memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry) - offsetof (struct elf_link_hash_entry, size))); /* Assume that we have been called by a non-ELF symbol reader. @@ -1408,12 +1510,11 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, old indirect symbol. Also used for copying flags to a weakdef. */ void -_bfd_elf_link_hash_copy_indirect (const struct elf_backend_data *bed, +_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info, struct elf_link_hash_entry *dir, struct elf_link_hash_entry *ind) { - bfd_signed_vma tmp; - bfd_signed_vma lowest_valid = bed->can_refcount; + struct elf_link_hash_table *htab; /* Copy down any references that we may have already seen to the symbol which just became indirect. */ @@ -1430,33 +1531,32 @@ _bfd_elf_link_hash_copy_indirect (const struct elf_backend_data *bed, /* Copy over the global and procedure linkage table refcount entries. These may have been already set up by a check_relocs routine. */ - tmp = dir->got.refcount; - if (tmp < lowest_valid) + htab = elf_hash_table (info); + if (ind->got.refcount > htab->init_got_refcount.refcount) { - dir->got.refcount = ind->got.refcount; - ind->got.refcount = tmp; + if (dir->got.refcount < 0) + dir->got.refcount = 0; + dir->got.refcount += ind->got.refcount; + ind->got.refcount = htab->init_got_refcount.refcount; } - else - BFD_ASSERT (ind->got.refcount < lowest_valid); - tmp = dir->plt.refcount; - if (tmp < lowest_valid) + if (ind->plt.refcount > htab->init_plt_refcount.refcount) { - dir->plt.refcount = ind->plt.refcount; - ind->plt.refcount = tmp; + if (dir->plt.refcount < 0) + dir->plt.refcount = 0; + dir->plt.refcount += ind->plt.refcount; + ind->plt.refcount = htab->init_plt_refcount.refcount; } - else - BFD_ASSERT (ind->plt.refcount < lowest_valid); - if (dir->dynindx == -1) + if (ind->dynindx != -1) { + if (dir->dynindx != -1) + _bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index); dir->dynindx = ind->dynindx; dir->dynstr_index = ind->dynstr_index; ind->dynindx = -1; ind->dynstr_index = 0; } - else - BFD_ASSERT (ind->dynindx == -1); } void @@ -1464,7 +1564,7 @@ _bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h, bfd_boolean force_local) { - h->plt = elf_hash_table (info)->init_offset; + h->plt = elf_hash_table (info)->init_plt_offset; h->needs_plt = 0; if (force_local) { @@ -1486,23 +1586,25 @@ _bfd_elf_link_hash_table_init bfd *abfd, struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, struct bfd_hash_table *, - const char *)) + const char *), + unsigned int entsize) { bfd_boolean ret; + int can_refcount = get_elf_backend_data (abfd)->can_refcount; table->dynamic_sections_created = FALSE; table->dynobj = NULL; - /* Make sure can_refcount is extended to the width and signedness of - init_refcount before we subtract one from it. */ - table->init_refcount.refcount = get_elf_backend_data (abfd)->can_refcount; - table->init_refcount.refcount -= 1; - table->init_offset.offset = -(bfd_vma) 1; + table->init_got_refcount.refcount = can_refcount - 1; + table->init_plt_refcount.refcount = can_refcount - 1; + table->init_got_offset.offset = -(bfd_vma) 1; + table->init_plt_offset.offset = -(bfd_vma) 1; /* The first dynamic symbol is a dummy. */ table->dynsymcount = 1; table->dynstr = NULL; table->bucketcount = 0; table->needed = NULL; table->hgot = NULL; + table->hplt = NULL; table->merge_info = NULL; memset (&table->stab_info, 0, sizeof (table->stab_info)); memset (&table->eh_info, 0, sizeof (table->eh_info)); @@ -1513,7 +1615,7 @@ _bfd_elf_link_hash_table_init table->loaded = NULL; table->is_relocatable_executable = FALSE; - ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc); + ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); table->root.type = bfd_link_elf_hash_table; return ret; @@ -1531,7 +1633,8 @@ _bfd_elf_link_hash_table_create (bfd *abfd) if (ret == NULL) return NULL; - if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc)) + if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc, + sizeof (struct elf_link_hash_entry))) { free (ret); return NULL; @@ -1565,7 +1668,7 @@ bfd_elf_get_dyn_lib_class (bfd *abfd) } void -bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class) +bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class) { if (bfd_get_flavour (abfd) == bfd_target_elf_flavour && bfd_get_format (abfd) == bfd_object) @@ -1728,6 +1831,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) name = bfd_elf_string_from_elf_section (abfd, elf_elfheader (abfd)->e_shstrndx, hdr->sh_name); + if (name == NULL) + return FALSE; switch (hdr->sh_type) { @@ -1743,11 +1848,15 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) case SHT_FINI_ARRAY: /* .fini_array section. */ case SHT_PREINIT_ARRAY: /* .preinit_array section. */ case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ + case SHT_GNU_HASH: /* .gnu.hash section. */ return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); case SHT_DYNAMIC: /* Dynamic linking information. */ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) return FALSE; + if (hdr->sh_link > elf_numsections (abfd) + || elf_elfsections (abfd)[hdr->sh_link] == NULL) + return FALSE; if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) { Elf_Internal_Shdr *dynsymhdr; @@ -1782,7 +1891,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (elf_onesymtab (abfd) == shindex) return TRUE; - BFD_ASSERT (hdr->sh_entsize == bed->s->sizeof_sym); + if (hdr->sh_entsize != bed->s->sizeof_sym) + return FALSE; BFD_ASSERT (elf_onesymtab (abfd) == 0); elf_onesymtab (abfd) = shindex; elf_tdata (abfd)->symtab_hdr = *hdr; @@ -1833,7 +1943,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (elf_dynsymtab (abfd) == shindex) return TRUE; - BFD_ASSERT (hdr->sh_entsize == bed->s->sizeof_sym); + if (hdr->sh_entsize != bed->s->sizeof_sym) + return FALSE; BFD_ASSERT (elf_dynsymtab (abfd) == 0); elf_dynsymtab (abfd) = shindex; elf_tdata (abfd)->dynsymtab_hdr = *hdr; @@ -1895,6 +2006,9 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; if (hdr2->sh_link == shindex) { + /* Prevent endless recursion on broken objects. */ + if (i == shindex) + return FALSE; if (! bfd_section_from_shdr (abfd, i)) return FALSE; if (elf_onesymtab (abfd) == i) @@ -1914,6 +2028,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) Elf_Internal_Shdr *hdr2; unsigned int num_sec = elf_numsections (abfd); + if (hdr->sh_entsize + != (bfd_size_type) (hdr->sh_type == SHT_REL + ? bed->s->sizeof_rel : bed->s->sizeof_rela)) + return FALSE; + /* Check for a bogus link to avoid crashing. */ if ((hdr->sh_link >= SHN_LORESERVE && hdr->sh_link <= SHN_HIRESERVE) || hdr->sh_link >= num_sec) @@ -1967,8 +2086,13 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) represent such a section, so at least for now, we don't try. We just present it as a normal section. We also can't use it as a reloc section if it points to the null - section. */ - if (hdr->sh_link != elf_onesymtab (abfd) || hdr->sh_info == SHN_UNDEF) + section, an invalid section, or another reloc section. */ + if (hdr->sh_link != elf_onesymtab (abfd) + || hdr->sh_info == SHN_UNDEF + || (hdr->sh_info >= SHN_LORESERVE && hdr->sh_info <= SHN_HIRESERVE) + || hdr->sh_info >= num_sec + || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL + || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA) return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); @@ -2002,25 +2126,23 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) abfd->flags |= HAS_RELOC; return TRUE; } - break; case SHT_GNU_verdef: elf_dynverdef (abfd) = shindex; elf_tdata (abfd)->dynverdef_hdr = *hdr; return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); - break; case SHT_GNU_versym: + if (hdr->sh_entsize != sizeof (Elf_External_Versym)) + return FALSE; elf_dynversym (abfd) = shindex; elf_tdata (abfd)->dynversym_hdr = *hdr; return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); - 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, shindex); - break; case SHT_SHLIB: return TRUE; @@ -2029,6 +2151,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) /* We need a BFD section for objcopy and relocatable linking, and it's handy to have the signature available as the section name. */ + if (hdr->sh_entsize != GRP_ENTRY_SIZE) + return FALSE; name = group_signature (abfd, hdr); if (name == NULL) return FALSE; @@ -2058,8 +2182,52 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) default: /* Check for any processor-specific section types. */ - return bed->elf_backend_section_from_shdr (abfd, hdr, name, - shindex); + if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex)) + return TRUE; + + if (hdr->sh_type >= SHT_LOUSER && hdr->sh_type <= SHT_HIUSER) + { + if ((hdr->sh_flags & SHF_ALLOC) != 0) + /* FIXME: How to properly handle allocated section reserved + for applications? */ + (*_bfd_error_handler) + (_("%B: don't know how to handle allocated, application " + "specific section `%s' [0x%8x]"), + abfd, name, hdr->sh_type); + else + /* Allow sections reserved for applications. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + } + else if (hdr->sh_type >= SHT_LOPROC + && hdr->sh_type <= SHT_HIPROC) + /* FIXME: We should handle this section. */ + (*_bfd_error_handler) + (_("%B: don't know how to handle processor specific section " + "`%s' [0x%8x]"), + abfd, name, hdr->sh_type); + else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS) + { + /* Unrecognised OS-specific sections. */ + if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0) + /* SHF_OS_NONCONFORMING indicates that special knowledge is + required to correctly process the section and the file should + be rejected with an error message. */ + (*_bfd_error_handler) + (_("%B: don't know how to handle OS specific section " + "`%s' [0x%8x]"), + abfd, name, hdr->sh_type); + else + /* Otherwise it should be processed. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + } + else + /* FIXME: We should handle this section. */ + (*_bfd_error_handler) + (_("%B: don't know how to handle section `%s' [0x%8x]"), + abfd, name, hdr->sh_type); + + return FALSE; } return TRUE; @@ -2117,71 +2285,159 @@ bfd_section_from_elf_index (bfd *abfd, unsigned int index) return elf_elfsections (abfd)[index]->bfd_section; } -static struct bfd_elf_special_section const special_sections[] = -{ - { ".bss", 4, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { ".gnu.linkonce.b",15, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { ".comment", 8, 0, SHT_PROGBITS, 0 }, - { ".data", 5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".data1", 6, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".debug", 6, 0, SHT_PROGBITS, 0 }, - { ".fini", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".init", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".line", 5, 0, SHT_PROGBITS, 0 }, - { ".rodata", 7, -2, SHT_PROGBITS, SHF_ALLOC }, - { ".rodata1", 8, 0, SHT_PROGBITS, SHF_ALLOC }, - { ".tbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, - { ".tdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, - { ".text", 5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".init_array", 11, 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, - { ".fini_array", 11, 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, - { ".preinit_array", 14, 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, - { ".debug_line", 11, 0, SHT_PROGBITS, 0 }, - { ".debug_info", 11, 0, SHT_PROGBITS, 0 }, - { ".debug_abbrev", 13, 0, SHT_PROGBITS, 0 }, - { ".debug_aranges", 14, 0, SHT_PROGBITS, 0 }, - { ".dynamic", 8, 0, SHT_DYNAMIC, SHF_ALLOC }, - { ".dynstr", 7, 0, SHT_STRTAB, SHF_ALLOC }, - { ".dynsym", 7, 0, SHT_DYNSYM, SHF_ALLOC }, - { ".got", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".hash", 5, 0, SHT_HASH, SHF_ALLOC }, - { ".interp", 7, 0, SHT_PROGBITS, 0 }, - { ".plt", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".shstrtab", 9, 0, SHT_STRTAB, 0 }, - { ".strtab", 7, 0, SHT_STRTAB, 0 }, - { ".symtab", 7, 0, SHT_SYMTAB, 0 }, - { ".gnu.version", 12, 0, SHT_GNU_versym, 0 }, - { ".gnu.version_d", 14, 0, SHT_GNU_verdef, 0 }, - { ".gnu.version_r", 14, 0, SHT_GNU_verneed, 0 }, - { ".note.GNU-stack",15, 0, SHT_PROGBITS, 0 }, - { ".note", 5, -1, SHT_NOTE, 0 }, - { ".rela", 5, -1, SHT_RELA, 0 }, - { ".rel", 4, -1, SHT_REL, 0 }, - { ".stabstr", 5, 3, SHT_STRTAB, 0 }, - { ".gnu.liblist", 12, 0, SHT_GNU_LIBLIST, SHF_ALLOC }, - { ".gnu.conflict", 13, 0, SHT_RELA, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } +static const struct bfd_elf_special_section special_sections_b[] = +{ + { STRING_COMMA_LEN (".bss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_c[] = +{ + { STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_d[] = +{ + { STRING_COMMA_LEN (".data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".data1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".debug"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".debug_line"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".debug_info"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".debug_abbrev"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".debug_aranges"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".dynamic"), 0, SHT_DYNAMIC, SHF_ALLOC }, + { STRING_COMMA_LEN (".dynstr"), 0, SHT_STRTAB, SHF_ALLOC }, + { STRING_COMMA_LEN (".dynsym"), 0, SHT_DYNSYM, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_f[] = +{ + { STRING_COMMA_LEN (".fini"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { STRING_COMMA_LEN (".fini_array"), 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_g[] = +{ + { STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".gnu.version"), 0, SHT_GNU_versym, 0 }, + { STRING_COMMA_LEN (".gnu.version_d"), 0, SHT_GNU_verdef, 0 }, + { STRING_COMMA_LEN (".gnu.version_r"), 0, SHT_GNU_verneed, 0 }, + { STRING_COMMA_LEN (".gnu.liblist"), 0, SHT_GNU_LIBLIST, SHF_ALLOC }, + { STRING_COMMA_LEN (".gnu.conflict"), 0, SHT_RELA, SHF_ALLOC }, + { STRING_COMMA_LEN (".gnu.hash"), 0, SHT_GNU_HASH, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_h[] = +{ + { STRING_COMMA_LEN (".hash"), 0, SHT_HASH, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_i[] = +{ + { STRING_COMMA_LEN (".init"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { STRING_COMMA_LEN (".init_array"), 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".interp"), 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_l[] = +{ + { STRING_COMMA_LEN (".line"), 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_n[] = +{ + { STRING_COMMA_LEN (".note.GNU-stack"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".note"), -1, SHT_NOTE, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_p[] = +{ + { STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_r[] = +{ + { STRING_COMMA_LEN (".rodata"), -2, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".rodata1"), 0, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".rela"), -1, SHT_RELA, 0 }, + { STRING_COMMA_LEN (".rel"), -1, SHT_REL, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_s[] = +{ + { STRING_COMMA_LEN (".shstrtab"), 0, SHT_STRTAB, 0 }, + { STRING_COMMA_LEN (".strtab"), 0, SHT_STRTAB, 0 }, + { STRING_COMMA_LEN (".symtab"), 0, SHT_SYMTAB, 0 }, + /* See struct bfd_elf_special_section declaration for the semantics of + this special case where .prefix_length != strlen (.prefix). */ + { ".stabstr", 5, 3, SHT_STRTAB, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section special_sections_t[] = +{ + { STRING_COMMA_LEN (".text"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { STRING_COMMA_LEN (".tbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, + { STRING_COMMA_LEN (".tdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, + { NULL, 0, 0, 0, 0 } +}; + +static const struct bfd_elf_special_section *special_sections[] = +{ + special_sections_b, /* 'b' */ + special_sections_c, /* 'b' */ + special_sections_d, /* 'd' */ + NULL, /* 'e' */ + special_sections_f, /* 'f' */ + special_sections_g, /* 'g' */ + special_sections_h, /* 'h' */ + special_sections_i, /* 'i' */ + NULL, /* 'j' */ + NULL, /* 'k' */ + special_sections_l, /* 'l' */ + NULL, /* 'm' */ + special_sections_n, /* 'n' */ + NULL, /* 'o' */ + special_sections_p, /* 'p' */ + NULL, /* 'q' */ + special_sections_r, /* 'r' */ + special_sections_s, /* 's' */ + special_sections_t, /* 't' */ }; -static const struct bfd_elf_special_section * -get_special_section (const char *name, - const struct bfd_elf_special_section *special_sections, - unsigned int rela) +const struct bfd_elf_special_section * +_bfd_elf_get_special_section (const char *name, + const struct bfd_elf_special_section *spec, + unsigned int rela) { int i; - int len = strlen (name); + int len; + + len = strlen (name); - for (i = 0; special_sections[i].prefix != NULL; i++) + for (i = 0; spec[i].prefix != NULL; i++) { int suffix_len; - int prefix_len = special_sections[i].prefix_length; + int prefix_len = spec[i].prefix_length; if (len < prefix_len) continue; - if (memcmp (name, special_sections[i].prefix, prefix_len) != 0) + if (memcmp (name, spec[i].prefix, prefix_len) != 0) continue; - suffix_len = special_sections[i].suffix_length; + suffix_len = spec[i].suffix_length; if (suffix_len <= 0) { if (name[prefix_len] != 0) @@ -2190,7 +2446,7 @@ get_special_section (const char *name, continue; if (name[prefix_len] != '.' && (suffix_len == -2 - || (rela && special_sections[i].type == SHT_REL))) + || (rela && spec[i].type == SHT_REL))) continue; } } @@ -2199,41 +2455,58 @@ get_special_section (const char *name, if (len < prefix_len + suffix_len) continue; if (memcmp (name + len - suffix_len, - special_sections[i].prefix + prefix_len, + spec[i].prefix + prefix_len, suffix_len) != 0) continue; } - return &special_sections[i]; + return &spec[i]; } return NULL; } const struct bfd_elf_special_section * -_bfd_elf_get_sec_type_attr (bfd *abfd, const char *name) +_bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec) { - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - const struct bfd_elf_special_section *ssect = NULL; + int i; + const struct bfd_elf_special_section *spec; + const struct elf_backend_data *bed; /* See if this is one of the special sections. */ - if (name) + if (sec->name == NULL) + return NULL; + + bed = get_elf_backend_data (abfd); + spec = bed->special_sections; + if (spec) { - unsigned int rela = bed->default_use_rela_p; + spec = _bfd_elf_get_special_section (sec->name, + bed->special_sections, + sec->use_rela_p); + if (spec != NULL) + return spec; + } - if (bed->special_sections) - ssect = get_special_section (name, bed->special_sections, rela); + if (sec->name[0] != '.') + return NULL; - if (! ssect) - ssect = get_special_section (name, special_sections, rela); - } + i = sec->name[1] - 'b'; + if (i < 0 || i > 't' - 'b') + return NULL; - return ssect; + spec = special_sections[i]; + + if (spec == NULL) + return NULL; + + return _bfd_elf_get_special_section (sec->name, spec, sec->use_rela_p); } bfd_boolean _bfd_elf_new_section_hook (bfd *abfd, asection *sec) { struct bfd_elf_section_data *sdata; + const struct elf_backend_data *bed; const struct bfd_elf_special_section *ssect; sdata = (struct bfd_elf_section_data *) sec->used_by_bfd; @@ -2245,13 +2518,20 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec) sec->used_by_bfd = sdata; } - /* When we read a file, we don't need section type and flags unless - it is a linker created section. They will be overridden in - _bfd_elf_make_section_from_shdr anyway. */ - if (abfd->direction != read_direction + /* Indicate whether or not this section should use RELA relocations. */ + bed = get_elf_backend_data (abfd); + sec->use_rela_p = bed->default_use_rela_p; + + /* When we read a file, we don't need to set ELF section type and + flags. They will be overridden in _bfd_elf_make_section_from_shdr + anyway. We will set ELF section type and flags for all linker + created sections. If user specifies BFD section flags, we will + set ELF section type and flags based on BFD section flags in + elf_fake_sections. */ + if ((!sec->flags && abfd->direction != read_direction) || (sec->flags & SEC_LINKER_CREATED) != 0) { - ssect = _bfd_elf_get_sec_type_attr (abfd, sec->name); + ssect = (*bed->get_sec_type_attr) (abfd, sec); if (ssect != NULL) { elf_section_type (sec) = ssect->type; @@ -2259,10 +2539,7 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec) } } - /* Indicate whether or not this section should use RELA relocations. */ - sec->use_rela_p = get_elf_backend_data (abfd)->default_use_rela_p; - - return TRUE; + return _bfd_generic_new_section_hook (abfd, sec); } /* Create a new bfd section from an ELF program header. @@ -2471,7 +2748,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) return; } - this_hdr->sh_flags = 0; + /* Don't clear sh_flags. Assembler may set additional bits. */ if ((asect->flags & SEC_ALLOC) != 0 || asect->user_set_vma) @@ -2494,32 +2771,10 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) if (this_hdr->sh_type == SHT_NULL) { if ((asect->flags & SEC_GROUP) != 0) - { - /* We also need to mark SHF_GROUP here for relocatable - link. */ - struct bfd_link_order *l; - asection *elt; - - for (l = asect->map_head.link_order; l != NULL; l = l->next) - if (l->type == bfd_indirect_link_order - && (elt = elf_next_in_group (l->u.indirect.section)) != NULL) - do - { - /* The name is not important. Anything will do. */ - elf_group_name (elt->output_section) = "G"; - elf_section_flags (elt->output_section) |= SHF_GROUP; - - elt = elf_next_in_group (elt); - /* During a relocatable link, the lists are - circular. */ - } - while (elt != elf_next_in_group (l->u.indirect.section)); - - this_hdr->sh_type = SHT_GROUP; - } + this_hdr->sh_type = SHT_GROUP; else if ((asect->flags & SEC_ALLOC) != 0 - && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) - || (asect->flags & SEC_NEVER_LOAD) != 0)) + && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + || (asect->flags & SEC_NEVER_LOAD) != 0)) this_hdr->sh_type = SHT_NOBITS; else this_hdr->sh_type = SHT_PROGBITS; @@ -2592,6 +2847,10 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) case SHT_GROUP: this_hdr->sh_entsize = 4; break; + + case SHT_GNU_HASH: + this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4; + break; } if ((asect->flags & SEC_ALLOC) != 0) @@ -2612,16 +2871,18 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) if ((asect->flags & SEC_THREAD_LOCAL) != 0) { this_hdr->sh_flags |= SHF_TLS; - if (asect->size == 0 && (asect->flags & SEC_HAS_CONTENTS) == 0) + if (asect->size == 0 + && (asect->flags & SEC_HAS_CONTENTS) == 0) { - struct bfd_link_order *o; + struct bfd_link_order *o = asect->map_tail.link_order; this_hdr->sh_size = 0; - for (o = asect->map_head.link_order; o != NULL; o = o->next) - if (this_hdr->sh_size < o->offset + o->size) + if (o != NULL) + { this_hdr->sh_size = o->offset + o->size; - if (this_hdr->sh_size) - this_hdr->sh_type = SHT_NOBITS; + if (this_hdr->sh_size != 0) + this_hdr->sh_type = SHT_NOBITS; + } } } @@ -2651,7 +2912,6 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) unsigned long symindx; asection *elt, *first; unsigned char *loc; - struct bfd_link_order *l; bfd_boolean gas; /* Ignore linker created group section. See elfNN_ia64_object_p in @@ -2720,22 +2980,6 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) break; } - /* If this is a relocatable link, then the above did nothing because - SEC is the output section. Look through the input sections - instead. */ - for (l = sec->map_head.link_order; l != NULL; l = l->next) - if (l->type == bfd_indirect_link_order - && (elt = elf_next_in_group (l->u.indirect.section)) != NULL) - do - { - loc -= 4; - H_PUT_32 (abfd, - elf_section_data (elt->output_section)->this_idx, loc); - elt = elf_next_in_group (elt); - /* During a relocatable link, the lists are circular. */ - } - while (elt != elf_next_in_group (l->u.indirect.section)); - if ((loc -= 4) != sec->contents) abort (); @@ -2753,7 +2997,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) asection *sec; unsigned int section_number, secn; Elf_Internal_Shdr **i_shdrp; - bfd_size_type amt; struct bfd_elf_section_data *d; section_number = 1; @@ -2857,13 +3100,11 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) /* Set up the list of section header pointers, in agreement with the indices. */ - amt = section_number * sizeof (Elf_Internal_Shdr *); - i_shdrp = bfd_zalloc (abfd, amt); + i_shdrp = bfd_zalloc2 (abfd, section_number, sizeof (Elf_Internal_Shdr *)); if (i_shdrp == NULL) return FALSE; - amt = sizeof (Elf_Internal_Shdr); - i_shdrp[0] = bfd_zalloc (abfd, amt); + i_shdrp[0] = bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr)); if (i_shdrp[0] == NULL) { bfd_release (abfd, i_shdrp); @@ -2918,67 +3159,60 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) { s = elf_linked_to_section (sec); if (s) - d->this_hdr.sh_link = elf_section_data (s)->this_idx; - else { - struct bfd_link_order *p; - - /* Find out what the corresponding section in output - is. */ - for (p = sec->map_head.link_order; p != NULL; p = p->next) + /* elf_linked_to_section points to the input section. */ + if (link_info != NULL) { - s = p->u.indirect.section; - if (p->type == bfd_indirect_link_order - && (bfd_get_flavour (s->owner) - == bfd_target_elf_flavour)) + /* Check discarded linkonce section. */ + if (elf_discarded_section (s)) { - Elf_Internal_Shdr ** const elf_shdrp - = elf_elfsections (s->owner); - int elfsec - = _bfd_elf_section_from_bfd_section (s->owner, s); - elfsec = elf_shdrp[elfsec]->sh_link; - /* PR 290: - The Intel C compiler generates SHT_IA_64_UNWIND with - SHF_LINK_ORDER. But it doesn't set the sh_link or - sh_info fields. Hence we could get the situation - where elfsec is 0. */ - if (elfsec == 0) - { - const struct elf_backend_data *bed - = get_elf_backend_data (abfd); - if (bed->link_order_error_handler) - bed->link_order_error_handler - (_("%B: warning: sh_link not set for section `%A'"), - abfd, s); - } - else + asection *kept; + (*_bfd_error_handler) + (_("%B: sh_link of section `%A' points to discarded section `%A' of `%B'"), + abfd, d->this_hdr.bfd_section, + s, s->owner); + /* Point to the kept section if it has the same + size as the discarded one. */ + kept = _bfd_elf_check_kept_section (s); + if (kept == NULL) { - s = elf_shdrp[elfsec]->bfd_section; - if (elf_discarded_section (s)) - { - asection *kept; - (*_bfd_error_handler) - (_("%B: sh_link of section `%A' points to discarded section `%A' of `%B'"), - abfd, d->this_hdr.bfd_section, - s, s->owner); - /* Point to the kept section if it has - the same size as the discarded - one. */ - kept = _bfd_elf_check_kept_section (s); - if (kept == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - s = kept; - } - s = s->output_section; - BFD_ASSERT (s != NULL); - d->this_hdr.sh_link = elf_section_data (s)->this_idx; + bfd_set_error (bfd_error_bad_value); + return FALSE; } - break; + s = kept; + } + + s = s->output_section; + BFD_ASSERT (s != NULL); + } + else + { + /* Handle objcopy. */ + if (s->output_section == NULL) + { + (*_bfd_error_handler) + (_("%B: sh_link of section `%A' points to removed section `%A' of `%B'"), + abfd, d->this_hdr.bfd_section, s, s->owner); + bfd_set_error (bfd_error_bad_value); + return FALSE; } + s = s->output_section; } + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + } + else + { + /* PR 290: + The Intel C compiler generates SHT_IA_64_UNWIND with + SHF_LINK_ORDER. But it doesn't set the sh_link or + sh_info fields. Hence we could get the situation + where s is NULL. */ + const struct elf_backend_data *bed + = get_elf_backend_data (abfd); + if (bed->link_order_error_handler) + bed->link_order_error_handler + (_("%B: warning: sh_link not set for section `%A'"), + abfd, sec); } } @@ -3012,7 +3246,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) string section. We look for a section with the same name but without the trailing ``str'', and set its sh_link field to point to this section. */ - if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0 + if (CONST_STRNEQ (sec->name, ".stab") && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0) { size_t len; @@ -3062,6 +3296,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) break; case SHT_HASH: + case SHT_GNU_HASH: case SHT_GNU_versym: /* sh_link is the section header index of the symbol table this hash table or version table is for. */ @@ -3087,7 +3322,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) /* Map symbol from it's internal number to the external number, moving all local symbols to be at the head of the list. */ -static int +static bfd_boolean sym_is_global (bfd *abfd, asymbol *sym) { /* If the backend has a special mapping, use it. */ @@ -3100,6 +3335,20 @@ sym_is_global (bfd *abfd, asymbol *sym) || bfd_is_com_section (bfd_get_section (sym))); } +/* Don't output section symbols for sections that are not going to be + output. Also, don't output section symbols for reloc and other + special sections. */ + +static bfd_boolean +ignore_section_sym (bfd *abfd, asymbol *sym) +{ + return ((sym->flags & BSF_SECTION_SYM) != 0 + && (sym->value != 0 + || (sym->section->owner != abfd + && (sym->section->output_section->owner != abfd + || sym->section->output_offset != 0)))); +} + static bfd_boolean elf_map_symbols (bfd *abfd) { @@ -3114,7 +3363,6 @@ elf_map_symbols (bfd *abfd) unsigned int idx; asection *asect; asymbol **new_syms; - bfd_size_type amt; #ifdef DEBUG fprintf (stderr, "elf_map_symbols\n"); @@ -3128,8 +3376,7 @@ elf_map_symbols (bfd *abfd) } max_index++; - amt = max_index * sizeof (asymbol *); - sect_syms = bfd_zalloc (abfd, amt); + sect_syms = bfd_zalloc2 (abfd, max_index, sizeof (asymbol *)); if (sect_syms == NULL) return FALSE; elf_section_syms (abfd) = sect_syms; @@ -3142,51 +3389,29 @@ elf_map_symbols (bfd *abfd) asymbol *sym = syms[idx]; if ((sym->flags & BSF_SECTION_SYM) != 0 - && sym->value == 0) + && !ignore_section_sym (abfd, sym)) { - asection *sec; + asection *sec = sym->section; - sec = sym->section; + if (sec->owner != abfd) + sec = sec->output_section; - if (sec->owner != NULL) - { - if (sec->owner != abfd) - { - if (sec->output_offset != 0) - continue; - - sec = sec->output_section; - - /* Empty sections in the input files may have had a - section symbol created for them. (See the comment - near the end of _bfd_generic_link_output_symbols in - linker.c). If the linker script discards such - sections then we will reach this point. Since we know - that we cannot avoid this case, we detect it and skip - the abort and the assignment to the sect_syms array. - To reproduce this particular case try running the - linker testsuite test ld-scripts/weak.exp for an ELF - port that uses the generic linker. */ - if (sec->owner == NULL) - continue; - - BFD_ASSERT (sec->owner == abfd); - } - sect_syms[sec->index] = syms[idx]; - } + sect_syms[sec->index] = syms[idx]; } } /* Classify all of the symbols. */ for (idx = 0; idx < symcount; idx++) { + if (ignore_section_sym (abfd, syms[idx])) + continue; if (!sym_is_global (abfd, syms[idx])) num_locals++; else num_globals++; } - /* We will be adding a section symbol for each BFD section. Most normal + /* We will be adding a section symbol for each normal BFD section. Most sections will already have a section symbol in outsymbols, but eg. SHT_GROUP sections will not, and we need the section symbol mapped at least in that case. */ @@ -3202,8 +3427,7 @@ elf_map_symbols (bfd *abfd) } /* Now sort the symbols so the local symbols are first. */ - amt = (num_locals + num_globals) * sizeof (asymbol *); - new_syms = bfd_alloc (abfd, amt); + new_syms = bfd_alloc2 (abfd, num_locals + num_globals, sizeof (asymbol *)); if (new_syms == NULL) return FALSE; @@ -3213,6 +3437,8 @@ elf_map_symbols (bfd *abfd) asymbol *sym = syms[idx]; unsigned int i; + if (ignore_section_sym (abfd, sym)) + continue; if (!sym_is_global (abfd, sym)) i = num_locals2++; else @@ -3376,47 +3602,131 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, return TRUE; } -/* Create a mapping from a set of sections to a program segment. */ +/* Make an initial estimate of the size of the program header. If we + get the number wrong here, we'll redo section placement. */ -static struct elf_segment_map * -make_mapping (bfd *abfd, - asection **sections, - unsigned int from, - unsigned int to, - bfd_boolean phdr) +static bfd_size_type +get_program_header_size (bfd *abfd, struct bfd_link_info *info) { - struct elf_segment_map *m; - unsigned int i; - asection **hdrpp; - bfd_size_type amt; + size_t segs; + asection *s; + const struct elf_backend_data *bed; - amt = sizeof (struct elf_segment_map); - amt += (to - from - 1) * sizeof (asection *); - m = bfd_zalloc (abfd, amt); - if (m == 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; + /* Assume we will need exactly two PT_LOAD segments: one for text + and one for data. */ + segs = 2; - if (from == 0 && phdr) + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) { - /* Include the headers in the first PT_LOAD segment. */ - m->includes_filehdr = 1; - m->includes_phdrs = 1; + /* If we have a loadable interpreter section, we need a + PT_INTERP segment. In this case, assume we also need a + PT_PHDR segment, although that may not be true for all + targets. */ + segs += 2; } - return m; -} - -/* Create the PT_DYNAMIC segment, which includes DYNSEC. Returns NULL - on failure. */ + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) + { + /* We need a PT_DYNAMIC segment. */ + ++segs; + + if (elf_tdata (abfd)->relro) + { + /* We need a PT_GNU_RELRO segment only when there is a + PT_DYNAMIC segment. */ + ++segs; + } + } -struct elf_segment_map * -_bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec) -{ + if (elf_tdata (abfd)->eh_frame_hdr) + { + /* We need a PT_GNU_EH_FRAME segment. */ + ++segs; + } + + if (elf_tdata (abfd)->stack_flags) + { + /* We need a PT_GNU_STACK segment. */ + ++segs; + } + + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LOAD) != 0 + && CONST_STRNEQ (s->name, ".note")) + { + /* We need a PT_NOTE segment. */ + ++segs; + } + } + + for (s = abfd->sections; s != NULL; s = s->next) + { + if (s->flags & SEC_THREAD_LOCAL) + { + /* We need a PT_TLS segment. */ + ++segs; + break; + } + } + + /* Let the backend count up any program headers it might need. */ + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_additional_program_headers) + { + int a; + + a = (*bed->elf_backend_additional_program_headers) (abfd, info); + if (a == -1) + abort (); + segs += a; + } + + return segs * bed->s->sizeof_phdr; +} + +/* Create a mapping from a set of sections to a program segment. */ + +static struct elf_segment_map * +make_mapping (bfd *abfd, + asection **sections, + unsigned int from, + unsigned int to, + bfd_boolean phdr) +{ + struct elf_segment_map *m; + unsigned int i; + asection **hdrpp; + bfd_size_type amt; + + amt = sizeof (struct elf_segment_map); + amt += (to - from - 1) * sizeof (asection *); + m = bfd_zalloc (abfd, amt); + if (m == 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; +} + +/* Create the PT_DYNAMIC segment, which includes DYNSEC. Returns NULL + on failure. */ + +struct elf_segment_map * +_bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec) +{ struct elf_segment_map *m; m = bfd_zalloc (abfd, sizeof (struct elf_segment_map)); @@ -3430,360 +3740,413 @@ _bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec) return m; } -/* Set up a mapping from BFD sections to program segments. */ +/* Possibly add or remove segments from the segment map. */ static bfd_boolean -map_sections_to_segments (bfd *abfd) +elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info) { - asection **sections = NULL; - asection *s; - unsigned int i; - unsigned int count; - struct elf_segment_map *mfirst; - struct elf_segment_map **pm; - struct elf_segment_map *m; - asection *last_hdr; - bfd_vma last_size; - unsigned int phdr_index; - bfd_vma maxpagesize; - asection **hdrpp; - bfd_boolean phdr_in_segment = TRUE; - bfd_boolean writable; - int tls_count = 0; - asection *first_tls = NULL; - asection *dynsec, *eh_frame_hdr; - bfd_size_type amt; - - if (elf_tdata (abfd)->segment_map != NULL) - return TRUE; + struct elf_segment_map **m; + const struct elf_backend_data *bed; - if (bfd_count_sections (abfd) == 0) - return TRUE; + /* The placement algorithm assumes that non allocated sections are + not in PT_LOAD segments. We ensure this here by removing such + sections from the segment map. We also remove excluded + sections. Finally, any PT_LOAD segment without sections is + removed. */ + m = &elf_tdata (abfd)->segment_map; + while (*m) + { + unsigned int i, new_count; - /* Select the allocated sections, and sort them. */ + for (new_count = 0, i = 0; i < (*m)->count; i++) + { + if (((*m)->sections[i]->flags & SEC_EXCLUDE) == 0 + && (((*m)->sections[i]->flags & SEC_ALLOC) != 0 + || (*m)->p_type != PT_LOAD)) + { + (*m)->sections[new_count] = (*m)->sections[i]; + new_count++; + } + } + (*m)->count = new_count; - amt = bfd_count_sections (abfd) * sizeof (asection *); - sections = bfd_malloc (amt); - if (sections == NULL) - goto error_return; + if ((*m)->p_type == PT_LOAD && (*m)->count == 0) + *m = (*m)->next; + else + m = &(*m)->next; + } - i = 0; - for (s = abfd->sections; s != NULL; s = s->next) + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_modify_segment_map != NULL) { - if ((s->flags & SEC_ALLOC) != 0) - { - sections[i] = s; - ++i; - } + if (!(*bed->elf_backend_modify_segment_map) (abfd, info)) + return FALSE; } - BFD_ASSERT (i <= bfd_count_sections (abfd)); - count = i; - qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); + return TRUE; +} - /* Build the mapping. */ +/* Set up a mapping from BFD sections to program segments. */ - mfirst = NULL; - pm = &mfirst; +bfd_boolean +_bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) +{ + unsigned int count; + struct elf_segment_map *m; + asection **sections = NULL; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); - /* If we have a .interp section, then create a PT_PHDR segment for - the program headers and a PT_INTERP segment for the .interp - section. */ - s = bfd_get_section_by_name (abfd, ".interp"); - if (s != NULL && (s->flags & SEC_LOAD) != 0) + if (elf_tdata (abfd)->segment_map == NULL + && bfd_count_sections (abfd) != 0) { - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - 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; + asection *s; + unsigned int i; + struct elf_segment_map *mfirst; + struct elf_segment_map **pm; + asection *last_hdr; + bfd_vma last_size; + unsigned int phdr_index; + bfd_vma maxpagesize; + asection **hdrpp; + bfd_boolean phdr_in_segment = TRUE; + bfd_boolean writable; + int tls_count = 0; + asection *first_tls = NULL; + asection *dynsec, *eh_frame_hdr; + bfd_size_type amt; - *pm = m; - pm = &m->next; + /* Select the allocated sections, and sort them. */ - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) + sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *)); + if (sections == NULL) goto error_return; - m->next = NULL; - m->p_type = PT_INTERP; - m->count = 1; - m->sections[0] = s; - - *pm = m; - pm = &m->next; - } - - /* Look through the sections. We put sections in the same program - segment when the start of the second section can be placed within - a few bytes of the end of the first section. */ - last_hdr = NULL; - last_size = 0; - phdr_index = 0; - maxpagesize = get_elf_backend_data (abfd)->maxpagesize; - writable = FALSE; - dynsec = bfd_get_section_by_name (abfd, ".dynamic"); - if (dynsec != NULL - && (dynsec->flags & SEC_LOAD) == 0) - dynsec = NULL; - - /* Deal with -Ttext or something similar such that the first section - is not adjacent to the program headers. This is an - approximation, since at this point we don't know exactly how many - program headers we will need. */ - if (count > 0) - { - bfd_size_type phdr_size; - - phdr_size = elf_tdata (abfd)->program_header_size; - if (phdr_size == 0) - phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr; - if ((abfd->flags & D_PAGED) == 0 - || sections[0]->lma < phdr_size - || sections[0]->lma % maxpagesize < phdr_size % maxpagesize) - phdr_in_segment = FALSE; - } - - for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) - { - asection *hdr; - bfd_boolean new_segment; - hdr = *hdrpp; - - /* See if this section and the last one will fit in the same - segment. */ - - if (last_hdr == NULL) - { - /* If we don't have a segment yet, then we don't need a new - one (we build the last one after this loop). */ - new_segment = FALSE; - } - else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma) - { - /* If this section has a different relation between the - virtual address and the load address, then we need a new - segment. */ - new_segment = TRUE; - } - else if (BFD_ALIGN (last_hdr->lma + last_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 | SEC_THREAD_LOCAL)) == 0 - && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0) - { - /* We don't want to put a loadable section after a - nonloadable section in the same segment. - Consider .tbss sections as loadable for this purpose. */ - new_segment = TRUE; - } - else if ((abfd->flags & D_PAGED) == 0) + i = 0; + for (s = abfd->sections; s != NULL; s = s->next) { - /* 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; + if ((s->flags & SEC_ALLOC) != 0) + { + sections[i] = s; + ++i; + } } - else if (! writable - && (hdr->flags & SEC_READONLY) == 0 - && (((last_hdr->lma + last_size - 1) - & ~(maxpagesize - 1)) - != (hdr->lma & ~(maxpagesize - 1)))) + BFD_ASSERT (i <= bfd_count_sections (abfd)); + count = i; + + qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); + + /* Build the mapping. */ + + mfirst = NULL; + pm = &mfirst; + + /* If we have a .interp section, then create a PT_PHDR segment for + the program headers and a PT_INTERP segment for the .interp + section. */ + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) { - /* 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; + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + 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; + + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_INTERP; + m->count = 1; + m->sections[0] = s; + + *pm = m; + pm = &m->next; } - else + + /* Look through the sections. We put sections in the same program + segment when the start of the second section can be placed within + a few bytes of the end of the first section. */ + last_hdr = NULL; + last_size = 0; + phdr_index = 0; + maxpagesize = bed->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) { - /* Otherwise, we can use the same segment. */ - new_segment = FALSE; + bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size; + + if (phdr_size == (bfd_size_type) -1) + phdr_size = get_program_header_size (abfd, info); + if ((abfd->flags & D_PAGED) == 0 + || sections[0]->lma < phdr_size + || sections[0]->lma % maxpagesize < phdr_size % maxpagesize) + phdr_in_segment = FALSE; } - if (! new_segment) + for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) { + asection *hdr; + bfd_boolean new_segment; + + hdr = *hdrpp; + + /* See if this section and the last one will fit in the same + segment. */ + + if (last_hdr == NULL) + { + /* If we don't have a segment yet, then we don't need a new + one (we build the last one after this loop). */ + new_segment = FALSE; + } + else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma) + { + /* If this section has a different relation between the + virtual address and the load address, then we need a new + segment. */ + new_segment = TRUE; + } + else if (BFD_ALIGN (last_hdr->lma + last_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 | SEC_THREAD_LOCAL)) == 0 + && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0) + { + /* We don't want to put a loadable section after a + nonloadable section in the same segment. + Consider .tbss sections as loadable for this purpose. */ + 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 + && (((last_hdr->lma + last_size - 1) + & ~(maxpagesize - 1)) + != (hdr->lma & ~(maxpagesize - 1)))) + { + /* 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; + /* .tbss sections effectively have zero size. */ + if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) + != SEC_THREAD_LOCAL) + last_size = hdr->size; + else + last_size = 0; + continue; + } + + /* We need a new program segment. We must create a new program + header holding all the sections from phdr_index until hdr. */ + + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; + if ((hdr->flags & SEC_READONLY) == 0) writable = TRUE; + else + writable = FALSE; + last_hdr = hdr; /* .tbss sections effectively have zero size. */ if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL) last_size = hdr->size; else last_size = 0; - continue; + phdr_index = i; + phdr_in_segment = FALSE; } - /* We need a new program segment. We must create a new program - header holding all the sections from phdr_index until hdr. */ + /* Create a final PT_LOAD program segment. */ + if (last_hdr != NULL) + { + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); + if (m == NULL) + goto error_return; - m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); - if (m == NULL) - goto error_return; + *pm = m; + pm = &m->next; + } - *pm = m; - pm = &m->next; + /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ + if (dynsec != NULL) + { + m = _bfd_elf_make_dynamic_segment (abfd, dynsec); + if (m == NULL) + goto error_return; + *pm = m; + pm = &m->next; + } - if ((hdr->flags & SEC_READONLY) == 0) - writable = TRUE; - else - writable = FALSE; + /* 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 + && CONST_STRNEQ (s->name, ".note")) + { + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_NOTE; + m->count = 1; + m->sections[0] = s; - last_hdr = hdr; - /* .tbss sections effectively have zero size. */ - if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL) - last_size = hdr->size; - else - last_size = 0; - phdr_index = i; - phdr_in_segment = FALSE; - } + *pm = m; + pm = &m->next; + } + if (s->flags & SEC_THREAD_LOCAL) + { + if (! tls_count) + first_tls = s; + tls_count++; + } + } - /* Create a final PT_LOAD program segment. */ - if (last_hdr != NULL) - { - m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); - if (m == NULL) - goto error_return; + /* If there are any SHF_TLS output sections, add PT_TLS segment. */ + if (tls_count > 0) + { + int i; - *pm = m; - pm = &m->next; - } + amt = sizeof (struct elf_segment_map); + amt += (tls_count - 1) * sizeof (asection *); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_TLS; + m->count = tls_count; + /* Mandated PF_R. */ + m->p_flags = PF_R; + m->p_flags_valid = 1; + for (i = 0; i < tls_count; ++i) + { + BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL); + m->sections[i] = first_tls; + first_tls = first_tls->next; + } - /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ - if (dynsec != NULL) - { - m = _bfd_elf_make_dynamic_segment (abfd, dynsec); - if (m == NULL) - goto error_return; - *pm = m; - pm = &m->next; - } + *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) + /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME + segment. */ + eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr; + if (eh_frame_hdr != NULL + && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0) { amt = sizeof (struct elf_segment_map); m = bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; - m->p_type = PT_NOTE; + m->p_type = PT_GNU_EH_FRAME; m->count = 1; - m->sections[0] = s; + m->sections[0] = eh_frame_hdr->output_section; *pm = m; pm = &m->next; } - if (s->flags & SEC_THREAD_LOCAL) - { - if (! tls_count) - first_tls = s; - tls_count++; - } - } - - /* If there are any SHF_TLS output sections, add PT_TLS segment. */ - if (tls_count > 0) - { - int i; - amt = sizeof (struct elf_segment_map); - amt += (tls_count - 1) * sizeof (asection *); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - goto error_return; - m->next = NULL; - m->p_type = PT_TLS; - m->count = tls_count; - /* Mandated PF_R. */ - m->p_flags = PF_R; - m->p_flags_valid = 1; - for (i = 0; i < tls_count; ++i) + if (elf_tdata (abfd)->stack_flags) { - BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL); - m->sections[i] = first_tls; - first_tls = first_tls->next; - } - - *pm = m; - pm = &m->next; - } + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_STACK; + m->p_flags = elf_tdata (abfd)->stack_flags; + m->p_flags_valid = 1; - /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME - segment. */ - eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr; - if (eh_frame_hdr != NULL - && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0) - { - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - goto error_return; - m->next = NULL; - m->p_type = PT_GNU_EH_FRAME; - m->count = 1; - m->sections[0] = eh_frame_hdr->output_section; + *pm = m; + pm = &m->next; + } - *pm = m; - pm = &m->next; - } + if (dynsec != NULL && elf_tdata (abfd)->relro) + { + /* We make a PT_GNU_RELRO segment only when there is a + PT_DYNAMIC segment. */ + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_RELRO; + m->p_flags = PF_R; + m->p_flags_valid = 1; - if (elf_tdata (abfd)->stack_flags) - { - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - goto error_return; - m->next = NULL; - m->p_type = PT_GNU_STACK; - m->p_flags = elf_tdata (abfd)->stack_flags; - m->p_flags_valid = 1; + *pm = m; + pm = &m->next; + } - *pm = m; - pm = &m->next; + free (sections); + elf_tdata (abfd)->segment_map = mfirst; } - if (elf_tdata (abfd)->relro) - { - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - goto error_return; - m->next = NULL; - m->p_type = PT_GNU_RELRO; - m->p_flags = PF_R; - m->p_flags_valid = 1; - - *pm = m; - pm = &m->next; - } + if (!elf_modify_segment_map (abfd, info)) + return FALSE; - free (sections); - sections = NULL; + for (count = 0, m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++count; + elf_tdata (abfd)->program_header_size = count * bed->s->sizeof_phdr; - elf_tdata (abfd)->segment_map = mfirst; return TRUE; error_return: @@ -3879,115 +4242,63 @@ vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize) return ((vma - off) % maxpagesize); } -/* Assign file positions to the sections based on the mapping from - sections to segments. This function also sets up some fields in - the file header, and writes out the program headers. */ - -static bfd_boolean -assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - unsigned int count; - struct elf_segment_map *m; - unsigned int alloc; - Elf_Internal_Phdr *phdrs; - file_ptr off, voff; - bfd_vma filehdr_vaddr, filehdr_paddr; - bfd_vma phdrs_vaddr, phdrs_paddr; - Elf_Internal_Phdr *p; - bfd_size_type amt; - - if (elf_tdata (abfd)->segment_map == NULL) - { - if (! map_sections_to_segments (abfd)) - return FALSE; - } - else - { - /* The placement algorithm assumes that non allocated sections are - not in PT_LOAD segments. We ensure this here by removing such - sections from the segment map. */ - for (m = elf_tdata (abfd)->segment_map; - m != NULL; - m = m->next) - { - unsigned int new_count; - unsigned int i; - - if (m->p_type != PT_LOAD) - continue; - - new_count = 0; - for (i = 0; i < m->count; i ++) - { - if ((m->sections[i]->flags & SEC_ALLOC) != 0) - { - if (i != new_count) - m->sections[new_count] = m->sections[i]; - - new_count ++; - } - } +/* Assign file positions to the sections based on the mapping from + sections to segments. This function also sets up some fields in + the file header. */ - if (new_count != m->count) - m->count = new_count; - } - } +static bfd_boolean +assign_file_positions_for_load_sections (bfd *abfd, + struct bfd_link_info *link_info) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_segment_map *m; + Elf_Internal_Phdr *phdrs; + Elf_Internal_Phdr *p; + file_ptr off, voff; + bfd_size_type maxpagesize; + unsigned int alloc; + unsigned int i; - if (bed->elf_backend_modify_segment_map) - { - if (! (*bed->elf_backend_modify_segment_map) (abfd, link_info)) - return FALSE; - } + if (link_info == NULL + && !elf_modify_segment_map (abfd, link_info)) + return FALSE; - count = 0; + alloc = 0; for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) - ++count; + ++alloc; elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr; elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr; - elf_elfheader (abfd)->e_phnum = count; + elf_elfheader (abfd)->e_phnum = alloc; + + if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1) + elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr; + else + BFD_ASSERT (elf_tdata (abfd)->program_header_size + == alloc * bed->s->sizeof_phdr); - if (count == 0) + if (alloc == 0) { elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr; return TRUE; } - /* 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. */ - alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr; - if (alloc != 0 && count > alloc) - { - ((*_bfd_error_handler) - (_("%B: Not enough room for program headers (allocated %u, need %u)"), - abfd, alloc, count)); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (alloc == 0) - alloc = count; - - amt = alloc * sizeof (Elf_Internal_Phdr); - phdrs = bfd_alloc (abfd, amt); + phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr)); + elf_tdata (abfd)->phdr = phdrs; if (phdrs == NULL) return FALSE; + maxpagesize = 1; + if ((abfd->flags & D_PAGED) != 0) + maxpagesize = bed->maxpagesize; + off = bed->s->sizeof_ehdr; off += alloc * bed->s->sizeof_phdr; - filehdr_vaddr = 0; - filehdr_paddr = 0; - phdrs_vaddr = 0; - phdrs_paddr = 0; - for (m = elf_tdata (abfd)->segment_map, p = phdrs; m != NULL; m = m->next, p++) { - unsigned int i; asection **secpp; /* If elf_segment_map is not from map_sections_to_segments, the @@ -4012,27 +4323,58 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) p->p_type = m->p_type; p->p_flags = m->p_flags; + if (m->count == 0) + p->p_vaddr = 0; + else + p->p_vaddr = m->sections[0]->vma; + + if (m->p_paddr_valid) + p->p_paddr = m->p_paddr; + else if (m->count == 0) + p->p_paddr = 0; + else + p->p_paddr = m->sections[0]->lma; + + if (p->p_type == PT_LOAD + && (abfd->flags & D_PAGED) != 0) + { + /* p_align in demand paged PT_LOAD segments effectively stores + the maximum page size. When copying an executable with + objcopy, we set m->p_align from the input file. Use this + value for maxpagesize rather than bed->maxpagesize, which + may be different. Note that we use maxpagesize for PT_TLS + segment alignment later in this function, so we are relying + on at least one PT_LOAD segment appearing before a PT_TLS + segment. */ + if (m->p_align_valid) + maxpagesize = m->p_align; + + p->p_align = maxpagesize; + } + else if (m->count == 0) + p->p_align = 1 << bed->s->log_file_align; + else + p->p_align = 0; + if (p->p_type == PT_LOAD && m->count > 0) { bfd_size_type align; bfd_vma adjust; + unsigned int align_power = 0; - if ((abfd->flags & D_PAGED) != 0) - align = bed->maxpagesize; - else + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { - unsigned int align_power = 0; - for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) - { - unsigned int secalign; + unsigned int secalign; - secalign = bfd_get_section_alignment (abfd, *secpp); - if (secalign > align_power) - align_power = secalign; - } - align = (bfd_size_type) 1 << align_power; + secalign = bfd_get_section_alignment (abfd, *secpp); + if (secalign > align_power) + align_power = secalign; } + align = (bfd_size_type) 1 << align_power; + + if (align < maxpagesize) + align = maxpagesize; adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align); off += adjust; @@ -4048,7 +4390,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) .tbss, we need to look at the next section to decide whether the segment has any loadable sections. */ i = 0; - while ((m->sections[i]->flags & SEC_LOAD) == 0) + while ((m->sections[i]->flags & SEC_LOAD) == 0 + && (m->sections[i]->flags & SEC_HAS_CONTENTS) == 0) { if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0 || ++i >= m->count) @@ -4073,26 +4416,6 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) return FALSE; } - if (m->count == 0) - p->p_vaddr = 0; - else - p->p_vaddr = m->sections[0]->vma; - - if (m->p_paddr_valid) - p->p_paddr = m->p_paddr; - else if (m->count == 0) - p->p_paddr = 0; - else - p->p_paddr = m->sections[0]->lma; - - if (p->p_type == PT_LOAD - && (abfd->flags & D_PAGED) != 0) - p->p_align = bed->maxpagesize; - else if (m->count == 0) - p->p_align = 1 << bed->s->log_file_align; - else - p->p_align = 0; - p->p_offset = 0; p->p_filesz = 0; p->p_memsz = 0; @@ -4121,11 +4444,6 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (! m->p_paddr_valid) p->p_paddr -= off; } - if (p->p_type == PT_LOAD) - { - filehdr_vaddr = p->p_vaddr; - filehdr_paddr = p->p_paddr; - } } if (m->includes_phdrs) @@ -4133,15 +4451,7 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (! m->p_flags_valid) p->p_flags |= PF_R; - if (m->includes_filehdr) - { - if (p->p_type == PT_LOAD) - { - phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr; - phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr; - } - } - else + if (!m->includes_filehdr) { p->p_offset = bed->s->sizeof_ehdr; @@ -4152,14 +4462,6 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (! m->p_paddr_valid) p->p_paddr -= off - p->p_offset; } - - if (p->p_type == PT_LOAD) - { - phdrs_vaddr = p->p_vaddr; - phdrs_paddr = p->p_paddr; - } - else - phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; } p->p_filesz += alloc * bed->s->sizeof_phdr; @@ -4181,6 +4483,11 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) } } + /* Set up p_filesz, p_memsz, p_align and p_flags from the section + maps. Set filepos for sections in PT_LOAD segments, and in + core files, for sections in PT_NOTE segments. + assign_file_positions_for_non_load_sections will set filepos + for other sections and update p_filesz for other segments. */ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { asection *sec; @@ -4189,7 +4496,7 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) sec = *secpp; flags = sec->flags; - align = 1 << bfd_get_section_alignment (abfd, sec); + align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec); if (p->p_type == PT_LOAD || p->p_type == PT_TLS) @@ -4212,14 +4519,15 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) } /* .tbss is special. It doesn't contribute to p_memsz of normal segments. */ - else if ((flags & SEC_THREAD_LOCAL) == 0 - || p->p_type == PT_TLS) + else if ((flags & SEC_ALLOC) != 0 + && ((flags & SEC_THREAD_LOCAL) == 0 + || p->p_type == PT_TLS)) { /* The section VMA must equal the file position modulo the page size. */ bfd_size_type page = align; - if ((abfd->flags & D_PAGED) != 0) - page = bed->maxpagesize; + if (page < maxpagesize) + page = maxpagesize; adjust = vma_page_aligned_bias (sec->vma, p->p_vaddr + p->p_memsz, page); @@ -4252,7 +4560,7 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) { if (p->p_type == PT_LOAD) { - sec->filepos = off; + sec->filepos = off + voff; /* FIXME: The SEC_HAS_CONTENTS test here dates back to 1997, and the exact reason for it isn't clear. One plausible explanation is that it is to work around @@ -4277,34 +4585,28 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) p->p_filesz += sec->size; p->p_memsz += sec->size; } - /* PR ld/594: Sections in note segments which are not loaded - contribute to the file size but not the in-memory size. */ - else if (p->p_type == PT_NOTE - && (flags & SEC_HAS_CONTENTS) != 0) - p->p_filesz += sec->size; /* .tbss is special. It doesn't contribute to p_memsz of normal segments. */ - else if ((flags & SEC_THREAD_LOCAL) == 0 - || p->p_type == PT_TLS) + else if ((flags & SEC_ALLOC) != 0 + && ((flags & SEC_THREAD_LOCAL) == 0 + || p->p_type == PT_TLS)) p->p_memsz += sec->size; if (p->p_type == PT_TLS && sec->size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0) { - struct bfd_link_order *o; - bfd_vma tbss_size = 0; - - for (o = sec->map_head.link_order; o != NULL; o = o->next) - if (tbss_size < o->offset + o->size) - tbss_size = o->offset + o->size; - - p->p_memsz += tbss_size; + struct bfd_link_order *o = sec->map_tail.link_order; + if (o != NULL) + p->p_memsz += o->offset + o->size; } - if (align > p->p_align - && (p->p_type != PT_LOAD || (abfd->flags & D_PAGED) == 0)) + if (p->p_type == PT_GNU_RELRO) + p->p_align = 1; + else if (align > p->p_align + && (p->p_type != PT_LOAD + || (abfd->flags & D_PAGED) == 0)) p->p_align = align; } @@ -4319,34 +4621,133 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) } } + elf_tdata (abfd)->next_file_pos = off; + return TRUE; +} + +/* Assign file positions for the other sections. */ + +static bfd_boolean +assign_file_positions_for_non_load_sections (bfd *abfd, + struct bfd_link_info *link_info) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + Elf_Internal_Shdr **i_shdrpp; + Elf_Internal_Shdr **hdrpp; + Elf_Internal_Phdr *phdrs; + Elf_Internal_Phdr *p; + struct elf_segment_map *m; + bfd_vma filehdr_vaddr, filehdr_paddr; + bfd_vma phdrs_vaddr, phdrs_paddr; + file_ptr off; + unsigned int num_sec; + unsigned int i; + unsigned int count; + + i_shdrpp = elf_elfsections (abfd); + num_sec = elf_numsections (abfd); + off = elf_tdata (abfd)->next_file_pos; + for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) + { + struct elf_obj_tdata *tdata = elf_tdata (abfd); + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if (hdr->bfd_section != NULL + && (hdr->bfd_section->filepos != 0 + || (hdr->sh_type == SHT_NOBITS + && hdr->contents == NULL))) + hdr->sh_offset = hdr->bfd_section->filepos; + else if ((hdr->sh_flags & SHF_ALLOC) != 0) + { + if (hdr->sh_size != 0) + ((*_bfd_error_handler) + (_("%B: warning: allocated section `%s' not in segment"), + abfd, + (hdr->bfd_section == NULL + ? "*unknown*" + : hdr->bfd_section->name))); + /* We don't need to page align empty sections. */ + if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0) + off += vma_page_aligned_bias (hdr->sh_addr, off, + bed->maxpagesize); + else + off += vma_page_aligned_bias (hdr->sh_addr, off, + hdr->sh_addralign); + off = _bfd_elf_assign_file_position_for_section (hdr, off, + FALSE); + } + else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) + && hdr->bfd_section == NULL) + || hdr == i_shdrpp[tdata->symtab_section] + || hdr == i_shdrpp[tdata->symtab_shndx_section] + || hdr == i_shdrpp[tdata->strtab_section]) + hdr->sh_offset = -1; + else + off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + + if (i == SHN_LORESERVE - 1) + { + i += SHN_HIRESERVE + 1 - SHN_LORESERVE; + hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE; + } + } + /* Now that we have set the section file positions, we can set up the file positions for the non PT_LOAD segments. */ + count = 0; + filehdr_vaddr = 0; + filehdr_paddr = 0; + phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; + phdrs_paddr = 0; + phdrs = elf_tdata (abfd)->phdr; + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + ++count; + if (p->p_type != PT_LOAD) + continue; + + if (m->includes_filehdr) + { + filehdr_vaddr = p->p_vaddr; + filehdr_paddr = p->p_paddr; + } + if (m->includes_phdrs) + { + phdrs_vaddr = p->p_vaddr; + phdrs_paddr = p->p_paddr; + if (m->includes_filehdr) + { + phdrs_vaddr += bed->s->sizeof_ehdr; + phdrs_paddr += bed->s->sizeof_ehdr; + } + } + } + for (m = elf_tdata (abfd)->segment_map, p = phdrs; m != NULL; m = m->next, p++) { - if (p->p_type != PT_LOAD && m->count > 0) + if (m->count != 0) { - BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs); - /* If the section has not yet been assigned a file position, - do so now. The ARM BPABI requires that .dynamic section - not be marked SEC_ALLOC because it is not part of any - PT_LOAD segment, so it will not be processed above. */ - if (p->p_type == PT_DYNAMIC && m->sections[0]->filepos == 0) + if (p->p_type != PT_LOAD + && (p->p_type != PT_NOTE || bfd_get_format (abfd) != bfd_core)) { - unsigned int i; - Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); - - i = 1; - while (i_shdrpp[i]->bfd_section != m->sections[0]) - ++i; - off = (_bfd_elf_assign_file_position_for_section - (i_shdrpp[i], off, TRUE)); - p->p_filesz = m->sections[0]->size; + Elf_Internal_Shdr *hdr; + BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs); + + hdr = &elf_section_data (m->sections[m->count - 1])->this_hdr; + p->p_filesz = (m->sections[m->count - 1]->filepos + - m->sections[0]->filepos); + if (hdr->sh_type != SHT_NOBITS) + p->p_filesz += hdr->sh_size; + + p->p_offset = m->sections[0]->filepos; } - p->p_offset = m->sections[0]->filepos; } - if (m->count == 0) + else { if (m->includes_filehdr) { @@ -4369,8 +4770,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (lp->p_type == PT_LOAD && lp->p_vaddr <= link_info->relro_end && lp->p_vaddr >= link_info->relro_start - && lp->p_vaddr + lp->p_filesz - >= link_info->relro_end) + && (lp->p_vaddr + lp->p_filesz + >= link_info->relro_end)) break; } @@ -4385,138 +4786,18 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) p->p_align = 1; p->p_flags = (lp->p_flags & ~PF_W); } - else - { - memset (p, 0, sizeof *p); - p->p_type = PT_NULL; - } - } - } - } - - /* Clear out any program headers we allocated but did not use. */ - for (; count < alloc; count++, p++) - { - memset (p, 0, sizeof *p); - p->p_type = PT_NULL; - } - - elf_tdata (abfd)->phdr = phdrs; - - elf_tdata (abfd)->next_file_pos = off; - - /* Write out the program headers. */ - if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 - || bed->s->write_out_phdrs (abfd, phdrs, alloc) != 0) - return FALSE; - - return TRUE; -} - -/* Get the size of the program header. - - If this is called by the linker before any of the section VMA's are set, it - can't calculate the correct value for a strange memory layout. This only - happens when SIZEOF_HEADERS is used in a linker script. In this case, - SORTED_HDRS is NULL and we assume the normal scenario of one text and one - data segment (exclusive of .interp and .dynamic). - - ??? User written scripts must either not use SIZEOF_HEADERS, or assume there - will be two segments. */ - -static bfd_size_type -get_program_header_size (bfd *abfd) -{ - size_t segs; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - /* We can't return a different result each time we're called. */ - 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; - - s = bfd_get_section_by_name (abfd, ".interp"); - if (s != NULL && (s->flags & SEC_LOAD) != 0) - { - /* If we have a loadable interpreter section, we need a - PT_INTERP segment. In this case, assume we also need a - PT_PHDR segment, although that may not be true for all - targets. */ - segs += 2; - } - - if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) - { - /* We need a PT_DYNAMIC segment. */ - ++segs; - } - - if (elf_tdata (abfd)->eh_frame_hdr) - { - /* We need a PT_GNU_EH_FRAME segment. */ - ++segs; - } - - if (elf_tdata (abfd)->stack_flags) - { - /* We need a PT_GNU_STACK segment. */ - ++segs; - } - - if (elf_tdata (abfd)->relro) - { - /* We need a PT_GNU_RELRO segment. */ - ++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; - } - } - - for (s = abfd->sections; s != NULL; s = s->next) - { - if (s->flags & SEC_THREAD_LOCAL) - { - /* We need a PT_TLS segment. */ - ++segs; - break; - } - } - - /* Let the backend count up any program headers it might need. */ - if (bed->elf_backend_additional_program_headers) - { - int a; - - a = (*bed->elf_backend_additional_program_headers) (abfd); - if (a == -1) - abort (); - segs += a; + else + { + memset (p, 0, sizeof *p); + p->p_type = PT_NULL; + } + } + } } - elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; - return elf_tdata (abfd)->program_header_size; + elf_tdata (abfd)->next_file_pos = off; + + return TRUE; } /* Work out the file positions of all the sections. This is called by @@ -4537,16 +4818,16 @@ static bfd_boolean assign_file_positions_except_relocs (bfd *abfd, struct bfd_link_info *link_info) { - struct elf_obj_tdata * const tdata = elf_tdata (abfd); - Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd); - Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); - unsigned int num_sec = elf_numsections (abfd); + struct elf_obj_tdata *tdata = elf_tdata (abfd); + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); file_ptr off; const struct elf_backend_data *bed = get_elf_backend_data (abfd); if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 && bfd_get_format (abfd) != bfd_core) { + Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); + unsigned int num_sec = elf_numsections (abfd); Elf_Internal_Shdr **hdrpp; unsigned int i; @@ -4581,57 +4862,30 @@ assign_file_positions_except_relocs (bfd *abfd, } else { - unsigned int i; - Elf_Internal_Shdr **hdrpp; + unsigned int alloc; /* Assign file positions for the loaded sections based on the assignment of sections to segments. */ - if (! assign_file_positions_for_segments (abfd, link_info)) + if (!assign_file_positions_for_load_sections (abfd, link_info)) return FALSE; - /* Assign file positions for the other sections. */ + /* And for non-load sections. */ + if (!assign_file_positions_for_non_load_sections (abfd, link_info)) + return FALSE; - off = elf_tdata (abfd)->next_file_pos; - for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) + if (bed->elf_backend_modify_program_headers != NULL) { - Elf_Internal_Shdr *hdr; + if (!(*bed->elf_backend_modify_program_headers) (abfd, link_info)) + return FALSE; + } - hdr = *hdrpp; - if (hdr->bfd_section != NULL - && hdr->bfd_section->filepos != 0) - hdr->sh_offset = hdr->bfd_section->filepos; - else if ((hdr->sh_flags & SHF_ALLOC) != 0) - { - ((*_bfd_error_handler) - (_("%B: warning: allocated section `%s' not in segment"), - abfd, - (hdr->bfd_section == NULL - ? "*unknown*" - : hdr->bfd_section->name))); - if ((abfd->flags & D_PAGED) != 0) - off += vma_page_aligned_bias (hdr->sh_addr, off, - bed->maxpagesize); - else - off += vma_page_aligned_bias (hdr->sh_addr, off, - hdr->sh_addralign); - off = _bfd_elf_assign_file_position_for_section (hdr, off, - FALSE); - } - else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) - && hdr->bfd_section == NULL) - || hdr == i_shdrpp[tdata->symtab_section] - || hdr == i_shdrpp[tdata->symtab_shndx_section] - || hdr == i_shdrpp[tdata->strtab_section]) - hdr->sh_offset = -1; - else - off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + /* Write out the program headers. */ + alloc = tdata->program_header_size / bed->s->sizeof_phdr; + if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 + || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0) + return FALSE; - if (i == SHN_LORESERVE - 1) - { - i += SHN_HIRESERVE + 1 - SHN_LORESERVE; - hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE; - } - } + off = tdata->next_file_pos; } /* Place the section headers. */ @@ -4639,7 +4893,7 @@ assign_file_positions_except_relocs (bfd *abfd, i_ehdrp->e_shoff = off; off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; - elf_tdata (abfd)->next_file_pos = off; + tdata->next_file_pos = off; return TRUE; } @@ -4804,8 +5058,9 @@ _bfd_elf_write_object_contents (bfd *abfd) } /* Write out the section header names. */ - if (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0 - || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd))) + if (elf_shstrtab (abfd) != NULL + && (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0 + || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))) return FALSE; if (bed->elf_backend_final_write_processing) @@ -4877,13 +5132,14 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr) && (flags & BSF_SECTION_SYM) && asym_ptr->section) { + asection *sec; int indx; - if (asym_ptr->section->output_section != NULL) - indx = asym_ptr->section->output_section->index; - else - indx = asym_ptr->section->index; - if (indx < elf_num_section_syms (abfd) + sec = asym_ptr->section; + if (sec->owner != abfd && sec->output_section != NULL) + sec = sec->output_section; + if (sec->owner == abfd + && (indx = sec->index) < elf_num_section_syms (abfd) && elf_section_syms (abfd)[indx] != NULL) asym_ptr->udata.i = elf_section_syms (abfd)[indx]->udata.i; } @@ -4914,10 +5170,10 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr) return idx; } -/* Copy private BFD data. This copies any program header information. */ +/* Rewrite program header information. */ static bfd_boolean -copy_private_bfd_data (bfd *ibfd, bfd *obfd) +rewrite_elf_program_header (bfd *ibfd, bfd *obfd) { Elf_Internal_Ehdr *iehdr; struct elf_segment_map *map; @@ -4933,13 +5189,6 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) unsigned int phdr_adjust_num = 0; const struct elf_backend_data *bed; - 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; - bed = get_elf_backend_data (ibfd); iehdr = elf_elfheader (ibfd); @@ -5152,7 +5401,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) all of the sections we have selected. */ amt = sizeof (struct elf_segment_map); amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); - map = bfd_alloc (obfd, amt); + map = bfd_zalloc (obfd, amt); if (map == NULL) return FALSE; @@ -5232,8 +5481,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) /* Gcc 2.96 miscompiles this code on mips. Don't do casting here to work around this long long bug. */ - amt = section_count * sizeof (asection *); - sections = bfd_malloc (amt); + sections = bfd_malloc2 (section_count, sizeof (asection *)); if (sections == NULL) return FALSE; @@ -5500,6 +5748,253 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) return TRUE; } +/* Copy ELF program header information. */ + +static bfd_boolean +copy_elf_program_header (bfd *ibfd, bfd *obfd) +{ + Elf_Internal_Ehdr *iehdr; + struct elf_segment_map *map; + struct elf_segment_map *map_first; + struct elf_segment_map **pointer_to_map; + Elf_Internal_Phdr *segment; + unsigned int i; + unsigned int num_segments; + bfd_boolean phdr_included = FALSE; + + iehdr = elf_elfheader (ibfd); + + map_first = NULL; + pointer_to_map = &map_first; + + num_segments = elf_elfheader (ibfd)->e_phnum; + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + { + asection *section; + unsigned int section_count; + bfd_size_type amt; + Elf_Internal_Shdr *this_hdr; + + /* FIXME: Do we need to copy PT_NULL segment? */ + if (segment->p_type == PT_NULL) + continue; + + /* Compute how many sections are in this segment. */ + for (section = ibfd->sections, section_count = 0; + section != NULL; + section = section->next) + { + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + section_count++; + } + + /* Allocate a segment map big enough to contain + all of the sections we have selected. */ + amt = sizeof (struct elf_segment_map); + if (section_count != 0) + amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); + map = bfd_zalloc (obfd, amt); + if (map == NULL) + return FALSE; + + /* Initialize the fields of the output segment map with the + input segment. */ + map->next = NULL; + map->p_type = segment->p_type; + map->p_flags = segment->p_flags; + map->p_flags_valid = 1; + map->p_paddr = segment->p_paddr; + map->p_paddr_valid = 1; + map->p_align = segment->p_align; + map->p_align_valid = 1; + + /* Determine if this segment contains the ELF file header + and if it contains the program headers themselves. */ + map->includes_filehdr = (segment->p_offset == 0 + && segment->p_filesz >= iehdr->e_ehsize); + + map->includes_phdrs = 0; + if (! phdr_included || segment->p_type != PT_LOAD) + { + map->includes_phdrs = + (segment->p_offset <= (bfd_vma) iehdr->e_phoff + && (segment->p_offset + segment->p_filesz + >= ((bfd_vma) iehdr->e_phoff + + iehdr->e_phnum * iehdr->e_phentsize))); + + if (segment->p_type == PT_LOAD && map->includes_phdrs) + phdr_included = TRUE; + } + + if (section_count != 0) + { + unsigned int isec = 0; + + for (section = ibfd->sections; + section != NULL; + section = section->next) + { + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + map->sections[isec++] = section->output_section; + } + } + + map->count = section_count; + *pointer_to_map = map; + pointer_to_map = &map->next; + } + + elf_tdata (obfd)->segment_map = map_first; + return TRUE; +} + +/* Copy private BFD data. This copies or rewrites ELF program header + information. */ + +static bfd_boolean +copy_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + 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; + + if (ibfd->xvec == obfd->xvec) + { + /* Check if any sections in the input BFD covered by ELF program + header are changed. */ + Elf_Internal_Phdr *segment; + asection *section, *osec; + unsigned int i, num_segments; + Elf_Internal_Shdr *this_hdr; + + /* Initialize the segment mark field. */ + for (section = obfd->sections; section != NULL; + section = section->next) + section->segment_mark = FALSE; + + num_segments = elf_elfheader (ibfd)->e_phnum; + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + { + for (section = ibfd->sections; + section != NULL; section = section->next) + { + /* We mark the output section so that we know it comes + from the input BFD. */ + osec = section->output_section; + if (osec) + osec->segment_mark = TRUE; + + /* Check if this section is covered by the segment. */ + this_hdr = &(elf_section_data(section)->this_hdr); + if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) + { + /* FIXME: Check if its output section is changed or + removed. What else do we need to check? */ + if (osec == NULL + || section->flags != osec->flags + || section->lma != osec->lma + || section->vma != osec->vma + || section->size != osec->size + || section->rawsize != osec->rawsize + || section->alignment_power != osec->alignment_power) + goto rewrite; + } + } + } + + /* Check to see if any output section doesn't come from the + input BFD. */ + for (section = obfd->sections; section != NULL; + section = section->next) + { + if (section->segment_mark == FALSE) + goto rewrite; + else + section->segment_mark = FALSE; + } + + return copy_elf_program_header (ibfd, obfd); + } + +rewrite: + return rewrite_elf_program_header (ibfd, obfd); +} + +/* Initialize private output section information from input section. */ + +bfd_boolean +_bfd_elf_init_private_section_data (bfd *ibfd, + asection *isec, + bfd *obfd, + asection *osec, + struct bfd_link_info *link_info) + +{ + Elf_Internal_Shdr *ihdr, *ohdr; + bfd_boolean need_group = link_info == NULL || link_info->relocatable; + + if (ibfd->xvec->flavour != bfd_target_elf_flavour + || obfd->xvec->flavour != bfd_target_elf_flavour) + return TRUE; + + /* Don't copy the output ELF section type from input if the + output BFD section flags have been set to something different. + elf_fake_sections will set ELF section type based on BFD + section flags. */ + if (osec->flags == isec->flags || !osec->flags) + { + BFD_ASSERT (osec->flags == isec->flags + || (!osec->flags + && elf_section_type (osec) == SHT_NULL)); + elf_section_type (osec) = elf_section_type (isec); + } + + /* FIXME: Is this correct for all OS/PROC specific flags? */ + elf_section_flags (osec) |= (elf_section_flags (isec) + & (SHF_MASKOS | SHF_MASKPROC)); + + /* Set things up for objcopy and relocatable link. The output + SHT_GROUP section will have its elf_next_in_group pointing back + to the input group members. Ignore linker created group section. + See elfNN_ia64_object_p in elfxx-ia64.c. */ + if (need_group) + { + if (elf_sec_group (isec) == NULL + || (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0) + { + if (elf_section_flags (isec) & SHF_GROUP) + elf_section_flags (osec) |= SHF_GROUP; + elf_next_in_group (osec) = elf_next_in_group (isec); + elf_group_name (osec) = elf_group_name (isec); + } + } + + ihdr = &elf_section_data (isec)->this_hdr; + + /* We need to handle elf_linked_to_section for SHF_LINK_ORDER. We + don't use the output section of the linked-to section since it + may be NULL at this point. */ + if ((ihdr->sh_flags & SHF_LINK_ORDER) != 0) + { + ohdr = &elf_section_data (osec)->this_hdr; + ohdr->sh_flags |= SHF_LINK_ORDER; + elf_linked_to_section (osec) = elf_linked_to_section (isec); + } + + osec->use_rela_p = isec->use_rela_p; + + return TRUE; +} + /* Copy private section information. This copies over the entsize field, and sometimes the info field. */ @@ -5526,20 +6021,8 @@ _bfd_elf_copy_private_section_data (bfd *ibfd, || ihdr->sh_type == SHT_GNU_verdef) ohdr->sh_info = ihdr->sh_info; - /* Set things up for objcopy. The output SHT_GROUP section will - have its elf_next_in_group pointing back to the input group - members. Ignore linker created group section. See - elfNN_ia64_object_p in elfxx-ia64.c. */ - if (elf_sec_group (isec) == NULL - || (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0) - { - elf_next_in_group (osec) = elf_next_in_group (isec); - elf_group_name (osec) = elf_group_name (isec); - } - - osec->use_rela_p = isec->use_rela_p; - - return TRUE; + return _bfd_elf_init_private_section_data (ibfd, isec, obfd, osec, + NULL); } /* Copy private header information. */ @@ -5547,6 +6030,8 @@ _bfd_elf_copy_private_section_data (bfd *ibfd, bfd_boolean _bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) { + asection *isec; + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour || bfd_get_flavour (obfd) != bfd_target_elf_flavour) return TRUE; @@ -5562,6 +6047,27 @@ _bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) return FALSE; } + /* _bfd_elf_copy_private_section_data copied over the SHF_GROUP flag + but this might be wrong if we deleted the group section. */ + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + if (elf_section_type (isec) == SHT_GROUP + && isec->output_section == NULL) + { + asection *first = elf_next_in_group (isec); + asection *s = first; + while (s != NULL) + { + if (s->output_section != NULL) + { + elf_section_flags (s->output_section) &= ~SHF_GROUP; + elf_group_name (s->output_section) = NULL; + } + s = elf_next_in_group (s); + if (s == first) + break; + } + } + return TRUE; } @@ -5655,8 +6161,7 @@ swap_out_syms (bfd *abfd, symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; symstrtab_hdr->sh_type = SHT_STRTAB; - amt = (bfd_size_type) (1 + symcount) * bed->s->sizeof_sym; - outbound_syms = bfd_alloc (abfd, amt); + outbound_syms = bfd_alloc2 (abfd, 1 + symcount, bed->s->sizeof_sym); if (outbound_syms == NULL) { _bfd_stringtab_free (stt); @@ -5669,7 +6174,8 @@ swap_out_syms (bfd *abfd, if (symtab_shndx_hdr->sh_name != 0) { amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx); - outbound_shndx = bfd_zalloc (abfd, amt); + outbound_shndx = bfd_zalloc2 (abfd, 1 + symcount, + sizeof (Elf_External_Sym_Shndx)); if (outbound_shndx == NULL) { _bfd_stringtab_free (stt); @@ -6082,7 +6588,6 @@ bfd_boolean _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) { bfd_byte *contents = NULL; - bfd_size_type amt; unsigned int freeidx = 0; if (elf_dynverref (abfd) != 0) @@ -6091,11 +6596,12 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) Elf_External_Verneed *everneed; Elf_Internal_Verneed *iverneed; unsigned int i; + bfd_byte *contents_end; hdr = &elf_tdata (abfd)->dynverref_hdr; - amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed); - elf_tdata (abfd)->verref = bfd_zalloc (abfd, amt); + elf_tdata (abfd)->verref = bfd_zalloc2 (abfd, hdr->sh_info, + sizeof (Elf_Internal_Verneed)); if (elf_tdata (abfd)->verref == NULL) goto error_return; @@ -6103,11 +6609,22 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) contents = bfd_malloc (hdr->sh_size); if (contents == NULL) - goto error_return; + { +error_return_verref: + elf_tdata (abfd)->verref = NULL; + elf_tdata (abfd)->cverrefs = 0; + goto error_return; + } if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) - goto error_return; + goto error_return_verref; + + if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verneed)) + goto error_return_verref; + BFD_ASSERT (sizeof (Elf_External_Verneed) + == sizeof (Elf_External_Vernaux)); + contents_end = contents + hdr->sh_size - sizeof (Elf_External_Verneed); everneed = (Elf_External_Verneed *) contents; iverneed = elf_tdata (abfd)->verref; for (i = 0; i < hdr->sh_info; i++, iverneed++) @@ -6124,11 +6641,21 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) bfd_elf_string_from_elf_section (abfd, hdr->sh_link, iverneed->vn_file); if (iverneed->vn_filename == NULL) - goto error_return; + goto error_return_verref; + + if (iverneed->vn_cnt == 0) + iverneed->vn_auxptr = NULL; + else + { + iverneed->vn_auxptr = bfd_alloc2 (abfd, iverneed->vn_cnt, + sizeof (Elf_Internal_Vernaux)); + if (iverneed->vn_auxptr == NULL) + goto error_return_verref; + } - amt = iverneed->vn_cnt; - amt *= sizeof (Elf_Internal_Vernaux); - iverneed->vn_auxptr = bfd_alloc (abfd, amt); + if (iverneed->vn_aux + > (size_t) (contents_end - (bfd_byte *) everneed)) + goto error_return_verref; evernaux = ((Elf_External_Vernaux *) ((bfd_byte *) everneed + iverneed->vn_aux)); @@ -6141,13 +6668,17 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) bfd_elf_string_from_elf_section (abfd, hdr->sh_link, ivernaux->vna_name); if (ivernaux->vna_nodename == NULL) - goto error_return; + goto error_return_verref; if (j + 1 < iverneed->vn_cnt) ivernaux->vna_nextptr = ivernaux + 1; else ivernaux->vna_nextptr = NULL; + if (ivernaux->vna_next + > (size_t) (contents_end - (bfd_byte *) evernaux)) + goto error_return_verref; + evernaux = ((Elf_External_Vernaux *) ((bfd_byte *) evernaux + ivernaux->vna_next)); @@ -6160,6 +6691,10 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) else iverneed->vn_nextref = NULL; + if (iverneed->vn_next + > (size_t) (contents_end - (bfd_byte *) everneed)) + goto error_return_verref; + everneed = ((Elf_External_Verneed *) ((bfd_byte *) everneed + iverneed->vn_next)); } @@ -6177,6 +6712,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) Elf_Internal_Verdef iverdefmem; unsigned int i; unsigned int maxidx; + bfd_byte *contents_end_def, *contents_end_aux; hdr = &elf_tdata (abfd)->dynverdef_hdr; @@ -6187,6 +6723,16 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) goto error_return; + if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verdef)) + goto error_return; + + BFD_ASSERT (sizeof (Elf_External_Verdef) + >= sizeof (Elf_External_Verdaux)); + contents_end_def = contents + hdr->sh_size + - sizeof (Elf_External_Verdef); + contents_end_aux = contents + hdr->sh_size + - sizeof (Elf_External_Verdaux); + /* We know the number of entries in the section but not the maximum index. Therefore we have to run through all entries and find the maximum. */ @@ -6199,6 +6745,10 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx) maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION); + if (iverdefmem.vd_next + > (size_t) (contents_end_def - (bfd_byte *) everdef)) + goto error_return; + everdef = ((Elf_External_Verdef *) ((bfd_byte *) everdef + iverdefmem.vd_next)); } @@ -6210,8 +6760,8 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) else freeidx = ++maxidx; } - amt = (bfd_size_type) maxidx * sizeof (Elf_Internal_Verdef); - elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt); + elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, maxidx, + sizeof (Elf_Internal_Verdef)); if (elf_tdata (abfd)->verdef == NULL) goto error_return; @@ -6227,15 +6777,32 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); + if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0) + { +error_return_verdef: + elf_tdata (abfd)->verdef = NULL; + elf_tdata (abfd)->cverdefs = 0; + goto error_return; + } + iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1]; memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef)); iverdef->vd_bfd = abfd; - amt = (bfd_size_type) iverdef->vd_cnt * sizeof (Elf_Internal_Verdaux); - iverdef->vd_auxptr = bfd_alloc (abfd, amt); - if (iverdef->vd_auxptr == NULL) - goto error_return; + if (iverdef->vd_cnt == 0) + iverdef->vd_auxptr = NULL; + else + { + iverdef->vd_auxptr = bfd_alloc2 (abfd, iverdef->vd_cnt, + sizeof (Elf_Internal_Verdaux)); + if (iverdef->vd_auxptr == NULL) + goto error_return_verdef; + } + + if (iverdef->vd_aux + > (size_t) (contents_end_aux - (bfd_byte *) everdef)) + goto error_return_verdef; everdaux = ((Elf_External_Verdaux *) ((bfd_byte *) everdef + iverdef->vd_aux)); @@ -6248,20 +6815,25 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) bfd_elf_string_from_elf_section (abfd, hdr->sh_link, iverdaux->vda_name); if (iverdaux->vda_nodename == NULL) - goto error_return; + goto error_return_verdef; if (j + 1 < iverdef->vd_cnt) iverdaux->vda_nextptr = iverdaux + 1; else iverdaux->vda_nextptr = NULL; + if (iverdaux->vda_next + > (size_t) (contents_end_aux - (bfd_byte *) everdaux)) + goto error_return_verdef; + everdaux = ((Elf_External_Verdaux *) ((bfd_byte *) everdaux + iverdaux->vda_next)); } - iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename; + if (iverdef->vd_cnt) + iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename; - if (i + 1 < hdr->sh_info) + if ((size_t) (iverdef - iverdefarr) + 1 < maxidx) iverdef->vd_nextdef = iverdef + 1; else iverdef->vd_nextdef = NULL; @@ -6280,8 +6852,8 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) else freeidx++; - amt = (bfd_size_type) freeidx * sizeof (Elf_Internal_Verdef); - elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt); + elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, freeidx, + sizeof (Elf_Internal_Verdef)); if (elf_tdata (abfd)->verdef == NULL) goto error_return; @@ -6305,10 +6877,11 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd); if (iverdef->vd_nodename == NULL) - goto error_return; + goto error_return_verdef; iverdef->vd_nextdef = NULL; - amt = (bfd_size_type) sizeof (Elf_Internal_Verdaux); - iverdef->vd_auxptr = bfd_alloc (abfd, amt); + iverdef->vd_auxptr = bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux)); + if (iverdef->vd_auxptr == NULL) + goto error_return_verdef; iverdaux = iverdef->vd_auxptr; iverdaux->vda_nodename = iverdef->vd_nodename; @@ -6445,8 +7018,6 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, if (state == symbol_seen) state = file_after_symbol_seen; continue; - case STT_SECTION: - continue; case STT_NOTYPE: case STT_FUNC: if (bfd_get_section (&q->symbol) == section @@ -6455,12 +7026,10 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, { func = (asymbol *) q; low_func = q->symbol.value; - if (file == NULL) - filename = NULL; - else if (ELF_ST_BIND (q->internal_elf_sym.st_info) != STB_LOCAL - && state == file_after_symbol_seen) - filename = NULL; - else + filename = NULL; + if (file != NULL + && (ELF_ST_BIND (q->internal_elf_sym.st_info) == STB_LOCAL + || state != file_after_symbol_seen)) filename = bfd_asymbol_name (file); } break; @@ -6538,14 +7107,62 @@ _bfd_elf_find_nearest_line (bfd *abfd, return TRUE; } +/* Find the line for a symbol. */ + +bfd_boolean +_bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol, + const char **filename_ptr, unsigned int *line_ptr) +{ + return _bfd_dwarf2_find_line (abfd, symbols, symbol, + filename_ptr, line_ptr, 0, + &elf_tdata (abfd)->dwarf2_find_line_info); +} + +/* After a call to bfd_find_nearest_line, successive calls to + bfd_find_inliner_info can be used to get source information about + each level of function inlining that terminated at the address + passed to bfd_find_nearest_line. Currently this is only supported + for DWARF2 with appropriate DWARF3 extensions. */ + +bfd_boolean +_bfd_elf_find_inliner_info (bfd *abfd, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *line_ptr) +{ + bfd_boolean found; + found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr, + functionname_ptr, line_ptr, + & elf_tdata (abfd)->dwarf2_find_line_info); + return found; +} + int -_bfd_elf_sizeof_headers (bfd *abfd, bfd_boolean reloc) +_bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info) { - int ret; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + int ret = bed->s->sizeof_ehdr; + + if (!info->relocatable) + { + bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size; + + if (phdr_size == (bfd_size_type) -1) + { + struct elf_segment_map *m; + + phdr_size = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + phdr_size += bed->s->sizeof_phdr; + + if (phdr_size == 0) + phdr_size = get_program_header_size (abfd, info); + } + + elf_tdata (abfd)->program_header_size = phdr_size; + ret += phdr_size; + } - ret = get_elf_backend_data (abfd)->s->sizeof_ehdr; - if (! reloc) - ret += get_program_header_size (abfd); return ret; } @@ -6681,12 +7298,11 @@ _bfd_elf_close_and_cleanup (bfd *abfd) { if (bfd_get_format (abfd) == bfd_object) { - if (elf_shstrtab (abfd) != NULL) + if (elf_tdata (abfd) != NULL && elf_shstrtab (abfd) != NULL) _bfd_elf_strtab_free (elf_shstrtab (abfd)); + _bfd_dwarf2_cleanup_debug_info (abfd); } - _bfd_dwarf2_cleanup_debug_info (abfd); - return _bfd_generic_close_and_cleanup (abfd); } @@ -6736,13 +7352,12 @@ elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect) if (bfd_get_section_by_name (abfd, name) != NULL) return TRUE; - sect2 = bfd_make_section (abfd, name); + sect2 = bfd_make_section_with_flags (abfd, name, sect->flags); if (sect2 == NULL) return FALSE; sect2->size = sect->size; sect2->filepos = sect->filepos; - sect2->flags = sect->flags; sect2->alignment_power = sect->alignment_power; return TRUE; } @@ -6774,12 +7389,12 @@ _bfd_elfcore_make_pseudosection (bfd *abfd, return FALSE; memcpy (threaded_name, buf, len); - sect = bfd_make_section_anyway (abfd, threaded_name); + sect = bfd_make_section_anyway_with_flags (abfd, threaded_name, + SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = size; sect->filepos = filepos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; return elfcore_maybe_make_sect (abfd, name, sect); @@ -7058,7 +7673,7 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) return FALSE; memcpy (name, buf, len); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; @@ -7073,7 +7688,6 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg); #endif - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; if (!elfcore_maybe_make_sect (abfd, ".reg", sect)) @@ -7088,7 +7702,7 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) return FALSE; memcpy (name, buf, len); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; @@ -7103,7 +7717,6 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg); #endif - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; return elfcore_maybe_make_sect (abfd, ".reg2", sect); @@ -7144,7 +7757,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) memcpy (name, buf, len); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; @@ -7152,7 +7765,6 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) sect->filepos = (note->descpos + offsetof (struct win32_pstatus, data.thread_info.thread_context)); - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; if (pstatus.data.thread_info.is_active_thread) @@ -7172,14 +7784,13 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) memcpy (name, buf, len); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = note->descsz; sect->filepos = note->descpos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; break; @@ -7249,13 +7860,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) case NT_AUXV: { - asection *sect = bfd_make_section_anyway (abfd, ".auxv"); + asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv", + SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = note->descsz; sect->filepos = note->descpos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; return TRUE; @@ -7363,7 +7974,7 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) } static bfd_boolean -elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid) +elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid) { void *ddata = note->descdata; char buf[100]; @@ -7395,20 +8006,19 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid) elf_tdata (abfd)->core_lwpid = *tid; /* Make a ".qnx_core_status/%d" section. */ - sprintf (buf, ".qnx_core_status/%ld", (long) *tid); + sprintf (buf, ".qnx_core_status/%ld", *tid); name = bfd_alloc (abfd, strlen (buf) + 1); if (name == NULL) return FALSE; strcpy (name, buf); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = note->descsz; sect->filepos = note->descpos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; return (elfcore_maybe_make_sect (abfd, ".qnx_core_status", sect)); @@ -7417,7 +8027,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid) static bfd_boolean elfcore_grok_nto_regs (bfd *abfd, Elf_Internal_Note *note, - pid_t tid, + long tid, char *base) { char buf[100]; @@ -7425,20 +8035,19 @@ elfcore_grok_nto_regs (bfd *abfd, asection *sect; /* Make a "(base)/%d" section. */ - sprintf (buf, "%s/%ld", base, (long) tid); + sprintf (buf, "%s/%ld", base, tid); name = bfd_alloc (abfd, strlen (buf) + 1); if (name == NULL) return FALSE; strcpy (name, buf); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = note->descsz; sect->filepos = note->descpos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; /* This is the current thread. */ @@ -7459,7 +8068,7 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note) /* Every GREG section has a STATUS section before it. Store the tid from the previous call to pass down to the next gregs function. */ - static pid_t tid = 1; + static long tid = 1; switch (note->type) { @@ -7623,8 +8232,8 @@ elfcore_write_pstatus (bfd *abfd, char *buf, int *bufsiz, long pid, - int cursig, - const void *gregs) + int cursig ATTRIBUTE_UNUSED, + const void *gregs ATTRIBUTE_UNUSED) { pstatus_t pstat; char *note_name = "CORE"; @@ -7700,12 +8309,12 @@ elfcore_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4); in.descpos = offset + (in.descdata - buf); - if (strncmp (in.namedata, "NetBSD-CORE", 11) == 0) + if (CONST_STRNEQ (in.namedata, "NetBSD-CORE")) { if (! elfcore_grok_netbsd_note (abfd, &in)) goto error; } - else if (strncmp (in.namedata, "QNX", 3) == 0) + else if (CONST_STRNEQ (in.namedata, "QNX")) { if (! elfcore_grok_nto_note (abfd, &in)) goto error; @@ -8002,6 +8611,10 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, continue; *s = **p->sym_ptr_ptr; + /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since + we are defining a symbol, ensure one of them is set. */ + if ((s->flags & BSF_LOCAL) == 0) + s->flags |= BSF_GLOBAL; s->section = plt; s->value = addr - plt->vma; s->name = names; @@ -8080,10 +8693,8 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2) /* If both are .gnu.linkonce sections, they have to have the same section name. */ - if (strncmp (sec1->name, ".gnu.linkonce", - sizeof ".gnu.linkonce" - 1) == 0 - && strncmp (sec2->name, ".gnu.linkonce", - sizeof ".gnu.linkonce" - 1) == 0) + if (CONST_STRNEQ (sec1->name, ".gnu.linkonce") + && CONST_STRNEQ (sec2->name, ".gnu.linkonce")) return strcmp (sec1->name + sizeof ".gnu.linkonce", sec2->name + sizeof ".gnu.linkonce") == 0; @@ -8224,3 +8835,23 @@ done: return result; } + +/* It is only used by x86-64 so far. */ +asection _bfd_elf_large_com_section + = BFD_FAKE_SECTION (_bfd_elf_large_com_section, + SEC_IS_COMMON, NULL, "LARGE_COMMON", 0); + +/* Return TRUE if 2 section types are compatible. */ + +bfd_boolean +_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec, + bfd *bbfd, const asection *bsec) +{ + if (asec == NULL + || bsec == NULL + || abfd->xvec->flavour != bfd_target_elf_flavour + || bbfd->xvec->flavour != bfd_target_elf_flavour) + return TRUE; + + return elf_section_type (asec) == elf_section_type (bsec); +}