X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gold%2Foutput.cc;h=428a880b147f4c47e348a5343e777bfbbfd5cbd4;hb=cedfc77485dbb566619dc1e2d729ce0a70d1a4ad;hp=f34a7d82573e7aab10e56912d46c44693a8fb3d4;hpb=cfbf0e3c5b637d66b2b1aeadecae9c187b825b2f;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/output.cc b/gold/output.cc index f34a7d8257..428a880b14 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1,6 +1,6 @@ // output.cc -- manage the output file for gold -// Copyright (C) 2006-2015 Free Software Foundation, Inc. +// Copyright (C) 2006-2019 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -127,14 +127,26 @@ namespace gold static int gold_fallocate(int o, off_t offset, off_t len) { + if (len <= 0) + return 0; + #ifdef HAVE_POSIX_FALLOCATE if (parameters->options().posix_fallocate()) - return ::posix_fallocate(o, offset, len); + { + int err = ::posix_fallocate(o, offset, len); + if (err != EINVAL && err != ENOSYS && err != EOPNOTSUPP) + return err; + } #endif // defined(HAVE_POSIX_FALLOCATE) + #ifdef HAVE_FALLOCATE - if (::fallocate(o, 0, offset, len) == 0) - return 0; + { + int err = ::fallocate(o, 0, offset, len); + if (err != EINVAL && err != ENOSYS && err != EOPNOTSUPP) + return err; + } #endif // defined(HAVE_FALLOCATE) + if (::ftruncate(o, offset + len) < 0) return errno; return 0; @@ -1252,6 +1264,19 @@ Output_data_reloc_base os->set_should_link_to_dynsym(); } +// Standard relocation writer, which just calls Output_reloc::write(). + +template +struct Output_reloc_writer +{ + typedef Output_reloc Output_reloc_type; + typedef std::vector Relocs; + + static void + write(typename Relocs::const_iterator p, unsigned char* pov) + { p->write(pov); } +}; + // Write out relocation data. template @@ -1259,32 +1284,8 @@ void Output_data_reloc_base::do_write( Output_file* of) { - const off_t off = this->offset(); - const off_t oview_size = this->data_size(); - unsigned char* const oview = of->get_output_view(off, oview_size); - - if (this->sort_relocs()) - { - gold_assert(dynamic); - std::sort(this->relocs_.begin(), this->relocs_.end(), - Sort_relocs_comparison()); - } - - unsigned char* pov = oview; - for (typename Relocs::const_iterator p = this->relocs_.begin(); - p != this->relocs_.end(); - ++p) - { - p->write(pov); - pov += reloc_size; - } - - gold_assert(pov - oview == oview_size); - - of->write_output_view(off, oview_size, oview); - - // We no longer need the relocation entries. - this->relocs_.clear(); + typedef Output_reloc_writer Writer; + this->do_write_generic(of); } // Class Output_relocatable_relocs. @@ -1437,7 +1438,7 @@ Output_data_got::Got_entry::write( val = parameters->target().plt_address_for_local(object, lsi); else { - uint64_t lval = object->local_symbol_value(lsi, 0); + uint64_t lval = object->local_symbol_value(lsi, this->addend_); val = convert_types(lval); if (this->use_plt_or_tls_offset_ && is_tls) val += parameters->target().tls_offset_for_local(object, lsi, @@ -1548,6 +1549,27 @@ Output_data_got::add_local( return true; } +// Add an entry for a local symbol plus ADDEND to the GOT. This returns +// true if this is a new GOT entry, false if the symbol already has a GOT +// entry. + +template +bool +Output_data_got::add_local( + Relobj* object, + unsigned int symndx, + unsigned int got_type, + uint64_t addend) +{ + if (object->local_has_got_offset(symndx, got_type, addend)) + return false; + + unsigned int got_offset = this->add_got_entry(Got_entry(object, symndx, + false, addend)); + object->set_local_got_offset(symndx, got_type, got_offset, addend); + return true; +} + // Like add_local, but use the PLT offset. template @@ -1586,6 +1608,27 @@ Output_data_got::add_local_with_rel( rel_dyn->add_local_generic(object, symndx, r_type, this, got_offset, 0); } +// Add an entry for a local symbol plus ADDEND to the GOT, and add a dynamic +// relocation of type R_TYPE for the GOT entry. + +template +void +Output_data_got::add_local_with_rel( + Relobj* object, + unsigned int symndx, + unsigned int got_type, + Output_data_reloc_generic* rel_dyn, + unsigned int r_type, uint64_t addend) +{ + if (object->local_has_got_offset(symndx, got_type, addend)) + return; + + unsigned int got_offset = this->add_got_entry(Got_entry()); + object->set_local_got_offset(symndx, got_type, got_offset, addend); + rel_dyn->add_local_generic(object, symndx, r_type, this, got_offset, + addend); +} + // Add a pair of entries for a local symbol to the GOT, and add // a dynamic relocation of type R_TYPE using the section symbol of // the output section to which input section SHNDX maps, on the first. @@ -1612,6 +1655,32 @@ Output_data_got::add_local_pair_with_rel( rel_dyn->add_output_section_generic(os, r_type, this, got_offset, 0); } +// Add a pair of entries for a local symbol plus ADDEND to the GOT, and add +// a dynamic relocation of type R_TYPE using the section symbol of +// the output section to which input section SHNDX maps, on the first. +// The first got entry will have a value of zero, the second the +// value of the local symbol. +template +void +Output_data_got::add_local_pair_with_rel( + Relobj* object, + unsigned int symndx, + unsigned int shndx, + unsigned int got_type, + Output_data_reloc_generic* rel_dyn, + unsigned int r_type, uint64_t addend) +{ + if (object->local_has_got_offset(symndx, got_type, addend)) + return; + + unsigned int got_offset = + this->add_got_entry_pair(Got_entry(), + Got_entry(object, symndx, false, addend)); + object->set_local_got_offset(symndx, got_type, got_offset, addend); + Output_section* os = object->output_section(shndx); + rel_dyn->add_output_section_generic(os, r_type, this, got_offset, addend); +} + // Add a pair of entries for a local symbol to the GOT, and add // a dynamic relocation of type R_TYPE using STN_UNDEF on the first. // The first got entry will have a value of zero, the second the @@ -1825,6 +1894,27 @@ Output_data_dynamic::do_adjust_output_section(Output_section* os) gold_unreachable(); } +// Get a dynamic entry offset. + +unsigned int +Output_data_dynamic::get_entry_offset(elfcpp::DT tag) const +{ + int dyn_size; + + if (parameters->target().get_size() == 32) + dyn_size = elfcpp::Elf_sizes<32>::dyn_size; + else if (parameters->target().get_size() == 64) + dyn_size = elfcpp::Elf_sizes<64>::dyn_size; + else + gold_unreachable(); + + for (size_t i = 0; i < entries_.size(); ++i) + if (entries_[i].tag() == tag) + return i * dyn_size; + + return -1U; +} + // Set the final data size. void @@ -2305,7 +2395,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, lookup_maps_(new Output_section_lookup_maps), free_list_(), free_space_fill_(NULL), - patch_space_(0) + patch_space_(0), + reloc_section_(NULL) { // An unallocated section has no address. Forcing this means that // we don't need special treatment for symbols defined in debug @@ -2357,7 +2448,13 @@ Output_section::add_input_section(Layout* layout, unsigned int reloc_shndx, bool have_sections_script) { + section_size_type input_section_size = shdr.get_sh_size(); + section_size_type uncompressed_size; elfcpp::Elf_Xword addralign = shdr.get_sh_addralign(); + if (object->section_is_compressed(shndx, &uncompressed_size, + &addralign)) + input_section_size = uncompressed_size; + if ((addralign & (addralign - 1)) != 0) { object->error(_("invalid alignment %lu for section \"%s\""), @@ -2407,11 +2504,6 @@ Output_section::add_input_section(Layout* layout, } } - section_size_type input_section_size = shdr.get_sh_size(); - section_size_type uncompressed_size; - if (object->section_is_compressed(shndx, &uncompressed_size)) - input_section_size = uncompressed_size; - off_t offset_in_section; if (this->has_fixed_layout()) @@ -3087,17 +3179,17 @@ Output_section::set_final_data_size() uint64_t address = this->address(); off_t startoff = this->offset(); - off_t off = startoff + this->first_input_offset_; + off_t off = this->first_input_offset_; for (Input_section_list::iterator p = this->input_sections_.begin(); p != this->input_sections_.end(); ++p) { off = align_address(off, p->addralign()); - p->set_address_and_file_offset(address + (off - startoff), off, + p->set_address_and_file_offset(address + off, startoff + off, startoff); off += p->data_size(); } - data_size = off - startoff; + data_size = off; } // For full incremental links, we want to allocate some patch space @@ -3455,8 +3547,10 @@ Output_section::Input_section_sort_section_prefix_special_ordering_compare const Output_section::Input_section_sort_entry& s2) const { // Some input section names have special ordering requirements. - int o1 = Layout::special_ordering_of_input_section(s1.section_name().c_str()); - int o2 = Layout::special_ordering_of_input_section(s2.section_name().c_str()); + const char *s1_section_name = s1.section_name().c_str(); + const char *s2_section_name = s2.section_name().c_str(); + int o1 = Layout::special_ordering_of_input_section(s1_section_name); + int o2 = Layout::special_ordering_of_input_section(s2_section_name); if (o1 != o2) { if (o1 < 0) @@ -3466,6 +3560,8 @@ Output_section::Input_section_sort_section_prefix_special_ordering_compare else return o1 < o2; } + else if (is_prefix_of(".text.sorted", s1_section_name)) + return strcmp(s1_section_name, s2_section_name) <= 0; // Keep input order otherwise. return s1.index() < s2.index(); @@ -3503,7 +3599,7 @@ Output_section::update_section_layout( if (p->is_input_section() || p->is_relaxed_input_section()) { - Object* obj = (p->is_input_section() + Relobj* obj = (p->is_input_section() ? p->relobj() : p->relaxed_input_section()->relobj()); unsigned int shndx = p->shndx(); @@ -4320,12 +4416,14 @@ Output_segment::set_section_addresses(const Target* target, this->offset_ = orig_off; off_t off = 0; - uint64_t ret; + off_t foff = *poff; + uint64_t ret = 0; for (int i = 0; i < static_cast(ORDER_MAX); ++i) { if (i == static_cast(ORDER_RELRO_LAST)) { *poff += last_relro_pad; + foff += last_relro_pad; addr += last_relro_pad; if (this->output_lists_[i].empty()) { @@ -4337,12 +4435,20 @@ Output_segment::set_section_addresses(const Target* target, } addr = this->set_section_list_addresses(layout, reset, &this->output_lists_[i], - addr, poff, pshndx, &in_tls); - if (i < static_cast(ORDER_SMALL_BSS)) - { - this->filesz_ = *poff - orig_off; - off = *poff; - } + addr, poff, &foff, pshndx, + &in_tls); + + // FOFF tracks the last offset used for the file image, + // and *POFF tracks the last offset used for the memory image. + // When not using a linker script, bss sections should all + // be processed in the ORDER_SMALL_BSS and later buckets. + gold_assert(*poff == foff + || i == static_cast(ORDER_TLS_BSS) + || i >= static_cast(ORDER_SMALL_BSS) + || layout->script_options()->saw_sections_clause()); + + this->filesz_ = foff - orig_off; + off = foff; ret = addr; } @@ -4407,6 +4513,7 @@ uint64_t Output_segment::set_section_list_addresses(Layout* layout, bool reset, Output_data_list* pdl, uint64_t addr, off_t* poff, + off_t* pfoff, unsigned int* pshndx, bool* in_tls) { @@ -4416,10 +4523,14 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, off_t maxoff = startoff; off_t off = startoff; + off_t foff = *pfoff; for (Output_data_list::iterator p = pdl->begin(); p != pdl->end(); ++p) { + bool is_bss = (*p)->is_section_type(elfcpp::SHT_NOBITS); + bool is_tls = (*p)->is_section_flag_set(elfcpp::SHF_TLS); + if (reset) (*p)->reset_address_and_file_offset(); @@ -4429,7 +4540,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, { uint64_t align = (*p)->addralign(); - if ((*p)->is_section_flag_set(elfcpp::SHF_TLS)) + if (is_tls) { // Give the first TLS section the alignment of the // entire TLS segment. Otherwise the TLS segment as a @@ -4464,8 +4575,11 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, if (!parameters->incremental_update()) { + gold_assert(off == foff || is_bss); off = align_address(off, align); - (*p)->set_address_and_file_offset(addr + (off - startoff), off); + if (is_tls || !is_bss) + foff = off; + (*p)->set_address_and_file_offset(addr + (off - startoff), foff); } else { @@ -4473,6 +4587,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, (*p)->pre_finalize_data_size(); off_t current_size = (*p)->current_data_size(); off = layout->allocate(current_size, align, startoff); + foff = off; if (off == -1) { gold_assert((*p)->output_section() != NULL); @@ -4480,7 +4595,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, "relink with --incremental-full"), (*p)->output_section()->name()); } - (*p)->set_address_and_file_offset(addr + (off - startoff), off); + (*p)->set_address_and_file_offset(addr + (off - startoff), foff); if ((*p)->data_size() > current_size) { gold_assert((*p)->output_section() != NULL); @@ -4495,13 +4610,22 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, // For incremental updates, use the fixed offset for the // high-water mark computation. off = (*p)->offset(); + foff = off; } else { // The script may have inserted a skip forward, but it // better not have moved backward. if ((*p)->address() >= addr + (off - startoff)) - off += (*p)->address() - (addr + (off - startoff)); + { + if (!is_bss && off > foff) + gold_warning(_("script places BSS section in the middle " + "of a LOAD segment; space will be allocated " + "in the file")); + off += (*p)->address() - (addr + (off - startoff)); + if (is_tls || !is_bss) + foff = off; + } else { if (!layout->script_options()->saw_sections_clause()) @@ -4525,7 +4649,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, os->name(), previous_dot, dot); } } - (*p)->set_file_offset(off); + (*p)->set_file_offset(foff); (*p)->finalize_data_size(); } @@ -4540,10 +4664,14 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, // We want to ignore the size of a SHF_TLS SHT_NOBITS // section. Such a section does not affect the size of a // PT_LOAD segment. - if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS) - || !(*p)->is_section_type(elfcpp::SHT_NOBITS)) + if (!is_tls || !is_bss) off += (*p)->data_size(); + // We don't allocate space in the file for SHT_NOBITS sections, + // unless a script has force-placed one in the middle of a segment. + if (!is_bss) + foff = off; + if (off > maxoff) maxoff = off; @@ -4555,6 +4683,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, } *poff = maxoff; + *pfoff = foff; return addr + (maxoff - startoff); } @@ -4690,7 +4819,7 @@ Output_segment::first_section() const return (*p)->output_section(); } } - gold_unreachable(); + return NULL; } // Return the number of Output_sections in an Output_segment.