Index: gold/arm.cc =================================================================== RCS file: /cvs/src/src/gold/arm.cc,v retrieving revision 1.67 diff -u -u -p -r1.67 arm.cc --- gold/arm.cc 27 Jan 2010 15:17:46 -0000 1.67 +++ gold/arm.cc 29 Jan 2010 00:31:48 -0000 @@ -1405,7 +1405,8 @@ class Arm_relobj : public Sized_relobj<3 : Sized_relobj<32, big_endian>(name, input_file, offset, ehdr), stub_tables_(), local_symbol_is_thumb_function_(), attributes_section_data_(NULL), mapping_symbols_info_(), - section_has_cortex_a8_workaround_(NULL), exidx_section_map_() + section_has_cortex_a8_workaround_(NULL), exidx_section_map_(), + output_local_symbol_count_needs_update_(false) { } ~Arm_relobj() @@ -1530,6 +1531,20 @@ class Arm_relobj : public Sized_relobj<3 : NULL); } + // Whether output local symbol count needs updating. + bool + output_local_symbol_count_needs_update() const + { return this->output_local_symbol_count_needs_update_; } + + // Set output_local_symbol_count_needs_update flag to be true. + void + set_output_local_symbol_count_needs_update() + { this->output_local_symbol_count_needs_update_ = true; } + + // Update output local symbol count at the end of relaxation. + void + update_output_local_symbol_count(); + protected: // Post constructor setup. void @@ -1606,6 +1621,8 @@ class Arm_relobj : public Sized_relobj<3 std::vector* section_has_cortex_a8_workaround_; // Map a text section to its associated .ARM.exidx section, if there is one. Exidx_section_map exidx_section_map_; + // Whether output local symbol count needs updating. + bool output_local_symbol_count_needs_update_; }; // Arm_dynobj class. @@ -4827,7 +4844,10 @@ Arm_exidx_cantunwind::do_fixed_endian_wr // 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 // EXIDX_CANTUNWIND value. - elfcpp::Swap<32, big_endian>::writeval(wv, output_address); + uint32_t prel31_offset = output_address - this->address(); + if (utils::has_overflow<31>(offset)) + gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry")); + elfcpp::Swap<32, big_endian>::writeval(wv, prel31_offset & 0x7fffffffU); elfcpp::Swap<32, big_endian>::writeval(wv + 1, elfcpp::EXIDX_CANTUNWIND); of->write_output_view(this->offset(), oview_size, oview); @@ -5430,6 +5450,10 @@ Arm_output_section::fix_exid // The whole EXIDX section got merged. Remove it from output. gold_assert(section_offset_map == NULL); exidx_relobj->set_output_section(exidx_shndx, NULL); + + // All local symbols defined in this input section will be dropped. + // We need to adjust output local symbol count. + arm_relobj->set_output_local_symbol_count_needs_update(); } else if (deleted_bytes > 0) { @@ -5441,6 +5465,11 @@ Arm_output_section::fix_exid *section_offset_map, deleted_bytes); this->add_relaxed_input_section(merged_section); arm_relobj->convert_input_section_to_relaxed_section(exidx_shndx); + + // All local symbols defined in discarded portions of this input + // section will be dropped. We need to adjust output local symbol + // count. + arm_relobj->set_output_local_symbol_count_needs_update(); } else { @@ -6067,6 +6096,99 @@ Arm_relobj::do_gc_process_re } } +// Update output local symbol count. Owing to EXIDX entry merging, some local +// symbols will be removed in output. Adjust output local symbol count +// accordingly. We can only changed the static output local symbol count. It +// is too late to change the dynamic symbols. + +template +void +Arm_relobj::update_output_local_symbol_count() +{ + // Caller should check that this needs updating. We want caller checking + // because output_local_symbol_count_needs_update() is most likely inlined. + gold_assert(this->output_local_symbol_count_needs_update_); + + gold_assert(this->symtab_shndx() != -1U); + if (this->symtab_shndx() == 0) + { + // This object has no symbols. Weird but legal. + return; + } + + // Read the symbol table section header. + const unsigned int symtab_shndx = this->symtab_shndx(); + elfcpp::Shdr<32, big_endian> + symtabshdr(this, this->elf_file()->section_header(symtab_shndx)); + gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + + // Read the local symbols. + const int sym_size = elfcpp::Elf_sizes<32>::sym_size; + const unsigned int loccount = this->local_symbol_count(); + gold_assert(loccount == symtabshdr.get_sh_info()); + off_t locsize = loccount * sym_size; + const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), + locsize, true, true); + + // Loop over the local symbols. + + typedef typename Sized_relobj<32, big_endian>::Output_sections + Output_sections; + const Output_sections& out_sections(this->output_sections()); + unsigned int shnum = this->shnum(); + unsigned int count = 0; + // Skip the first, dummy, symbol. + psyms += sym_size; + for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size) + { + elfcpp::Sym<32, big_endian> sym(psyms); + + Symbol_value<32>& lv((*this->local_values())[i]); + + // This local symbol was already discarded by do_count_local_symbols. + if (!lv.needs_output_symtab_entry()) + continue; + + bool is_ordinary; + unsigned int shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(), + &is_ordinary); + + if (shndx < shnum) + { + Output_section* os = out_sections[shndx]; + + // This local symbol no longer has an output section. Discard it. + if (os == NULL) + { + lv.set_no_output_symtab_entry(); + continue; + } + + // Currently we only discard parts of EXIDX input sections. + // We explicitly check for a merged EXIDX input section to avoid + // calling Output_section_data::output_offset unless necessary. + if ((this->get_output_section_offset(shndx) == invalid_address) + && (this->exidx_input_section_by_shndx(shndx) != NULL)) + { + section_offset_type output_offset = + os->output_offset(this, shndx, lv.input_value()); + if (output_offset == -1) + { + // This symbol is defined in a part of an EXIDX input section + // that is discarded due to entry merging. + lv.set_no_output_symtab_entry(); + continue; + } + } + } + + ++count; + } + + this->set_output_local_symbol_count(count); + this->output_local_symbol_count_needs_update_ = false; +} + // Arm_dynobj methods. // Read the symbol information. @@ -6726,6 +6848,8 @@ Target_arm::Scan::global(Sym break; case elfcpp::R_ARM_REL32: + break; + case elfcpp::R_ARM_PREL31: { // Make a dynamic relocation if necessary. @@ -9477,10 +9601,27 @@ Target_arm::do_relax( // Finalize the stubs in the last relaxation pass. if (!continue_relaxation) - for (Stub_table_iterator sp = this->stub_tables_.begin(); - (sp != this->stub_tables_.end()) && !any_stub_table_changed; - ++sp) - (*sp)->finalize_stubs(); + { + for (Stub_table_iterator sp = this->stub_tables_.begin(); + (sp != this->stub_tables_.end()) && !any_stub_table_changed; + ++sp) + (*sp)->finalize_stubs(); + + // Update output local symbol counts of objects if necessary. + for (Input_objects::Relobj_iterator op = input_objects->relobj_begin(); + op != input_objects->relobj_end(); + ++op) + { + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(*op); + + // Update output local symbol counts. We need to discard local + // 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(); + } + } return continue_relaxation; } Index: gold/object.h =================================================================== RCS file: /cvs/src/src/gold/object.h,v retrieving revision 1.90 diff -u -u -p -r1.90 object.h --- gold/object.h 26 Jan 2010 21:29:10 -0000 1.90 +++ gold/object.h 29 Jan 2010 00:31:48 -0000 @@ -1689,6 +1689,11 @@ class Sized_relobj : public Relobj do_relocate_sections(const Symbol_table* symtab, const Layout* layout, const unsigned char* pshdrs, Views* pviews); + // Allow a child to set output local symbol count. + void + set_output_local_symbol_count(unsigned int value) + { this->output_local_symbol_count_ = value; } + private: // For convenience. typedef Sized_relobj This;