diff options
Diffstat (limited to 'gold/arm.cc')
-rw-r--r-- | gold/arm.cc | 283 |
1 files changed, 187 insertions, 96 deletions
diff --git a/gold/arm.cc b/gold/arm.cc index 6556828..69a21c0 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1104,6 +1104,10 @@ class Arm_exidx_merged_section : public Output_relaxed_input_section const Arm_exidx_section_offset_map& section_offset_map, uint32_t deleted_bytes); + // Build output contents. + void + build_contents(const unsigned char*, section_size_type); + // Return the original EXIDX input section. const Arm_exidx_input_section& exidx_input_section() const @@ -1128,6 +1132,10 @@ class Arm_exidx_merged_section : public Output_relaxed_input_section const Arm_exidx_input_section& exidx_input_section_; // Section offset map. const Arm_exidx_section_offset_map& section_offset_map_; + // Merged section contents. We need to keep build the merged section + // and save it here to avoid accessing the original EXIDX section when + // we cannot lock the sections' object. + unsigned char* section_contents_; }; // A class to wrap an ordinary input section containing executable code. @@ -1138,11 +1146,12 @@ class Arm_input_section : public Output_relaxed_input_section public: Arm_input_section(Relobj* relobj, unsigned int shndx) : Output_relaxed_input_section(relobj, shndx, 1), - original_addralign_(1), original_size_(0), stub_table_(NULL) + original_addralign_(1), original_size_(0), stub_table_(NULL), + original_contents_(NULL) { } ~Arm_input_section() - { } + { delete[] this->original_contents_; } // Initialize. void @@ -1228,6 +1237,10 @@ class Arm_input_section : public Output_relaxed_input_section uint32_t original_size_; // Stub table. Stub_table<big_endian>* stub_table_; + // Original section contents. We have to make a copy here since the file + // containing the original section may not be locked when we need to access + // the contents. + unsigned char* original_contents_; }; // Arm_exidx_fixup class. This is used to define a number of methods @@ -1247,14 +1260,17 @@ class Arm_exidx_fixup ~Arm_exidx_fixup() { delete this->section_offset_map_; } - // Process an EXIDX section for entry merging. Return number of bytes to - // be deleted in output. If parts of the input EXIDX section are merged - // a heap allocated Arm_exidx_section_offset_map is store in the located - // PSECTION_OFFSET_MAP. The caller owns the map and is reponsible for - // releasing it. + // Process an EXIDX section for entry merging. SECTION_CONTENTS points + // to the EXIDX contents and SECTION_SIZE is the size of the contents. Return + // number of bytes to be deleted in output. If parts of the input EXIDX + // section are merged a heap allocated Arm_exidx_section_offset_map is store + // in the located PSECTION_OFFSET_MAP. The caller owns the map and is + // reponsible for releasing it. template<bool big_endian> uint32_t process_exidx_section(const Arm_exidx_input_section* exidx_input_section, + const unsigned char* section_contents, + section_size_type section_size, Arm_exidx_section_offset_map** psection_offset_map); // Append an EXIDX_CANTUNWIND entry pointing at the end of the last @@ -1339,7 +1355,7 @@ class Arm_output_section : public Output_section // Group input sections for stub generation. void - group_sections(section_size_type, bool, Target_arm<big_endian>*); + group_sections(section_size_type, bool, Target_arm<big_endian>*, const Task*); // Downcast a base pointer to an Arm_output_section pointer. This is // not type-safe but we only use Arm_output_section not the base class. @@ -1358,7 +1374,8 @@ class Arm_output_section : public Output_section fix_exidx_coverage(Layout* layout, const Text_section_list& sorted_text_section, Symbol_table* symtab, - bool merge_exidx_entries); + bool merge_exidx_entries, + const Task* task); // Link an EXIDX section into its corresponding text section. void @@ -1374,7 +1391,8 @@ class Arm_output_section : public Output_section Input_section_list::const_iterator, Input_section_list::const_iterator, Target_arm<big_endian>*, - std::vector<Output_relaxed_input_section*>*); + std::vector<Output_relaxed_input_section*>*, + const Task* task); }; // Arm_exidx_input_section class. This represents an EXIDX input section. @@ -1386,9 +1404,10 @@ class Arm_exidx_input_section static_cast<section_offset_type>(-1); Arm_exidx_input_section(Relobj* relobj, unsigned int shndx, - unsigned int link, uint32_t size, uint32_t addralign) + unsigned int link, uint32_t size, + uint32_t addralign, uint32_t text_size) : relobj_(relobj), shndx_(shndx), link_(link), size_(size), - addralign_(addralign), has_errors_(false) + addralign_(addralign), text_size_(text_size), has_errors_(false) { } ~Arm_exidx_input_section() @@ -1416,11 +1435,16 @@ class Arm_exidx_input_section size() const { return this->size_; } - // Reutnr address alignment of EXIDX input section. + // Return address alignment of EXIDX input section. uint32_t addralign() const { return this->addralign_; } + // Return size of the associated text input section. + uint32_t + text_size() const + { return this->text_size_; } + // Whether there are any errors in the EXIDX input section. bool has_errors() const @@ -1442,6 +1466,8 @@ class Arm_exidx_input_section uint32_t size_; // Address alignment of this. For ARM 32-bit is sufficient. uint32_t addralign_; + // Size of associated text section. + uint32_t text_size_; // Whether this has any errors. bool has_errors_; }; @@ -2499,7 +2525,7 @@ class Target_arm : public Sized_target<32, big_endian> { return !parameters->options().relocatable(); } bool - do_relax(int, const Input_objects*, Symbol_table*, Layout*); + do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*); // Determine whether an object attribute tag takes an integer, a // string or both. @@ -2802,7 +2828,7 @@ class Target_arm : public Sized_target<32, big_endian> // Group input sections for stub generation. void - group_sections(Layout*, section_size_type, bool); + group_sections(Layout*, section_size_type, bool, const Task*); // Scan a relocation for stub generation. void @@ -2827,7 +2853,8 @@ class Target_arm : public Sized_target<32, big_endian> // Fix .ARM.exidx section coverage. void fix_exidx_coverage(Layout*, const Input_objects*, - Arm_output_section<big_endian>*, Symbol_table*); + Arm_output_section<big_endian>*, Symbol_table*, + const Task*); // Functors for STL set. struct output_section_address_less_than @@ -5086,13 +5113,23 @@ Arm_input_section<big_endian>::init() Relobj* relobj = this->relobj(); unsigned int shndx = this->shndx(); - // Cache these to speed up size and alignment queries. It is too slow - // to call section_addraglin and section_size every time. + // We have to cache original size, alignment and contents to avoid locking + // the original file. this->original_addralign_ = convert_types<uint32_t, uint64_t>(relobj->section_addralign(shndx)); + + // This is not efficient but we expect only a small number of relaxed + // input sections for stubs. + section_size_type section_size; + const unsigned char* section_contents = + relobj->section_contents(shndx, §ion_size, false); this->original_size_ = convert_types<uint32_t, uint64_t>(relobj->section_size(shndx)); + gold_assert(this->original_contents_ == NULL); + this->original_contents_ = new unsigned char[section_size]; + memcpy(this->original_contents_, section_contents, section_size); + // We want to make this look like the original input section after // output sections are finalized. Output_section* os = relobj->output_section(shndx); @@ -5110,10 +5147,9 @@ void Arm_input_section<big_endian>::do_write(Output_file* of) { // We have to write out the original section content. - section_size_type section_size; - const unsigned char* section_contents = - this->relobj()->section_contents(this->shndx(), §ion_size, false); - of->write(this->offset(), section_contents, section_size); + gold_assert(this->original_contents_ != NULL); + of->write(this->offset(), this->original_contents_, + this->original_size_); // If this owns a stub table and it is not empty, write it. if (this->is_stub_table_owner() && !this->stub_table_->empty()) @@ -5184,8 +5220,18 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) Arm_address output_offset = arm_relobj->get_output_section_offset(this->shndx_); Arm_address section_start; + section_size_type section_size; + + // Find out the end of the text section referred by this. if (output_offset != Arm_relobj<big_endian>::invalid_address) - section_start = os->address() + output_offset; + { + section_start = os->address() + output_offset; + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_link(this->shndx_); + gold_assert(exidx_input_section != NULL); + section_size = + convert_to_section_size_type(exidx_input_section->text_size()); + } else { // Currently this only happens for a relaxed section. @@ -5193,11 +5239,11 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) os->find_relaxed_input_section(this->relobj_, this->shndx_); gold_assert(poris != NULL); section_start = poris->address(); + section_size = convert_to_section_size_type(poris->data_size()); } // We always append this to the end of an EXIDX section. - Arm_address output_address = - section_start + this->relobj_->section_size(this->shndx_); + Arm_address output_address = section_start + section_size; // Write out the entry. The first word either points to the beginning // or after the end of a text section. The second word is the special @@ -5229,9 +5275,59 @@ Arm_exidx_merged_section::Arm_exidx_merged_section( exidx_input_section_(exidx_input_section), section_offset_map_(section_offset_map) { + // If we retain or discard the whole EXIDX input section, we would + // not be here. + gold_assert(deleted_bytes != 0 + && deleted_bytes != this->exidx_input_section_.size()); + // Fix size here so that we do not need to implement set_final_data_size. - this->set_data_size(exidx_input_section.size() - deleted_bytes); + uint32_t size = exidx_input_section.size() - deleted_bytes; + this->set_data_size(size); this->fix_data_size(); + + // Allocate buffer for section contents and build contents. + this->section_contents_ = new unsigned char[size]; +} + +// Build the contents of a merged EXIDX output section. + +void +Arm_exidx_merged_section::build_contents( + const unsigned char* original_contents, + section_size_type original_size) +{ + // Go over spans of input offsets and write only those that are not + // discarded. + section_offset_type in_start = 0; + section_offset_type out_start = 0; + section_offset_type in_max = + convert_types<section_offset_type>(original_size); + section_offset_type out_max = + convert_types<section_offset_type>(this->data_size()); + for (Arm_exidx_section_offset_map::const_iterator p = + this->section_offset_map_.begin(); + p != this->section_offset_map_.end(); + ++p) + { + section_offset_type in_end = p->first; + gold_assert(in_end >= in_start); + section_offset_type out_end = p->second; + size_t in_chunk_size = convert_types<size_t>(in_end - in_start + 1); + if (out_end != -1) + { + size_t out_chunk_size = + convert_types<size_t>(out_end - out_start + 1); + + gold_assert(out_chunk_size == in_chunk_size + && in_end < in_max && out_end < out_max); + + memcpy(this->section_contents_ + out_start, + original_contents + in_start, + out_chunk_size); + out_start += out_chunk_size; + } + in_start += in_chunk_size; + } } // Given an input OBJECT, an input section index SHNDX within that @@ -5290,11 +5386,6 @@ Arm_exidx_merged_section::do_output_offset( void Arm_exidx_merged_section::do_write(Output_file* of) { - // If we retain or discard the whole EXIDX input section, we would - // not be here. - gold_assert(this->data_size() != this->exidx_input_section_.size() - && this->data_size() != 0); - off_t offset = this->offset(); const section_size_type oview_size = this->data_size(); unsigned char* const oview = of->get_output_view(offset, oview_size); @@ -5302,38 +5393,7 @@ Arm_exidx_merged_section::do_write(Output_file* of) Output_section* os = this->relobj()->output_section(this->shndx()); gold_assert(os != NULL); - // Get contents of EXIDX input section. - section_size_type section_size; - const unsigned char* section_contents = - this->relobj()->section_contents(this->shndx(), §ion_size, false); - gold_assert(section_size == this->exidx_input_section_.size()); - - // Go over spans of input offsets and write only those that are not - // discarded. - section_offset_type in_start = 0; - section_offset_type out_start = 0; - for(Arm_exidx_section_offset_map::const_iterator p = - this->section_offset_map_.begin(); - p != this->section_offset_map_.end(); - ++p) - { - section_offset_type in_end = p->first; - gold_assert(in_end >= in_start); - section_offset_type out_end = p->second; - size_t in_chunk_size = convert_types<size_t>(in_end - in_start + 1); - if (out_end != -1) - { - size_t out_chunk_size = - convert_types<size_t>(out_end - out_start + 1); - gold_assert(out_chunk_size == in_chunk_size); - memcpy(oview + out_start, section_contents + in_start, - out_chunk_size); - out_start += out_chunk_size; - } - in_start += in_chunk_size; - } - - gold_assert(convert_to_section_size_type(out_start) == oview_size); + memcpy(oview, this->section_contents_, oview_size); of->write_output_view(this->offset(), oview_size, oview); } @@ -5414,21 +5474,22 @@ Arm_exidx_fixup::update_offset_map( } // Process EXIDX_INPUT_SECTION for EXIDX entry merging. Return the number of -// bytes deleted. If some entries are merged, also store a pointer to a newly -// created Arm_exidx_section_offset_map object in *PSECTION_OFFSET_MAP. The -// caller owns the map and is responsible for releasing it after use. +// bytes deleted. SECTION_CONTENTS points to the contents of the EXIDX +// section and SECTION_SIZE is the number of bytes pointed by SECTION_CONTENTS. +// If some entries are merged, also store a pointer to a newly created +// Arm_exidx_section_offset_map object in *PSECTION_OFFSET_MAP. The caller +// owns the map and is responsible for releasing it after use. template<bool big_endian> uint32_t Arm_exidx_fixup::process_exidx_section( const Arm_exidx_input_section* exidx_input_section, + const unsigned char* section_contents, + section_size_type section_size, Arm_exidx_section_offset_map** psection_offset_map) { Relobj* relobj = exidx_input_section->relobj(); unsigned shndx = exidx_input_section->shndx(); - section_size_type section_size; - const unsigned char* section_contents = - relobj->section_contents(shndx, §ion_size, false); if ((section_size % 8) != 0) { @@ -5508,7 +5569,8 @@ Arm_output_section<big_endian>::create_stub_group( Input_section_list::const_iterator end, Input_section_list::const_iterator owner, Target_arm<big_endian>* target, - std::vector<Output_relaxed_input_section*>* new_relaxed_sections) + std::vector<Output_relaxed_input_section*>* new_relaxed_sections, + const Task* task) { // We use a different kind of relaxed section in an EXIDX section. // The static casting from Output_relaxed_input_section to @@ -5531,7 +5593,9 @@ Arm_output_section<big_endian>::create_stub_group( else { gold_assert(owner->is_input_section()); - // Create a new relaxed input section. + // Create a new relaxed input section. We need to lock the original + // file. + Task_lock_obj<Object> tl(task, owner->relobj()); arm_input_section = target->new_arm_input_section(owner->relobj(), owner->shndx()); new_relaxed_sections->push_back(arm_input_section); @@ -5576,7 +5640,8 @@ void Arm_output_section<big_endian>::group_sections( section_size_type group_size, bool stubs_always_after_branch, - Target_arm<big_endian>* target) + Target_arm<big_endian>* target, + const Task* task) { // We only care about sections containing code. if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0) @@ -5633,7 +5698,8 @@ Arm_output_section<big_endian>::group_sections( { gold_assert(group_end != this->input_sections().end()); this->create_stub_group(group_begin, group_end, group_end, - target, &new_relaxed_sections); + target, &new_relaxed_sections, + task); state = NO_GROUP; } else @@ -5655,7 +5721,7 @@ Arm_output_section<big_endian>::group_sections( { gold_assert(group_end != this->input_sections().end()); this->create_stub_group(group_begin, group_end, stub_table, - target, &new_relaxed_sections); + target, &new_relaxed_sections, task); state = NO_GROUP; } break; @@ -5665,9 +5731,10 @@ Arm_output_section<big_endian>::group_sections( } // If we see an input section and currently there is no group, start - // a new one. Skip any empty sections. + // a new one. Skip any empty sections. We look at the data size + // instead of calling p->relobj()->section_size() to avoid locking. if ((p->is_input_section() || p->is_relaxed_input_section()) - && (p->relobj()->section_size(p->shndx()) != 0)) + && (p->data_size() != 0)) { if (state == NO_GROUP) { @@ -5692,7 +5759,7 @@ Arm_output_section<big_endian>::group_sections( (state == FINDING_STUB_SECTION ? group_end : stub_table), - target, &new_relaxed_sections); + target, &new_relaxed_sections, task); } // Convert input section into relaxed input section in a batch. @@ -5740,7 +5807,8 @@ Arm_output_section<big_endian>::fix_exidx_coverage( Layout* layout, const Text_section_list& sorted_text_sections, Symbol_table* symtab, - bool merge_exidx_entries) + bool merge_exidx_entries, + const Task* task) { // We should only do this for the EXIDX output section. gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX); @@ -5823,10 +5891,19 @@ Arm_output_section<big_endian>::fix_exidx_coverage( continue; } + // We need to access the contents of the EXIDX section, lock the + // object here. + Task_lock_obj<Object> tl(task, exidx_relobj); + section_size_type exidx_size; + const unsigned char* exidx_contents = + exidx_relobj->section_contents(exidx_shndx, &exidx_size, false); + // Fix up coverage and append input section to output data list. Arm_exidx_section_offset_map* section_offset_map = NULL; uint32_t deleted_bytes = exidx_fixup.process_exidx_section<big_endian>(exidx_input_section, + exidx_contents, + exidx_size, §ion_offset_map); if (deleted_bytes == exidx_input_section->size()) @@ -5844,9 +5921,12 @@ Arm_output_section<big_endian>::fix_exidx_coverage( // Some entries are merged. We need to convert this EXIDX input // section into a relaxed section. gold_assert(section_offset_map != NULL); + Arm_exidx_merged_section* merged_section = new Arm_exidx_merged_section(*exidx_input_section, *section_offset_map, deleted_bytes); + merged_section->build_contents(exidx_contents, exidx_size); + const std::string secname = exidx_relobj->section_name(exidx_shndx); this->add_relaxed_input_section(layout, merged_section, secname); arm_relobj->convert_input_section_to_relaxed_section(exidx_shndx); @@ -6541,7 +6621,8 @@ Arm_relobj<big_endian>::make_exidx_input_section( // Create an Arm_exidx_input_section object for this EXIDX section. Arm_exidx_input_section* exidx_input_section = new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(), - shdr.get_sh_addralign()); + shdr.get_sh_addralign(), + text_shdr.get_sh_size()); gold_assert(this->exidx_section_map_[shndx] == NULL); this->exidx_section_map_[shndx] = exidx_input_section; @@ -6647,10 +6728,10 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd) section_offset_type section_offset = shdr.get_sh_offset(); section_size_type section_size = convert_to_section_size_type(shdr.get_sh_size()); - File_view* view = this->get_lasting_view(section_offset, - section_size, true, false); + const unsigned char* view = + this->get_view(section_offset, section_size, true, false); this->attributes_section_data_ = - new Attributes_section_data(view->data(), section_size); + new Attributes_section_data(view, section_size); } else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) { @@ -6725,7 +6806,7 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd) locsize, true, true); // Process the deferred EXIDX sections. - for(unsigned int i = 0; i < deferred_exidx_sections.size(); ++i) + for (unsigned int i = 0; i < deferred_exidx_sections.size(); ++i) { unsigned int shndx = deferred_exidx_sections[i]; elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size); @@ -6909,10 +6990,10 @@ Arm_dynobj<big_endian>::do_read_symbols(Read_symbols_data* sd) section_offset_type section_offset = shdr.get_sh_offset(); section_size_type section_size = convert_to_section_size_type(shdr.get_sh_size()); - File_view* view = this->get_lasting_view(section_offset, - section_size, true, false); + const unsigned char* view = + this->get_view(section_offset, section_size, true, false); this->attributes_section_data_ = - new Attributes_section_data(view->data(), section_size); + new Attributes_section_data(view, section_size); break; } } @@ -11160,7 +11241,8 @@ void Target_arm<big_endian>::group_sections( Layout* layout, section_size_type group_size, - bool stubs_always_after_branch) + bool stubs_always_after_branch, + const Task* task) { // Group input sections and insert stub table Layout::Section_list section_list; @@ -11172,7 +11254,7 @@ Target_arm<big_endian>::group_sections( Arm_output_section<big_endian>* output_section = Arm_output_section<big_endian>::as_arm_output_section(*p); output_section->group_sections(group_size, stubs_always_after_branch, - this); + this, task); } } @@ -11184,7 +11266,8 @@ Target_arm<big_endian>::do_relax( int pass, const Input_objects* input_objects, Symbol_table* symtab, - Layout* layout) + Layout* layout, + const Task* task) { // No need to generate stubs if this is a relocatable link. gold_assert(!parameters->options().relocatable()); @@ -11233,7 +11316,7 @@ Target_arm<big_endian>::do_relax( stub_group_size = std::max(stub_group_size, cortex_a8_group_size); } - group_sections(layout, stub_group_size, stubs_always_after_branch); + group_sections(layout, stub_group_size, stubs_always_after_branch, task); // Also fix .ARM.exidx section coverage. Arm_output_section<big_endian>* exidx_output_section = NULL; @@ -11257,7 +11340,7 @@ Target_arm<big_endian>::do_relax( if (exidx_output_section != NULL) { this->fix_exidx_coverage(layout, input_objects, exidx_output_section, - symtab); + symtab, task); done_exidx_fixup = true; } } @@ -11306,6 +11389,9 @@ Target_arm<big_endian>::do_relax( { Arm_relobj<big_endian>* arm_relobj = Arm_relobj<big_endian>::as_arm_relobj(*op); + // Lock the object so we can read from it. This is only called + // single-threaded from Layout::finalize, so it is OK to lock. + Task_lock_obj<Object> tl(task, arm_relobj); arm_relobj->scan_sections_for_stubs(this, symtab, layout); } @@ -11336,7 +11422,7 @@ Target_arm<big_endian>::do_relax( // need to update output sections, so we record all output sections needing // update above and scan the sections here to find out what sections need // to be updated. - for(Layout::Section_list::const_iterator p = layout->section_list().begin(); + for (Layout::Section_list::const_iterator p = layout->section_list().begin(); p != layout->section_list().end(); ++p) { @@ -11368,7 +11454,11 @@ Target_arm<big_endian>::do_relax( // symbols defined in parts of input sections that are discarded by // relaxation. if (arm_relobj->output_local_symbol_count_needs_update()) - arm_relobj->update_output_local_symbol_count(); + { + // We need to lock the object's file to update it. + Task_lock_obj<Object> tl(task, arm_relobj); + arm_relobj->update_output_local_symbol_count(); + } } } @@ -11710,7 +11800,8 @@ Target_arm<big_endian>::fix_exidx_coverage( Layout* layout, const Input_objects* input_objects, Arm_output_section<big_endian>* exidx_section, - Symbol_table* symtab) + Symbol_table* symtab, + const Task* task) { // We need to look at all the input sections in output in ascending // order of of output address. We do that by building a sorted list @@ -11751,7 +11842,7 @@ Target_arm<big_endian>::fix_exidx_coverage( typedef typename Arm_output_section<big_endian>::Text_section_list Text_section_list; Text_section_list sorted_text_sections; - for(typename Sorted_output_section_list::iterator p = + for (typename Sorted_output_section_list::iterator p = sorted_output_sections.begin(); p != sorted_output_sections.end(); ++p) @@ -11762,7 +11853,7 @@ Target_arm<big_endian>::fix_exidx_coverage( } exidx_section->fix_exidx_coverage(layout, sorted_text_sections, symtab, - merge_exidx_entries()); + merge_exidx_entries(), task); } Target_selector_arm<false> target_selector_arm; |