diff options
Diffstat (limited to 'gold/output.cc')
-rw-r--r-- | gold/output.cc | 155 |
1 files changed, 141 insertions, 14 deletions
diff --git a/gold/output.cc b/gold/output.cc index f0d7985..2a7400d 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -12,6 +12,7 @@ #include "object.h" #include "symtab.h" #include "reloc.h" +#include "merge.h" #include "output.h" namespace gold @@ -790,9 +791,9 @@ off_t Output_section::Input_section::data_size() const { if (this->is_input_section()) - return this->data_size_; + return this->u1_.data_size; else - return this->u_.posd->data_size(); + return this->u2_.posd->data_size(); } // Set the address and file offset. @@ -802,9 +803,33 @@ Output_section::Input_section::set_address(uint64_t addr, off_t off, off_t secoff) { if (this->is_input_section()) - this->u_.object->set_section_offset(this->shndx_, off - secoff); + this->u2_.object->set_section_offset(this->shndx_, off - secoff); else - this->u_.posd->set_address(addr, off); + this->u2_.posd->set_address(addr, off); +} + +// Try to turn an input address into an output address. + +bool +Output_section::Input_section::output_address(const Relobj* object, + unsigned int shndx, + off_t offset, + uint64_t output_section_address, + uint64_t *poutput) const +{ + if (!this->is_input_section()) + return this->u2_.posd->output_address(object, shndx, offset, + output_section_address, poutput); + else + { + if (this->u2_.object != object) + return false; + off_t output_offset; + Output_section* os = object->output_section(shndx, &output_offset); + gold_assert(os != NULL); + *poutput = output_section_address + output_offset + offset; + return true; + } } // Write out the data. We don't have to do anything for an input @@ -815,7 +840,7 @@ void Output_section::Input_section::write(Output_file* of) { if (!this->is_input_section()) - this->u_.posd->write(of); + this->u2_.posd->write(of); } // Output_section methods. @@ -823,7 +848,7 @@ Output_section::Input_section::write(Output_file* of) // Construct an Output_section. NAME will point into a Stringpool. Output_section::Output_section(const char* name, elfcpp::Elf_Word type, - elfcpp::Elf_Xword flags, bool may_add_data) + elfcpp::Elf_Xword flags) : name_(name), addralign_(0), entsize_(0), @@ -838,7 +863,6 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, dynsym_index_(0), input_sections_(), first_input_offset_(0), - may_add_data_(may_add_data), needs_symtab_index_(false), needs_dynsym_index_(false), should_link_to_symtab_(false), @@ -873,8 +897,6 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx, const char* secname, const elfcpp::Shdr<size, big_endian>& shdr) { - gold_assert(this->may_add_data_); - elfcpp::Elf_Xword addralign = shdr.get_sh_addralign(); if ((addralign & (addralign - 1)) != 0) { @@ -887,6 +909,20 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx, if (addralign > this->addralign_) this->addralign_ = addralign; + // If this is a SHF_MERGE section, we pass all the input sections to + // a Output_data_merge. + if ((shdr.get_sh_flags() & elfcpp::SHF_MERGE) != 0) + { + if (this->add_merge_input_section(object, shndx, shdr.get_sh_flags(), + shdr.get_sh_entsize(), + addralign)) + { + // Tell the relocation routines that they need to call the + // output_address method to determine the final address. + return -1; + } + } + off_t ssize = this->data_size(); ssize = align_address(ssize, addralign); this->set_data_size(ssize + shdr.get_sh_size()); @@ -907,18 +943,107 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx, void Output_section::add_output_section_data(Output_section_data* posd) { - gold_assert(this->may_add_data_); + Input_section inp(posd); + this->add_output_section_data(&inp); +} + +// Add arbitrary data to an output section by Input_section. +void +Output_section::add_output_section_data(Input_section* inp) +{ if (this->input_sections_.empty()) this->first_input_offset_ = this->data_size(); - this->input_sections_.push_back(Input_section(posd)); + this->input_sections_.push_back(*inp); - uint64_t addralign = posd->addralign(); + uint64_t addralign = inp->addralign(); if (addralign > this->addralign_) this->addralign_ = addralign; - posd->set_output_section(this); + inp->set_output_section(this); +} + +// Add a merge section to an output section. + +void +Output_section::add_output_merge_section(Output_section_data* posd, + bool is_string, uint64_t entsize) +{ + Input_section inp(posd, is_string, entsize); + this->add_output_section_data(&inp); +} + +// Add an input section to a SHF_MERGE section. + +bool +Output_section::add_merge_input_section(Relobj* object, unsigned int shndx, + uint64_t flags, uint64_t entsize, + uint64_t addralign) +{ + // We only merge constants if the alignment is not more than the + // entry size. This could be handled, but it's unusual. + if (addralign > entsize) + return false; + + bool is_string = (flags & elfcpp::SHF_STRINGS) != 0; + Input_section_list::iterator p; + for (p = this->input_sections_.begin(); + p != this->input_sections_.end(); + ++p) + if (p->is_merge_section(is_string, entsize)) + break; + + // We handle the actual constant merging in Output_merge_data or + // Output_merge_string_data. + if (p != this->input_sections_.end()) + p->add_input_section(object, shndx); + else + { + Output_section_data* posd; + if (!is_string) + posd = new Output_merge_data(entsize); + else if (entsize == 1) + posd = new Output_merge_string<char>(); + else if (entsize == 2) + posd = new Output_merge_string<uint16_t>(); + else if (entsize == 4) + posd = new Output_merge_string<uint32_t>(); + else + return false; + + this->add_output_merge_section(posd, is_string, entsize); + posd->add_input_section(object, shndx); + } + + return true; +} + +// Return the output virtual address of OFFSET relative to the start +// of input section SHNDX in object OBJECT. + +uint64_t +Output_section::output_address(const Relobj* object, unsigned int shndx, + off_t offset) const +{ + uint64_t addr = this->address() + this->first_input_offset_; + for (Input_section_list::const_iterator p = this->input_sections_.begin(); + p != this->input_sections_.end(); + ++p) + { + addr = align_address(addr, p->addralign()); + uint64_t output; + if (p->output_address(object, shndx, offset, addr, &output)) + return output; + addr += p->data_size(); + } + + // If we get here, it means that we don't know the mapping for this + // input section. This might happen in principle if + // add_input_section were called before add_output_section_data. + // But it should never actually happen. + + gold_unreachable(); } // Set the address of an Output_section. This is where we handle @@ -1189,7 +1314,8 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff, return ret; } -// Set the addresses in a list of Output_data structures. +// Set the addresses and file offsets in a list of Output_data +// structures. uint64_t Output_segment::set_section_list_addresses(Output_data_list* pdl, @@ -1541,3 +1667,4 @@ template class Output_data_got<64, true>; } // End namespace gold. + |