diff options
Diffstat (limited to 'gold/output.cc')
-rw-r--r-- | gold/output.cc | 65 |
1 files changed, 49 insertions, 16 deletions
diff --git a/gold/output.cc b/gold/output.cc index 8e043d7..cf934fb 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -3165,17 +3165,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 @@ -4398,12 +4398,14 @@ Output_segment::set_section_addresses(const Target* target, this->offset_ = orig_off; off_t off = 0; + off_t foff = *poff; uint64_t ret = 0; for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i) { if (i == static_cast<int>(ORDER_RELRO_LAST)) { *poff += last_relro_pad; + foff += last_relro_pad; addr += last_relro_pad; if (this->output_lists_[i].empty()) { @@ -4415,12 +4417,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<int>(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<int>(ORDER_TLS_BSS) + || i >= static_cast<int>(ORDER_SMALL_BSS) + || layout->script_options()->saw_sections_clause()); + + this->filesz_ = foff - orig_off; + off = foff; ret = addr; } @@ -4485,6 +4495,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) { @@ -4494,10 +4505,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(); @@ -4507,7 +4522,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 @@ -4542,8 +4557,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 { @@ -4551,6 +4569,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); @@ -4558,7 +4577,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); @@ -4573,13 +4592,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()) @@ -4603,7 +4631,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(); } @@ -4618,10 +4646,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; @@ -4633,6 +4665,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, } *poff = maxoff; + *pfoff = foff; return addr + (maxoff - startoff); } |