diff options
Diffstat (limited to 'bfd/elf.c')
-rw-r--r-- | bfd/elf.c | 272 |
1 files changed, 131 insertions, 141 deletions
@@ -1391,14 +1391,23 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, /* Set local fields. */ ret->indx = -1; ret->dynindx = -1; - ret->got = ret->plt = htab->init_refcount; - memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry) - - offsetof (struct elf_link_hash_entry, size))); + 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; /* 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->non_elf = 1; + ret->elf_link_hash_flags = ELF_LINK_NON_ELF; } return entry; @@ -1418,12 +1427,13 @@ _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->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; + 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); if (ind->root.type != bfd_link_hash_indirect) return; @@ -1465,10 +1475,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->needs_plt = 0; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; if (force_local) { - h->forced_local = 1; + h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL; if (h->dynindx != -1) { h->dynindx = -1; @@ -1739,7 +1749,6 @@ 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. */ @@ -2133,8 +2142,6 @@ 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 } }; @@ -2972,17 +2979,6 @@ 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 @@ -3880,8 +3876,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (alloc != 0 && count > alloc) { ((*_bfd_error_handler) - (_("%B: Not enough room for program headers (allocated %u, need %u)"), - abfd, alloc, count)); + (_("%s: Not enough room for program headers (allocated %u, need %u)"), + bfd_get_filename (abfd), alloc, count)); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -3920,63 +3916,32 @@ 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->count > 0 + && (m->sections[0]->flags & SEC_ALLOC) != 0) { - bfd_size_type align; - bfd_vma adjust; - if ((abfd->flags & D_PAGED) != 0) - align = bed->maxpagesize; + off += vma_page_aligned_bias (m->sections[0]->vma, off, + bed->maxpagesize); else { - unsigned int align_power = 0; + bfd_size_type align; + + align = 0; for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { - unsigned int secalign; + bfd_size_type secalign; secalign = bfd_get_section_alignment (abfd, *secpp); - if (secalign > align_power) - align_power = secalign; + if (secalign > align) + align = secalign; } - align = (bfd_size_type) 1 << align_power; - } - 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; - } - } + off += vma_page_aligned_bias (m->sections[0]->vma, off, + 1 << align); } } /* Make sure the .dynamic section is the first section in the @@ -3986,8 +3951,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) && strcmp (m->sections[0]->name, ".dynamic") != 0) { _bfd_error_handler - (_("%B: The first section in the PT_DYNAMIC segment is not the .dynamic section"), - abfd); + (_("%s: The first section in the PT_DYNAMIC segment is not the .dynamic section"), + bfd_get_filename (abfd)); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -4030,8 +3995,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (p->p_vaddr < (bfd_vma) off) { (*_bfd_error_handler) - (_("%B: Not enough room for program headers, try linking with -N"), - abfd); + (_("%s: Not enough room for program headers, try linking with -N"), + bfd_get_filename (abfd)); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -4089,7 +4054,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 + voff; + p->p_offset = off; else { file_ptr adjust; @@ -4100,6 +4065,8 @@ 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; @@ -4110,97 +4077,117 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) flags = sec->flags; align = 1 << bfd_get_section_alignment (abfd, sec); - if (p->p_type == PT_LOAD - || p->p_type == PT_TLS) + /* 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) { bfd_signed_vma adjust; if ((flags & SEC_LOAD) != 0) { - adjust = sec->lma - (p->p_paddr + p->p_filesz); + adjust = sec->lma - (p->p_paddr + p->p_memsz); if (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; + adjust = 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) + else if ((flags & SEC_ALLOC) != 0) { /* The section VMA must equal the file position - modulo the page size. */ - bfd_size_type page = align; + modulo the page size. FIXME: I'm not sure if + this adjustment is really necessary. We used to + not have the SEC_LOAD case just above, and then + this was necessary, but now I'm not sure. */ if ((abfd->flags & D_PAGED) != 0) - page = bed->maxpagesize; - adjust = vma_page_aligned_bias (sec->vma, - p->p_vaddr + p->p_memsz, - page); + 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; + } 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 section at i == 0 is the one that actually contains - everything. */ + /* The actual "note" segment has i == 0. + This is the one that actually contains everything. */ if (i == 0) { sec->filepos = off; - off += sec->size; p->p_filesz = sec->size; - p->p_memsz = 0; - p->p_align = 1; + off += sec->size; + voff = off; } else { - /* The rest are fake sections that shouldn't be written. */ + /* Fake sections -- don't need to be written. */ sec->filepos = 0; sec->size = 0; - sec->flags = 0; - continue; + flags = sec->flags = 0; } + p->p_memsz = 0; + p->p_align = 1; } else { - 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 ((sec->flags & SEC_LOAD) != 0 + || (sec->flags & SEC_THREAD_LOCAL) == 0 + || p->p_type == PT_TLS) + p->p_memsz += sec->size; if ((flags & SEC_LOAD) != 0) - { - 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; + p->p_filesz += sec->size; if (p->p_type == PT_TLS && sec->size == 0 @@ -4516,8 +4503,8 @@ assign_file_positions_except_relocs (bfd *abfd, else if ((hdr->sh_flags & SHF_ALLOC) != 0) { ((*_bfd_error_handler) - (_("%B: warning: allocated section `%s' not in segment"), - abfd, + (_("%s: warning: allocated section `%s' not in segment"), + bfd_get_filename (abfd), (hdr->bfd_section == NULL ? "*unknown*" : hdr->bfd_section->name))); @@ -6318,6 +6305,9 @@ 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: @@ -6327,7 +6317,7 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, break; case STT_NOTYPE: case STT_FUNC: - if (bfd_get_section (&q->symbol) == section + if (q->symbol.section == section && q->symbol.value >= low_func && q->symbol.value <= offset) { @@ -7746,7 +7736,7 @@ _bfd_elf_rel_local_sym (bfd *abfd, bfd_vma _bfd_elf_section_offset (bfd *abfd, - struct bfd_link_info *info, + struct bfd_link_info *info ATTRIBUTE_UNUSED, asection *sec, bfd_vma offset) { @@ -7756,7 +7746,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, info, sec, offset); + return _bfd_elf_eh_frame_section_offset (abfd, sec, offset); default: return offset; } |