X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf.c;h=be77cc94c3bed24b7b44af041db40df3d1a63309;hb=0e71e4955cd1a6ad7d03775dec5df49323204dec;hp=d1fa2c0c907ff58c7a71050645b2d1bd66d48e58;hpb=90e3cdf2a90318ccd4b5612d1e9fbd56ada53d84;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf.c b/bfd/elf.c index d1fa2c0c90..be77cc94c3 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 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -405,11 +405,16 @@ bfd_elf_get_elf_syms (bfd *ibfd, /* Look up a symbol name. */ const char * -bfd_elf_local_sym_name (bfd *abfd, Elf_Internal_Sym *isym) +bfd_elf_sym_name (bfd *abfd, + Elf_Internal_Shdr *symtab_hdr, + Elf_Internal_Sym *isym) { unsigned int iname = isym->st_name; - unsigned int shindex = elf_tdata (abfd)->symtab_hdr.sh_link; - if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION) + unsigned int shindex = symtab_hdr->sh_link; + if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION + /* Check for a bogus st_shndx to avoid crashing. */ + && isym->st_shndx < elf_numsections (abfd) + && !(isym->st_shndx >= SHN_LORESERVE && isym->st_shndx <= SHN_HIRESERVE)) { iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name; shindex = elf_elfheader (abfd)->e_shstrndx; @@ -448,7 +453,7 @@ group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr) &isym, esym, &eshndx) == NULL) return NULL; - return bfd_elf_local_sym_name (abfd, &isym); + return bfd_elf_sym_name (abfd, hdr, &isym); } /* Set next_in_group list pointer, and group name for NEWSECT. */ @@ -659,29 +664,6 @@ bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec) return elf_next_in_group (sec) != NULL; } -bfd_boolean -bfd_elf_discard_group (bfd *abfd ATTRIBUTE_UNUSED, - asection *group ATTRIBUTE_UNUSED) -{ -#if 0 - asection *first = elf_next_in_group (group); - asection *s = first; - - while (s != NULL) - { - s->output_section = bfd_abs_section_ptr; - s = elf_next_in_group (s); - /* These lists are circular. */ - if (s == first) - break; - } -#else - /* FIXME: Never used. Remove it! */ - abort (); -#endif - return TRUE; -} - /* Make a BFD section from an ELF section. We store a pointer to the BFD section in the bfd_section field of the header. */ @@ -1192,7 +1174,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL) || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL)) { - if (! _bfd_elf_slurp_version_tables (abfd)) + if (! _bfd_elf_slurp_version_tables (abfd, FALSE)) return FALSE; } @@ -1391,23 +1373,14 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, /* Set local fields. */ ret->indx = -1; ret->dynindx = -1; - ret->dynstr_index = 0; - ret->elf_hash_value = 0; - ret->weakdef = NULL; - ret->verinfo.verdef = NULL; - ret->vtable_entries_size = 0; - ret->vtable_entries_used = NULL; - ret->vtable_parent = NULL; - ret->got = htab->init_refcount; - ret->plt = htab->init_refcount; - ret->size = 0; - ret->type = STT_NOTYPE; - ret->other = 0; + ret->got = ret->plt = htab->init_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. This flag is then reset by the code which reads an ELF input file. This ensures that a symbol created by a non-ELF symbol reader will have the flag set correctly. */ - ret->elf_link_hash_flags = ELF_LINK_NON_ELF; + ret->non_elf = 1; } return entry; @@ -1427,13 +1400,12 @@ _bfd_elf_link_hash_copy_indirect (const struct elf_backend_data *bed, /* Copy down any references that we may have already seen to the symbol which just became indirect. */ - dir->elf_link_hash_flags - |= ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC - | ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_REGULAR_NONWEAK - | ELF_LINK_NON_GOT_REF - | ELF_LINK_HASH_NEEDS_PLT - | ELF_LINK_POINTER_EQUALITY_NEEDED); + dir->ref_dynamic |= ind->ref_dynamic; + dir->ref_regular |= ind->ref_regular; + dir->ref_regular_nonweak |= ind->ref_regular_nonweak; + dir->non_got_ref |= ind->non_got_ref; + dir->needs_plt |= ind->needs_plt; + dir->pointer_equality_needed |= ind->pointer_equality_needed; if (ind->root.type != bfd_link_hash_indirect) return; @@ -1475,10 +1447,10 @@ _bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info, bfd_boolean force_local) { h->plt = elf_hash_table (info)->init_offset; - h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + h->needs_plt = 0; if (force_local) { - h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL; + h->forced_local = 1; if (h->dynindx != -1) { h->dynindx = -1; @@ -1749,6 +1721,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) case SHT_INIT_ARRAY: /* .init_array section. */ case SHT_FINI_ARRAY: /* .fini_array section. */ case SHT_PREINIT_ARRAY: /* .preinit_array section. */ + case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ return _bfd_elf_make_section_from_shdr (abfd, hdr, name); case SHT_DYNAMIC: /* Dynamic linking information. */ @@ -1873,17 +1846,6 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) that objcopy can handle it. */ break; } -#if 0 /* Not handling other string tables specially right now. */ - hdr2 = elf_elfsections (abfd)[i]; /* in case it moved */ - /* We have a strtab for some random other section. */ - newsect = (asection *) hdr2->bfd_section; - if (!newsect) - break; - hdr->bfd_section = newsect; - hdr2 = &elf_section_data (newsect)->str_hdr; - *hdr2 = *hdr; - elf_elfsections (abfd)[shindex] = hdr2; -#endif } } } @@ -2104,6 +2066,7 @@ bfd_section_from_elf_index (bfd *abfd, unsigned int index) 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 }, @@ -2141,6 +2104,8 @@ static struct bfd_elf_special_section const special_sections[] = { ".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 } }; @@ -2731,18 +2696,35 @@ assign_section_numbers (bfd *abfd) unsigned int section_number, secn; Elf_Internal_Shdr **i_shdrp; bfd_size_type amt; + struct bfd_elf_section_data *d; section_number = 1; _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd)); + /* Put SHT_GROUP sections first. */ for (sec = abfd->sections; sec; sec = sec->next) { - struct bfd_elf_section_data *d = elf_section_data (sec); + d = elf_section_data (sec); - if (section_number == SHN_LORESERVE) - section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; - d->this_idx = section_number++; + if (d->this_hdr.sh_type == SHT_GROUP) + { + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + d->this_idx = section_number++; + } + } + + for (sec = abfd->sections; sec; sec = sec->next) + { + d = elf_section_data (sec); + + if (d->this_hdr.sh_type != SHT_GROUP) + { + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + d->this_idx = section_number++; + } _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name); if ((sec->flags & SEC_RELOC) == 0) d->rel_idx = 0; @@ -2978,6 +2960,17 @@ assign_section_numbers (bfd *abfd) d->this_hdr.sh_link = elf_section_data (s)->this_idx; break; + case SHT_GNU_LIBLIST: + /* sh_link is the section header index of the prelink library + list + used for the dynamic entries, or the symbol table, or the + version strings. */ + s = bfd_get_section_by_name (abfd, (sec->flags & SEC_ALLOC) + ? ".dynstr" : ".gnu.libstr"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + break; + case SHT_HASH: case SHT_GNU_versym: /* sh_link is the section header index of the symbol table @@ -3328,6 +3321,25 @@ make_mapping (bfd *abfd, 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)); + if (m == NULL) + return NULL; + m->next = NULL; + m->p_type = PT_DYNAMIC; + m->count = 1; + m->sections[0] = dynsec; + + return m; +} + /* Set up a mapping from BFD sections to program segments. */ static bfd_boolean @@ -3565,15 +3577,9 @@ map_sections_to_segments (bfd *abfd) /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ if (dynsec != NULL) { - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); + m = _bfd_elf_make_dynamic_segment (abfd, dynsec); if (m == NULL) goto error_return; - m->next = NULL; - m->p_type = PT_DYNAMIC; - m->count = 1; - m->sections[0] = dynsec; - *pm = m; pm = &m->next; } @@ -3853,7 +3859,10 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) elf_elfheader (abfd)->e_phnum = count; if (count == 0) - return TRUE; + { + 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 @@ -3862,8 +3871,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (alloc != 0 && count > alloc) { ((*_bfd_error_handler) - (_("%s: Not enough room for program headers (allocated %u, need %u)"), - bfd_get_filename (abfd), alloc, count)); + (_("%B: Not enough room for program headers (allocated %u, need %u)"), + abfd, alloc, count)); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -3902,32 +3911,63 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) qsort (m->sections, (size_t) m->count, sizeof (asection *), elf_sort_sections); + /* An ELF segment (described by Elf_Internal_Phdr) may contain a + number of sections with contents contributing to both p_filesz + and p_memsz, followed by a number of sections with no contents + that just contribute to p_memsz. In this loop, OFF tracks next + available file offset for PT_LOAD and PT_NOTE segments. VOFF is + an adjustment we use for segments that have no file contents + but need zero filled memory allocation. */ + voff = 0; p->p_type = m->p_type; p->p_flags = m->p_flags; if (p->p_type == PT_LOAD - && m->count > 0 - && (m->sections[0]->flags & SEC_ALLOC) != 0) + && m->count > 0) { + bfd_size_type align; + bfd_vma adjust; + if ((abfd->flags & D_PAGED) != 0) - off += vma_page_aligned_bias (m->sections[0]->vma, off, - bed->maxpagesize); + align = bed->maxpagesize; else { - bfd_size_type align; - - align = 0; + unsigned int align_power = 0; for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { - bfd_size_type secalign; + unsigned int secalign; secalign = bfd_get_section_alignment (abfd, *secpp); - if (secalign > align) - align = secalign; + if (secalign > align_power) + align_power = secalign; } + align = (bfd_size_type) 1 << align_power; + } - off += vma_page_aligned_bias (m->sections[0]->vma, off, - 1 << align); + adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align); + off += adjust; + if (adjust != 0 + && !m->includes_filehdr + && !m->includes_phdrs + && (ufile_ptr) off >= align) + { + /* If the first section isn't loadable, the same holds for + any other sections. Since the segment won't need file + space, we can make p_offset overlap some prior segment. + However, .tbss is special. If a segment starts with + .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) + { + if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0 + || ++i >= m->count) + { + off -= adjust; + voff = adjust - align; + break; + } + } } } /* Make sure the .dynamic section is the first section in the @@ -3937,8 +3977,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) && strcmp (m->sections[0]->name, ".dynamic") != 0) { _bfd_error_handler - (_("%s: The first section in the PT_DYNAMIC segment is not the .dynamic section"), - bfd_get_filename (abfd)); + (_("%B: The first section in the PT_DYNAMIC segment is not the .dynamic section"), + abfd); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -3981,8 +4021,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (p->p_vaddr < (bfd_vma) off) { (*_bfd_error_handler) - (_("%s: Not enough room for program headers, try linking with -N"), - bfd_get_filename (abfd)); + (_("%B: Not enough room for program headers, try linking with -N"), + abfd); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -4040,7 +4080,7 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)) { if (! m->includes_filehdr && ! m->includes_phdrs) - p->p_offset = off; + p->p_offset = off + voff; else { file_ptr adjust; @@ -4051,8 +4091,6 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) } } - voff = off; - for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { asection *sec; @@ -4063,117 +4101,97 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) flags = sec->flags; align = 1 << bfd_get_section_alignment (abfd, sec); - /* The section may have artificial alignment forced by a - link script. Notice this case by the gap between the - cumulative phdr lma and the section's lma. */ - if (p->p_paddr + p->p_memsz < sec->lma) - { - bfd_vma adjust = sec->lma - (p->p_paddr + p->p_memsz); - - p->p_memsz += adjust; - if (p->p_type == PT_LOAD - || (p->p_type == PT_NOTE - && bfd_get_format (abfd) == bfd_core)) - { - off += adjust; - voff += adjust; - } - if ((flags & SEC_LOAD) != 0 - || (flags & SEC_THREAD_LOCAL) != 0) - p->p_filesz += adjust; - } - - if (p->p_type == PT_LOAD) + if (p->p_type == PT_LOAD + || p->p_type == PT_TLS) { bfd_signed_vma adjust; if ((flags & SEC_LOAD) != 0) { - adjust = sec->lma - (p->p_paddr + p->p_memsz); + adjust = sec->lma - (p->p_paddr + p->p_filesz); if (adjust < 0) - adjust = 0; + { + (*_bfd_error_handler) + (_("%B: section %A lma 0x%lx overlaps previous sections"), + abfd, sec, (unsigned long) sec->lma); + adjust = 0; + } + off += adjust; + p->p_filesz += adjust; + p->p_memsz += adjust; } - else if ((flags & SEC_ALLOC) != 0) + /* .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) { /* The section VMA must equal the file position - modulo the page size. FIXME: I'm not sure if - this adjustment is really necessary. We used to - not have the SEC_LOAD case just above, and then - this was necessary, but now I'm not sure. */ + modulo the page size. */ + bfd_size_type page = align; if ((abfd->flags & D_PAGED) != 0) - adjust = vma_page_aligned_bias (sec->vma, voff, - bed->maxpagesize); - else - adjust = vma_page_aligned_bias (sec->vma, voff, - align); - } - else - adjust = 0; - - if (adjust != 0) - { - if (i == 0) - { - (* _bfd_error_handler) (_("\ -Error: First section in segment (%s) starts at 0x%x whereas the segment starts at 0x%x"), - bfd_section_name (abfd, sec), - sec->lma, - p->p_paddr); - return FALSE; - } + page = bed->maxpagesize; + adjust = vma_page_aligned_bias (sec->vma, + p->p_vaddr + p->p_memsz, + page); p->p_memsz += adjust; - off += adjust; - voff += adjust; - if ((flags & SEC_LOAD) != 0) - p->p_filesz += adjust; } - - sec->filepos = off; - - /* We check SEC_HAS_CONTENTS here because if NOLOAD is - used in a linker script we may have a section with - SEC_LOAD clear but which is supposed to have - contents. */ - if ((flags & SEC_LOAD) != 0 - || (flags & SEC_HAS_CONTENTS) != 0) - off += sec->size; - - if ((flags & SEC_ALLOC) != 0 - && ((flags & SEC_LOAD) != 0 - || (flags & SEC_THREAD_LOCAL) == 0)) - voff += sec->size; } if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core) { - /* The actual "note" segment has i == 0. - This is the one that actually contains everything. */ + /* The section at i == 0 is the one that actually contains + everything. */ if (i == 0) { sec->filepos = off; - p->p_filesz = sec->size; off += sec->size; - voff = off; + p->p_filesz = sec->size; + p->p_memsz = 0; + p->p_align = 1; } else { - /* Fake sections -- don't need to be written. */ + /* The rest are fake sections that shouldn't be written. */ sec->filepos = 0; sec->size = 0; - flags = sec->flags = 0; + sec->flags = 0; + continue; } - p->p_memsz = 0; - p->p_align = 1; } else { - if ((sec->flags & SEC_LOAD) != 0 - || (sec->flags & SEC_THREAD_LOCAL) == 0 - || p->p_type == PT_TLS) - p->p_memsz += sec->size; + if (p->p_type == PT_LOAD) + { + sec->filepos = off; + /* 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 + a problem we have with linker scripts using data + statements in NOLOAD sections. I don't think it + makes a great deal of sense to have such a section + assigned to a PT_LOAD segment, but apparently + people do this. The data statement results in a + bfd_data_link_order being built, and these need + section contents to write into. Eventually, we get + to _bfd_elf_write_object_contents which writes any + section with contents to the output. Make room + here for the write, so that following segments are + not trashed. */ + if ((flags & SEC_LOAD) != 0 + || (flags & SEC_HAS_CONTENTS) != 0) + off += sec->size; + } if ((flags & SEC_LOAD) != 0) - p->p_filesz += sec->size; + { + p->p_filesz += sec->size; + p->p_memsz += 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) + p->p_memsz += sec->size; if (p->p_type == PT_TLS && sec->size == 0 @@ -4214,6 +4232,22 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a if (p->p_type != PT_LOAD && 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) + { + 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; + } p->p_offset = m->sections[0]->filepos; } if (m->count == 0) @@ -4393,10 +4427,13 @@ get_program_header_size (bfd *abfd) _bfd_elf_compute_section_file_positions. All the section sizes and VMAs must be known before this is called. - We do not consider reloc sections at this point, unless they form - part of the loadable image. Reloc sections are assigned file - positions in assign_file_positions_for_relocs, which is called by - write_object_contents and final_link. + Reloc sections come in two flavours: Those processed specially as + "side-channel" data attached to a section to which they apply, and + those that bfd doesn't process as relocations. The latter sort are + stored in a normal bfd section by bfd_section_from_shdr. We don't + consider the former sort here, unless they form part of the loadable + image. Reloc sections not assigned here will be handled later by + assign_file_positions_for_relocs. We also don't set the positions of the .symtab and .strtab here. */ @@ -4428,8 +4465,8 @@ assign_file_positions_except_relocs (bfd *abfd, Elf_Internal_Shdr *hdr; hdr = *hdrpp; - if (hdr->sh_type == SHT_REL - || hdr->sh_type == SHT_RELA + if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) + && hdr->bfd_section == NULL) || i == tdata->symtab_section || i == tdata->symtab_shndx_section || i == tdata->strtab_section) @@ -4470,8 +4507,8 @@ assign_file_positions_except_relocs (bfd *abfd, else if ((hdr->sh_flags & SHF_ALLOC) != 0) { ((*_bfd_error_handler) - (_("%s: warning: allocated section `%s' not in segment"), - bfd_get_filename (abfd), + (_("%B: warning: allocated section `%s' not in segment"), + abfd, (hdr->bfd_section == NULL ? "*unknown*" : hdr->bfd_section->name))); @@ -4484,8 +4521,8 @@ assign_file_positions_except_relocs (bfd *abfd, off = _bfd_elf_assign_file_position_for_section (hdr, off, FALSE); } - else if (hdr->sh_type == SHT_REL - || hdr->sh_type == SHT_RELA + 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]) @@ -4580,18 +4617,8 @@ prep_headers (bfd *abfd) /* If we're building an executable, we'll need a program header table. */ if (abfd->flags & EXEC_P) - { - /* It all happens later. */ -#if 0 - i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr); - - /* elf_build_phdrs() returns a (NULL-terminated) array of - Elf_Internal_Phdrs. */ - i_phdrp = elf_build_phdrs (abfd, i_ehdrp, i_shdrp, &i_ehdrp->e_phnum); - i_ehdrp->e_phoff = outbase; - outbase += i_ehdrp->e_phentsize * i_ehdrp->e_phnum; -#endif - } + /* It all happens later. */ + ; else { i_ehdrp->e_phentsize = 0; @@ -4894,7 +4921,9 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) 4. The section has not already been allocated to a previous segment. 5. PT_GNU_STACK segments do not include any sections. 6. PT_TLS segment includes only SHF_TLS sections. - 7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments. */ + 7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments. + 8. PT_DYNAMIC should not contain empty sections at the beginning + (with the possible exception of .dynamic). */ #define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed) \ ((((segment->p_paddr \ ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr) \ @@ -4908,6 +4937,13 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) && (segment->p_type == PT_LOAD \ || segment->p_type == PT_TLS \ || (section->flags & SEC_THREAD_LOCAL) == 0) \ + && (segment->p_type != PT_DYNAMIC \ + || SECTION_SIZE (section, segment) > 0 \ + || (segment->p_paddr \ + ? segment->p_paddr != section->lma \ + : segment->p_vaddr != section->vma) \ + || (strcmp (bfd_get_section_name (ibfd, section), ".dynamic") \ + == 0)) \ && ! section->segment_mark) /* Returns TRUE iff seg1 starts after the end of seg2. */ @@ -5368,31 +5404,6 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) -= (count - phdr_adjust_num) * iehdr->e_phentsize; } -#if 0 - /* Final Step: Sort the segments into ascending order of physical - address. */ - if (map_first != NULL) - { - struct elf_segment_map *prev; - - prev = map_first; - for (map = map_first->next; map != NULL; prev = map, map = map->next) - { - /* Yes I know - its a bubble sort.... */ - if (map->next != NULL && (map->next->p_paddr < map->p_paddr)) - { - /* Swap map and map->next. */ - prev->next = map->next; - map->next = map->next->next; - prev->next->next = map; - - /* Restart loop. */ - map = map_first; - } - } - } -#endif - #undef SEGMENT_END #undef SECTION_SIZE #undef IS_CONTAINED_BY_VMA @@ -5897,10 +5908,10 @@ _bfd_elf_canonicalize_dynamic_symtab (bfd *abfd, return symcount; } -/* Return the size required for the dynamic reloc entries. Any - section that was actually installed in the BFD, and has type - SHT_REL or SHT_RELA, and uses the dynamic symbol table, is - considered to be a dynamic reloc section. */ +/* Return the size required for the dynamic reloc entries. Any loadable + section that was actually installed in the BFD, and has type SHT_REL + or SHT_RELA, and uses the dynamic symbol table, is considered to be a + dynamic reloc section. */ long _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd) @@ -5916,7 +5927,8 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd) ret = sizeof (arelent *); for (s = abfd->sections; s != NULL; s = s->next) - if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) + if ((s->flags & SEC_LOAD) != 0 + && elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) && (elf_section_data (s)->this_hdr.sh_type == SHT_REL || elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) ret += ((s->size / elf_section_data (s)->this_hdr.sh_entsize) @@ -5925,14 +5937,13 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd) return ret; } -/* Canonicalize the dynamic relocation entries. Note that we return - the dynamic relocations as a single block, although they are - actually associated with particular sections; the interface, which - was designed for SunOS style shared libraries, expects that there - is only one set of dynamic relocs. Any section that was actually - installed in the BFD, and has type SHT_REL or SHT_RELA, and uses - the dynamic symbol table, is considered to be a dynamic reloc - section. */ +/* Canonicalize the dynamic relocation entries. Note that we return the + dynamic relocations as a single block, although they are actually + associated with particular sections; the interface, which was + designed for SunOS style shared libraries, expects that there is only + one set of dynamic relocs. Any loadable section that was actually + installed in the BFD, and has type SHT_REL or SHT_RELA, and uses the + dynamic symbol table, is considered to be a dynamic reloc section. */ long _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd, @@ -5953,7 +5964,8 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd, ret = 0; for (s = abfd->sections; s != NULL; s = s->next) { - if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) + if ((s->flags & SEC_LOAD) != 0 + && elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) && (elf_section_data (s)->this_hdr.sh_type == SHT_REL || elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) { @@ -5978,10 +5990,94 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd, /* Read in the version information. */ bfd_boolean -_bfd_elf_slurp_version_tables (bfd *abfd) +_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) + { + Elf_Internal_Shdr *hdr; + Elf_External_Verneed *everneed; + Elf_Internal_Verneed *iverneed; + unsigned int i; + + 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); + if (elf_tdata (abfd)->verref == NULL) + goto error_return; + + elf_tdata (abfd)->cverrefs = hdr->sh_info; + + contents = bfd_malloc (hdr->sh_size); + if (contents == NULL) + 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; + + everneed = (Elf_External_Verneed *) contents; + iverneed = elf_tdata (abfd)->verref; + for (i = 0; i < hdr->sh_info; i++, iverneed++) + { + Elf_External_Vernaux *evernaux; + Elf_Internal_Vernaux *ivernaux; + unsigned int j; + + _bfd_elf_swap_verneed_in (abfd, everneed, iverneed); + + iverneed->vn_bfd = abfd; + + iverneed->vn_filename = + bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + iverneed->vn_file); + if (iverneed->vn_filename == NULL) + goto error_return; + + amt = iverneed->vn_cnt; + amt *= sizeof (Elf_Internal_Vernaux); + iverneed->vn_auxptr = bfd_alloc (abfd, amt); + + evernaux = ((Elf_External_Vernaux *) + ((bfd_byte *) everneed + iverneed->vn_aux)); + ivernaux = iverneed->vn_auxptr; + for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++) + { + _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux); + + ivernaux->vna_nodename = + bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + ivernaux->vna_name); + if (ivernaux->vna_nodename == NULL) + goto error_return; + + if (j + 1 < iverneed->vn_cnt) + ivernaux->vna_nextptr = ivernaux + 1; + else + ivernaux->vna_nextptr = NULL; + + evernaux = ((Elf_External_Vernaux *) + ((bfd_byte *) evernaux + ivernaux->vna_next)); + + if (ivernaux->vna_other > freeidx) + freeidx = ivernaux->vna_other; + } + + if (i + 1 < hdr->sh_info) + iverneed->vn_nextref = iverneed + 1; + else + iverneed->vn_nextref = NULL; + + everneed = ((Elf_External_Verneed *) + ((bfd_byte *) everneed + iverneed->vn_next)); + } + + free (contents); + contents = NULL; + } if (elf_dynverdef (abfd) != 0) { @@ -6018,6 +6114,13 @@ _bfd_elf_slurp_version_tables (bfd *abfd) ((bfd_byte *) everdef + iverdefmem.vd_next)); } + if (default_imported_symver) + { + if (freeidx > maxidx) + maxidx = ++freeidx; + else + freeidx = ++maxidx; + } amt = (bfd_size_type) maxidx * sizeof (Elf_Internal_Verdef); elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt); if (elf_tdata (abfd)->verdef == NULL) @@ -6081,85 +6184,46 @@ _bfd_elf_slurp_version_tables (bfd *abfd) free (contents); contents = NULL; } - - if (elf_dynverref (abfd) != 0) + else if (default_imported_symver) { - Elf_Internal_Shdr *hdr; - Elf_External_Verneed *everneed; - Elf_Internal_Verneed *iverneed; - unsigned int i; - - 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); - if (elf_tdata (abfd)->verref == NULL) - goto error_return; - - elf_tdata (abfd)->cverrefs = hdr->sh_info; + if (freeidx < 3) + freeidx = 3; + else + freeidx++; - contents = bfd_malloc (hdr->sh_size); - if (contents == NULL) - goto error_return; - if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 - || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) + amt = (bfd_size_type) freeidx * sizeof (Elf_Internal_Verdef); + elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt); + if (elf_tdata (abfd)->verdef == NULL) goto error_return; - everneed = (Elf_External_Verneed *) contents; - iverneed = elf_tdata (abfd)->verref; - for (i = 0; i < hdr->sh_info; i++, iverneed++) - { - Elf_External_Vernaux *evernaux; - Elf_Internal_Vernaux *ivernaux; - unsigned int j; - - _bfd_elf_swap_verneed_in (abfd, everneed, iverneed); - - iverneed->vn_bfd = abfd; - - iverneed->vn_filename = - bfd_elf_string_from_elf_section (abfd, hdr->sh_link, - iverneed->vn_file); - if (iverneed->vn_filename == NULL) - goto error_return; - - amt = iverneed->vn_cnt; - amt *= sizeof (Elf_Internal_Vernaux); - iverneed->vn_auxptr = bfd_alloc (abfd, amt); - - evernaux = ((Elf_External_Vernaux *) - ((bfd_byte *) everneed + iverneed->vn_aux)); - ivernaux = iverneed->vn_auxptr; - for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++) - { - _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux); + elf_tdata (abfd)->cverdefs = freeidx; + } - ivernaux->vna_nodename = - bfd_elf_string_from_elf_section (abfd, hdr->sh_link, - ivernaux->vna_name); - if (ivernaux->vna_nodename == NULL) - goto error_return; + /* Create a default version based on the soname. */ + if (default_imported_symver) + { + Elf_Internal_Verdef *iverdef; + Elf_Internal_Verdaux *iverdaux; - if (j + 1 < iverneed->vn_cnt) - ivernaux->vna_nextptr = ivernaux + 1; - else - ivernaux->vna_nextptr = NULL; + iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];; - evernaux = ((Elf_External_Vernaux *) - ((bfd_byte *) evernaux + ivernaux->vna_next)); - } + iverdef->vd_version = VER_DEF_CURRENT; + iverdef->vd_flags = 0; + iverdef->vd_ndx = freeidx; + iverdef->vd_cnt = 1; - if (i + 1 < hdr->sh_info) - iverneed->vn_nextref = iverneed + 1; - else - iverneed->vn_nextref = NULL; + iverdef->vd_bfd = abfd; - everneed = ((Elf_External_Verneed *) - ((bfd_byte *) everneed + iverneed->vn_next)); - } + iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd); + if (iverdef->vd_nodename == NULL) + goto error_return; + iverdef->vd_nextdef = NULL; + amt = (bfd_size_type) sizeof (Elf_Internal_Verdaux); + iverdef->vd_auxptr = bfd_alloc (abfd, amt); - free (contents); - contents = NULL; + iverdaux = iverdef->vd_auxptr; + iverdaux->vda_nodename = iverdef->vd_nodename; + iverdaux->vda_nextptr = NULL; } return TRUE; @@ -6258,13 +6322,24 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, const char **functionname_ptr) { const char *filename; - asymbol *func; + asymbol *func, *file; bfd_vma low_func; asymbol **p; + /* ??? Given multiple file symbols, it is impossible to reliably + choose the right file name for global symbols. File symbols are + local symbols, and thus all file symbols must sort before any + global symbols. The ELF spec may be interpreted to say that a + file symbol must sort before other local symbols, but currently + ld -r doesn't do this. So, for ld -r output, it is possible to + 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; filename = NULL; func = NULL; + file = NULL; low_func = 0; + state = nothing_seen; for (p = symbols; *p != NULL; p++) { @@ -6272,27 +6347,37 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, q = (elf_symbol_type *) *p; - if (bfd_get_section (&q->symbol) != section) - continue; - switch (ELF_ST_TYPE (q->internal_elf_sym.st_info)) { default: break; case STT_FILE: - filename = bfd_asymbol_name (&q->symbol); - break; + file = &q->symbol; + if (state == symbol_seen) + state = file_after_symbol_seen; + continue; + case STT_SECTION: + continue; case STT_NOTYPE: case STT_FUNC: - if (q->symbol.section == section + if (bfd_get_section (&q->symbol) == section && q->symbol.value >= low_func && q->symbol.value <= offset) { 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 = bfd_asymbol_name (file); } break; } + if (state == nothing_seen) + state = symbol_seen; } if (func == NULL) @@ -7238,14 +7323,17 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid) } static bfd_boolean -elfcore_grok_nto_gregs (bfd *abfd, Elf_Internal_Note *note, pid_t tid) +elfcore_grok_nto_regs (bfd *abfd, + Elf_Internal_Note *note, + pid_t tid, + char *base) { char buf[100]; char *name; asection *sect; - /* Make a ".reg/%d" section. */ - sprintf (buf, ".reg/%d", tid); + /* Make a "(base)/%d" section. */ + sprintf (buf, "%s/%d", base, tid); name = bfd_alloc (abfd, strlen (buf) + 1); if (name == NULL) @@ -7263,7 +7351,7 @@ elfcore_grok_nto_gregs (bfd *abfd, Elf_Internal_Note *note, pid_t tid) /* This is the current thread. */ if (elf_tdata (abfd)->core_lwpid == tid) - return elfcore_maybe_make_sect (abfd, ".reg", sect); + return elfcore_maybe_make_sect (abfd, base, sect); return TRUE; } @@ -7283,11 +7371,16 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note) switch (note->type) { - case BFD_QNT_CORE_INFO: return elfcore_make_note_pseudosection (abfd, ".qnx_core_info", note); - case BFD_QNT_CORE_STATUS: return elfcore_grok_nto_status (abfd, note, &tid); - case BFD_QNT_CORE_GREG: return elfcore_grok_nto_gregs (abfd, note, tid); - case BFD_QNT_CORE_FPREG: return elfcore_grok_prfpreg (abfd, note); - default: return TRUE; + case BFD_QNT_CORE_INFO: + return elfcore_make_note_pseudosection (abfd, ".qnx_core_info", note); + case BFD_QNT_CORE_STATUS: + return elfcore_grok_nto_status (abfd, note, &tid); + case BFD_QNT_CORE_GREG: + return elfcore_grok_nto_regs (abfd, note, tid, ".reg"); + case BFD_QNT_CORE_FPREG: + return elfcore_grok_nto_regs (abfd, note, tid, ".reg2"); + default: + return TRUE; } } @@ -7703,7 +7796,7 @@ _bfd_elf_rel_local_sym (bfd *abfd, bfd_vma _bfd_elf_section_offset (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct bfd_link_info *info, asection *sec, bfd_vma offset) { @@ -7713,7 +7806,7 @@ _bfd_elf_section_offset (bfd *abfd, return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info, offset); case ELF_INFO_TYPE_EH_FRAME: - return _bfd_elf_eh_frame_section_offset (abfd, sec, offset); + return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset); default: return offset; } @@ -7744,7 +7837,12 @@ bfd_elf_bfd_from_remote_memory } long -_bfd_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret) +_bfd_elf_get_synthetic_symtab (bfd *abfd, + long symcount ATTRIBUTE_UNUSED, + asymbol **syms ATTRIBUTE_UNUSED, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) { const struct elf_backend_data *bed = get_elf_backend_data (abfd); asection *relplt; @@ -7758,10 +7856,14 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret) char *names; asection *plt; + *ret = NULL; + if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) return 0; - *ret = NULL; + if (dynsymcount <= 0) + return 0; + if (!bed->plt_sym_val) return 0; @@ -7782,7 +7884,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret) return 0; slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; - if (! (*slurp_relocs) (abfd, relplt, relsyms, TRUE)) + if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) return -1; count = relplt->size / hdr->sh_entsize;