X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf.c;h=cee9b7a4455164f6f6af1f18762c3f926e88d817;hb=4b0f07110e55b09f44ef95a36e4d7ca4612de33c;hp=005f8f629f19a371de31d260f82f8267a97e7b68;hpb=bb864ac122ca01559e202562d69b7619027e8e2c;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf.c b/bfd/elf.c index 005f8f629f..cee9b7a445 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1,7 +1,8 @@ /* ELF executable support for BFD. Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -231,7 +232,7 @@ bfd_elf_gnu_hash (const char *namearg) bfd_boolean bfd_elf_allocate_object (bfd *abfd, size_t object_size, - enum elf_object_id object_id) + enum elf_target_id object_id) { BFD_ASSERT (object_size >= sizeof (struct elf_obj_tdata)); abfd->tdata.any = bfd_zalloc (abfd, object_size); @@ -248,7 +249,7 @@ bfd_boolean bfd_elf_make_generic_object (bfd *abfd) { return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata), - GENERIC_ELF_TDATA); + GENERIC_ELF_DATA); } bfd_boolean @@ -258,7 +259,7 @@ bfd_elf_mkcorefile (bfd *abfd) return bfd_elf_make_generic_object (abfd); } -char * +static char * bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) { Elf_Internal_Shdr **i_shdrp; @@ -282,7 +283,7 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) /* Allocate and clear an extra byte at the end, to prevent crashes in case the string table is not terminated. */ if (shstrtabsize + 1 <= 1 - || (shstrtab = bfd_alloc (abfd, shstrtabsize + 1)) == NULL + || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL || bfd_seek (abfd, offset, SEEK_SET) != 0) shstrtab = NULL; else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize) @@ -330,7 +331,7 @@ bfd_elf_string_from_elf_section (bfd *abfd, (shindex == shstrndx && strindex == hdr->sh_name ? ".shstrtab" : bfd_elf_string_from_elf_section (abfd, shstrndx, hdr->sh_name))); - return ""; + return NULL; } return ((char *) hdr->contents) + strindex; @@ -358,6 +359,7 @@ bfd_elf_get_elf_syms (bfd *ibfd, const bfd_byte *esym; Elf_External_Sym_Shndx *alloc_extshndx; Elf_External_Sym_Shndx *shndx; + Elf_Internal_Sym *alloc_intsym; Elf_Internal_Sym *isym; Elf_Internal_Sym *isymend; const struct elf_backend_data *bed; @@ -379,6 +381,7 @@ bfd_elf_get_elf_syms (bfd *ibfd, /* Read the symbols. */ alloc_ext = NULL; alloc_extshndx = NULL; + alloc_intsym = NULL; bed = get_elf_backend_data (ibfd); extsym_size = bed->s->sizeof_sym; amt = symcount * extsym_size; @@ -404,8 +407,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_malloc2 (symcount, - sizeof (Elf_External_Sym_Shndx)); + alloc_extshndx = (Elf_External_Sym_Shndx *) + bfd_malloc2 (symcount, sizeof (Elf_External_Sym_Shndx)); extshndx_buf = alloc_extshndx; } if (extshndx_buf == NULL @@ -419,14 +422,17 @@ bfd_elf_get_elf_syms (bfd *ibfd, if (intsym_buf == NULL) { - intsym_buf = bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym)); + alloc_intsym = (Elf_Internal_Sym *) + bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym)); + intsym_buf = alloc_intsym; if (intsym_buf == NULL) goto out; } /* Convert the symbols to internal form. */ isymend = intsym_buf + symcount; - for (esym = extsym_buf, isym = intsym_buf, shndx = extshndx_buf; + for (esym = (const bfd_byte *) extsym_buf, isym = intsym_buf, + shndx = extshndx_buf; isym < isymend; esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL) if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym)) @@ -435,6 +441,8 @@ bfd_elf_get_elf_syms (bfd *ibfd, (*_bfd_error_handler) (_("%B symbol number %lu references " "nonexistent SHT_SYMTAB_SHNDX section"), ibfd, (unsigned long) symoffset); + if (alloc_intsym != NULL) + free (alloc_intsym); intsym_buf = NULL; goto out; } @@ -558,8 +566,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) bfd_size_type amt; elf_tdata (abfd)->num_group = num_group; - elf_tdata (abfd)->group_sect_ptr - = bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *)); + elf_tdata (abfd)->group_sect_ptr = (Elf_Internal_Shdr **) + bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *)); if (elf_tdata (abfd)->group_sect_ptr == NULL) return FALSE; @@ -580,8 +588,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_alloc2 (abfd, shdr->sh_size, - sizeof (*dest) / 4); + shdr->contents = (unsigned char *) + bfd_alloc2 (abfd, shdr->sh_size, sizeof (*dest) / 4); /* PR binutils/4110: Handle corrupt group headers. */ if (shdr->contents == NULL) { @@ -726,18 +734,18 @@ _bfd_elf_setup_sections (bfd *abfd) } else { - asection *link = NULL; + asection *linksec = NULL; if (elfsec < elf_numsections (abfd)) { this_hdr = elf_elfsections (abfd)[elfsec]; - link = this_hdr->bfd_section; + linksec = this_hdr->bfd_section; } /* PR 1991, 2008: Some strip/objcopy may leave an incorrect value in sh_link. We don't want to proceed. */ - if (link == NULL) + if (linksec == NULL) { (*_bfd_error_handler) (_("%B: sh_link [%d] in section `%A' is incorrect"), @@ -745,7 +753,7 @@ _bfd_elf_setup_sections (bfd *abfd) result = FALSE; } - elf_linked_to_section (s) = link; + elf_linked_to_section (s) = linksec; } } } @@ -890,7 +898,14 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, { NULL, 0 }, /* 'p' */ { NULL, 0 }, /* 'q' */ { NULL, 0 }, /* 'r' */ - { STRING_COMMA_LEN ("stab") } /* 's' */ + { STRING_COMMA_LEN ("stab") }, /* 's' */ + { NULL, 0 }, /* 't' */ + { NULL, 0 }, /* 'u' */ + { NULL, 0 }, /* 'v' */ + { NULL, 0 }, /* 'w' */ + { NULL, 0 }, /* 'x' */ + { NULL, 0 }, /* 'y' */ + { STRING_COMMA_LEN ("zdebug") } /* 'z' */ }; if (name [0] == '.') @@ -928,20 +943,12 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, PT_NOTEs from the core files are currently not parsed using BFD. */ if (hdr->sh_type == SHT_NOTE) { - char *contents; + bfd_byte *contents; - contents = bfd_malloc (hdr->sh_size); - if (!contents) + if (!bfd_malloc_and_get_section (abfd, newsect, &contents)) return FALSE; - if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0, - hdr->sh_size) - || !elf_parse_notes (abfd, contents, hdr->sh_size, -1)) - { - free (contents); - return FALSE; - } - + elf_parse_notes (abfd, (char *) contents, hdr->sh_size, -1); free (contents); } @@ -966,25 +973,8 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, phdr = elf_tdata (abfd)->phdr; for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) { - /* This section is part of this segment if its file - offset plus size lies within the segment's memory - span and, if the section is loaded, the extent of the - loaded data lies within the extent of the segment. - - Note - we used to check the p_paddr field as well, and - refuse to set the LMA if it was 0. This is wrong - though, as a perfectly valid initialised segment can - have a p_paddr of zero. Some architectures, eg ARM, - place special significance on the address 0 and - executables need to be able to have a segment which - covers this address. */ if (phdr->p_type == PT_LOAD - && (bfd_vma) hdr->sh_offset >= phdr->p_offset - && (hdr->sh_offset + hdr->sh_size - <= phdr->p_offset + phdr->p_memsz) - && ((flags & SEC_LOAD) == 0 - || (hdr->sh_offset + hdr->sh_size - <= phdr->p_offset + phdr->p_filesz))) + && ELF_IS_SECTION_IN_SEGMENT (hdr, phdr)) { if ((flags & SEC_LOAD) == 0) newsect->lma = (phdr->p_paddr @@ -1015,45 +1005,6 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, return TRUE; } -/* -INTERNAL_FUNCTION - bfd_elf_find_section - -SYNOPSIS - struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name); - -DESCRIPTION - Helper functions for GDB to locate the string tables. - Since BFD hides string tables from callers, GDB needs to use an - internal hook to find them. Sun's .stabstr, in particular, - isn't even pointed to by the .stab section, so ordinary - mechanisms wouldn't work to find it, even if we had some. -*/ - -struct elf_internal_shdr * -bfd_elf_find_section (bfd *abfd, char *name) -{ - Elf_Internal_Shdr **i_shdrp; - char *shstrtab; - unsigned int max; - unsigned int i; - - i_shdrp = elf_elfsections (abfd); - if (i_shdrp != NULL) - { - shstrtab = bfd_elf_get_str_section (abfd, - elf_elfheader (abfd)->e_shstrndx); - if (shstrtab != NULL) - { - max = elf_numsections (abfd); - for (i = 1; i < max; i++) - if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name)) - return i_shdrp[i]; - } - } - return 0; -} - const char *const bfd_elf_section_type_names[] = { "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB", "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", @@ -1142,7 +1093,7 @@ get_segment_type (unsigned int p_type) bfd_boolean _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) { - FILE *f = farg; + FILE *f = (FILE *) farg; Elf_Internal_Phdr *p; asection *s; bfd_byte *dynbuf = NULL; @@ -1385,7 +1336,7 @@ bfd_elf_print_symbol (bfd *abfd, asymbol *symbol, bfd_print_symbol_type how) { - FILE *file = filep; + FILE *file = (FILE *) filep; switch (how) { case bfd_print_symbol_name: @@ -1394,7 +1345,7 @@ bfd_elf_print_symbol (bfd *abfd, case bfd_print_symbol_more: fprintf (file, "elf "); bfd_fprintf_vma (abfd, file, symbol->value); - fprintf (file, " %lx", (long) symbol->flags); + fprintf (file, " %lx", (unsigned long) symbol->flags); break; case bfd_print_symbol_all: { @@ -1565,10 +1516,25 @@ bfd_section_from_shdr (bfd *abfd, unsigned int 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) + if (hdr->sh_link > elf_numsections (abfd)) + { + /* PR 10478: Accept Solaris binaries with a sh_link + field set to SHN_BEFORE or SHN_AFTER. */ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_i386: + case bfd_arch_sparc: + if (hdr->sh_link == (SHN_LORESERVE & 0xffff) /* SHN_BEFORE */ + || hdr->sh_link == ((SHN_LORESERVE + 1) & 0xffff) /* SHN_AFTER */) + break; + /* Otherwise fall through. */ + default: + return FALSE; + } + } + else if (elf_elfsections (abfd)[hdr->sh_link] == NULL) return FALSE; - if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) + else if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) { Elf_Internal_Shdr *dynsymhdr; @@ -1604,6 +1570,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (hdr->sh_entsize != bed->s->sizeof_sym) return FALSE; + if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size) + return FALSE; BFD_ASSERT (elf_onesymtab (abfd) == 0); elf_onesymtab (abfd) = shindex; elf_tdata (abfd)->symtab_hdr = *hdr; @@ -1760,8 +1728,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) reject them, but, unfortunately, some people need to use them. We scan through the section headers; if we find only one suitable symbol table, we clobber the sh_link to point - to it. I hope this doesn't break anything. */ - if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB + to it. I hope this doesn't break anything. + + Don't do it on executable nor shared library. */ + if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0 + && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_DYNSYM) { unsigned int scan; @@ -1796,8 +1767,10 @@ 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, an invalid section, or another reloc section. */ + section, an invalid section, another reloc section, or its + sh_link points to the null section. */ if (hdr->sh_link != elf_onesymtab (abfd) + || hdr->sh_link == SHN_UNDEF || hdr->sh_info == SHN_UNDEF || hdr->sh_info >= num_sec || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL @@ -1819,7 +1792,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) bfd_size_type amt; BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL); amt = sizeof (*hdr2); - hdr2 = bfd_alloc (abfd, amt); + hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); if (hdr2 == NULL) return FALSE; elf_section_data (target_sect)->rel_hdr2 = hdr2; @@ -1859,14 +1832,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) return TRUE; case SHT_GROUP: - /* We need a BFD section for objcopy and relocatable linking, - and it's handy to have the signature available as the section - name. */ if (! IS_VALID_GROUP_SECTION_HEADER (hdr)) return FALSE; - name = group_signature (abfd, hdr); - if (name == NULL) - return FALSE; if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) return FALSE; if (hdr->contents != NULL) @@ -1959,28 +1926,24 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) return TRUE; } -/* Return the section for the local symbol specified by ABFD, R_SYMNDX. - Return SEC for sections that have no elf section, and NULL on error. */ +/* Return the local symbol specified by ABFD, R_SYMNDX. */ -asection * -bfd_section_from_r_symndx (bfd *abfd, - struct sym_sec_cache *cache, - asection *sec, - unsigned long r_symndx) +Elf_Internal_Sym * +bfd_sym_from_r_symndx (struct sym_cache *cache, + bfd *abfd, + unsigned long r_symndx) { unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE; - asection *s; if (cache->abfd != abfd || cache->indx[ent] != r_symndx) { Elf_Internal_Shdr *symtab_hdr; unsigned char esym[sizeof (Elf64_External_Sym)]; Elf_External_Sym_Shndx eshndx; - Elf_Internal_Sym isym; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx, - &isym, esym, &eshndx) == NULL) + &cache->sym[ent], esym, &eshndx) == NULL) return NULL; if (cache->abfd != abfd) @@ -1989,25 +1952,20 @@ bfd_section_from_r_symndx (bfd *abfd, cache->abfd = abfd; } cache->indx[ent] = r_symndx; - cache->shndx[ent] = isym.st_shndx; } - s = bfd_section_from_elf_index (abfd, cache->shndx[ent]); - if (s != NULL) - return s; - - return sec; + return &cache->sym[ent]; } /* Given an ELF section number, retrieve the corresponding BFD section. */ asection * -bfd_section_from_elf_index (bfd *abfd, unsigned int index) +bfd_section_from_elf_index (bfd *abfd, unsigned int sec_index) { - if (index >= elf_numsections (abfd)) + if (sec_index >= elf_numsections (abfd)) return NULL; - return elf_elfsections (abfd)[index]->bfd_section; + return elf_elfsections (abfd)[sec_index]->bfd_section; } static const struct bfd_elf_special_section special_sections_b[] = @@ -2119,6 +2077,15 @@ static const struct bfd_elf_special_section special_sections_t[] = { NULL, 0, 0, 0, 0 } }; +static const struct bfd_elf_special_section special_sections_z[] = +{ + { STRING_COMMA_LEN (".zdebug_line"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".zdebug_info"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".zdebug_abbrev"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".zdebug_aranges"), 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } +}; + static const struct bfd_elf_special_section *special_sections[] = { special_sections_b, /* 'b' */ @@ -2140,6 +2107,12 @@ static const struct bfd_elf_special_section *special_sections[] = special_sections_r, /* 'r' */ special_sections_s, /* 's' */ special_sections_t, /* 't' */ + NULL, /* 'u' */ + NULL, /* 'v' */ + NULL, /* 'w' */ + NULL, /* 'x' */ + NULL, /* 'y' */ + special_sections_z /* 'z' */ }; const struct bfd_elf_special_section * @@ -2216,7 +2189,7 @@ _bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec) return NULL; i = sec->name[1] - 'b'; - if (i < 0 || i > 't' - 'b') + if (i < 0 || i > 'z' - 'b') return NULL; spec = special_sections[i]; @@ -2237,7 +2210,8 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec) sdata = (struct bfd_elf_section_data *) sec->used_by_bfd; if (sdata == NULL) { - sdata = bfd_zalloc (abfd, sizeof (*sdata)); + sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, + sizeof (*sdata)); if (sdata == NULL) return FALSE; sec->used_by_bfd = sdata; @@ -2292,8 +2266,8 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec) bfd_boolean _bfd_elf_make_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, - int index, - const char *typename) + int hdr_index, + const char *type_name) { asection *newsect; char *name; @@ -2307,9 +2281,9 @@ _bfd_elf_make_section_from_phdr (bfd *abfd, if (hdr->p_filesz > 0) { - sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : ""); + sprintf (namebuf, "%s%d%s", type_name, hdr_index, split ? "a" : ""); len = strlen (namebuf) + 1; - name = bfd_alloc (abfd, len); + name = (char *) bfd_alloc (abfd, len); if (!name) return FALSE; memcpy (name, namebuf, len); @@ -2343,9 +2317,9 @@ _bfd_elf_make_section_from_phdr (bfd *abfd, { bfd_vma align; - sprintf (namebuf, "%s%d%s", typename, index, split ? "b" : ""); + sprintf (namebuf, "%s%d%s", type_name, hdr_index, split ? "b" : ""); len = strlen (namebuf) + 1; - name = bfd_alloc (abfd, len); + name = (char *) bfd_alloc (abfd, len); if (!name) return FALSE; memcpy (name, namebuf, len); @@ -2382,51 +2356,51 @@ _bfd_elf_make_section_from_phdr (bfd *abfd, } bfd_boolean -bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index) +bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index) { const struct elf_backend_data *bed; switch (hdr->p_type) { case PT_NULL: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "null"); + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "null"); case PT_LOAD: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "load"); + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "load"); case PT_DYNAMIC: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "dynamic"); + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "dynamic"); case PT_INTERP: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "interp"); + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "interp"); case PT_NOTE: - if (! _bfd_elf_make_section_from_phdr (abfd, hdr, index, "note")) + if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "note")) return FALSE; if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz)) return FALSE; return TRUE; case PT_SHLIB: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "shlib"); + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "shlib"); case PT_PHDR: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "phdr"); + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "phdr"); case PT_GNU_EH_FRAME: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "eh_frame_hdr"); case PT_GNU_STACK: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack"); + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "stack"); case PT_GNU_RELRO: - return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "relro"); + return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "relro"); default: /* Check for any processor-specific program segment types. */ bed = get_elf_backend_data (abfd); - return bed->elf_backend_section_from_phdr (abfd, hdr, index, "proc"); + return bed->elf_backend_section_from_phdr (abfd, hdr, hdr_index, "proc"); } } @@ -2444,7 +2418,7 @@ _bfd_elf_init_reloc_shdr (bfd *abfd, const struct elf_backend_data *bed = get_elf_backend_data (abfd); bfd_size_type amt = sizeof ".rela" + strlen (asect->name); - name = bfd_alloc (abfd, amt); + name = (char *) bfd_alloc (abfd, amt); if (name == NULL) return FALSE; sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name); @@ -2466,13 +2440,25 @@ _bfd_elf_init_reloc_shdr (bfd *abfd, return TRUE; } +/* Return the default section type based on the passed in section flags. */ + +int +bfd_elf_get_default_section_type (flagword flags) +{ + if ((flags & SEC_ALLOC) != 0 + && ((flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0 + || (flags & SEC_NEVER_LOAD) != 0)) + return SHT_NOBITS; + return SHT_PROGBITS; +} + /* Set up an ELF internal section header for a section. */ static void elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) { const struct elf_backend_data *bed = get_elf_backend_data (abfd); - bfd_boolean *failedptr = failedptrarg; + bfd_boolean *failedptr = (bfd_boolean *) failedptrarg; Elf_Internal_Shdr *this_hdr; unsigned int sh_type; @@ -2515,12 +2501,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) asect->flags. */ if ((asect->flags & SEC_GROUP) != 0) 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)) - sh_type = SHT_NOBITS; else - sh_type = SHT_PROGBITS; + sh_type = bfd_elf_get_default_section_type (asect->flags); if (this_hdr->sh_type == SHT_NULL) this_hdr->sh_type = sh_type; @@ -2668,13 +2650,15 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) *failedptr = TRUE; } -/* Fill in the contents of a SHT_GROUP section. */ +/* Fill in the contents of a SHT_GROUP section. Called from + _bfd_elf_compute_section_file_positions for gas, objcopy, and + when ELF targets use the generic linker, ld. Called for ld -r + from bfd_elf_final_link. */ void bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) { - bfd_boolean *failedptr = failedptrarg; - unsigned long symindx; + bfd_boolean *failedptr = (bfd_boolean *) failedptrarg; asection *elt, *first; unsigned char *loc; bfd_boolean gas; @@ -2685,27 +2669,56 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) || *failedptr) return; - symindx = 0; - if (elf_group_id (sec) != NULL) - symindx = elf_group_id (sec)->udata.i; + if (elf_section_data (sec)->this_hdr.sh_info == 0) + { + unsigned long symindx = 0; + + /* elf_group_id will have been set up by objcopy and the + generic linker. */ + if (elf_group_id (sec) != NULL) + symindx = elf_group_id (sec)->udata.i; - if (symindx == 0) + if (symindx == 0) + { + /* If called from the assembler, swap_out_syms will have set up + elf_section_syms. */ + BFD_ASSERT (elf_section_syms (abfd) != NULL); + symindx = elf_section_syms (abfd)[sec->index]->udata.i; + } + elf_section_data (sec)->this_hdr.sh_info = symindx; + } + else if (elf_section_data (sec)->this_hdr.sh_info == (unsigned int) -2) { - /* If called from the assembler, swap_out_syms will have set up - elf_section_syms; If called for "ld -r", use target_index. */ - if (elf_section_syms (abfd) != NULL) - symindx = elf_section_syms (abfd)[sec->index]->udata.i; - else - symindx = sec->target_index; + /* The ELF backend linker sets sh_info to -2 when the group + signature symbol is global, and thus the index can't be + set until all local symbols are output. */ + asection *igroup = elf_sec_group (elf_next_in_group (sec)); + struct bfd_elf_section_data *sec_data = elf_section_data (igroup); + unsigned long symndx = sec_data->this_hdr.sh_info; + unsigned long extsymoff = 0; + struct elf_link_hash_entry *h; + + if (!elf_bad_symtab (igroup->owner)) + { + Elf_Internal_Shdr *symtab_hdr; + + symtab_hdr = &elf_tdata (igroup->owner)->symtab_hdr; + extsymoff = symtab_hdr->sh_info; + } + h = elf_sym_hashes (igroup->owner)[symndx - extsymoff]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + elf_section_data (sec)->this_hdr.sh_info = h->indx; } - elf_section_data (sec)->this_hdr.sh_info = symindx; /* The contents won't be allocated for "ld -r" or objcopy. */ gas = TRUE; if (sec->contents == NULL) { gas = FALSE; - sec->contents = bfd_alloc (abfd, sec->size); + sec->contents = (unsigned char *) bfd_alloc (abfd, sec->size); /* Arrange for the section to be written out. */ elf_section_data (sec)->this_hdr.contents = sec->contents; @@ -2730,16 +2743,18 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) while (elt != NULL) { asection *s; - unsigned int idx; - loc -= 4; s = elt; if (!gas) s = s->output_section; - idx = 0; - if (s != NULL) - idx = elf_section_data (s)->this_idx; - H_PUT_32 (abfd, idx, loc); + if (s != NULL + && !bfd_is_abs_section (s)) + { + unsigned int idx = elf_section_data (s)->this_idx; + + loc -= 4; + H_PUT_32 (abfd, idx, loc); + } elt = elf_next_in_group (elt); if (elt == first) break; @@ -2763,6 +2778,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) unsigned int section_number, secn; Elf_Internal_Shdr **i_shdrp; struct bfd_elf_section_data *d; + bfd_boolean need_symtab; section_number = 1; @@ -2818,7 +2834,11 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name); elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section; - if (bfd_get_symcount (abfd) > 0) + need_symtab = (bfd_get_symcount (abfd) > 0 + || (link_info == NULL + && ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC)) + == HAS_RELOC))); + if (need_symtab) { t->symtab_section = section_number++; _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name); @@ -2843,11 +2863,13 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) /* Set up the list of section header pointers, in agreement with the indices. */ - i_shdrp = bfd_zalloc2 (abfd, section_number, sizeof (Elf_Internal_Shdr *)); + i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc2 (abfd, section_number, + sizeof (Elf_Internal_Shdr *)); if (i_shdrp == NULL) return FALSE; - i_shdrp[0] = bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr)); + i_shdrp[0] = (Elf_Internal_Shdr *) bfd_zalloc (abfd, + sizeof (Elf_Internal_Shdr)); if (i_shdrp[0] == NULL) { bfd_release (abfd, i_shdrp); @@ -2857,7 +2879,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) elf_elfsections (abfd) = i_shdrp; i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr; - if (bfd_get_symcount (abfd) > 0) + if (need_symtab) { i_shdrp[t->symtab_section] = &t->symtab_hdr; if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF)) @@ -2871,10 +2893,11 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) for (sec = abfd->sections; sec; sec = sec->next) { - struct bfd_elf_section_data *d = elf_section_data (sec); asection *s; const char *name; + d = elf_section_data (sec); + i_shdrp[d->this_idx] = &d->this_hdr; if (d->rel_idx != 0) i_shdrp[d->rel_idx] = &d->rel_hdr; @@ -2996,7 +3019,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) char *alc; len = strlen (sec->name); - alc = bfd_malloc (len - 2); + alc = (char *) bfd_malloc (len - 2); if (alc == NULL) return FALSE; memcpy (alc, sec->name, len - 3); @@ -3072,23 +3095,21 @@ sym_is_global (bfd *abfd, asymbol *sym) if (bed->elf_backend_sym_is_global) return (*bed->elf_backend_sym_is_global) (abfd, sym); - return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 + return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 || bfd_is_und_section (bfd_get_section (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. */ + output. */ 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)))); + && !(sym->section->owner == abfd + || (sym->section->output_section->owner == abfd + && sym->section->output_offset == 0))); } static bfd_boolean @@ -3118,7 +3139,7 @@ elf_map_symbols (bfd *abfd) } max_index++; - sect_syms = bfd_zalloc2 (abfd, max_index, sizeof (asymbol *)); + sect_syms = (asymbol **) bfd_zalloc2 (abfd, max_index, sizeof (asymbol *)); if (sect_syms == NULL) return FALSE; elf_section_syms (abfd) = sect_syms; @@ -3131,6 +3152,7 @@ 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 = sym->section; @@ -3169,7 +3191,8 @@ elf_map_symbols (bfd *abfd) } /* Now sort the symbols so the local symbols are first. */ - new_syms = bfd_alloc2 (abfd, num_locals + num_globals, sizeof (asymbol *)); + new_syms = (asymbol **) bfd_alloc2 (abfd, num_locals + num_globals, + sizeof (asymbol *)); if (new_syms == NULL) return FALSE; @@ -3251,6 +3274,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, bfd_boolean failed; struct bfd_strtab_hash *strtab = NULL; Elf_Internal_Shdr *shstrtab_hdr; + bfd_boolean need_symtab; if (abfd->output_has_begun) return TRUE; @@ -3275,7 +3299,11 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, return FALSE; /* The backend linker builds symbol table information itself. */ - if (link_info == NULL && bfd_get_symcount (abfd) > 0) + need_symtab = (link_info == NULL + && (bfd_get_symcount (abfd) > 0 + || ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC)) + == HAS_RELOC))); + if (need_symtab) { /* Non-zero if doing a relocatable link. */ int relocatable_p = ! (abfd->flags & (EXEC_P | DYNAMIC)); @@ -3306,7 +3334,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, if (!assign_file_positions_except_relocs (abfd, link_info)) return FALSE; - if (link_info == NULL && bfd_get_symcount (abfd) > 0) + if (need_symtab) { file_ptr off; Elf_Internal_Shdr *hdr; @@ -3368,7 +3396,7 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info) ++segs; } - if (info->relro) + if (info != NULL && info->relro) { /* We need a PT_GNU_RELRO segment. */ ++segs; @@ -3473,7 +3501,7 @@ make_mapping (bfd *abfd, amt = sizeof (struct elf_segment_map); amt += (to - from - 1) * sizeof (asection *); - m = bfd_zalloc (abfd, amt); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) return NULL; m->next = NULL; @@ -3500,7 +3528,8 @@ _bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec) { struct elf_segment_map *m; - m = bfd_zalloc (abfd, sizeof (struct elf_segment_map)); + m = (struct elf_segment_map *) bfd_zalloc (abfd, + sizeof (struct elf_segment_map)); if (m == NULL) return NULL; m->next = NULL; @@ -3591,7 +3620,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) /* Select the allocated sections, and sort them. */ - sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *)); + sections = (asection **) bfd_malloc2 (bfd_count_sections (abfd), + sizeof (asection *)); if (sections == NULL) goto error_return; @@ -3621,7 +3651,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) if (s != NULL && (s->flags & SEC_LOAD) != 0) { amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -3635,7 +3665,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) pm = &m->next; amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -3699,8 +3729,15 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) segment. */ new_segment = TRUE; } - else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) - < BFD_ALIGN (hdr->lma, maxpagesize)) + /* In the next test we have to be careful when last_hdr->lma is close + to the end of the address space. If the aligned address wraps + around to the start of the address space, then there are no more + pages left in memory and it is OK to assume that the current + section can be included in the current segment. */ + else if ((BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + maxpagesize + > last_hdr->lma) + && (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + maxpagesize + <= hdr->lma)) { /* If putting this section in this segment would force us to skip a page in the segment, then we need a new segment. */ @@ -3743,8 +3780,13 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) } /* Allow interested parties a chance to override our decision. */ - if (last_hdr && info->callbacks->override_segment_assignment) - new_segment = info->callbacks->override_segment_assignment (info, abfd, hdr, last_hdr, new_segment); + if (last_hdr != NULL + && info != NULL + && info->callbacks->override_segment_assignment != NULL) + new_segment + = info->callbacks->override_segment_assignment (info, abfd, hdr, + last_hdr, + new_segment); if (! new_segment) { @@ -3818,7 +3860,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) && CONST_STRNEQ (s->name, ".note")) { asection *s2; - unsigned count = 1; + + count = 1; amt = sizeof (struct elf_segment_map); if (s->alignment_power == 2) for (s2 = s; s2->next != NULL; s2 = s2->next) @@ -3833,7 +3876,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) break; } amt += (count - 1) * sizeof (asection *); - m = bfd_zalloc (abfd, amt); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -3861,11 +3904,9 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) /* 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); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -3874,7 +3915,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) /* Mandated PF_R. */ m->p_flags = PF_R; m->p_flags_valid = 1; - for (i = 0; i < tls_count; ++i) + for (i = 0; i < (unsigned int) tls_count; ++i) { BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL); m->sections[i] = first_tls; @@ -3892,7 +3933,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0) { amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -3907,7 +3948,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) if (elf_tdata (abfd)->stack_flags) { amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -3919,7 +3960,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) pm = &m->next; } - if (info->relro) + if (info != NULL && info->relro) { for (m = mfirst; m != NULL; m = m->next) { @@ -3940,7 +3981,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) if (m != NULL) { amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; @@ -4085,6 +4126,22 @@ print_segment_map (const struct elf_segment_map *m) putc ('\n',stderr); } +static bfd_boolean +write_zeros (bfd *abfd, file_ptr pos, bfd_size_type len) +{ + void *buf; + bfd_boolean ret; + + if (bfd_seek (abfd, pos, SEEK_SET) != 0) + return FALSE; + buf = bfd_zmalloc (len); + if (buf == NULL) + return FALSE; + ret = bfd_bwrite (buf, len, abfd) == len; + free (buf); + return ret; +} + /* 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. */ @@ -4101,14 +4158,19 @@ assign_file_positions_for_load_sections (bfd *abfd, bfd_size_type maxpagesize; unsigned int alloc; unsigned int i, j; + bfd_vma header_pad = 0; if (link_info == NULL - && !elf_modify_segment_map (abfd, link_info, FALSE)) + && !_bfd_elf_map_sections_to_segments (abfd, link_info)) return FALSE; alloc = 0; for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) - ++alloc; + { + ++alloc; + if (m->header_size) + header_pad = m->header_size; + } elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr; elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr; @@ -4126,7 +4188,21 @@ assign_file_positions_for_load_sections (bfd *abfd, return TRUE; } - phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr)); + /* We're writing the size in elf_tdata (abfd)->program_header_size, + see assign_file_positions_except_relocs, so make sure we have + that amount allocated, with trailing space cleared. + The variable alloc contains the computed need, while elf_tdata + (abfd)->program_header_size contains the size used for the + layout. + See ld/emultempl/elf-generic.em:gld${EMULATION_NAME}_map_segments + where the layout is forced to according to a larger size in the + last iterations for the testcase ld-elf/header. */ + BFD_ASSERT (elf_tdata (abfd)->program_header_size % bed->s->sizeof_phdr + == 0); + phdrs = (Elf_Internal_Phdr *) + bfd_zalloc2 (abfd, + (elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr), + sizeof (Elf_Internal_Phdr)); elf_tdata (abfd)->phdr = phdrs; if (phdrs == NULL) return FALSE; @@ -4137,6 +4213,11 @@ assign_file_positions_for_load_sections (bfd *abfd, off = bed->s->sizeof_ehdr; off += alloc * bed->s->sizeof_phdr; + if (header_pad < (bfd_vma) off) + header_pad = 0; + else + header_pad -= off; + off += header_pad; for (m = elf_tdata (abfd)->segment_map, p = phdrs, j = 0; m != NULL; @@ -4233,21 +4314,14 @@ assign_file_positions_for_load_sections (bfd *abfd, elf_section_type (m->sections[i]) = SHT_NOBITS; /* Find out whether this segment contains any loadable - sections. If the first section isn't loadable, the same - holds for any other sections. */ - i = 0; - while (elf_section_type (m->sections[i]) == SHT_NOBITS) - { - /* If a segment starts with .tbss, we need to look - at the next section to decide whether the segment - has any loadable sections. */ - if ((elf_section_flags (m->sections[i]) & SHF_TLS) == 0 - || ++i >= m->count) - { - no_contents = TRUE; - break; - } - } + sections. */ + no_contents = TRUE; + for (i = 0; i < m->count; i++) + if (elf_section_type (m->sections[i]) != SHT_NOBITS) + { + no_contents = FALSE; + break; + } off_adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align); off += off_adjust; @@ -4331,6 +4405,11 @@ assign_file_positions_for_load_sections (bfd *abfd, p->p_filesz += alloc * bed->s->sizeof_phdr; p->p_memsz += alloc * bed->s->sizeof_phdr; + if (m->count) + { + p->p_filesz += header_pad; + p->p_memsz += header_pad; + } } if (p->p_type == PT_LOAD @@ -4371,19 +4450,44 @@ assign_file_positions_for_load_sections (bfd *abfd, && ((this_hdr->sh_flags & SHF_TLS) == 0 || p->p_type == PT_TLS)))) { - bfd_signed_vma adjust = sec->lma - (p->p_paddr + p->p_memsz); + bfd_signed_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz); - if (adjust < 0) + if (sec->vma < p->p_vaddr + p->p_memsz) { (*_bfd_error_handler) - (_("%B: section %A lma 0x%lx overlaps previous sections"), - abfd, sec, (unsigned long) sec->lma); + (_("%B: section %A vma 0x%lx overlaps previous sections"), + abfd, sec, (unsigned long) sec->vma); adjust = 0; } p->p_memsz += adjust; + if (p->p_paddr + p->p_memsz != sec->lma) + { + /* This behavior is a compromise--ld has long + silently changed the lma of sections when + lma - vma is not equal for every section in a + pheader--but only in the internal elf structures. + Silently changing the lma is probably a bug, but + changing it would have subtle and unknown + consequences for existing scripts. + + Instead modify the bfd data structure to reflect + what happened. This at least fixes the values + for the lma in the mapfile. */ + sec->lma = p->p_paddr + p->p_memsz; + } + if (this_hdr->sh_type != SHT_NOBITS) { + if (p->p_filesz + adjust < p->p_memsz) + { + /* We have a PROGBITS section following NOBITS ones. + Allocate file space for the NOBITS section(s) and + zero it. */ + adjust = p->p_memsz - p->p_filesz; + if (!write_zeros (abfd, off, adjust)) + return FALSE; + } off += adjust; p->p_filesz += adjust; } @@ -4583,7 +4687,59 @@ assign_file_positions_for_non_load_sections (bfd *abfd, m != NULL; m = m->next, p++) { - if (m->count != 0) + if (p->p_type == PT_GNU_RELRO) + { + const Elf_Internal_Phdr *lp; + + BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs); + + if (link_info != NULL) + { + /* During linking the range of the RELRO segment is passed + in link_info. */ + for (lp = phdrs; lp < phdrs + count; ++lp) + { + if (lp->p_type == PT_LOAD + && lp->p_vaddr >= link_info->relro_start + && lp->p_vaddr < link_info->relro_end + && lp->p_vaddr + lp->p_filesz >= link_info->relro_end) + break; + } + } + else + { + /* Otherwise we are copying an executable or shared + library, but we need to use the same linker logic. */ + for (lp = phdrs; lp < phdrs + count; ++lp) + { + if (lp->p_type == PT_LOAD + && lp->p_paddr == p->p_paddr) + break; + } + } + + if (lp < phdrs + count) + { + p->p_vaddr = lp->p_vaddr; + p->p_paddr = lp->p_paddr; + p->p_offset = lp->p_offset; + if (link_info != NULL) + p->p_filesz = link_info->relro_end - lp->p_vaddr; + else if (m->p_size_valid) + p->p_filesz = m->p_size; + else + abort (); + p->p_memsz = p->p_filesz; + p->p_align = 1; + p->p_flags = (lp->p_flags & ~PF_W); + } + else + { + memset (p, 0, sizeof *p); + p->p_type = PT_NULL; + } + } + else if (m->count != 0) { if (p->p_type != PT_LOAD && (p->p_type != PT_NOTE @@ -4599,87 +4755,20 @@ assign_file_positions_for_non_load_sections (bfd *abfd, p->p_filesz = sect->filepos - m->sections[0]->filepos; if (hdr->sh_type != SHT_NOBITS) p->p_filesz += hdr->sh_size; - - if (p->p_type == PT_GNU_RELRO) - { - /* When we get here, we are copying executable - or shared library. But we need to use the same - linker logic. */ - Elf_Internal_Phdr *lp; - - for (lp = phdrs; lp < phdrs + count; ++lp) - { - if (lp->p_type == PT_LOAD - && lp->p_paddr == p->p_paddr) - break; - } - - if (lp < phdrs + count) - { - /* We should use p_size if it is valid since it - may contain the first few bytes of the next - SEC_ALLOC section. */ - if (m->p_size_valid) - p->p_filesz = m->p_size; - else - abort (); - p->p_vaddr = lp->p_vaddr; - p->p_offset = lp->p_offset; - p->p_memsz = p->p_filesz; - p->p_align = 1; - } - else - abort (); - } - else - p->p_offset = m->sections[0]->filepos; + p->p_offset = m->sections[0]->filepos; } } - else + else if (m->includes_filehdr) { - if (m->includes_filehdr) - { - p->p_vaddr = filehdr_vaddr; - if (! m->p_paddr_valid) - p->p_paddr = filehdr_paddr; - } - else if (m->includes_phdrs) - { - p->p_vaddr = phdrs_vaddr; - if (! m->p_paddr_valid) - p->p_paddr = phdrs_paddr; - } - else if (p->p_type == PT_GNU_RELRO) - { - Elf_Internal_Phdr *lp; - - for (lp = phdrs; lp < phdrs + count; ++lp) - { - 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)) - break; - } - - if (lp < phdrs + count - && link_info->relro_end > lp->p_vaddr) - { - p->p_vaddr = lp->p_vaddr; - p->p_paddr = lp->p_paddr; - p->p_offset = lp->p_offset; - p->p_filesz = link_info->relro_end - lp->p_vaddr; - p->p_memsz = p->p_filesz; - p->p_align = 1; - p->p_flags = (lp->p_flags & ~PF_W); - } - else - { - memset (p, 0, sizeof *p); - p->p_type = PT_NULL; - } - } + p->p_vaddr = filehdr_vaddr; + if (! m->p_paddr_valid) + p->p_paddr = filehdr_paddr; + } + else if (m->includes_phdrs) + { + p->p_vaddr = phdrs_vaddr; + if (! m->p_paddr_valid) + p->p_paddr = phdrs_paddr; } } @@ -4968,34 +5057,34 @@ unsigned int _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect) { const struct elf_backend_data *bed; - unsigned int index; + unsigned int sec_index; if (elf_section_data (asect) != NULL && elf_section_data (asect)->this_idx != 0) return elf_section_data (asect)->this_idx; if (bfd_is_abs_section (asect)) - index = SHN_ABS; + sec_index = SHN_ABS; else if (bfd_is_com_section (asect)) - index = SHN_COMMON; + sec_index = SHN_COMMON; else if (bfd_is_und_section (asect)) - index = SHN_UNDEF; + sec_index = SHN_UNDEF; else - index = SHN_BAD; + sec_index = SHN_BAD; bed = get_elf_backend_data (abfd); if (bed->elf_backend_section_from_bfd_section) { - int retval = index; + int retval = sec_index; if ((*bed->elf_backend_section_from_bfd_section) (abfd, asect, &retval)) return retval; } - if (index == SHN_BAD) + if (sec_index == SHN_BAD) bfd_set_error (bfd_error_nonrepresentable_section); - return index; + return sec_index; } /* Given a BFD symbol, return the index in the ELF symbol table, or -1 @@ -5330,7 +5419,7 @@ rewrite_elf_program_header (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_zalloc (obfd, amt); + map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); if (map == NULL) return FALSE; @@ -5414,7 +5503,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) pointers that we are interested in. As these sections get assigned to a segment, they are removed from this array. */ - sections = bfd_malloc2 (section_count, sizeof (asection *)); + sections = (asection **) bfd_malloc2 (section_count, sizeof (asection *)); if (sections == NULL) return FALSE; @@ -5539,19 +5628,32 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) /* Offset the segment physical address from the lma to allow for space taken up by elf headers. */ if (map->includes_filehdr) - map->p_paddr -= iehdr->e_ehsize; + { + if (map->p_paddr >= iehdr->e_ehsize) + map->p_paddr -= iehdr->e_ehsize; + else + { + map->includes_filehdr = FALSE; + map->includes_phdrs = FALSE; + } + } if (map->includes_phdrs) { - map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize; - - /* iehdr->e_phnum is just an estimate of the number - of program headers that we will need. Make a note - here of the number we used and the segment we chose - to hold these headers, so that we can adjust the - offset when we know the correct value. */ - phdr_adjust_num = iehdr->e_phnum; - phdr_adjust_seg = map; + if (map->p_paddr >= iehdr->e_phnum * iehdr->e_phentsize) + { + map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize; + + /* iehdr->e_phnum is just an estimate of the number + of program headers that we will need. Make a note + here of the number we used and the segment we chose + to hold these headers, so that we can adjust the + offset when we know the correct value. */ + phdr_adjust_num = iehdr->e_phnum; + phdr_adjust_seg = map; + } + else + map->includes_phdrs = FALSE; } } @@ -5647,7 +5749,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) and carry on looping. */ amt = sizeof (struct elf_segment_map); amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); - map = bfd_alloc (obfd, amt); + map = (struct elf_segment_map *) bfd_alloc (obfd, amt); if (map == NULL) { free (sections); @@ -5768,7 +5870,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) amt = sizeof (struct elf_segment_map); if (section_count != 0) amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); - map = bfd_zalloc (obfd, amt); + map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); if (map == NULL) return FALSE; @@ -5784,14 +5886,13 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) map->p_align_valid = 1; map->p_vaddr_offset = 0; - if (map->p_type == PT_GNU_RELRO - && segment->p_filesz == segment->p_memsz) + if (map->p_type == PT_GNU_RELRO) { /* The PT_GNU_RELRO segment may contain the first a few bytes in the .got.plt section even if the whole .got.plt section isn't in the PT_GNU_RELRO segment. We won't change the size of the PT_GNU_RELRO segment. */ - map->p_size = segment->p_filesz; + map->p_size = segment->p_memsz; map->p_size_valid = 1; } @@ -5813,6 +5914,10 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) phdr_included = TRUE; } + if (map->includes_filehdr && first_section) + /* We need to keep the space used by the headers fixed. */ + map->header_size = first_section->vma - segment->p_vaddr; + if (!map->includes_phdrs && !map->includes_filehdr && map->p_paddr_valid) @@ -5951,18 +6056,21 @@ _bfd_elf_init_private_section_data (bfd *ibfd, { Elf_Internal_Shdr *ihdr, *ohdr; - bfd_boolean need_group = link_info == NULL || link_info->relocatable; + bfd_boolean final_link = 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. */ + /* For objcopy and relocatable link, don't copy the output ELF + section type from input if the output BFD section flags have been + set to something different. For a final link allow some flags + that the linker clears to differ. */ if (elf_section_type (osec) == SHT_NULL - && (osec->flags == isec->flags || !osec->flags)) + && (osec->flags == isec->flags + || (final_link + && ((osec->flags ^ isec->flags) + & ~ (SEC_LINK_ONCE | SEC_LINK_DUPLICATES)) == 0))) elf_section_type (osec) = elf_section_type (isec); /* FIXME: Is this correct for all OS/PROC specific flags? */ @@ -5973,7 +6081,7 @@ _bfd_elf_init_private_section_data (bfd *ibfd, 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 (!final_link) { if (elf_sec_group (isec) == NULL || (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0) @@ -5981,7 +6089,7 @@ _bfd_elf_init_private_section_data (bfd *ibfd, 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); + elf_section_data (osec)->group = elf_section_data (isec)->group; } } @@ -6032,52 +6140,92 @@ _bfd_elf_copy_private_section_data (bfd *ibfd, NULL); } -/* Copy private header information. */ +/* Look at all the SHT_GROUP sections in IBFD, making any adjustments + necessary if we are removing either the SHT_GROUP section or any of + the group member sections. DISCARDED is the value that a section's + output_section has if the section will be discarded, NULL when this + function is called from objcopy, bfd_abs_section_ptr when called + from the linker. */ bfd_boolean -_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) +_bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded) { asection *isec; - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - /* Copy over private BFD data if it has not already been copied. - This must be done here, rather than in the copy_private_bfd_data - entry point, because the latter is called after the section - contents have been set, which means that the program headers have - already been worked out. */ - if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL) - { - if (! copy_private_bfd_data (ibfd, 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) + if (elf_section_type (isec) == SHT_GROUP) { asection *first = elf_next_in_group (isec); asection *s = first; + bfd_size_type removed = 0; + while (s != NULL) { - if (s->output_section != NULL) + /* If this member section is being output but the + SHT_GROUP section is not, then clear the group info + set up by _bfd_elf_copy_private_section_data. */ + if (s->output_section != discarded + && isec->output_section == discarded) { elf_section_flags (s->output_section) &= ~SHF_GROUP; elf_group_name (s->output_section) = NULL; } + /* Conversely, if the member section is not being output + but the SHT_GROUP section is, then adjust its size. */ + else if (s->output_section == discarded + && isec->output_section != discarded) + removed += 4; s = elf_next_in_group (s); if (s == first) break; } + if (removed != 0) + { + if (discarded != NULL) + { + /* If we've been called for ld -r, then we need to + adjust the input section size. This function may + be called multiple times, so save the original + size. */ + if (isec->rawsize == 0) + isec->rawsize = isec->size; + isec->size = isec->rawsize - removed; + } + else + { + /* Adjust the output section size when called from + objcopy. */ + isec->output_section->size -= removed; + } + } } return TRUE; } +/* Copy private header information. */ + +bfd_boolean +_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) +{ + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + /* Copy over private BFD data if it has not already been copied. + This must be done here, rather than in the copy_private_bfd_data + entry point, because the latter is called after the section + contents have been set, which means that the program headers have + already been worked out. */ + if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL) + { + if (! copy_private_bfd_data (ibfd, obfd)) + return FALSE; + } + + return _bfd_elf_fixup_group_sections (ibfd, NULL); +} + /* Copy private symbol information. If this symbol is in a section which we did not map into a BFD section, try to map the section index correctly. We use special macro definitions for the mapped @@ -6169,7 +6317,8 @@ swap_out_syms (bfd *abfd, symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; symstrtab_hdr->sh_type = SHT_STRTAB; - outbound_syms = bfd_alloc2 (abfd, 1 + symcount, bed->s->sizeof_sym); + outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount, + bed->s->sizeof_sym); if (outbound_syms == NULL) { _bfd_stringtab_free (stt); @@ -6182,8 +6331,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_zalloc2 (abfd, 1 + symcount, - sizeof (Elf_External_Sym_Shndx)); + outbound_shndx = (bfd_byte *) + bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx)); if (outbound_shndx == NULL) { _bfd_stringtab_free (stt); @@ -6344,6 +6493,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), if ((flags & BSF_THREAD_LOCAL) != 0) type = STT_TLS; + else if ((flags & BSF_GNU_INDIRECT_FUNCTION) != 0) + type = STT_GNU_IFUNC; else if ((flags & BSF_FUNCTION) != 0) type = STT_FUNC; else if ((flags & BSF_OBJECT) != 0) @@ -6377,9 +6528,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), if (type == STT_OBJECT) sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON); else -#else - sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); #endif + sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); } else if (bfd_is_und_section (syms[idx]->section)) sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK) @@ -6394,6 +6544,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), if (flags & BSF_LOCAL) bind = STB_LOCAL; + else if (flags & BSF_GNU_UNIQUE) + bind = STB_GNU_UNIQUE; else if (flags & BSF_WEAK) bind = STB_WEAK; else if (flags & BSF_GLOBAL) @@ -6618,14 +6770,14 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) hdr = &elf_tdata (abfd)->dynverref_hdr; - elf_tdata (abfd)->verref = bfd_zalloc2 (abfd, hdr->sh_info, - sizeof (Elf_Internal_Verneed)); + elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) + bfd_zalloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed)); if (elf_tdata (abfd)->verref == NULL) goto error_return; elf_tdata (abfd)->cverrefs = hdr->sh_info; - contents = bfd_malloc (hdr->sh_size); + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); if (contents == NULL) { error_return_verref: @@ -6665,8 +6817,9 @@ error_return_verref: iverneed->vn_auxptr = NULL; else { - iverneed->vn_auxptr = bfd_alloc2 (abfd, iverneed->vn_cnt, - sizeof (Elf_Internal_Vernaux)); + iverneed->vn_auxptr = (struct elf_internal_vernaux *) + bfd_alloc2 (abfd, iverneed->vn_cnt, + sizeof (Elf_Internal_Vernaux)); if (iverneed->vn_auxptr == NULL) goto error_return_verref; } @@ -6734,7 +6887,7 @@ error_return_verref: hdr = &elf_tdata (abfd)->dynverdef_hdr; - contents = bfd_malloc (hdr->sh_size); + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); if (contents == NULL) goto error_return; if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 @@ -6778,8 +6931,8 @@ error_return_verref: else freeidx = ++maxidx; } - elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, maxidx, - sizeof (Elf_Internal_Verdef)); + elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) + bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef)); if (elf_tdata (abfd)->verdef == NULL) goto error_return; @@ -6812,8 +6965,9 @@ error_return_verdef: iverdef->vd_auxptr = NULL; else { - iverdef->vd_auxptr = bfd_alloc2 (abfd, iverdef->vd_cnt, - sizeof (Elf_Internal_Verdaux)); + iverdef->vd_auxptr = (struct elf_internal_verdaux *) + bfd_alloc2 (abfd, iverdef->vd_cnt, + sizeof (Elf_Internal_Verdaux)); if (iverdef->vd_auxptr == NULL) goto error_return_verdef; } @@ -6870,8 +7024,8 @@ error_return_verdef: else freeidx++; - elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, freeidx, - sizeof (Elf_Internal_Verdef)); + elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) + bfd_zalloc2 (abfd, freeidx, sizeof (Elf_Internal_Verdef)); if (elf_tdata (abfd)->verdef == NULL) goto error_return; @@ -6897,7 +7051,8 @@ error_return_verdef: if (iverdef->vd_nodename == NULL) goto error_return_verdef; iverdef->vd_nextdef = NULL; - iverdef->vd_auxptr = bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux)); + iverdef->vd_auxptr = (struct elf_internal_verdaux *) + bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux)); if (iverdef->vd_auxptr == NULL) goto error_return_verdef; @@ -6920,7 +7075,7 @@ _bfd_elf_make_empty_symbol (bfd *abfd) elf_symbol_type *newsym; bfd_size_type amt = sizeof (elf_symbol_type); - newsym = bfd_zalloc (abfd, amt); + newsym = (elf_symbol_type *) bfd_zalloc (abfd, amt); if (!newsym) return NULL; else @@ -6994,7 +7149,7 @@ _bfd_elf_set_arch_mach (bfd *abfd, for error reporting. */ static bfd_boolean -elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, +elf_find_function (bfd *abfd, asection *section, asymbol **symbols, bfd_vma offset, @@ -7014,6 +7169,7 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, make a better choice of file name for local symbols by ignoring file symbols appearing after a given local symbol. */ enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); filename = NULL; func = NULL; @@ -7024,20 +7180,22 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, for (p = symbols; *p != NULL; p++) { elf_symbol_type *q; + unsigned int type; q = (elf_symbol_type *) *p; - switch (ELF_ST_TYPE (q->internal_elf_sym.st_info)) + type = ELF_ST_TYPE (q->internal_elf_sym.st_info); + switch (type) { - default: - break; case STT_FILE: file = &q->symbol; if (state == symbol_seen) state = file_after_symbol_seen; continue; + default: + if (!bed->is_function_type (type)) + break; case STT_NOTYPE: - case STT_FUNC: if (bfd_get_section (&q->symbol) == section && q->symbol.value >= low_func && q->symbol.value <= offset) @@ -7345,6 +7503,8 @@ _bfd_elf_rel_vtable_reloc_fn out details about the corefile. */ #ifdef HAVE_SYS_PROCFS_H +/* Needed for new procfs interface on sparc-solaris. */ +# define _STRUCTURED_PROC 1 # include #endif @@ -7402,7 +7562,7 @@ _bfd_elfcore_make_pseudosection (bfd *abfd, sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd)); len = strlen (buf) + 1; - threaded_name = bfd_alloc (abfd, len); + threaded_name = (char *) bfd_alloc (abfd, len); if (threaded_name == NULL) return FALSE; memcpy (threaded_name, buf, len); @@ -7526,12 +7686,63 @@ elfcore_grok_prxfpreg (bfd *abfd, Elf_Internal_Note *note) return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note); } +/* Linux dumps the Intel XSAVE extended state in a note named "LINUX" + with a note type of NT_X86_XSTATE. Just include the whole note's + contents literally. */ + +static bfd_boolean +elfcore_grok_xstatereg (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-xstate", note); +} + static bfd_boolean elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note) { return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vmx", note); } +static bfd_boolean +elfcore_grok_ppc_vsx (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vsx", note); +} + +static bfd_boolean +elfcore_grok_s390_high_gprs (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-high-gprs", note); +} + +static bfd_boolean +elfcore_grok_s390_timer (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-timer", note); +} + +static bfd_boolean +elfcore_grok_s390_todcmp (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-todcmp", note); +} + +static bfd_boolean +elfcore_grok_s390_todpreg (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-todpreg", note); +} + +static bfd_boolean +elfcore_grok_s390_ctrs (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-ctrs", note); +} + +static bfd_boolean +elfcore_grok_s390_prefix (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-s390-prefix", note); +} #if defined (HAVE_PRPSINFO_T) typedef prpsinfo_t elfcore_psinfo_t; @@ -7555,7 +7766,7 @@ char * _bfd_elfcore_strndup (bfd *abfd, char *start, size_t max) { char *dups; - char *end = memchr (start, '\0', max); + char *end = (char *) memchr (start, '\0', max); size_t len; if (end == NULL) @@ -7563,7 +7774,7 @@ _bfd_elfcore_strndup (bfd *abfd, char *start, size_t max) else len = end - start; - dups = bfd_alloc (abfd, len + 1); + dups = (char *) bfd_alloc (abfd, len + 1); if (dups == NULL) return NULL; @@ -7687,7 +7898,10 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) memcpy (&lwpstat, note->descdata, sizeof (lwpstat)); elf_tdata (abfd)->core_lwpid = lwpstat.pr_lwpid; - elf_tdata (abfd)->core_signal = lwpstat.pr_cursig; + /* Do not overwrite the core signal if it has already been set by + another thread. */ + if (elf_tdata (abfd)->core_signal == 0) + elf_tdata (abfd)->core_signal = lwpstat.pr_cursig; /* Make a ".reg/999" section. */ @@ -7783,7 +7997,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) sprintf (buf, ".reg/%ld", (long) bfd_get_32 (abfd, note->descdata + 8)); len = strlen (buf) + 1; - name = bfd_alloc (abfd, len); + name = (char *) bfd_alloc (abfd, len); if (name == NULL) return FALSE; @@ -7811,10 +8025,10 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) /* Make a ".module/xxxxxxxx" section. */ /* module_info.base_address */ base_addr = bfd_get_32 (abfd, note->descdata + 4); - sprintf (buf, ".module/%08lx", (long) base_addr); + sprintf (buf, ".module/%08lx", (unsigned long) base_addr); len = strlen (buf) + 1; - name = bfd_alloc (abfd, len); + name = (char *) bfd_alloc (abfd, len); if (name == NULL) return FALSE; @@ -7880,6 +8094,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) else return TRUE; + case NT_X86_XSTATE: /* Linux XSAVE extension */ + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_xstatereg (abfd, note); + else + return TRUE; + case NT_PPC_VMX: if (note->namesz == 6 && strcmp (note->namedata, "LINUX") == 0) @@ -7887,6 +8108,55 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) else return TRUE; + case NT_PPC_VSX: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_vsx (abfd, note); + else + return TRUE; + + case NT_S390_HIGH_GPRS: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_high_gprs (abfd, note); + else + return TRUE; + + case NT_S390_TIMER: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_timer (abfd, note); + else + return TRUE; + + case NT_S390_TODCMP: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_todcmp (abfd, note); + else + return TRUE; + + case NT_S390_TODPREG: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_todpreg (abfd, note); + else + return TRUE; + + case NT_S390_CTRS: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_ctrs (abfd, note); + else + return TRUE; + + case NT_S390_PREFIX: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_s390_prefix (abfd, note); + else + return TRUE; + case NT_PRPSINFO: case NT_PSINFO: if (bed->elf_backend_grok_psinfo) @@ -7918,7 +8188,7 @@ static bfd_boolean elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note) { elf_tdata (abfd)->build_id_size = note->descsz; - elf_tdata (abfd)->build_id = bfd_alloc (abfd, note->descsz); + elf_tdata (abfd)->build_id = (bfd_byte *) bfd_alloc (abfd, note->descsz); if (elf_tdata (abfd)->build_id == NULL) return FALSE; @@ -8038,6 +8308,70 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) /* NOTREACHED */ } +static bfd_boolean +elfcore_grok_openbsd_procinfo (bfd *abfd, Elf_Internal_Note *note) +{ + /* Signal number at offset 0x08. */ + elf_tdata (abfd)->core_signal + = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08); + + /* Process ID at offset 0x20. */ + elf_tdata (abfd)->core_pid + = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x20); + + /* Command name at 0x48 (max 32 bytes, including nul). */ + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 0x48, 31); + + return TRUE; +} + +static bfd_boolean +elfcore_grok_openbsd_note (bfd *abfd, Elf_Internal_Note *note) +{ + if (note->type == NT_OPENBSD_PROCINFO) + return elfcore_grok_openbsd_procinfo (abfd, note); + + if (note->type == NT_OPENBSD_REGS) + return elfcore_make_note_pseudosection (abfd, ".reg", note); + + if (note->type == NT_OPENBSD_FPREGS) + return elfcore_make_note_pseudosection (abfd, ".reg2", note); + + if (note->type == NT_OPENBSD_XFPREGS) + return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note); + + if (note->type == NT_OPENBSD_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->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; + + return TRUE; + } + + if (note->type == NT_OPENBSD_WCOOKIE) + { + asection *sect = bfd_make_section_anyway_with_flags (abfd, ".wcookie", + SEC_HAS_CONTENTS); + + if (sect == NULL) + return FALSE; + sect->size = note->descsz; + sect->filepos = note->descpos; + sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; + + return TRUE; + } + + return TRUE; +} + static bfd_boolean elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid) { @@ -8073,7 +8407,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid) /* Make a ".qnx_core_status/%d" section. */ sprintf (buf, ".qnx_core_status/%ld", *tid); - name = bfd_alloc (abfd, strlen (buf) + 1); + name = (char *) bfd_alloc (abfd, strlen (buf) + 1); if (name == NULL) return FALSE; strcpy (name, buf); @@ -8102,7 +8436,7 @@ elfcore_grok_nto_regs (bfd *abfd, /* Make a "(base)/%d" section. */ sprintf (buf, "%s/%ld", base, tid); - name = bfd_alloc (abfd, strlen (buf) + 1); + name = (char *) bfd_alloc (abfd, strlen (buf) + 1); if (name == NULL) return FALSE; strcpy (name, buf); @@ -8159,7 +8493,7 @@ elfcore_grok_spu_note (bfd *abfd, Elf_Internal_Note *note) /* Use note name as section name. */ len = note->namesz; - name = bfd_alloc (abfd, len); + name = (char *) bfd_alloc (abfd, len); if (name == NULL) return FALSE; memcpy (name, note->namedata, len); @@ -8213,7 +8547,7 @@ elfcore_write_note (bfd *abfd, newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4); - buf = realloc (buf, *bufsiz + newspace); + buf = (char *) realloc (buf, *bufsiz + newspace); if (buf == NULL) return buf; dest = buf + *bufsiz; @@ -8441,6 +8775,15 @@ elfcore_write_prxfpreg (bfd *abfd, note_name, NT_PRXFPREG, xfpregs, size); } +char * +elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz, + const void *xfpregs, int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_X86_XSTATE, xfpregs, size); +} + char * elfcore_write_ppc_vmx (bfd *abfd, char *buf, @@ -8453,6 +8796,91 @@ elfcore_write_ppc_vmx (bfd *abfd, note_name, NT_PPC_VMX, ppc_vmx, size); } +char * +elfcore_write_ppc_vsx (bfd *abfd, + char *buf, + int *bufsiz, + const void *ppc_vsx, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_PPC_VSX, ppc_vsx, size); +} + +static char * +elfcore_write_s390_high_gprs (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_high_gprs, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_HIGH_GPRS, + s390_high_gprs, size); +} + +char * +elfcore_write_s390_timer (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_timer, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_TIMER, s390_timer, size); +} + +char * +elfcore_write_s390_todcmp (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_todcmp, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_TODCMP, s390_todcmp, size); +} + +char * +elfcore_write_s390_todpreg (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_todpreg, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_TODPREG, s390_todpreg, size); +} + +char * +elfcore_write_s390_ctrs (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_ctrs, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_CTRS, s390_ctrs, size); +} + +char * +elfcore_write_s390_prefix (bfd *abfd, + char *buf, + int *bufsiz, + const void *s390_prefix, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_S390_PREFIX, s390_prefix, size); +} + char * elfcore_write_register_note (bfd *abfd, char *buf, @@ -8465,8 +8893,24 @@ elfcore_write_register_note (bfd *abfd, return elfcore_write_prfpreg (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-xfp") == 0) return elfcore_write_prxfpreg (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-xstate") == 0) + return elfcore_write_xstatereg (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-ppc-vmx") == 0) return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-ppc-vsx") == 0) + return elfcore_write_ppc_vsx (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-high-gprs") == 0) + return elfcore_write_s390_high_gprs (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-timer") == 0) + return elfcore_write_s390_timer (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-todcmp") == 0) + return elfcore_write_s390_todcmp (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-todpreg") == 0) + return elfcore_write_s390_todpreg (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-ctrs") == 0) + return elfcore_write_s390_ctrs (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-s390-prefix") == 0) + return elfcore_write_s390_prefix (abfd, buf, bufsiz, data, size); return NULL; } @@ -8482,14 +8926,23 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset) Elf_External_Note *xnp = (Elf_External_Note *) p; Elf_Internal_Note in; + if (offsetof (Elf_External_Note, name) > buf - p + size) + return FALSE; + in.type = H_GET_32 (abfd, xnp->type); in.namesz = H_GET_32 (abfd, xnp->namesz); in.namedata = xnp->name; + if (in.namesz > buf - in.namedata + size) + return FALSE; in.descsz = H_GET_32 (abfd, xnp->descsz); in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4); in.descpos = offset + (in.descdata - buf); + if (in.descsz != 0 + && (in.descdata >= buf + size + || in.descsz > buf - in.descdata + size)) + return FALSE; switch (bfd_get_format (abfd)) { @@ -8502,6 +8955,11 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset) if (! elfcore_grok_netbsd_note (abfd, &in)) return FALSE; } + else if (CONST_STRNEQ (in.namedata, "OpenBSD")) + { + if (! elfcore_grok_openbsd_note (abfd, &in)) + return FALSE; + } else if (CONST_STRNEQ (in.namedata, "QNX")) { if (! elfcore_grok_nto_note (abfd, &in)) @@ -8545,7 +9003,7 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) if (bfd_seek (abfd, offset, SEEK_SET) != 0) return FALSE; - buf = bfd_malloc (size); + buf = (char *) bfd_malloc (size); if (buf == NULL) return FALSE; @@ -8741,7 +9199,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, relplt_name = bed->relplt_name; if (relplt_name == NULL) - relplt_name = bed->default_use_rela_p ? ".rela.plt" : ".rel.plt"; + relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt"; relplt = bfd_get_section_by_name (abfd, relplt_name); if (relplt == NULL) return 0; @@ -8762,17 +9220,27 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, count = relplt->size / hdr->sh_entsize; size = count * sizeof (asymbol); p = relplt->relocation; - for (i = 0; i < count; i++, p++) - size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); + for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) + { + size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); + if (p->addend != 0) + { +#ifdef BFD64 + size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64); +#else + size += sizeof ("+0x") - 1 + 8; +#endif + } + } - s = *ret = bfd_malloc (size); + s = *ret = (asymbol *) bfd_malloc (size); if (s == NULL) return -1; names = (char *) (s + count); p = relplt->relocation; n = 0; - for (i = 0; i < count; i++, p++) + for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel) { size_t len; bfd_vma addr; @@ -8786,6 +9254,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, we are defining a symbol, ensure one of them is set. */ if ((s->flags & BSF_LOCAL) == 0) s->flags |= BSF_GLOBAL; + s->flags |= BSF_SYNTHETIC; s->section = plt; s->value = addr - plt->vma; s->name = names; @@ -8793,6 +9262,19 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, len = strlen ((*p->sym_ptr_ptr)->name); memcpy (names, (*p->sym_ptr_ptr)->name, len); names += len; + if (p->addend != 0) + { + char buf[30], *a; + + memcpy (names, "+0x", sizeof ("+0x") - 1); + names += sizeof ("+0x") - 1; + bfd_sprintf_vma (abfd, buf, p->addend); + for (a = buf; *a == '0'; ++a) + ; + len = strlen (a); + memcpy (names, a, len); + names += len; + } memcpy (names, "@plt", sizeof ("@plt")); names += sizeof ("@plt"); ++s, ++n; @@ -8815,15 +9297,23 @@ _bfd_elf_set_osabi (bfd * abfd, i_ehdrp = elf_elfheader (abfd); i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; + + /* To make things simpler for the loader on Linux systems we set the + osabi field to ELFOSABI_LINUX if the binary contains symbols of + the STT_GNU_IFUNC type. */ + if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE + && elf_tdata (abfd)->has_ifunc_symbols) + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_LINUX; } /* Return TRUE for ELF symbol types that represent functions. This is the default version of this function, which is sufficient for - most targets. It returns true if TYPE is STT_FUNC. */ + most targets. It returns true if TYPE is STT_FUNC or STT_GNU_IFUNC. */ bfd_boolean _bfd_elf_is_function_type (unsigned int type) { - return (type == STT_FUNC); + return (type == STT_FUNC + || type == STT_GNU_IFUNC); }