diff -rcp ../binutils-2.20.51.0.10.original/elfcpp/i386.h elfcpp/i386.h *** ../binutils-2.20.51.0.10.original/elfcpp/i386.h 2010-08-10 15:13:23.000000000 +0100 --- elfcpp/i386.h 2010-08-10 15:14:09.000000000 +0100 *************** *** 1,6 **** // i386.h -- ELF definitions specific to EM_386 -*- C++ -*- ! // Copyright 2006, 2007, Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of elfcpp. --- 1,6 ---- // i386.h -- ELF definitions specific to EM_386 -*- C++ -*- ! // Copyright 2006, 2007, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of elfcpp. *************** enum *** 85,90 **** --- 85,91 ---- R_386_TLS_DESC_CALL = 40, // Marker of call through TLS desc for relaxation R_386_TLS_DESC = 41, // TLS descriptor containing pointer to code and // to argument, returning TLS offset for symbol + R_386_IRELATIVE = 42, // Adjust indirectly by program base // Used by Intel. R_386_USED_BY_INTEL_200 = 200, // GNU vtable garbage collection extensions. diff -rcp ../binutils-2.20.51.0.10.original/elfcpp/powerpc.h elfcpp/powerpc.h *** ../binutils-2.20.51.0.10.original/elfcpp/powerpc.h 2010-08-10 15:13:23.000000000 +0100 --- elfcpp/powerpc.h 2010-08-10 15:14:09.000000000 +0100 *************** *** 1,6 **** // powerpc.h -- ELF definitions specific to EM_PPC and EM_PPC64 -*- C++ -*- ! // Copyright 2008, Free Software Foundation, Inc. // Written by David S. Miller . // This file is part of elfcpp. --- 1,6 ---- // powerpc.h -- ELF definitions specific to EM_PPC and EM_PPC64 -*- C++ -*- ! // Copyright 2008, 2010 Free Software Foundation, Inc. // Written by David S. Miller . // This file is part of elfcpp. *************** enum *** 165,174 **** R_PPC_EMB_RELST_HA = 114, R_PPC_EMB_BIT_FLD = 115, R_PPC_EMB_RELSDA = 116, ! R_PPC_RELAX32 = 245, ! R_PPC_RELAX32PC = 246, ! R_PPC_RELAX32_PLT = 247, ! R_PPC_RELAX32PC_PLT = 248, R_PPC_REL16 = 249, R_PPC_REL16_LO = 250, R_PPC_REL16_HI = 251, --- 165,172 ---- R_PPC_EMB_RELST_HA = 114, R_PPC_EMB_BIT_FLD = 115, R_PPC_EMB_RELSDA = 116, ! ! R_POWERPC_IRELATIVE = 248, R_PPC_REL16 = 249, R_PPC_REL16_LO = 250, R_PPC_REL16_HI = 251, diff -rcp ../binutils-2.20.51.0.10.original/elfcpp/sparc.h elfcpp/sparc.h *** ../binutils-2.20.51.0.10.original/elfcpp/sparc.h 2010-08-10 15:13:23.000000000 +0100 --- elfcpp/sparc.h 2010-08-10 15:14:09.000000000 +0100 *************** *** 1,6 **** // sparc.h -- ELF definitions specific to EM_SPARC -*- C++ -*- ! // Copyright 2008, Free Software Foundation, Inc. // Written by David S. Miller . // This file is part of elfcpp. --- 1,6 ---- // sparc.h -- ELF definitions specific to EM_SPARC -*- C++ -*- ! // Copyright 2008, 2010 Free Software Foundation, Inc. // Written by David S. Miller . // This file is part of elfcpp. *************** enum *** 141,146 **** --- 141,148 ---- R_SPARC_SIZE32 = 86, // size of symbol, 32-bit R_SPARC_SIZE64 = 87, // size of symbol, 64-bit + R_SPARC_IRELATIVE = 249, // Adjust indirectly by program base + // GNU vtable garbage collection extensions. R_SPARC_GNU_VTINHERIT = 250, R_SPARC_GNU_VTENTRY = 251, diff -rcp ../binutils-2.20.51.0.10.original/elfcpp/x86_64.h elfcpp/x86_64.h *** ../binutils-2.20.51.0.10.original/elfcpp/x86_64.h 2010-08-10 15:13:23.000000000 +0100 --- elfcpp/x86_64.h 2010-08-10 15:14:09.000000000 +0100 *************** *** 1,6 **** // x86-64.h -- ELF definitions specific to EM_X86_64 -*- C++ -*- ! // Copyright 2006, 2007, Free Software Foundation, Inc. // Written by Andrew Chatham. // This file is part of elfcpp. --- 1,6 ---- // x86-64.h -- ELF definitions specific to EM_X86_64 -*- C++ -*- ! // Copyright 2006, 2007, 2010 Free Software Foundation, Inc. // Written by Andrew Chatham. // This file is part of elfcpp. *************** enum *** 90,98 **** R_X86_64_GOTPC32_TLSDESC = 34, // 32-bit PC relative to TLS descriptor in GOT R_X86_64_TLSDESC_CALL = 35, // Relaxable call through TLS descriptor R_X86_64_TLSDESC = 36, // 2 by 64-bit TLS descriptor // GNU vtable garbage collection extensions. ! R_386_GNU_VTINHERIT = 250, ! R_386_GNU_VTENTRY = 251 }; } // End namespace elfcpp. --- 90,99 ---- R_X86_64_GOTPC32_TLSDESC = 34, // 32-bit PC relative to TLS descriptor in GOT R_X86_64_TLSDESC_CALL = 35, // Relaxable call through TLS descriptor R_X86_64_TLSDESC = 36, // 2 by 64-bit TLS descriptor + R_X86_64_IRELATIVE = 37, // Adjust indirectly by program base // GNU vtable garbage collection extensions. ! R_X86_64_GNU_VTINHERIT = 250, ! R_X86_64_GNU_VTENTRY = 251 }; } // End namespace elfcpp. diff -rcp ../binutils-2.20.51.0.10.original/gold/archive.cc gold/archive.cc *** ../binutils-2.20.51.0.10.original/gold/archive.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/archive.cc 2010-08-10 15:14:02.000000000 +0100 *************** *** 36,41 **** --- 36,42 ---- #include "readsyms.h" #include "symtab.h" #include "object.h" + #include "layout.h" #include "archive.h" #include "plugin.h" *************** Archive::read_symbols(off_t off) *** 603,610 **** } Archive::Should_include ! Archive::should_include_member(Symbol_table* symtab, const char* sym_name, ! Symbol** symp, std::string* why, char** tmpbufp, size_t* tmpbuflen) { // In an object file, and therefore in an archive map, an --- 604,612 ---- } Archive::Should_include ! Archive::should_include_member(Symbol_table* symtab, Layout* layout, ! const char* sym_name, Symbol** symp, ! std::string* why, char** tmpbufp, size_t* tmpbuflen) { // In an object file, and therefore in an archive map, an *************** Archive::should_include_member(Symbol_ta *** 648,660 **** if (sym == NULL) { // Check whether the symbol was named in a -u option. ! if (!parameters->options().is_undefined(sym_name)) ! return Archive::SHOULD_INCLUDE_UNKNOWN; ! else { *why = "-u "; *why += sym_name; } } else if (!sym->is_undefined()) return Archive::SHOULD_INCLUDE_NO; --- 650,671 ---- if (sym == NULL) { // Check whether the symbol was named in a -u option. ! if (parameters->options().is_undefined(sym_name)) { *why = "-u "; *why += sym_name; } + else if (layout->script_options()->is_referenced(sym_name)) + { + size_t alc = 100 + strlen(sym_name); + char* buf = new char[alc]; + snprintf(buf, alc, _("script or expression reference to %s"), + sym_name); + *why = buf; + delete[] buf; + } + else + return Archive::SHOULD_INCLUDE_UNKNOWN; } else if (!sym->is_undefined()) return Archive::SHOULD_INCLUDE_NO; *************** Archive::add_symbols(Symbol_table* symta *** 726,733 **** Symbol* sym; std::string why; Archive::Should_include t = ! Archive::should_include_member(symtab, sym_name, &sym, &why, ! &tmpbuf, &tmpbuflen); if (t == Archive::SHOULD_INCLUDE_NO || t == Archive::SHOULD_INCLUDE_YES) --- 737,744 ---- Symbol* sym; std::string why; Archive::Should_include t = ! Archive::should_include_member(symtab, layout, sym_name, &sym, ! &why, &tmpbuf, &tmpbuflen); if (t == Archive::SHOULD_INCLUDE_NO || t == Archive::SHOULD_INCLUDE_YES) *************** Archive::include_member(Symbol_table* sy *** 853,863 **** && this->searched_for() && obj == NULL && unconfigured) ! { ! if (obj != NULL) ! delete obj; ! return false; ! } if (obj == NULL) return true; --- 864,870 ---- && this->searched_for() && obj == NULL && unconfigured) ! return false; if (obj == NULL) return true; *************** Archive::include_member(Symbol_table* sy *** 874,880 **** } if (!input_objects->add_object(obj)) ! delete obj; else { { --- 881,893 ---- } if (!input_objects->add_object(obj)) ! { ! // If this is an external member of a thin archive, unlock the ! // file. ! if (obj->offset() == 0) ! obj->unlock(this->task_); ! delete obj; ! } else { { *************** Lib_group::add_symbols(Symbol_table* sym *** 1013,1018 **** --- 1026,1032 ---- && (member.sd_ == NULL || member.sd_->symbol_names != NULL)) { Archive::Should_include t = obj->should_include_member(symtab, + layout, member.sd_, &why); diff -rcp ../binutils-2.20.51.0.10.original/gold/archive.h gold/archive.h *** ../binutils-2.20.51.0.10.original/gold/archive.h 2010-08-10 15:12:04.000000000 +0100 --- gold/archive.h 2010-08-10 15:14:02.000000000 +0100 *************** class Archive *** 176,182 **** }; static Should_include ! should_include_member(Symbol_table* symtab, const char* sym_name, Symbol** symp, std::string* why, char** tmpbufp, size_t* tmpbuflen); --- 176,182 ---- }; static Should_include ! should_include_member(Symbol_table* symtab, Layout*, const char* sym_name, Symbol** symp, std::string* why, char** tmpbufp, size_t* tmpbuflen); diff -rcp ../binutils-2.20.51.0.10.original/gold/arm.cc gold/arm.cc *** ../binutils-2.20.51.0.10.original/gold/arm.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/arm.cc 2010-08-10 15:14:02.000000000 +0100 *************** class Arm_output_section : public Output *** 1324,1330 **** Arm_output_section(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) : Output_section(name, type, flags) ! { } ~Arm_output_section() { } --- 1324,1333 ---- Arm_output_section(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) : Output_section(name, type, flags) ! { ! if (type == elfcpp::SHT_ARM_EXIDX) ! this->set_always_keeps_input_sections(); ! } ~Arm_output_section() { } *************** class Arm_output_section : public Output *** 1352,1357 **** --- 1355,1364 ---- Symbol_table* symtab, bool merge_exidx_entries); + // Link an EXIDX section into its corresponding text section. + void + set_exidx_section_link(); + private: // For convenience. typedef Output_section::Input_section Input_section; *************** class Arm_exidx_input_section *** 1376,1382 **** Arm_exidx_input_section(Relobj* relobj, unsigned int shndx, unsigned int link, uint32_t size, uint32_t addralign) : relobj_(relobj), shndx_(shndx), link_(link), size_(size), ! addralign_(addralign) { } ~Arm_exidx_input_section() --- 1383,1389 ---- Arm_exidx_input_section(Relobj* relobj, unsigned int shndx, unsigned int link, uint32_t size, uint32_t addralign) : relobj_(relobj), shndx_(shndx), link_(link), size_(size), ! addralign_(addralign), has_errors_(false) { } ~Arm_exidx_input_section() *************** class Arm_exidx_input_section *** 1409,1414 **** --- 1416,1431 ---- addralign() const { return this->addralign_; } + // Whether there are any errors in the EXIDX input section. + bool + has_errors() const + { return this->has_errors_; } + + // Set has-errors flag. + void + set_has_errors() + { this->has_errors_ = true; } + private: // Object containing this. Relobj* relobj_; *************** class Arm_exidx_input_section *** 1420,1425 **** --- 1437,1444 ---- uint32_t size_; // Address alignment of this. For ARM 32-bit is sufficient. uint32_t addralign_; + // Whether this has any errors. + bool has_errors_; }; // Arm_relobj class. *************** class Arm_relobj : public Sized_relobj<3 *** 1581,1586 **** --- 1600,1621 ---- merge_flags_and_attributes() const { return this->merge_flags_and_attributes_; } + // Export list of EXIDX section indices. + void + get_exidx_shndx_list(std::vector* list) const + { + list->clear(); + for (Exidx_section_map::const_iterator p = this->exidx_section_map_.begin(); + p != this->exidx_section_map_.end(); + ++p) + { + if (p->second->shndx() == p->first) + list->push_back(p->first); + } + // Sort list to make result independent of implementation of map. + std::sort(list->begin(), list->end()); + } + protected: // Post constructor setup. void *************** class Arm_relobj : public Sized_relobj<3 *** 1653,1659 **** void make_exidx_input_section(unsigned int shndx, const elfcpp::Shdr<32, big_endian>& shdr, ! unsigned int text_shndx); // Return the output address of either a plain input section or a // relaxed input section. SHNDX is the section index. --- 1688,1695 ---- void make_exidx_input_section(unsigned int shndx, const elfcpp::Shdr<32, big_endian>& shdr, ! unsigned int text_shndx, ! const elfcpp::Shdr<32, big_endian>& text_shdr); // Return the output address of either a plain input section or a // relaxed input section. SHNDX is the section index. *************** class Target_arm : public Sized_target<3 *** 2764,2770 **** // Fix .ARM.exidx section coverage. void ! fix_exidx_coverage(Layout*, Arm_output_section*, Symbol_table*); // Functors for STL set. struct output_section_address_less_than --- 2800,2807 ---- // Fix .ARM.exidx section coverage. void ! fix_exidx_coverage(Layout*, const Input_objects*, ! Arm_output_section*, Symbol_table*); // Functors for STL set. struct output_section_address_less_than *************** Target_arm::got_section(Symb *** 4116,4137 **** this->got_ = new Arm_output_data_got(symtab, layout); ! Output_section* os; ! os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_, false, false, false, ! true); // The old GNU linker creates a .got.plt section. We just // create another set of data in the .got section. Note that we // always create a PLT if we create a GOT, although the PLT // might be empty. this->got_plt_ = new Output_data_space(4, "** GOT PLT"); ! os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_plt_, false, false, ! false, false); // The first three entries are reserved. this->got_plt_->set_current_data_size(3 * 4); --- 4153,4172 ---- this->got_ = new Arm_output_data_got(symtab, layout); ! layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_, ORDER_RELRO, true); ! // The old GNU linker creates a .got.plt section. We just // create another set of data in the .got section. Note that we // always create a PLT if we create a GOT, although the PLT // might be empty. this->got_plt_ = new Output_data_space(4, "** GOT PLT"); ! layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_plt_, ORDER_DATA, false); // The first three entries are reserved. this->got_plt_->set_current_data_size(3 * 4); *************** Target_arm::rel_dyn_section( *** 4159,4166 **** gold_assert(layout != NULL); this->rel_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, ! elfcpp::SHF_ALLOC, this->rel_dyn_, true, ! false, false, false); } return this->rel_dyn_; } --- 4194,4201 ---- gold_assert(layout != NULL); this->rel_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, ! elfcpp::SHF_ALLOC, this->rel_dyn_, ! ORDER_DYNAMIC_RELOCS, false); } return this->rel_dyn_; } *************** void *** 5657,5666 **** Arm_output_section::append_text_sections_to_list( Text_section_list* list) { - // We only care about text sections. - if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0) - return; - gold_assert((this->flags() & elfcpp::SHF_ALLOC) != 0); for (Input_section_list::const_iterator p = this->input_sections().begin(); --- 5692,5697 ---- *************** Arm_output_section::fix_exid *** 5733,5741 **** const Arm_exidx_input_section* exidx_input_section = arm_relobj->exidx_input_section_by_link(shndx); ! // If this text section has no EXIDX section, force an EXIDX_CANTUNWIND ! // entry pointing to the end of the last seen EXIDX section. ! if (exidx_input_section == NULL) { exidx_fixup.add_exidx_cantunwind_as_needed(); continue; --- 5764,5773 ---- const Arm_exidx_input_section* exidx_input_section = arm_relobj->exidx_input_section_by_link(shndx); ! // If this text section has no EXIDX section or if the EXIDX section ! // has errors, force an EXIDX_CANTUNWIND entry pointing to the end ! // of the last seen EXIDX section. ! if (exidx_input_section == NULL || exidx_input_section->has_errors()) { exidx_fixup.add_exidx_cantunwind_as_needed(); continue; *************** Arm_output_section::fix_exid *** 5819,5833 **** if (processed_input_sections.find(Section_id(p->relobj(), p->shndx())) == processed_input_sections.end()) { ! // We only discard a known EXIDX section because its linked ! // text section has been folded by ICF. Arm_relobj* arm_relobj = Arm_relobj::as_arm_relobj(p->relobj()); const Arm_exidx_input_section* exidx_input_section = arm_relobj->exidx_input_section_by_shndx(p->shndx()); gold_assert(exidx_input_section != NULL); ! unsigned int text_shndx = exidx_input_section->link(); ! gold_assert(symtab->is_section_folded(p->relobj(), text_shndx)); // Remove this from link. We also need to recount the // local symbols. --- 5851,5870 ---- if (processed_input_sections.find(Section_id(p->relobj(), p->shndx())) == processed_input_sections.end()) { ! // We discard a known EXIDX section because its linked ! // text section has been folded by ICF. We also discard an ! // EXIDX section with error, the output does not matter in this ! // case. We do this to avoid triggering asserts. Arm_relobj* arm_relobj = Arm_relobj::as_arm_relobj(p->relobj()); const Arm_exidx_input_section* exidx_input_section = arm_relobj->exidx_input_section_by_shndx(p->shndx()); gold_assert(exidx_input_section != NULL); ! if (!exidx_input_section->has_errors()) ! { ! unsigned int text_shndx = exidx_input_section->link(); ! gold_assert(symtab->is_section_folded(p->relobj(), text_shndx)); ! } // Remove this from link. We also need to recount the // local symbols. *************** Arm_output_section::fix_exid *** 5846,5851 **** --- 5883,5910 ---- this->set_section_offsets_need_adjustment(); } + // Link EXIDX output sections to text output sections. + + template + void + Arm_output_section::set_exidx_section_link() + { + gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX); + if (!this->input_sections().empty()) + { + Input_section_list::const_iterator p = this->input_sections().begin(); + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(p->relobj()); + unsigned exidx_shndx = p->shndx(); + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_shndx(exidx_shndx); + gold_assert(exidx_input_section != NULL); + unsigned int text_shndx = exidx_input_section->link(); + Output_section* os = arm_relobj->output_section(text_shndx); + this->set_link_section(os); + } + } + // Arm_relobj methods. // Determine if an input section is scannable for stub processing. SHDR is *************** void *** 6447,6474 **** Arm_relobj::make_exidx_input_section( unsigned int shndx, const elfcpp::Shdr<32, big_endian>& shdr, ! unsigned int text_shndx) { - // Issue an error and ignore this EXIDX section if it points to a text - // section already has an EXIDX section. - if (this->exidx_section_map_[text_shndx] != NULL) - { - gold_error(_("EXIDX sections %u and %u both link to text section %u " - "in %s"), - shndx, this->exidx_section_map_[text_shndx]->shndx(), - text_shndx, this->name().c_str()); - return; - } - // 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()); - this->exidx_section_map_[text_shndx] = exidx_input_section; - // Also map the EXIDX section index to this. gold_assert(this->exidx_section_map_[shndx] == NULL); this->exidx_section_map_[shndx] = exidx_input_section; } // Read the symbol information. --- 6506,6562 ---- Arm_relobj::make_exidx_input_section( unsigned int shndx, const elfcpp::Shdr<32, big_endian>& shdr, ! unsigned int text_shndx, ! const elfcpp::Shdr<32, big_endian>& text_shdr) { // 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()); gold_assert(this->exidx_section_map_[shndx] == NULL); this->exidx_section_map_[shndx] = exidx_input_section; + + if (text_shndx == elfcpp::SHN_UNDEF || text_shndx >= this->shnum()) + { + gold_error(_("EXIDX section %s(%u) links to invalid section %u in %s"), + this->section_name(shndx).c_str(), shndx, text_shndx, + this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else if (this->exidx_section_map_[text_shndx] != NULL) + { + unsigned other_exidx_shndx = + this->exidx_section_map_[text_shndx]->shndx(); + gold_error(_("EXIDX sections %s(%u) and %s(%u) both link to text section" + "%s(%u) in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(other_exidx_shndx).c_str(), + other_exidx_shndx, this->section_name(text_shndx).c_str(), + text_shndx, this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else + this->exidx_section_map_[text_shndx] = exidx_input_section; + + // Check section flags of text section. + if ((text_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + gold_error(_("EXIDX section %s(%u) links to non-allocated section %s(%u) " + " in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(text_shndx).c_str(), text_shndx, + this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else if ((text_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) == 0) + // I would like to make this an error but currenlty ld just ignores + // this. + gold_warning(_("EXIDX section %s(%u) links to non-executable section " + "%s(%u) in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(text_shndx).c_str(), text_shndx, + this->name().c_str()); } // Read the symbol information. *************** Arm_relobj::do_read_symbols( *** 6538,6556 **** else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) { unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link()); ! if (text_shndx >= this->shnum()) ! gold_error(_("EXIDX section %u linked to invalid section %u"), ! i, text_shndx); ! else if (text_shndx == elfcpp::SHN_UNDEF) deferred_exidx_sections.push_back(i); else ! this->make_exidx_input_section(i, shdr, text_shndx); } } // This is rare. if (!must_merge_flags_and_attributes) { this->merge_flags_and_attributes_ = false; return; } --- 6626,6646 ---- else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) { unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link()); ! if (text_shndx == elfcpp::SHN_UNDEF) deferred_exidx_sections.push_back(i); else ! { ! elfcpp::Shdr<32, big_endian> text_shdr(pshdrs ! + text_shndx * shdr_size); ! this->make_exidx_input_section(i, shdr, text_shndx, text_shdr); ! } } } // This is rare. if (!must_merge_flags_and_attributes) { + gold_assert(deferred_exidx_sections.empty()); this->merge_flags_and_attributes_ = false; return; } *************** Arm_relobj::do_read_symbols( *** 6606,6620 **** { unsigned int shndx = deferred_exidx_sections[i]; elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size); ! unsigned int text_shndx; Reloc_map::const_iterator it = reloc_map.find(shndx); ! if (it != reloc_map.end() ! && find_linked_text_section(pshdrs + it->second * shdr_size, ! psyms, &text_shndx)) ! this->make_exidx_input_section(shndx, shdr, text_shndx); ! else ! gold_error(_("EXIDX section %u has no linked text section."), ! shndx); } } } --- 6696,6709 ---- { unsigned int shndx = deferred_exidx_sections[i]; elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size); ! unsigned int text_shndx = elfcpp::SHN_UNDEF; Reloc_map::const_iterator it = reloc_map.find(shndx); ! if (it != reloc_map.end()) ! find_linked_text_section(pshdrs + it->second * shdr_size, ! psyms, &text_shndx); ! elfcpp::Shdr<32, big_endian> text_shdr(pshdrs ! + text_shndx * shdr_size); ! this->make_exidx_input_section(shndx, shdr, text_shndx, text_shdr); } } } *************** Output_data_plt_arm::Output_ *** 7069,7076 **** { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, ! elfcpp::SHF_ALLOC, this->rel_, true, false, ! false, false); } template --- 7158,7165 ---- { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, ! elfcpp::SHF_ALLOC, this->rel_, ! ORDER_DYNAMIC_PLT_RELOCS, false); } template *************** Target_arm::make_plt_entry(S *** 7232,7238 **** layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), ! this->plt_, false, false, false, false); } this->plt_->add_entry(gsym); } --- 7321,7327 ---- layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), ! this->plt_, ORDER_PLT, false); } this->plt_->add_entry(gsym); } *************** Target_arm::gc_process_reloc *** 8124,8130 **** typedef Target_arm Arm; typedef typename Target_arm::Scan Scan; ! gold::gc_process_relocs<32, big_endian, Arm, elfcpp::SHT_REL, Scan>( symtab, layout, this, --- 8213,8220 ---- typedef Target_arm Arm; typedef typename Target_arm::Scan Scan; ! gold::gc_process_relocs<32, big_endian, Arm, elfcpp::SHT_REL, Scan, ! typename Target_arm::Relocatable_size_for_reloc>( symtab, layout, this, *************** Target_arm::do_finalize_sect *** 8292,8299 **** == NULL); Output_segment* exidx_segment = layout->make_output_segment(elfcpp::PT_ARM_EXIDX, elfcpp::PF_R); ! exidx_segment->add_output_section(exidx_section, elfcpp::PF_R, ! false); } } --- 8382,8389 ---- == NULL); Output_segment* exidx_segment = layout->make_output_segment(elfcpp::PT_ARM_EXIDX, elfcpp::PF_R); ! exidx_segment->add_output_section_to_nonload(exidx_section, ! elfcpp::PF_R); } } *************** Target_arm::do_finalize_sect *** 8305,8313 **** new Output_attributes_section_data(*this->attributes_section_data_); layout->add_output_section_data(".ARM.attributes", elfcpp::SHT_ARM_ATTRIBUTES, 0, ! attributes_section, false, false, false, false); } } // Return whether a direct absolute static relocation needs to be applied. --- 8395,8414 ---- new Output_attributes_section_data(*this->attributes_section_data_); layout->add_output_section_data(".ARM.attributes", elfcpp::SHT_ARM_ATTRIBUTES, 0, ! attributes_section, ORDER_INVALID, false); } + + // Fix up links in section EXIDX headers. + for (Layout::Section_list::const_iterator p = layout->section_list().begin(); + p != layout->section_list().end(); + ++p) + if ((*p)->type() == elfcpp::SHT_ARM_EXIDX) + { + Arm_output_section* os = + Arm_output_section::as_arm_output_section(*p); + os->set_exidx_section_link(); + } } // Return whether a direct absolute static relocation needs to be applied. *************** Target_arm::do_relax( *** 10971,10982 **** group_sections(layout, stub_group_size, stubs_always_after_branch); // Also fix .ARM.exidx section coverage. ! Output_section* os = layout->find_output_section(".ARM.exidx"); ! if (os != NULL && os->type() == elfcpp::SHT_ARM_EXIDX) { ! Arm_output_section* exidx_output_section = ! Arm_output_section::as_arm_output_section(os); ! this->fix_exidx_coverage(layout, exidx_output_section, symtab); done_exidx_fixup = true; } } --- 11072,11099 ---- group_sections(layout, stub_group_size, stubs_always_after_branch); // Also fix .ARM.exidx section coverage. ! Arm_output_section* exidx_output_section = NULL; ! for (Layout::Section_list::const_iterator p = ! layout->section_list().begin(); ! p != layout->section_list().end(); ! ++p) ! if ((*p)->type() == elfcpp::SHT_ARM_EXIDX) ! { ! if (exidx_output_section == NULL) ! exidx_output_section = ! Arm_output_section::as_arm_output_section(*p); ! else ! // We cannot handle this now. ! gold_error(_("multiple SHT_ARM_EXIDX sections %s and %s in a " ! "non-relocatable link"), ! exidx_output_section->name(), ! (*p)->name()); ! } ! ! if (exidx_output_section != NULL) { ! this->fix_exidx_coverage(layout, input_objects, exidx_output_section, ! symtab); done_exidx_fixup = true; } } *************** template *** 11427,11432 **** --- 11544,11550 ---- void Target_arm::fix_exidx_coverage( Layout* layout, + const Input_objects* input_objects, Arm_output_section* exidx_section, Symbol_table* symtab) { *************** Target_arm::fix_exidx_covera *** 11439,11453 **** typedef std::set Sorted_output_section_list; Sorted_output_section_list sorted_output_sections; ! Layout::Section_list section_list; ! layout->get_allocated_sections(§ion_list); ! for (Layout::Section_list::const_iterator p = section_list.begin(); ! p != section_list.end(); ++p) { ! // We only care about output sections that contain executable code. ! if (((*p)->flags() & elfcpp::SHF_EXECINSTR) != 0) ! sorted_output_sections.insert(*p); } // Go over the output sections in ascending order of output addresses. --- 11557,11586 ---- typedef std::set Sorted_output_section_list; Sorted_output_section_list sorted_output_sections; ! ! // Find out all the output sections of input sections pointed by ! // EXIDX input sections. ! for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); ! p != input_objects->relobj_end(); ++p) { ! Arm_relobj* arm_relobj = ! Arm_relobj::as_arm_relobj(*p); ! std::vector shndx_list; ! arm_relobj->get_exidx_shndx_list(&shndx_list); ! for (size_t i = 0; i < shndx_list.size(); ++i) ! { ! const Arm_exidx_input_section* exidx_input_section = ! arm_relobj->exidx_input_section_by_shndx(shndx_list[i]); ! gold_assert(exidx_input_section != NULL); ! if (!exidx_input_section->has_errors()) ! { ! unsigned int text_shndx = exidx_input_section->link(); ! Output_section *os = arm_relobj->output_section(text_shndx); ! if (os != NULL && (os->flags() & elfcpp::SHF_ALLOC) != 0) ! sorted_output_sections.insert(os); ! } ! } } // Go over the output sections in ascending order of output addresses. diff -rcp ../binutils-2.20.51.0.10.original/gold/common.cc gold/common.cc *** ../binutils-2.20.51.0.10.original/gold/common.cc 2010-08-10 15:12:03.000000000 +0100 --- gold/common.cc 2010-08-10 15:14:02.000000000 +0100 *************** Symbol_table::do_allocate_commons_list( *** 298,305 **** Output_data_space *poc = new Output_data_space(addralign, ds_name); Output_section *os = layout->add_output_section_data(name, elfcpp::SHT_NOBITS, ! flags, poc, false, ! false, false, false); if (os != NULL) { if (commons_section_type == COMMONS_SMALL) --- 298,306 ---- Output_data_space *poc = new Output_data_space(addralign, ds_name); Output_section *os = layout->add_output_section_data(name, elfcpp::SHT_NOBITS, ! flags, poc, ! ORDER_INVALID, ! false); if (os != NULL) { if (commons_section_type == COMMONS_SMALL) diff -rcp ../binutils-2.20.51.0.10.original/gold/compressed_output.cc gold/compressed_output.cc *** ../binutils-2.20.51.0.10.original/gold/compressed_output.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/compressed_output.cc 2010-08-10 15:14:02.000000000 +0100 *************** *** 1,6 **** ! // compressed_output.cc -- manage compressed output sections for gold ! // Copyright 2007, 2008 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. --- 1,6 ---- ! // compressed_output.cc -- manage compressed debug sections for gold ! // Copyright 2007, 2008, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. *************** *** 33,38 **** --- 33,40 ---- namespace gold { + #ifdef HAVE_ZLIB_H + // Compress UNCOMPRESSED_DATA of size UNCOMPRESSED_SIZE. Returns true // if it successfully compressed, false if it failed for any reason // (including not having zlib support in the library). If it returns *************** namespace gold *** 42,49 **** // "ZLIB", and 8 bytes indicating the uncompressed size, in big-endian // order. - #ifdef HAVE_ZLIB_H - static bool zlib_compress(const unsigned char* uncompressed_data, unsigned long uncompressed_size, --- 44,49 ---- *************** zlib_compress(const unsigned char* uncom *** 81,86 **** --- 81,129 ---- } } + // Decompress COMPRESSED_DATA of size COMPRESSED_SIZE, into a buffer + // UNCOMPRESSED_DATA of size UNCOMPRESSED_SIZE. Returns TRUE if it + // decompressed successfully, false if it failed. The buffer, of + // appropriate size, is provided by the caller, and is typically part + // of the memory-mapped output file. + + static bool + zlib_decompress(const unsigned char* compressed_data, + unsigned long compressed_size, + unsigned char* uncompressed_data, + unsigned long uncompressed_size) + { + z_stream strm; + int rc; + + /* It is possible the section consists of several compressed + buffers concatenated together, so we uncompress in a loop. */ + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + strm.avail_in = compressed_size; + strm.next_in = const_cast(compressed_data); + strm.avail_out = uncompressed_size; + + rc = inflateInit(&strm); + while (strm.avail_in > 0) + { + if (rc != Z_OK) + return false; + strm.next_out = ((Bytef*) uncompressed_data + + (uncompressed_size - strm.avail_out)); + rc = inflate(&strm, Z_FINISH); + if (rc != Z_STREAM_END) + return false; + rc = inflateReset(&strm); + } + rc = inflateEnd(&strm); + if (rc != Z_OK || strm.avail_out != 0) + return false; + + return true; + } + #else // !defined(HAVE_ZLIB_H) static bool *************** zlib_compress(const unsigned char*, unsi *** 90,97 **** --- 133,194 ---- return false; } + static bool + zlib_decompress(const unsigned char*, unsigned long, + unsigned char*, unsigned long) + { + return false; + } + #endif // !defined(HAVE_ZLIB_H) + // Read the compression header of a compressed debug section and return + // the uncompressed size. + + uint64_t + get_uncompressed_size(const unsigned char* compressed_data, + section_size_type compressed_size) + { + const unsigned int zlib_header_size = 12; + + /* Verify the compression header. Currently, we support only zlib + compression, so it should be "ZLIB" followed by the uncompressed + section size, 8 bytes in big-endian order. */ + if (compressed_size >= zlib_header_size + && strncmp(reinterpret_cast(compressed_data), + "ZLIB", 4) == 0) + return elfcpp::Swap_unaligned<64, true>::readval(compressed_data + 4); + return -1ULL; + } + + // Decompress a compressed debug section directly into the output file. + + bool + decompress_input_section(const unsigned char* compressed_data, + unsigned long compressed_size, + unsigned char* uncompressed_data, + unsigned long uncompressed_size) + { + const unsigned int zlib_header_size = 12; + + /* Verify the compression header. Currently, we support only zlib + compression, so it should be "ZLIB" followed by the uncompressed + section size, 8 bytes in big-endian order. */ + if (compressed_size >= zlib_header_size + && strncmp(reinterpret_cast(compressed_data), + "ZLIB", 4) == 0) + { + unsigned long uncompressed_size_check = + elfcpp::Swap_unaligned<64, true>::readval(compressed_data + 4); + gold_assert(uncompressed_size_check == uncompressed_size); + return zlib_decompress(compressed_data + zlib_header_size, + compressed_size - zlib_header_size, + uncompressed_data, + uncompressed_size); + } + return false; + } + // Class Output_compressed_section. // Set the final data size of a compressed section. This is where diff -rcp ../binutils-2.20.51.0.10.original/gold/compressed_output.h gold/compressed_output.h *** ../binutils-2.20.51.0.10.original/gold/compressed_output.h 2010-08-10 15:11:28.000000000 +0100 --- gold/compressed_output.h 2010-08-10 15:14:02.000000000 +0100 *************** *** 1,6 **** // compressed_output.h -- compressed output sections for gold -*- C++ -*- ! // Copyright 2007, 2008 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. --- 1,6 ---- // compressed_output.h -- compressed output sections for gold -*- C++ -*- ! // Copyright 2007, 2008, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. *************** namespace gold *** 37,42 **** --- 37,54 ---- class General_options; + // Read the compression header of a compressed debug section and return + // the uncompressed size. + + extern uint64_t + get_uncompressed_size(const unsigned char*, section_size_type); + + // Decompress a compressed debug section directly into the output file. + + extern bool + decompress_input_section(const unsigned char*, unsigned long, unsigned char*, + unsigned long); + // This is used for a section whose data should be compressed. It is // a regular Output_section which computes its contents into a buffer // and then postprocesses it. diff -rcp ../binutils-2.20.51.0.10.original/gold/configure.ac gold/configure.ac *** ../binutils-2.20.51.0.10.original/gold/configure.ac 2010-08-10 15:12:03.000000000 +0100 --- gold/configure.ac 2010-08-10 15:14:02.000000000 +0100 *************** AC_CONFIG_SRCDIR(gold.cc) *** 7,13 **** AC_CANONICAL_TARGET ! AM_INIT_AUTOMAKE([no-dist]) AM_CONFIG_HEADER(config.h:config.in) --- 7,13 ---- AC_CANONICAL_TARGET ! AM_INIT_AUTOMAKE([no-dist parallel-tests]) AM_CONFIG_HEADER(config.h:config.in) diff -rcp ../binutils-2.20.51.0.10.original/gold/copy-relocs.cc gold/copy-relocs.cc *** ../binutils-2.20.51.0.10.original/gold/copy-relocs.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/copy-relocs.cc 2010-08-10 15:14:02.000000000 +0100 *************** Copy_relocs:: *** 141,148 **** layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! this->dynbss_, false, false, false, ! false); } Output_data_space* dynbss = this->dynbss_; --- 141,147 ---- layout->add_output_section_data(".bss", elfcpp::SHT_NOBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! this->dynbss_, ORDER_BSS, false); } Output_data_space* dynbss = this->dynbss_; diff -rcp ../binutils-2.20.51.0.10.original/gold/descriptors.cc gold/descriptors.cc *** ../binutils-2.20.51.0.10.original/gold/descriptors.cc 2010-08-10 15:12:03.000000000 +0100 --- gold/descriptors.cc 2010-08-10 15:14:02.000000000 +0100 *************** Descriptors::open(int descriptor, const *** 113,120 **** { Hold_lock hl(*this->lock_); ! gold_error(_("file %s was removed during the link"), ! this->open_descriptors_[descriptor].name); } errno = ENOENT; --- 113,119 ---- { Hold_lock hl(*this->lock_); ! gold_error(_("file %s was removed during the link"), name); } errno = ENOENT; diff -rcp ../binutils-2.20.51.0.10.original/gold/dwarf_reader.cc gold/dwarf_reader.cc *** ../binutils-2.20.51.0.10.original/gold/dwarf_reader.cc 2010-08-10 15:11:43.000000000 +0100 --- gold/dwarf_reader.cc 2010-08-10 15:14:02.000000000 +0100 *************** *** 32,37 **** --- 32,38 ---- #include "reloc.h" #include "dwarf_reader.h" #include "int_encoding.h" + #include "compressed_output.h" namespace gold { *************** Sized_dwarf_line_info: *** 80,85 **** --- 81,101 ---- if (this->buffer_ == NULL) return; + section_size_type uncompressed_size = 0; + unsigned char* uncompressed_data = NULL; + if (object->section_is_compressed(debug_shndx, &uncompressed_size)) + { + uncompressed_data = new unsigned char[uncompressed_size]; + if (!decompress_input_section(this->buffer_, + this->buffer_end_ - this->buffer_, + uncompressed_data, + uncompressed_size)) + object->error(_("could not decompress section %s"), + object->section_name(debug_shndx).c_str()); + this->buffer_ = uncompressed_data; + this->buffer_end_ = this->buffer_ + uncompressed_size; + } + // Find the relocation section for ".debug_line". // We expect these for relobjs (.o's) but not dynobjs (.so's). bool got_relocs = false; diff -rcp ../binutils-2.20.51.0.10.original/gold/dynobj.cc gold/dynobj.cc *** ../binutils-2.20.51.0.10.original/gold/dynobj.cc 2010-08-10 15:12:03.000000000 +0100 --- gold/dynobj.cc 2010-08-10 15:14:02.000000000 +0100 *************** Sized_dynobj::do_add_s *** 753,760 **** template Archive::Should_include ! Sized_dynobj::do_should_include_member( ! Symbol_table*, Read_symbols_data*, std::string*) { return Archive::SHOULD_INCLUDE_YES; } --- 753,762 ---- template Archive::Should_include ! Sized_dynobj::do_should_include_member(Symbol_table*, ! Layout*, ! Read_symbols_data*, ! std::string*) { return Archive::SHOULD_INCLUDE_YES; } diff -rcp ../binutils-2.20.51.0.10.original/gold/dynobj.h gold/dynobj.h *** ../binutils-2.20.51.0.10.original/gold/dynobj.h 2010-08-10 15:11:43.000000000 +0100 --- gold/dynobj.h 2010-08-10 15:14:02.000000000 +0100 *************** class Sized_dynobj : public Dynobj *** 178,184 **** do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include ! do_should_include_member(Symbol_table* symtab, Read_symbols_data*, std::string* why); // Get the size of a section. --- 178,184 ---- do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include ! do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, std::string* why); // Get the size of a section. diff -rcp ../binutils-2.20.51.0.10.original/gold/fileread.cc gold/fileread.cc *** ../binutils-2.20.51.0.10.original/gold/fileread.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/fileread.cc 2010-08-10 15:14:02.000000000 +0100 *************** File_read::get_mtime() *** 841,857 **** #endif } ! // Try to find a file in the extra search dirs. Returns true on success. ! static bool ! try_extra_search_path(int* pindex, const Input_file_argument* input_argument, ! std::string filename, std::string* found_name, ! std::string* namep) { if (input_argument->extra_search_path() == NULL) return false; std::string name = input_argument->extra_search_path(); ! if (!IS_DIR_SEPARATOR (name[name.length() - 1])) name += '/'; name += filename; --- 841,859 ---- #endif } ! // Try to find a file in the extra search dirs. Returns true on success. ! bool ! Input_file::try_extra_search_path(int* pindex, ! const Input_file_argument* input_argument, ! std::string filename, std::string* found_name, ! std::string* namep) ! { if (input_argument->extra_search_path() == NULL) return false; std::string name = input_argument->extra_search_path(); ! if (!IS_DIR_SEPARATOR(name[name.length() - 1])) name += '/'; name += filename; *************** try_extra_search_path(int* pindex, const *** 873,882 **** // In each, we look in extra_search_path + library_path to find // the file location, rather than the current directory. ! static bool ! find_file(const Dirsearch& dirpath, int* pindex, ! const Input_file_argument* input_argument, bool* is_in_sysroot, ! std::string* found_name, std::string* namep) { std::string name; --- 875,885 ---- // In each, we look in extra_search_path + library_path to find // the file location, rather than the current directory. ! bool ! Input_file::find_file(const Dirsearch& dirpath, int* pindex, ! const Input_file_argument* input_argument, ! bool* is_in_sysroot, ! std::string* found_name, std::string* namep) { std::string name; *************** find_file(const Dirsearch& dirpath, int* *** 914,924 **** else n1 = input_argument->name(); ! if (try_extra_search_path(pindex, input_argument, n1, found_name, namep)) return true; ! if (!n2.empty() && try_extra_search_path(pindex, input_argument, n2, ! found_name, namep)) return true; // It is not in the extra_search_path. --- 917,929 ---- else n1 = input_argument->name(); ! if (Input_file::try_extra_search_path(pindex, input_argument, n1, ! found_name, namep)) return true; ! if (!n2.empty() && Input_file::try_extra_search_path(pindex, ! input_argument, n2, ! found_name, namep)) return true; // It is not in the extra_search_path. *************** bool *** 969,976 **** Input_file::open(const Dirsearch& dirpath, const Task* task, int *pindex) { std::string name; ! if (!find_file(dirpath, pindex, this->input_argument_, &this->is_in_sysroot_, ! &this->found_name_, &name)) return false; // Now that we've figured out where the file lives, try to open it. --- 974,981 ---- Input_file::open(const Dirsearch& dirpath, const Task* task, int *pindex) { std::string name; ! if (!Input_file::find_file(dirpath, pindex, this->input_argument_, ! &this->is_in_sysroot_, &this->found_name_, &name)) return false; // Now that we've figured out where the file lives, try to open it. diff -rcp ../binutils-2.20.51.0.10.original/gold/fileread.h gold/fileread.h *** ../binutils-2.20.51.0.10.original/gold/fileread.h 2010-08-10 15:11:40.000000000 +0100 --- gold/fileread.h 2010-08-10 15:14:02.000000000 +0100 *************** class Input_file *** 565,570 **** --- 565,584 ---- format() const { return this->format_; } + // Try to find a file in the extra search dirs. Returns true on success. + static bool + try_extra_search_path(int* pindex, + const Input_file_argument* input_argument, + std::string filename, std::string* found_name, + std::string* namep); + + // Find the actual file. + static bool + find_file(const Dirsearch& dirpath, int* pindex, + const Input_file_argument* input_argument, + bool* is_in_sysroot, + std::string* found_name, std::string* namep); + private: Input_file(const Input_file&); Input_file& operator=(const Input_file&); diff -rcp ../binutils-2.20.51.0.10.original/gold/gc.h gold/gc.h *** ../binutils-2.20.51.0.10.original/gold/gc.h 2010-08-10 15:11:43.000000000 +0100 --- gold/gc.h 2010-08-10 15:14:02.000000000 +0100 *************** struct Symbols_data *** 151,156 **** --- 151,170 ---- section_size_type symbol_names_size; }; + // Relocations of type SHT_REL store the addend value in their bytes. + // This function returns the size of the embedded addend which is + // nothing but the size of the relocation. + + template + inline unsigned int + get_embedded_addend_size(int sh_type, int r_type, Relobj* obj) + { + if (sh_type != elfcpp::SHT_REL) + return 0; + Classify_reloc classify_reloc; + return classify_reloc.get_size_for_reloc(r_type, obj); + } + // This function implements the generic part of reloc // processing to map a section to all the sections it // references through relocs. It is called only during *************** struct Symbols_data *** 158,164 **** // folding (--icf). template inline void gc_process_relocs( Symbol_table* symtab, --- 172,178 ---- // folding (--icf). template inline void gc_process_relocs( Symbol_table* symtab, *************** gc_process_relocs( *** 185,190 **** --- 199,205 ---- Icf::Symbol_info* symvec = NULL; Icf::Addend_info* addendvec = NULL; Icf::Offset_info* offsetvec = NULL; + Icf::Reloc_addend_size_info* reloc_addend_size_vec = NULL; bool is_icf_tracked = false; const char* cident_section_name = NULL; *************** gc_process_relocs( *** 205,210 **** --- 220,226 ---- symvec = &reloc_info->symbol_info; addendvec = &reloc_info->addend_info; offsetvec = &reloc_info->offset_info; + reloc_addend_size_vec = &reloc_info->reloc_addend_size_info; } check_section_for_function_pointers = *************** gc_process_relocs( *** 243,248 **** --- 259,267 ---- uint64_t reloc_offset = convert_to_section_size_type(reloc.get_r_offset()); (*offsetvec).push_back(reloc_offset); + (*reloc_addend_size_vec).push_back( + get_embedded_addend_size(sh_type, r_type, + src_obj)); } // When doing safe folding, check to see if this relocation is that *************** gc_process_relocs( *** 316,321 **** --- 335,343 ---- uint64_t reloc_offset = convert_to_section_size_type(reloc.get_r_offset()); (*offsetvec).push_back(reloc_offset); + (*reloc_addend_size_vec).push_back( + get_embedded_addend_size(sh_type, r_type, + src_obj)); } if (gsym->source() != Symbol::FROM_OBJECT) diff -rcp ../binutils-2.20.51.0.10.original/gold/gold.cc gold/gold.cc *** ../binutils-2.20.51.0.10.original/gold/gold.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/gold.cc 2010-08-10 15:14:02.000000000 +0100 *************** queue_middle_tasks(const General_options *** 309,315 **** Mapfile* mapfile) { // Add any symbols named with -u options to the symbol table. ! symtab->add_undefined_symbols_from_command_line(); // If garbage collection was chosen, relocs have been read and processed // at this point by pre_middle_tasks. Layout can then be done for all --- 309,315 ---- Mapfile* mapfile) { // Add any symbols named with -u options to the symbol table. ! symtab->add_undefined_symbols_from_command_line(layout); // If garbage collection was chosen, relocs have been read and processed // at this point by pre_middle_tasks. Layout can then be done for all *************** queue_middle_tasks(const General_options *** 333,339 **** } } // Symbols named with -u should not be considered garbage. ! symtab->gc_mark_undef_symbols(); gold_assert(symtab->gc() != NULL); // Do a transitive closure on all references to determine the worklist. symtab->gc()->do_transitive_closure(); --- 333,339 ---- } } // Symbols named with -u should not be considered garbage. ! symtab->gc_mark_undef_symbols(layout); gold_assert(symtab->gc() != NULL); // Do a transitive closure on all references to determine the worklist. symtab->gc()->do_transitive_closure(); diff -rcp ../binutils-2.20.51.0.10.original/gold/i386.cc gold/i386.cc *** ../binutils-2.20.51.0.10.original/gold/i386.cc 2010-08-10 15:11:58.000000000 +0100 --- gold/i386.cc 2010-08-10 15:14:03.000000000 +0100 *************** *** 1,6 **** // i386.cc -- i386 target support for gold. ! // Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. --- 1,6 ---- // i386.cc -- i386 target support for gold. ! // Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. *************** class Target_i386 : public Target_freebs *** 59,66 **** Target_i386() : Target_freebsd<32, false>(&i386_info), ! got_(NULL), plt_(NULL), got_plt_(NULL), global_offset_table_(NULL), ! rel_dyn_(NULL), copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL), got_mod_index_offset_(-1U), tls_base_symbol_defined_(false) { } --- 59,67 ---- Target_i386() : Target_freebsd<32, false>(&i386_info), ! got_(NULL), plt_(NULL), got_plt_(NULL), got_tlsdesc_(NULL), ! global_offset_table_(NULL), rel_dyn_(NULL), ! copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL), got_mod_index_offset_(-1U), tls_base_symbol_defined_(false) { } *************** class Target_i386 : public Target_freebs *** 385,390 **** --- 386,399 ---- return this->got_plt_; } + // Get the GOT section for TLSDESC entries. + Output_data_got<32, false>* + got_tlsdesc_section() const + { + gold_assert(this->got_tlsdesc_ != NULL); + return this->got_tlsdesc_; + } + // Create a PLT entry for a global symbol. void make_plt_entry(Symbol_table*, Layout*, Symbol*); *************** class Target_i386 : public Target_freebs *** 447,452 **** --- 456,463 ---- Output_data_plt_i386* plt_; // The GOT PLT section. Output_data_space* got_plt_; + // The GOT section for TLSDESC relocations. + Output_data_got<32, false>* got_tlsdesc_; // The _GLOBAL_OFFSET_TABLE_ symbol. Symbol* global_offset_table_; // The dynamic reloc section. *************** Target_i386::got_section(Symbol_table* s *** 494,512 **** this->got_ = new Output_data_got<32, false>(); ! Output_section* os; ! os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_, false, true, true, ! false); this->got_plt_ = new Output_data_space(4, "** GOT PLT"); ! os = layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_plt_, false, false, false, ! true); // The first three entries are reserved. this->got_plt_->set_current_data_size(3 * 4); --- 505,521 ---- this->got_ = new Output_data_got<32, false>(); ! layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_, ORDER_RELRO_LAST, true); this->got_plt_ = new Output_data_space(4, "** GOT PLT"); ! layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_plt_, ORDER_NON_RELRO_FIRST, ! false); // The first three entries are reserved. this->got_plt_->set_current_data_size(3 * 4); *************** Target_i386::got_section(Symbol_table* s *** 523,528 **** --- 532,546 ---- elfcpp::STB_LOCAL, elfcpp::STV_HIDDEN, 0, false, false); + + // If there are any TLSDESC relocations, they get GOT entries in + // .got.plt after the jump slot entries. + this->got_tlsdesc_ = new Output_data_got<32, false>(); + layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + this->got_tlsdesc_, + ORDER_NON_RELRO_FIRST, false); } return this->got_; *************** Target_i386::rel_dyn_section(Layout* lay *** 538,545 **** gold_assert(layout != NULL); this->rel_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, ! elfcpp::SHF_ALLOC, this->rel_dyn_, true, ! false, false, false); } return this->rel_dyn_; } --- 556,563 ---- gold_assert(layout != NULL); this->rel_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, ! elfcpp::SHF_ALLOC, this->rel_dyn_, ! ORDER_DYNAMIC_RELOCS, false); } return this->rel_dyn_; } *************** Output_data_plt_i386::Output_data_plt_i3 *** 621,628 **** { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, ! elfcpp::SHF_ALLOC, this->rel_, true, ! false, false, false); } void --- 639,646 ---- { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, ! elfcpp::SHF_ALLOC, this->rel_, ! ORDER_DYNAMIC_PLT_RELOCS, false); } void *************** Output_data_plt_i386::rel_tls_desc(Layou *** 674,680 **** this->tls_desc_rel_ = new Reloc_section(false); layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, elfcpp::SHF_ALLOC, this->tls_desc_rel_, ! true, false, false, false); gold_assert(this->tls_desc_rel_->output_section() == this->rel_->output_section()); } --- 692,698 ---- this->tls_desc_rel_ = new Reloc_section(false); layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, elfcpp::SHF_ALLOC, this->tls_desc_rel_, ! ORDER_DYNAMIC_PLT_RELOCS, false); gold_assert(this->tls_desc_rel_->output_section() == this->rel_->output_section()); } *************** Target_i386::make_plt_entry(Symbol_table *** 825,831 **** layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), ! this->plt_, false, false, false, false); } this->plt_->add_entry(gsym); --- 843,849 ---- layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), ! this->plt_, ORDER_PLT, false); } this->plt_->add_entry(gsym); *************** Target_i386::Scan::local(Symbol_table* s *** 1119,1127 **** target->define_tls_base_symbol(symtab, layout); if (optimized_type == tls::TLSOPT_NONE) { ! // Create a double GOT entry with an R_386_TLS_DESC reloc. ! Output_data_got<32, false>* got ! = target->got_section(symtab, layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC)) { --- 1137,1149 ---- target->define_tls_base_symbol(symtab, layout); if (optimized_type == tls::TLSOPT_NONE) { ! // Create a double GOT entry with an R_386_TLS_DESC ! // reloc. The R_386_TLS_DESC reloc is resolved ! // lazily, so the GOT entry needs to be in an area in ! // .got.plt, not .got. Call got_section to make sure ! // the section has been created. ! target->got_section(symtab, layout); ! Output_data_got<32, false>* got = target->got_tlsdesc_section(); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC)) { *************** Target_i386::Scan::global(Symbol_table* *** 1503,1511 **** target->define_tls_base_symbol(symtab, layout); if (optimized_type == tls::TLSOPT_NONE) { ! // Create a double GOT entry with an R_386_TLS_DESC reloc. ! Output_data_got<32, false>* got ! = target->got_section(symtab, layout); Reloc_section* rt = target->rel_tls_desc_section(layout); got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt, elfcpp::R_386_TLS_DESC, 0); --- 1525,1537 ---- target->define_tls_base_symbol(symtab, layout); if (optimized_type == tls::TLSOPT_NONE) { ! // Create a double GOT entry with an R_386_TLS_DESC ! // reloc. The R_386_TLS_DESC reloc is resolved ! // lazily, so the GOT entry needs to be in an area in ! // .got.plt, not .got. Call got_section to make sure ! // the section has been created. ! target->got_section(symtab, layout); ! Output_data_got<32, false>* got = target->got_tlsdesc_section(); Reloc_section* rt = target->rel_tls_desc_section(layout); got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt, elfcpp::R_386_TLS_DESC, 0); *************** Target_i386::gc_process_relocs(Symbol_ta *** 1626,1632 **** const unsigned char* plocal_symbols) { gold::gc_process_relocs<32, false, Target_i386, elfcpp::SHT_REL, ! Target_i386::Scan>( symtab, layout, this, --- 1652,1659 ---- const unsigned char* plocal_symbols) { gold::gc_process_relocs<32, false, Target_i386, elfcpp::SHT_REL, ! Target_i386::Scan, ! Target_i386::Relocatable_size_for_reloc>( symtab, layout, this, *************** Target_i386::Relocate::relocate_tls(cons *** 2047,2064 **** unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE ? GOT_TYPE_TLS_NOFFSET : GOT_TYPE_TLS_DESC); ! unsigned int got_offset; if (gsym != NULL) { gold_assert(gsym->has_got_offset(got_type)); ! got_offset = gsym->got_offset(got_type) - target->got_size(); } else { unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); gold_assert(object->local_has_got_offset(r_sym, got_type)); ! got_offset = (object->local_got_offset(r_sym, got_type) ! - target->got_size()); } if (optimized_type == tls::TLSOPT_TO_IE) { --- 2074,2100 ---- unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE ? GOT_TYPE_TLS_NOFFSET : GOT_TYPE_TLS_DESC); ! unsigned int got_offset = 0; ! if (r_type == elfcpp::R_386_TLS_GOTDESC ! && optimized_type == tls::TLSOPT_NONE) ! { ! // We created GOT entries in the .got.tlsdesc portion of ! // the .got.plt section, but the offset stored in the ! // symbol is the offset within .got.tlsdesc. ! got_offset = (target->got_size() ! + target->got_plt_section()->data_size()); ! } if (gsym != NULL) { gold_assert(gsym->has_got_offset(got_type)); ! got_offset += gsym->got_offset(got_type) - target->got_size(); } else { unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); gold_assert(object->local_has_got_offset(r_sym, got_type)); ! got_offset += (object->local_got_offset(r_sym, got_type) ! - target->got_size()); } if (optimized_type == tls::TLSOPT_TO_IE) { diff -rcp ../binutils-2.20.51.0.10.original/gold/icf.cc gold/icf.cc *** ../binutils-2.20.51.0.10.original/gold/icf.cc 2010-08-10 15:11:43.000000000 +0100 --- gold/icf.cc 2010-08-10 15:14:03.000000000 +0100 *************** *** 145,150 **** --- 145,152 ---- #include "symtab.h" #include "libiberty.h" #include "demangle.h" + #include "elfcpp.h" + #include "int_encoding.h" namespace gold { *************** get_section_contents(bool first_iteratio *** 269,280 **** Icf::Addend_info a = (it_reloc_info_list->second).addend_info; // Stores the offset of the reloc. Icf::Offset_info o = (it_reloc_info_list->second).offset_info; Icf::Sections_reachable_info::iterator it_v = v.begin(); Icf::Symbol_info::iterator it_s = s.begin(); Icf::Addend_info::iterator it_a = a.begin(); Icf::Offset_info::iterator it_o = o.begin(); ! for (; it_v != v.end(); ++it_v, ++it_s, ++it_a, ++it_o) { // ADDEND_STR stores the symbol value and addend and offset, // each atmost 16 hex digits long. it_a points to a pair --- 271,286 ---- Icf::Addend_info a = (it_reloc_info_list->second).addend_info; // Stores the offset of the reloc. Icf::Offset_info o = (it_reloc_info_list->second).offset_info; + Icf::Reloc_addend_size_info reloc_addend_size_info = + (it_reloc_info_list->second).reloc_addend_size_info; Icf::Sections_reachable_info::iterator it_v = v.begin(); Icf::Symbol_info::iterator it_s = s.begin(); Icf::Addend_info::iterator it_a = a.begin(); Icf::Offset_info::iterator it_o = o.begin(); + Icf::Reloc_addend_size_info::iterator it_addend_size = + reloc_addend_size_info.begin(); ! for (; it_v != v.end(); ++it_v, ++it_s, ++it_a, ++it_o, ++it_addend_size) { // ADDEND_STR stores the symbol value and addend and offset, // each atmost 16 hex digits long. it_a points to a pair *************** get_section_contents(bool first_iteratio *** 372,377 **** --- 378,423 ---- if (addend < 0xffffff00) offset = offset + addend; + // For SHT_REL relocation sections, the addend is stored in the + // text section at the relocation offset. + uint64_t reloc_addend_value = 0; + const unsigned char* reloc_addend_ptr = + contents + static_cast(*it_o); + switch(*it_addend_size) + { + case 0: + { + break; + } + case 1: + { + reloc_addend_value = + read_from_pointer<8>(reloc_addend_ptr); + break; + } + case 2: + { + reloc_addend_value = + read_from_pointer<16>(reloc_addend_ptr); + break; + } + case 4: + { + reloc_addend_value = + read_from_pointer<32>(reloc_addend_ptr); + break; + } + case 8: + { + reloc_addend_value = + read_from_pointer<64>(reloc_addend_ptr); + break; + } + default: + gold_unreachable(); + } + offset = offset + reloc_addend_value; + section_size_type secn_len; const unsigned char* str_contents = (it_v->first)->section_contents(it_v->second, diff -rcp ../binutils-2.20.51.0.10.original/gold/icf.h gold/icf.h *** ../binutils-2.20.51.0.10.original/gold/icf.h 2010-08-10 15:12:03.000000000 +0100 --- gold/icf.h 2010-08-10 15:14:03.000000000 +0100 *************** class Icf *** 43,48 **** --- 43,49 ---- typedef std::vector Symbol_info; typedef std::vector > Addend_info; typedef std::vector Offset_info; + typedef std::vector Reloc_addend_size_info; typedef Unordered_map Uniq_secn_id_map; *************** class Icf *** 57,62 **** --- 58,64 ---- // This stores the symbol value and the addend for a reloc. Addend_info addend_info; Offset_info offset_info; + Reloc_addend_size_info reloc_addend_size_info; } Reloc_info; typedef Unordered_mapinsert(destination->end(), buffer, buffer + valsize / 8); } + // Read a possibly unaligned integer of SIZE from SOURCE. + + template + typename elfcpp::Valtype_base::Valtype + read_from_pointer(const unsigned char* source) + { + typename elfcpp::Valtype_base::Valtype return_value; + if (parameters->target().is_big_endian()) + return_value = elfcpp::Swap_unaligned::readval(source); + else + return_value = elfcpp::Swap_unaligned::readval(source); + return return_value; + } + // Read a possibly unaligned integer of SIZE. Update SOURCE after read. template diff -rcp ../binutils-2.20.51.0.10.original/gold/layout.cc gold/layout.cc *** ../binutils-2.20.51.0.10.original/gold/layout.cc 2010-08-10 15:12:03.000000000 +0100 --- gold/layout.cc 2010-08-10 15:14:03.000000000 +0100 *************** Layout::find_output_segment(elfcpp::PT t *** 409,417 **** Output_section* Layout::get_output_section(const char* name, Stringpool::Key name_key, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! bool is_interp, bool is_dynamic_linker_section, ! bool is_relro, bool is_last_relro, ! bool is_first_non_relro) { elfcpp::Elf_Xword lookup_flags = flags; --- 409,415 ---- Output_section* Layout::get_output_section(const char* name, Stringpool::Key name_key, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! Output_section_order order, bool is_relro) { elfcpp::Elf_Xword lookup_flags = flags; *************** Layout::get_output_section(const char* n *** 460,468 **** } if (os == NULL) ! os = this->make_output_section(name, type, flags, is_interp, ! is_dynamic_linker_section, is_relro, ! is_last_relro, is_first_non_relro); ins.first->second = os; return os; } --- 458,465 ---- } if (os == NULL) ! os = this->make_output_section(name, type, flags, order, is_relro); ! ins.first->second = os; return os; } *************** Layout::get_output_section(const char* n *** 482,490 **** Output_section* Layout::choose_output_section(const Relobj* relobj, const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! bool is_input_section, bool is_interp, ! bool is_dynamic_linker_section, bool is_relro, ! bool is_last_relro, bool is_first_non_relro) { // We should not see any input sections after we have attached // sections to segments. --- 479,486 ---- Output_section* Layout::choose_output_section(const Relobj* relobj, const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! bool is_input_section, Output_section_order order, ! bool is_relro) { // We should not see any input sections after we have attached // sections to segments. *************** Layout::choose_output_section(const Relo *** 546,555 **** name = this->namepool_.add(name, false, NULL); ! Output_section* os = ! this->make_output_section(name, type, flags, is_interp, ! is_dynamic_linker_section, is_relro, ! is_last_relro, is_first_non_relro); os->set_found_in_sections_clause(); // Special handling for NOLOAD sections. --- 542,550 ---- name = this->namepool_.add(name, false, NULL); ! Output_section* os = this->make_output_section(name, type, flags, ! order, is_relro); ! os->set_found_in_sections_clause(); // Special handling for NOLOAD sections. *************** Layout::choose_output_section(const Relo *** 591,599 **** // Find or make the output section. The output section is selected // based on the section name, type, and flags. ! return this->get_output_section(name, name_key, type, flags, is_interp, ! is_dynamic_linker_section, is_relro, ! is_last_relro, is_first_non_relro); } // Return the output section to use for input section SHNDX, with name --- 586,592 ---- // Find or make the output section. The output section is selected // based on the section name, type, and flags. ! return this->get_output_section(name, name_key, type, flags, order, is_relro); } // Return the output section to use for input section SHNDX, with name *************** Layout::layout(Sized_relobjnamepool_.add(name, true, NULL); ! os = this->make_output_section(name, sh_type, shdr.get_sh_flags(), false, ! false, false, false, false); } else { os = this->choose_output_section(object, name, sh_type, ! shdr.get_sh_flags(), true, false, ! false, false, false, false); if (os == NULL) return NULL; } --- 640,653 ---- && (shdr.get_sh_flags() & elfcpp::SHF_GROUP) != 0) { name = this->namepool_.add(name, true, NULL); ! os = this->make_output_section(name, sh_type, shdr.get_sh_flags(), ! ORDER_INVALID, false); } else { os = this->choose_output_section(object, name, sh_type, ! shdr.get_sh_flags(), true, ! ORDER_INVALID, false); if (os == NULL) return NULL; } *************** Layout::layout_reloc(Sized_relobjoptions().relocatable() || (data_section->flags() & elfcpp::SHF_GROUP) == 0) os = this->choose_output_section(object, name.c_str(), sh_type, ! shdr.get_sh_flags(), false, false, ! false, false, false, false); else { const char* n = this->namepool_.add(name.c_str(), true, NULL); os = this->make_output_section(n, sh_type, shdr.get_sh_flags(), ! false, false, false, false, false); } os->set_should_link_to_symtab(); --- 702,714 ---- if (!parameters->options().relocatable() || (data_section->flags() & elfcpp::SHF_GROUP) == 0) os = this->choose_output_section(object, name.c_str(), sh_type, ! shdr.get_sh_flags(), false, ! ORDER_INVALID, false); else { const char* n = this->namepool_.add(name.c_str(), true, NULL); os = this->make_output_section(n, sh_type, shdr.get_sh_flags(), ! ORDER_INVALID, false); } os->set_should_link_to_symtab(); *************** Layout::layout_group(Symbol_table* symta *** 764,771 **** Output_section* os = this->make_output_section(group_section_name, elfcpp::SHT_GROUP, shdr.get_sh_flags(), ! false, false, false, ! false, false); // We need to find a symbol with the signature in the symbol table. // If we don't find one now, we need to look again later. --- 757,763 ---- Output_section* os = this->make_output_section(group_section_name, elfcpp::SHT_GROUP, shdr.get_sh_flags(), ! ORDER_INVALID, false); // We need to find a symbol with the signature in the symbol table. // If we don't find one now, we need to look again later. *************** Layout::layout_eh_frame(Sized_relobjchoose_output_section(object, ! name, elfcpp::SHT_PROGBITS, ! elfcpp::SHF_ALLOC, ! false, false, false, ! false, false, false); if (os == NULL) return NULL; --- 807,816 ---- gold_assert((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0); const char* const name = ".eh_frame"; ! Output_section* os = this->choose_output_section(object, name, elfcpp::SHT_PROGBITS, ! elfcpp::SHF_ALLOC, false, ! ORDER_EHFRAME, false); if (os == NULL) return NULL; *************** Layout::layout_eh_frame(Sized_relobjoptions().eh_frame_hdr()) { Output_section* hdr_os = ! this->choose_output_section(NULL, ! ".eh_frame_hdr", elfcpp::SHT_PROGBITS, ! elfcpp::SHF_ALLOC, ! false, false, false, ! false, false, false); if (hdr_os != NULL) { --- 822,831 ---- if (parameters->options().eh_frame_hdr()) { Output_section* hdr_os = ! this->choose_output_section(NULL, ".eh_frame_hdr", elfcpp::SHT_PROGBITS, ! elfcpp::SHF_ALLOC, false, ! ORDER_EHFRAME, false); if (hdr_os != NULL) { *************** Layout::layout_eh_frame(Sized_relobjmake_output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R); ! hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R, false); } this->eh_frame_data_->set_eh_frame_hdr(hdr_posd); --- 840,847 ---- Output_segment* hdr_oseg; hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R); ! hdr_oseg->add_output_section_to_nonload(hdr_os, ! elfcpp::PF_R); } this->eh_frame_data_->set_eh_frame_hdr(hdr_posd); *************** Output_section* *** 905,919 **** Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, Output_section_data* posd, ! bool is_dynamic_linker_section, ! bool is_relro, bool is_last_relro, ! bool is_first_non_relro) { Output_section* os = this->choose_output_section(NULL, name, type, flags, ! false, false, ! is_dynamic_linker_section, ! is_relro, is_last_relro, ! is_first_non_relro); if (os != NULL) os->add_output_section_data(posd); return os; --- 894,903 ---- Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, Output_section_data* posd, ! Output_section_order order, bool is_relro) { Output_section* os = this->choose_output_section(NULL, name, type, flags, ! false, order, is_relro); if (os != NULL) os->add_output_section_data(posd); return os; *************** Layout::section_flags_to_segment(elfcpp: *** 944,964 **** static bool is_compressible_debug_section(const char* secname) { ! return (strncmp(secname, ".debug", sizeof(".debug") - 1) == 0); } // Make a new Output_section, and attach it to segments as ! // appropriate. IS_INTERP is true if this is the .interp section. ! // IS_DYNAMIC_LINKER_SECTION is true if this section is used by the ! // dynamic linker. IS_RELRO is true if this is a relro section. ! // IS_LAST_RELRO is true if this is the last relro section. ! // IS_FIRST_NON_RELRO is true if this is the first non relro section. Output_section* Layout::make_output_section(const char* name, elfcpp::Elf_Word type, ! elfcpp::Elf_Xword flags, bool is_interp, ! bool is_dynamic_linker_section, bool is_relro, ! bool is_last_relro, bool is_first_non_relro) { Output_section* os; if ((flags & elfcpp::SHF_ALLOC) == 0 --- 928,954 ---- static bool is_compressible_debug_section(const char* secname) { ! return (is_prefix_of(".debug", secname)); ! } ! ! // We may see compressed debug sections in input files. Return TRUE ! // if this is the name of a compressed debug section. ! ! bool ! is_compressed_debug_section(const char* secname) ! { ! return (is_prefix_of(".zdebug", secname)); } // Make a new Output_section, and attach it to segments as ! // appropriate. ORDER is the order in which this section should ! // appear in the output segment. IS_RELRO is true if this is a relro ! // (read-only after relocations) section. Output_section* Layout::make_output_section(const char* name, elfcpp::Elf_Word type, ! elfcpp::Elf_Xword flags, ! Output_section_order order, bool is_relro) { Output_section* os; if ((flags & elfcpp::SHF_ALLOC) == 0 *************** Layout::make_output_section(const char* *** 991,1006 **** os = target->make_output_section(name, type, flags); } ! if (is_interp) ! os->set_is_interp(); ! if (is_dynamic_linker_section) ! os->set_is_dynamic_linker_section(); if (is_relro) os->set_is_relro(); ! if (is_last_relro) ! os->set_is_last_relro(); ! if (is_first_non_relro) ! os->set_is_first_non_relro(); parameters->target().new_output_section(os); --- 981,1019 ---- os = target->make_output_section(name, type, flags); } ! // With -z relro, we have to recognize the special sections by name. ! // There is no other way. ! bool is_relro_local = false; ! if (!this->script_options_->saw_sections_clause() ! && parameters->options().relro() ! && type == elfcpp::SHT_PROGBITS ! && (flags & elfcpp::SHF_ALLOC) != 0 ! && (flags & elfcpp::SHF_WRITE) != 0) ! { ! if (strcmp(name, ".data.rel.ro") == 0) ! is_relro = true; ! else if (strcmp(name, ".data.rel.ro.local") == 0) ! { ! is_relro = true; ! is_relro_local = true; ! } ! else if (type == elfcpp::SHT_INIT_ARRAY ! || type == elfcpp::SHT_FINI_ARRAY ! || type == elfcpp::SHT_PREINIT_ARRAY) ! is_relro = true; ! else if (strcmp(name, ".ctors") == 0 ! || strcmp(name, ".dtors") == 0 ! || strcmp(name, ".jcr") == 0) ! is_relro = true; ! } ! if (is_relro) os->set_is_relro(); ! ! if (order == ORDER_INVALID && (flags & elfcpp::SHF_ALLOC) != 0) ! order = this->default_section_order(os, is_relro_local); ! ! os->set_order(order); parameters->target().new_output_section(os); *************** Layout::make_output_section(const char* *** 1016,1038 **** || strcmp(name, ".fini_array") == 0)) os->set_may_sort_attached_input_sections(); - // With -z relro, we have to recognize the special sections by name. - // There is no other way. - if (!this->script_options_->saw_sections_clause() - && parameters->options().relro() - && type == elfcpp::SHT_PROGBITS - && (flags & elfcpp::SHF_ALLOC) != 0 - && (flags & elfcpp::SHF_WRITE) != 0) - { - if (strcmp(name, ".data.rel.ro") == 0) - os->set_is_relro(); - else if (strcmp(name, ".data.rel.ro.local") == 0) - { - os->set_is_relro(); - os->set_is_relro_local(); - } - } - // Check for .stab*str sections, as .stab* sections need to link to // them. if (type == elfcpp::SHT_STRTAB --- 1029,1034 ---- *************** Layout::make_output_section(const char* *** 1050,1055 **** --- 1046,1119 ---- return os; } + // Return the default order in which a section should be placed in an + // output segment. This function captures a lot of the ideas in + // ld/scripttempl/elf.sc in the GNU linker. Note that the order of a + // linker created section is normally set when the section is created; + // this function is used for input sections. + + Output_section_order + Layout::default_section_order(Output_section* os, bool is_relro_local) + { + gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0); + bool is_write = (os->flags() & elfcpp::SHF_WRITE) != 0; + bool is_execinstr = (os->flags() & elfcpp::SHF_EXECINSTR) != 0; + bool is_bss = false; + + switch (os->type()) + { + default: + case elfcpp::SHT_PROGBITS: + break; + case elfcpp::SHT_NOBITS: + is_bss = true; + break; + case elfcpp::SHT_RELA: + case elfcpp::SHT_REL: + if (!is_write) + return ORDER_DYNAMIC_RELOCS; + break; + case elfcpp::SHT_HASH: + case elfcpp::SHT_DYNAMIC: + case elfcpp::SHT_SHLIB: + case elfcpp::SHT_DYNSYM: + case elfcpp::SHT_GNU_HASH: + case elfcpp::SHT_GNU_verdef: + case elfcpp::SHT_GNU_verneed: + case elfcpp::SHT_GNU_versym: + if (!is_write) + return ORDER_DYNAMIC_LINKER; + break; + case elfcpp::SHT_NOTE: + return is_write ? ORDER_RW_NOTE : ORDER_RO_NOTE; + } + + if ((os->flags() & elfcpp::SHF_TLS) != 0) + return is_bss ? ORDER_TLS_BSS : ORDER_TLS_DATA; + + if (!is_bss && !is_write) + { + if (is_execinstr) + { + if (strcmp(os->name(), ".init") == 0) + return ORDER_INIT; + else if (strcmp(os->name(), ".fini") == 0) + return ORDER_FINI; + } + return is_execinstr ? ORDER_TEXT : ORDER_READONLY; + } + + if (os->is_relro()) + return is_relro_local ? ORDER_RELRO_LOCAL : ORDER_RELRO; + + if (os->is_small_section()) + return is_bss ? ORDER_SMALL_BSS : ORDER_SMALL_DATA; + if (os->is_large_section()) + return is_bss ? ORDER_LARGE_BSS : ORDER_LARGE_DATA; + + return is_bss ? ORDER_BSS : ORDER_DATA; + } + // Attach output sections to segments. This is called after we have // seen all the input sections. *************** Layout::attach_allocated_section_to_segm *** 1139,1145 **** break; } ! (*p)->add_output_section(os, seg_flags, true); break; } --- 1203,1209 ---- break; } ! (*p)->add_output_section_to_load(this, os, seg_flags); break; } *************** Layout::attach_allocated_section_to_segm *** 1149,1155 **** seg_flags); if (os->is_large_data_section()) oseg->set_is_large_data_segment(); ! oseg->add_output_section(os, seg_flags, true); if (is_address_set) oseg->set_addresses(addr, addr); } --- 1213,1219 ---- seg_flags); if (os->is_large_data_section()) oseg->set_is_large_data_segment(); ! oseg->add_output_section_to_load(this, os, seg_flags); if (is_address_set) oseg->set_addresses(addr, addr); } *************** Layout::attach_allocated_section_to_segm *** 1167,1173 **** && (((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))) { ! (*p)->add_output_section(os, seg_flags, false); break; } } --- 1231,1237 ---- && (((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))) { ! (*p)->add_output_section_to_nonload(os, seg_flags); break; } } *************** Layout::attach_allocated_section_to_segm *** 1176,1182 **** { Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE, seg_flags); ! oseg->add_output_section(os, seg_flags, false); } } --- 1240,1246 ---- { Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE, seg_flags); ! oseg->add_output_section_to_nonload(os, seg_flags); } } *************** Layout::attach_allocated_section_to_segm *** 1186,1192 **** { if (this->tls_segment_ == NULL) this->make_output_segment(elfcpp::PT_TLS, seg_flags); ! this->tls_segment_->add_output_section(os, seg_flags, false); } // If -z relro is in effect, and we see a relro section, we create a --- 1250,1256 ---- { if (this->tls_segment_ == NULL) this->make_output_segment(elfcpp::PT_TLS, seg_flags); ! this->tls_segment_->add_output_section_to_nonload(os, seg_flags); } // If -z relro is in effect, and we see a relro section, we create a *************** Layout::attach_allocated_section_to_segm *** 1196,1202 **** gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W)); if (this->relro_segment_ == NULL) this->make_output_segment(elfcpp::PT_GNU_RELRO, seg_flags); ! this->relro_segment_->add_output_section(os, seg_flags, false); } } --- 1260,1266 ---- gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W)); if (this->relro_segment_ == NULL) this->make_output_segment(elfcpp::PT_GNU_RELRO, seg_flags); ! this->relro_segment_->add_output_section_to_nonload(os, seg_flags); } } *************** Layout::make_output_section_for_script( *** 1212,1219 **** if (section_type == Script_sections::ST_NOLOAD) sh_flags = 0; Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS, ! sh_flags, false, ! false, false, false, false); os->set_found_in_sections_clause(); if (section_type == Script_sections::ST_NOLOAD) os->set_is_noload(); --- 1276,1283 ---- if (section_type == Script_sections::ST_NOLOAD) sh_flags = 0; Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS, ! sh_flags, ORDER_INVALID, ! false); os->set_found_in_sections_clause(); if (section_type == Script_sections::ST_NOLOAD) os->set_is_noload(); *************** Layout::create_initial_dynamic_sections( *** 1285,1292 **** elfcpp::SHT_DYNAMIC, (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), ! false, false, true, ! true, false, false); this->dynamic_symbol_ = symtab->define_in_output_data("_DYNAMIC", NULL, Symbol_table::PREDEFINED, --- 1349,1356 ---- elfcpp::SHT_DYNAMIC, (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), ! false, ORDER_RELRO, ! true); this->dynamic_symbol_ = symtab->define_in_output_data("_DYNAMIC", NULL, Symbol_table::PREDEFINED, *************** Layout::relaxation_loop_body( *** 1591,1607 **** || this->script_options_->saw_sections_clause()); // If the address of the load segment we found has been set by ! // --section-start rather than by a script, then we don't want to ! // use it for the file and segment headers. if (load_seg != NULL && load_seg->are_addresses_set() ! && !this->script_options_->saw_sections_clause()) ! load_seg = NULL; // Lay out the segment headers. if (!parameters->options().relocatable()) { gold_assert(segment_headers != NULL); if (load_seg != NULL) load_seg->add_initial_output_data(segment_headers); if (phdr_seg != NULL) --- 1655,1695 ---- || this->script_options_->saw_sections_clause()); // If the address of the load segment we found has been set by ! // --section-start rather than by a script, then adjust the VMA and ! // LMA downward if possible to include the file and section headers. ! uint64_t header_gap = 0; if (load_seg != NULL && load_seg->are_addresses_set() ! && !this->script_options_->saw_sections_clause() ! && !parameters->options().relocatable()) ! { ! file_header->finalize_data_size(); ! segment_headers->finalize_data_size(); ! size_t sizeof_headers = (file_header->data_size() ! + segment_headers->data_size()); ! const uint64_t abi_pagesize = target->abi_pagesize(); ! uint64_t hdr_paddr = load_seg->paddr() - sizeof_headers; ! hdr_paddr &= ~(abi_pagesize - 1); ! uint64_t subtract = load_seg->paddr() - hdr_paddr; ! if (load_seg->paddr() < subtract || load_seg->vaddr() < subtract) ! load_seg = NULL; ! else ! { ! load_seg->set_addresses(load_seg->vaddr() - subtract, ! load_seg->paddr() - subtract); ! header_gap = subtract - sizeof_headers; ! } ! } // Lay out the segment headers. if (!parameters->options().relocatable()) { gold_assert(segment_headers != NULL); + if (header_gap != 0 && load_seg != NULL) + { + Output_data_zero_fill* z = new Output_data_zero_fill(header_gap, 1); + load_seg->add_initial_output_data(z); + } if (load_seg != NULL) load_seg->add_initial_output_data(segment_headers); if (phdr_seg != NULL) *************** Layout::create_note(const char* name, in *** 1971,1982 **** memcpy(buffer + 3 * (size / 8), name, namesz); elfcpp::Elf_Xword flags = 0; if (allocate) ! flags = elfcpp::SHF_ALLOC; Output_section* os = this->choose_output_section(NULL, section_name, elfcpp::SHT_NOTE, ! flags, false, false, ! false, false, false, false); if (os == NULL) return NULL; --- 2059,2073 ---- memcpy(buffer + 3 * (size / 8), name, namesz); elfcpp::Elf_Xword flags = 0; + Output_section_order order = ORDER_INVALID; if (allocate) ! { ! flags = elfcpp::SHF_ALLOC; ! order = ORDER_RO_NOTE; ! } Output_section* os = this->choose_output_section(NULL, section_name, elfcpp::SHT_NOTE, ! flags, false, order, false); if (os == NULL) return NULL; *************** Layout::create_executable_stack_info() *** 2055,2062 **** elfcpp::Elf_Xword flags = 0; if (is_stack_executable) flags |= elfcpp::SHF_EXECINSTR; ! this->make_output_section(name, elfcpp::SHT_PROGBITS, flags, false, ! false, false, false, false); } else { --- 2146,2153 ---- elfcpp::Elf_Xword flags = 0; if (is_stack_executable) flags |= elfcpp::SHF_EXECINSTR; ! this->make_output_section(name, elfcpp::SHT_PROGBITS, flags, ! ORDER_INVALID, false); } else { *************** Layout::create_incremental_info_sections *** 2217,2223 **** Output_section* inputs_os = this->make_output_section(incremental_inputs_name, elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0, ! false, false, false, false, false); Output_section_data* posd = this->incremental_inputs_->create_incremental_inputs_section_data(); inputs_os->add_output_section_data(posd); --- 2308,2314 ---- Output_section* inputs_os = this->make_output_section(incremental_inputs_name, elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0, ! ORDER_INVALID, false); Output_section_data* posd = this->incremental_inputs_->create_incremental_inputs_section_data(); inputs_os->add_output_section_data(posd); *************** Layout::create_incremental_info_sections *** 2227,2234 **** this->namepool_.add(".gnu_incremental_strtab", false, NULL); Output_section* strtab_os = this->make_output_section(incremental_strtab_name, elfcpp::SHT_STRTAB, ! 0, false, false, ! false, false, false); Output_data_strtab* strtab_data = new Output_data_strtab(this->incremental_inputs_->get_stringpool()); strtab_os->add_output_section_data(strtab_data); --- 2318,2325 ---- this->namepool_.add(".gnu_incremental_strtab", false, NULL); Output_section* strtab_os = this->make_output_section(incremental_strtab_name, elfcpp::SHT_STRTAB, ! 0, ORDER_INVALID, ! false); Output_data_strtab* strtab_data = new Output_data_strtab(this->incremental_inputs_->get_stringpool()); strtab_os->add_output_section_data(strtab_data); *************** Layout::segment_precedes(const Output_se *** 2321,2328 **** if (section_count1 > 0 && section_count2 == 0) return false; ! uint64_t paddr1 = seg1->first_section_load_address(); ! uint64_t paddr2 = seg2->first_section_load_address(); if (paddr1 != paddr2) return paddr1 < paddr2; } --- 2412,2419 ---- if (section_count1 > 0 && section_count2 == 0) return false; ! uint64_t paddr1 = seg1->paddr(); ! uint64_t paddr2 = seg2->paddr(); if (paddr1 != paddr2) return paddr1 < paddr2; } *************** Layout::create_symtab_sections(const Inp *** 2848,2855 **** const char* symtab_name = this->namepool_.add(".symtab", false, NULL); Output_section* osymtab = this->make_output_section(symtab_name, elfcpp::SHT_SYMTAB, ! 0, false, false, ! false, false, false); this->symtab_section_ = osymtab; Output_section_data* pos = new Output_data_fixed_space(off - startoff, --- 2939,2946 ---- const char* symtab_name = this->namepool_.add(".symtab", false, NULL); Output_section* osymtab = this->make_output_section(symtab_name, elfcpp::SHT_SYMTAB, ! 0, ORDER_INVALID, ! false); this->symtab_section_ = osymtab; Output_section_data* pos = new Output_data_fixed_space(off - startoff, *************** Layout::create_symtab_sections(const Inp *** 2870,2877 **** false, NULL); Output_section* osymtab_xindex = this->make_output_section(symtab_xindex_name, ! elfcpp::SHT_SYMTAB_SHNDX, 0, false, ! false, false, false, false); size_t symcount = (off - startoff) / symsize; this->symtab_xindex_ = new Output_symtab_xindex(symcount); --- 2961,2968 ---- false, NULL); Output_section* osymtab_xindex = this->make_output_section(symtab_xindex_name, ! elfcpp::SHT_SYMTAB_SHNDX, 0, ! ORDER_INVALID, false); size_t symcount = (off - startoff) / symsize; this->symtab_xindex_ = new Output_symtab_xindex(symcount); *************** Layout::create_symtab_sections(const Inp *** 2893,2900 **** const char* strtab_name = this->namepool_.add(".strtab", false, NULL); Output_section* ostrtab = this->make_output_section(strtab_name, elfcpp::SHT_STRTAB, ! 0, false, false, ! false, false, false); Output_section_data* pstr = new Output_data_strtab(&this->sympool_); ostrtab->add_output_section_data(pstr); --- 2984,2991 ---- const char* strtab_name = this->namepool_.add(".strtab", false, NULL); Output_section* ostrtab = this->make_output_section(strtab_name, elfcpp::SHT_STRTAB, ! 0, ORDER_INVALID, ! false); Output_section_data* pstr = new Output_data_strtab(&this->sympool_); ostrtab->add_output_section_data(pstr); *************** Layout::create_shstrtab() *** 2922,2929 **** const char* name = this->namepool_.add(".shstrtab", false, NULL); Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0, ! false, false, false, false, ! false); if (strcmp(parameters->options().compress_debug_sections(), "none") != 0) { --- 3013,3019 ---- const char* name = this->namepool_.add(".shstrtab", false, NULL); Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0, ! ORDER_INVALID, false); if (strcmp(parameters->options().compress_debug_sections(), "none") != 0) { *************** Layout::create_dynamic_symtab(const Inpu *** 3040,3047 **** Output_section* dynsym = this->choose_output_section(NULL, ".dynsym", elfcpp::SHT_DYNSYM, elfcpp::SHF_ALLOC, ! false, false, true, ! false, false, false); Output_section_data* odata = new Output_data_fixed_space(index * symsize, align, --- 3130,3138 ---- Output_section* dynsym = this->choose_output_section(NULL, ".dynsym", elfcpp::SHT_DYNSYM, elfcpp::SHF_ALLOC, ! false, ! ORDER_DYNAMIC_LINKER, ! false); Output_section_data* odata = new Output_data_fixed_space(index * symsize, align, *************** Layout::create_dynamic_symtab(const Inpu *** 3071,3077 **** this->choose_output_section(NULL, ".dynsym_shndx", elfcpp::SHT_SYMTAB_SHNDX, elfcpp::SHF_ALLOC, ! false, false, true, false, false, false); this->dynsym_xindex_ = new Output_symtab_xindex(index); --- 3162,3168 ---- this->choose_output_section(NULL, ".dynsym_shndx", elfcpp::SHT_SYMTAB_SHNDX, elfcpp::SHF_ALLOC, ! false, ORDER_DYNAMIC_LINKER, false); this->dynsym_xindex_ = new Output_symtab_xindex(index); *************** Layout::create_dynamic_symtab(const Inpu *** 3094,3101 **** Output_section* dynstr = this->choose_output_section(NULL, ".dynstr", elfcpp::SHT_STRTAB, elfcpp::SHF_ALLOC, ! false, false, true, ! false, false, false); Output_section_data* strdata = new Output_data_strtab(&this->dynpool_); dynstr->add_output_section_data(strdata); --- 3185,3193 ---- Output_section* dynstr = this->choose_output_section(NULL, ".dynstr", elfcpp::SHT_STRTAB, elfcpp::SHF_ALLOC, ! false, ! ORDER_DYNAMIC_LINKER, ! false); Output_section_data* strdata = new Output_data_strtab(&this->dynpool_); dynstr->add_output_section_data(strdata); *************** Layout::create_dynamic_symtab(const Inpu *** 3118,3129 **** Dynobj::create_elf_hash_table(*pdynamic_symbols, local_symcount, &phash, &hashlen); ! Output_section* hashsec = this->choose_output_section(NULL, ".hash", ! elfcpp::SHT_HASH, ! elfcpp::SHF_ALLOC, ! false, false, true, ! false, false, ! false); Output_section_data* hashdata = new Output_data_const_buffer(phash, hashlen, --- 3210,3219 ---- Dynobj::create_elf_hash_table(*pdynamic_symbols, local_symcount, &phash, &hashlen); ! Output_section* hashsec = ! this->choose_output_section(NULL, ".hash", elfcpp::SHT_HASH, ! elfcpp::SHF_ALLOC, false, ! ORDER_DYNAMIC_LINKER, false); Output_section_data* hashdata = new Output_data_const_buffer(phash, hashlen, *************** Layout::create_dynamic_symtab(const Inpu *** 3145,3156 **** Dynobj::create_gnu_hash_table(*pdynamic_symbols, local_symcount, &phash, &hashlen); ! Output_section* hashsec = this->choose_output_section(NULL, ".gnu.hash", ! elfcpp::SHT_GNU_HASH, ! elfcpp::SHF_ALLOC, ! false, false, true, ! false, false, ! false); Output_section_data* hashdata = new Output_data_const_buffer(phash, hashlen, --- 3235,3244 ---- Dynobj::create_gnu_hash_table(*pdynamic_symbols, local_symcount, &phash, &hashlen); ! Output_section* hashsec = ! this->choose_output_section(NULL, ".gnu.hash", elfcpp::SHT_GNU_HASH, ! elfcpp::SHF_ALLOC, false, ! ORDER_DYNAMIC_LINKER, false); Output_section_data* hashdata = new Output_data_const_buffer(phash, hashlen, *************** Layout::sized_create_version_sections( *** 3253,3260 **** Output_section* vsec = this->choose_output_section(NULL, ".gnu.version", elfcpp::SHT_GNU_versym, elfcpp::SHF_ALLOC, ! false, false, true, ! false, false, false); unsigned char* vbuf; unsigned int vsize; --- 3341,3349 ---- Output_section* vsec = this->choose_output_section(NULL, ".gnu.version", elfcpp::SHT_GNU_versym, elfcpp::SHF_ALLOC, ! false, ! ORDER_DYNAMIC_LINKER, ! false); unsigned char* vbuf; unsigned int vsize; *************** Layout::sized_create_version_sections( *** 3279,3286 **** vdsec= this->choose_output_section(NULL, ".gnu.version_d", elfcpp::SHT_GNU_verdef, elfcpp::SHF_ALLOC, ! false, false, true, false, false, ! false); unsigned char* vdbuf; unsigned int vdsize; --- 3368,3374 ---- vdsec= this->choose_output_section(NULL, ".gnu.version_d", elfcpp::SHT_GNU_verdef, elfcpp::SHF_ALLOC, ! false, ORDER_DYNAMIC_LINKER, false); unsigned char* vdbuf; unsigned int vdsize; *************** Layout::sized_create_version_sections( *** 3305,3312 **** vnsec = this->choose_output_section(NULL, ".gnu.version_r", elfcpp::SHT_GNU_verneed, elfcpp::SHF_ALLOC, ! false, false, true, false, false, ! false); unsigned char* vnbuf; unsigned int vnsize; --- 3393,3399 ---- vnsec = this->choose_output_section(NULL, ".gnu.version_r", elfcpp::SHT_GNU_verneed, elfcpp::SHF_ALLOC, ! false, ORDER_DYNAMIC_LINKER, false); unsigned char* vnbuf; unsigned int vnsize; *************** Layout::create_interp(const Target* targ *** 3346,3360 **** Output_section* osec = this->choose_output_section(NULL, ".interp", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC, ! false, true, true, ! false, false, false); osec->add_output_section_data(odata); if (!this->script_options_->saw_phdrs_clause()) { Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP, elfcpp::PF_R); ! oseg->add_output_section(osec, elfcpp::PF_R, false); } } --- 3433,3447 ---- Output_section* osec = this->choose_output_section(NULL, ".interp", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC, ! false, ORDER_INTERP, ! false); osec->add_output_section_data(odata); if (!this->script_options_->saw_phdrs_clause()) { Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP, elfcpp::PF_R); ! oseg->add_output_section_to_nonload(osec, elfcpp::PF_R); } } *************** Layout::finish_dynamic_section(const Inp *** 3462,3470 **** Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC, (elfcpp::PF_R | elfcpp::PF_W)); ! oseg->add_output_section(this->dynamic_section_, ! elfcpp::PF_R | elfcpp::PF_W, ! false); } Output_data_dynamic* const odyn = this->dynamic_data_; --- 3549,3556 ---- Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC, (elfcpp::PF_R | elfcpp::PF_W)); ! oseg->add_output_section_to_nonload(this->dynamic_section_, ! elfcpp::PF_R | elfcpp::PF_W); } Output_data_dynamic* const odyn = this->dynamic_data_; *************** Layout::finish_dynamic_section(const Inp *** 3562,3568 **** ++p) { if (((*p)->flags() & elfcpp::PF_W) == 0 ! && (*p)->dynamic_reloc_count() > 0) { have_textrel = true; break; --- 3648,3654 ---- ++p) { if (((*p)->flags() & elfcpp::PF_W) == 0 ! && (*p)->has_dynamic_reloc()) { have_textrel = true; break; *************** Layout::finish_dynamic_section(const Inp *** 3581,3587 **** { if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0 && ((*p)->flags() & elfcpp::SHF_WRITE) == 0 ! && ((*p)->dynamic_reloc_count() > 0)) { have_textrel = true; break; --- 3667,3673 ---- { if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0 && ((*p)->flags() & elfcpp::SHF_WRITE) == 0 ! && ((*p)->has_dynamic_reloc())) { have_textrel = true; break; *************** Layout::output_section_name(const char* *** 3772,3777 **** --- 3858,3877 ---- } } + // Compressed debug sections should be mapped to the corresponding + // uncompressed section. + if (is_compressed_debug_section(name)) + { + size_t len = strlen(name); + char *uncompressed_name = new char[len]; + uncompressed_name[0] = '.'; + gold_assert(name[0] == '.' && name[1] == 'z'); + strncpy(&uncompressed_name[1], &name[2], len - 2); + uncompressed_name[len - 1] = '\0'; + *plen = len - 1; + return uncompressed_name; + } + return name; } diff -rcp ../binutils-2.20.51.0.10.original/gold/layout.h gold/layout.h *** ../binutils-2.20.51.0.10.original/gold/layout.h 2010-08-10 15:12:04.000000000 +0100 --- gold/layout.h 2010-08-10 15:14:03.000000000 +0100 *************** class Output_reduced_debug_info_section; *** 59,64 **** --- 59,68 ---- class Eh_frame; class Target; + // Return TRUE if SECNAME is the name of a compressed debug section. + extern bool + is_compressed_debug_section(const char* secname); + // This task function handles mapping the input sections to output // sections and laying them out in memory. *************** class Kept_section *** 282,287 **** --- 286,392 ---- } u_; }; + // The ordering for output sections. This controls how output + // sections are ordered within a PT_LOAD output segment. + + enum Output_section_order + { + // Unspecified. Used for non-load segments. Also used for the file + // and segment headers. + ORDER_INVALID, + + // The PT_INTERP section should come first, so that the dynamic + // linker can pick it up quickly. + ORDER_INTERP, + + // Loadable read-only note sections come next so that the PT_NOTE + // segment is on the first page of the executable. + ORDER_RO_NOTE, + + // Put read-only sections used by the dynamic linker early in the + // executable to minimize paging. + ORDER_DYNAMIC_LINKER, + + // Put reloc sections used by the dynamic linker after other + // sections used by the dynamic linker; otherwise, objcopy and strip + // get confused. + ORDER_DYNAMIC_RELOCS, + + // Put the PLT reloc section after the other dynamic relocs; + // otherwise, prelink gets confused. + ORDER_DYNAMIC_PLT_RELOCS, + + // The .init section. + ORDER_INIT, + + // The PLT. + ORDER_PLT, + + // The regular text sections. + ORDER_TEXT, + + // The .fini section. + ORDER_FINI, + + // The read-only sections. + ORDER_READONLY, + + // The exception frame sections. + ORDER_EHFRAME, + + // The TLS sections come first in the data section. + ORDER_TLS_DATA, + ORDER_TLS_BSS, + + // Local RELRO (read-only after relocation) sections come before + // non-local RELRO sections. This data will be fully resolved by + // the prelinker. + ORDER_RELRO_LOCAL, + + // Non-local RELRO sections are grouped together after local RELRO + // sections. All RELRO sections must be adjacent so that they can + // all be put into a PT_GNU_RELRO segment. + ORDER_RELRO, + + // We permit marking exactly one output section as the last RELRO + // section. We do this so that the read-only GOT can be adjacent to + // the writable GOT. + ORDER_RELRO_LAST, + + // Similarly, we permit marking exactly one output section as the + // first non-RELRO section. + ORDER_NON_RELRO_FIRST, + + // The regular data sections come after the RELRO sections. + ORDER_DATA, + + // Large data sections normally go in large data segments. + ORDER_LARGE_DATA, + + // Group writable notes so that we can have a single PT_NOTE + // segment. + ORDER_RW_NOTE, + + // The small data sections must be at the end of the data sections, + // so that they can be adjacent to the small BSS sections. + ORDER_SMALL_DATA, + + // The BSS sections start here. + + // The small BSS sections must be at the start of the BSS sections, + // so that they can be adjacent to the small data sections. + ORDER_SMALL_BSS, + + // The regular BSS sections. + ORDER_BSS, + + // The large BSS sections come after the other BSS sections. + ORDER_LARGE_BSS, + + // Maximum value. + ORDER_MAX + }; + // This class handles the details of laying out input sections. class Layout *************** class Layout *** 367,384 **** layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags); // Add an Output_section_data to the layout. This is used for ! // special sections like the GOT section. IS_DYNAMIC_LINKER_SECTION ! // is true for sections which are used by the dynamic linker, such ! // as dynamic reloc sections. IS_RELRO is true for relro sections. ! // IS_LAST_RELRO is true for the last relro section. ! // IS_FIRST_NON_RELRO is true for the first section after the relro ! // sections. Output_section* add_output_section_data(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! Output_section_data*, bool is_dynamic_linker_section, ! bool is_relro, bool is_last_relro, ! bool is_first_non_relro); // Increase the size of the relro segment by this much. void --- 472,485 ---- layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags); // Add an Output_section_data to the layout. This is used for ! // special sections like the GOT section. ORDER is where the ! // section should wind up in the output segment. IS_RELRO is true ! // for relro sections. Output_section* add_output_section_data(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! Output_section_data*, Output_section_order order, ! bool is_relro); // Increase the size of the relro segment by this much. void *************** class Layout *** 451,456 **** --- 552,558 ---- { // Debugging sections can only be recognized by name. return (strncmp(name, ".debug", sizeof(".debug") - 1) == 0 + || strncmp(name, ".zdebug", sizeof(".zdebug") - 1) == 0 || strncmp(name, ".gnu.linkonce.wi.", sizeof(".gnu.linkonce.wi.") - 1) == 0 || strncmp(name, ".line", sizeof(".line") - 1) == 0 *************** class Layout *** 783,811 **** Output_section* get_output_section(const char* name, Stringpool::Key name_key, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! bool is_interp, bool is_dynamic_linker_section, ! bool is_relro, bool is_last_relro, ! bool is_first_non_relro); // Choose the output section for NAME in RELOBJ. Output_section* choose_output_section(const Relobj* relobj, const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! bool is_input_section, bool is_interp, ! bool is_dynamic_linker_section, bool is_relro, ! bool is_last_relro, bool is_first_non_relro); // Create a new Output_section. Output_section* make_output_section(const char* name, elfcpp::Elf_Word type, ! elfcpp::Elf_Xword flags, bool is_interp, ! bool is_dynamic_linker_section, bool is_relro, ! bool is_last_relro, bool is_first_non_relro); // Attach a section to a segment. void attach_section_to_segment(Output_section*); // Attach an allocated section to a segment. void attach_allocated_section_to_segment(Output_section*); --- 885,913 ---- Output_section* get_output_section(const char* name, Stringpool::Key name_key, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! Output_section_order order, bool is_relro); // Choose the output section for NAME in RELOBJ. Output_section* choose_output_section(const Relobj* relobj, const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, ! bool is_input_section, Output_section_order order, ! bool is_relro); // Create a new Output_section. Output_section* make_output_section(const char* name, elfcpp::Elf_Word type, ! elfcpp::Elf_Xword flags, Output_section_order order, ! bool is_relro); // Attach a section to a segment. void attach_section_to_segment(Output_section*); + // Get section order. + Output_section_order + default_section_order(Output_section*, bool is_relro_local); + // Attach an allocated section to a segment. void attach_allocated_section_to_segment(Output_section*); diff -rcp ../binutils-2.20.51.0.10.original/gold/Makefile.in gold/Makefile.in *** ../binutils-2.20.51.0.10.original/gold/Makefile.in 2010-08-10 15:11:28.000000000 +0100 --- gold/Makefile.in 2010-08-10 15:14:03.000000000 +0100 *************** RECURSIVE_TARGETS = all-recursive check- *** 147,157 **** RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ ! $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= DIST_SUBDIRS = $(SUBDIRS) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ --- 147,227 ---- RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ ! $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ ! check check-html recheck recheck-html ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= + am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; + am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; + am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; + am__install_max = 40 + am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` + am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" + am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' + am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' + # Restructured Text title and section. + am__rst_title = sed 's/.*/ & /;h;s/./=/g;p;x;p;g;p;s/.*//' + am__rst_section = sed 'p;s/./=/g;p;g' + # Put stdin (possibly several lines separated by ". ") in a box. + am__text_box = $(AWK) '{ \ + n = split($$0, lines, "\\. "); max = 0; \ + for (i = 1; i <= n; ++i) \ + if (max < length(lines[i])) \ + max = length(lines[i]); \ + for (i = 0; i < max; ++i) line = line "="; \ + print line; \ + for (i = 1; i <= n; ++i) if (lines[i]) print lines[i];\ + print line; \ + }' + # Solaris 10 'make', and several other traditional 'make' implementations, + # pass "-e" to $(SHELL). This contradicts POSIX. Work around the problem + # by disabling -e (using the XSI extension "set +e") if it's set. + am__sh_e_setup = case $$- in *e*) set +e;; esac + # To be inserted before the command running the test. Creates the + # directory for the log if needed. Stores in $dir the directory + # containing $f, in $tst the test, in $log the log, and passes + # TESTS_ENVIRONMENT. Save and restore TERM around use of + # TESTS_ENVIRONMENT, in case that unsets it. + am__check_pre = \ + $(am__sh_e_setup); \ + $(am__vpath_adj_setup) $(am__vpath_adj) \ + srcdir=$(srcdir); export srcdir; \ + rm -f $@-t; \ + trap 'st=$$?; rm -f '\''$(abs_builddir)/$@-t'\''; (exit $$st); exit $$st' \ + 1 2 13 15; \ + am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`; \ + test "x$$am__odir" = x. || $(MKDIR_P) "$$am__odir" || exit $$?; \ + if test -f "./$$f"; then dir=./; \ + elif test -f "$$f"; then dir=; \ + else dir="$(srcdir)/"; fi; \ + tst=$$dir$$f; log='$@'; __SAVED_TERM=$$TERM; \ + $(TESTS_ENVIRONMENT) + RECHECK_LOGS = $(TEST_LOGS) + TEST_SUITE_LOG = test-suite.log + TEST_SUITE_HTML = $(TEST_SUITE_LOG:.log=.html) + TEST_EXTENSIONS = @EXEEXT@ .test + LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) + am__test_logs1 = $(TESTS:=.log) + am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) + TEST_LOGS = $(am__test_logs2:.test.log=.log) + TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) + TEST_LOGS_TMP = $(TEST_LOGS:.log=.log-t) DIST_SUBDIRS = $(SUBDIRS) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ *************** all: config.h *** 453,459 **** $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: ! .SUFFIXES: .c .cc .o .obj .y am--refresh: @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) --- 523,529 ---- $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: ! .SUFFIXES: .c .cc .html .log .o .obj .test .test$(EXEEXT) .y am--refresh: @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) *************** GTAGS: *** 774,870 **** distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags ! check-TESTS: $(TESTS) ! @failed=0; all=0; xfail=0; xpass=0; skip=0; \ ! srcdir=$(srcdir); export srcdir; \ ! list=' $(TESTS) '; \ ! $(am__tty_colors); \ ! if test -n "$$list"; then \ ! for tst in $$list; do \ ! if test -f ./$$tst; then dir=./; \ ! elif test -f $$tst; then dir=; \ ! else dir="$(srcdir)/"; fi; \ ! if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ ! all=`expr $$all + 1`; \ ! case " $(XFAIL_TESTS) " in \ ! *[\ \ ]$$tst[\ \ ]*) \ ! xpass=`expr $$xpass + 1`; \ ! failed=`expr $$failed + 1`; \ ! col=$$red; res=XPASS; \ ! ;; \ ! *) \ ! col=$$grn; res=PASS; \ ! ;; \ ! esac; \ ! elif test $$? -ne 77; then \ ! all=`expr $$all + 1`; \ ! case " $(XFAIL_TESTS) " in \ ! *[\ \ ]$$tst[\ \ ]*) \ ! xfail=`expr $$xfail + 1`; \ ! col=$$lgn; res=XFAIL; \ ! ;; \ ! *) \ ! failed=`expr $$failed + 1`; \ ! col=$$red; res=FAIL; \ ! ;; \ ! esac; \ ! else \ ! skip=`expr $$skip + 1`; \ ! col=$$blu; res=SKIP; \ ! fi; \ ! echo "$${col}$$res$${std}: $$tst"; \ ! done; \ ! if test "$$all" -eq 1; then \ ! tests="test"; \ ! All=""; \ ! else \ ! tests="tests"; \ ! All="All "; \ ! fi; \ ! if test "$$failed" -eq 0; then \ ! if test "$$xfail" -eq 0; then \ ! banner="$$All$$all $$tests passed"; \ ! else \ ! if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ ! banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ ! fi; \ ! else \ ! if test "$$xpass" -eq 0; then \ ! banner="$$failed of $$all $$tests failed"; \ ! else \ ! if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ ! banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ ! fi; \ ! fi; \ ! dashes="$$banner"; \ ! skipped=""; \ ! if test "$$skip" -ne 0; then \ ! if test "$$skip" -eq 1; then \ ! skipped="($$skip test was not run)"; \ ! else \ ! skipped="($$skip tests were not run)"; \ ! fi; \ ! test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ ! dashes="$$skipped"; \ ! fi; \ ! report=""; \ ! if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ ! report="Please report to $(PACKAGE_BUGREPORT)"; \ ! test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ ! dashes="$$report"; \ ! fi; \ ! dashes=`echo "$$dashes" | sed s/./=/g`; \ ! if test "$$failed" -eq 0; then \ ! echo "$$grn$$dashes"; \ ! else \ ! echo "$$red$$dashes"; \ ! fi; \ ! echo "$$banner"; \ ! test -z "$$skipped" || echo "$$skipped"; \ ! test -z "$$report" || echo "$$report"; \ ! echo "$$dashes$$std"; \ ! test "$$failed" -eq 0; \ ! else :; fi check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS --- 844,1008 ---- distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags ! # To be appended to the command running the test. Handle the stdout ! # and stderr redirection, and catch the exit status. ! am__check_post = \ ! >$@-t 2>&1; \ ! estatus=$$?; \ ! if test -n '$(DISABLE_HARD_ERRORS)' \ ! && test $$estatus -eq 99; then \ ! estatus=1; \ ! fi; \ ! TERM=$$__SAVED_TERM; export TERM; \ ! $(am__tty_colors); \ ! xfailed=PASS; \ ! case " $(XFAIL_TESTS) " in \ ! *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ ! xfailed=XFAIL;; \ ! esac; \ ! case $$estatus:$$xfailed in \ ! 0:XFAIL) col=$$red; res=XPASS;; \ ! 0:*) col=$$grn; res=PASS ;; \ ! 77:*) col=$$blu; res=SKIP ;; \ ! 99:*) col=$$red; res=FAIL ;; \ ! *:XFAIL) col=$$lgn; res=XFAIL;; \ ! *:*) col=$$red; res=FAIL ;; \ ! esac; \ ! echo "$${col}$$res$${std}: $$f"; \ ! echo "$$res: $$f (exit: $$estatus)" | \ ! $(am__rst_section) >$@; \ ! cat $@-t >>$@; \ ! rm -f $@-t ! ! $(TEST_SUITE_LOG): $(TEST_LOGS) ! @$(am__sh_e_setup); \ ! list='$(TEST_LOGS)'; \ ! results=`for f in $$list; do \ ! read line < $$f && echo "$$line" || echo FAIL; \ ! done`; \ ! all=`echo "$$results" | sed '/^$$/d' | wc -l | sed -e 's/^[ ]*//'`; \ ! fail=`echo "$$results" | grep -c '^FAIL'`; \ ! pass=`echo "$$results" | grep -c '^PASS'`; \ ! skip=`echo "$$results" | grep -c '^SKIP'`; \ ! xfail=`echo "$$results" | grep -c '^XFAIL'`; \ ! xpass=`echo "$$results" | grep -c '^XPASS'`; \ ! failures=`expr $$fail + $$xpass`; \ ! all=`expr $$all - $$skip`; \ ! if test "$$all" -eq 1; then tests=test; All=; \ ! else tests=tests; All="All "; fi; \ ! case fail=$$fail:xpass=$$xpass:xfail=$$xfail in \ ! fail=0:xpass=0:xfail=0) \ ! msg="$$All$$all $$tests passed. "; \ ! exit=true;; \ ! fail=0:xpass=0:xfail=*) \ ! msg="$$All$$all $$tests behaved as expected"; \ ! if test "$$xfail" -eq 1; then xfailures=failure; \ ! else xfailures=failures; fi; \ ! msg="$$msg ($$xfail expected $$xfailures). "; \ ! exit=true;; \ ! fail=*:xpass=0:xfail=*) \ ! msg="$$fail of $$all $$tests failed. "; \ ! exit=false;; \ ! fail=*:xpass=*:xfail=*) \ ! msg="$$failures of $$all $$tests did not behave as expected"; \ ! if test "$$xpass" -eq 1; then xpasses=pass; \ ! else xpasses=passes; fi; \ ! msg="$$msg ($$xpass unexpected $$xpasses). "; \ ! exit=false;; \ ! *) \ ! echo >&2 "incorrect case"; exit 4;; \ ! esac; \ ! if test "$$skip" -ne 0; then \ ! if test "$$skip" -eq 1; then \ ! msg="$$msg($$skip test was not run). "; \ ! else \ ! msg="$$msg($$skip tests were not run). "; \ ! fi; \ ! fi; \ ! { \ ! echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ ! $(am__rst_title); \ ! echo "$$msg"; \ ! echo; \ ! echo ".. contents:: :depth: 2"; \ ! echo; \ ! for f in $$list; do \ ! read line < $$f; \ ! case $$line in \ ! PASS:*|XFAIL:*);; \ ! *) echo; cat $$f;; \ ! esac; \ ! done; \ ! } >$(TEST_SUITE_LOG).tmp; \ ! mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ ! if test "$$failures" -ne 0; then \ ! msg="$${msg}See $(subdir)/$(TEST_SUITE_LOG). "; \ ! if test -n "$(PACKAGE_BUGREPORT)"; then \ ! msg="$${msg}Please report to $(PACKAGE_BUGREPORT). "; \ ! fi; \ ! fi; \ ! test x"$$VERBOSE" = x || $$exit || cat $(TEST_SUITE_LOG); \ ! $(am__tty_colors); \ ! if $$exit; then \ ! echo $(ECHO_N) "$$grn$(ECHO_C)"; \ ! else \ ! echo $(ECHO_N) "$$red$(ECHO_C)"; \ ! fi; \ ! echo "$$msg" | $(am__text_box); \ ! echo $(ECHO_N) "$$std$(ECHO_C)"; \ ! $$exit ! ! # Run all the tests. ! check-TESTS: ! @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list ! @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) ! @set_logs=; if test "X$(TEST_LOGS)" = X.log; then \ ! set_logs=TEST_LOGS=; \ ! fi; \ ! $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) $$set_logs ! ! .log.html: ! @list='$(RST2HTML) $$RST2HTML rst2html rst2html.py'; \ ! for r2h in $$list; do \ ! if ($$r2h --version) >/dev/null 2>&1; then \ ! R2H=$$r2h; \ ! fi; \ ! done; \ ! if test -z "$$R2H"; then \ ! echo >&2 "cannot find rst2html, cannot create $@"; \ ! exit 2; \ ! fi; \ ! $$R2H $< >$@.tmp ! @mv $@.tmp $@ ! ! # Be sure to run check first, and then to convert the result. ! # Beware of concurrent executions. Run "check" not "check-TESTS", as ! # check-SCRIPTS and other dependencies are rebuilt by the former only. ! # And expect check to fail. ! check-html: ! @if $(MAKE) $(AM_MAKEFLAGS) check; then \ ! rv=0; else rv=$$?; \ ! fi; \ ! $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_HTML) || exit 4; \ ! exit $$rv ! recheck recheck-html: ! @target=`echo $@ | sed 's,^re,,'`; \ ! list='$(TEST_LOGS)'; \ ! list=`for f in $$list; do \ ! test -f $$f || continue; \ ! if read line < $$f; then \ ! case $$line in FAIL*|XPASS*) echo $$f;; esac; \ ! else echo $$f; fi; \ ! done | tr '\012\015' ' '`; \ ! $(MAKE) $(AM_MAKEFLAGS) $$target AM_MAKEFLAGS='$(AM_MAKEFLAGS) TEST_LOGS="'"$$list"'"' ! bootstrap-test.log: bootstrap-test ! @p='bootstrap-test'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) ! bootstrap-test-r.log: bootstrap-test-r ! @p='bootstrap-test-r'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) ! .test.log: ! @p='$<'; $(am__check_pre) $(TEST_LOG_COMPILE) "$$tst" $(am__check_post) ! @am__EXEEXT_TRUE@.test$(EXEEXT).log: ! @am__EXEEXT_TRUE@ @p='$<'; $(am__check_pre) $(TEST_LOG_COMPILE) "$$tst" $(am__check_post) check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS *************** install-strip: *** 887,892 **** --- 1025,1034 ---- `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS_TMP)" || rm -f $(TEST_LOGS_TMP) + -test -z "$(TEST_SUITE_HTML)" || rm -f $(TEST_SUITE_HTML) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: *************** ps-am: *** 973,983 **** uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check-am \ ! ctags-recursive install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ ! all all-am am--refresh check check-TESTS check-am clean \ ! clean-checkPROGRAMS clean-generic clean-noinstLIBRARIES \ clean-noinstPROGRAMS ctags ctags-recursive distclean \ distclean-compile distclean-generic distclean-hdr \ distclean-tags dvi dvi-am html html-am info info-am install \ --- 1115,1126 ---- uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check-am \ ! check-html ctags-recursive install-am install-strip recheck \ ! recheck-html tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ ! all all-am am--refresh check check-TESTS check-am check-html \ ! clean clean-checkPROGRAMS clean-generic clean-noinstLIBRARIES \ clean-noinstPROGRAMS ctags ctags-recursive distclean \ distclean-compile distclean-generic distclean-hdr \ distclean-tags dvi dvi-am html html-am info info-am install \ *************** uninstall-am: *** 988,995 **** install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ ! mostlyclean-generic pdf pdf-am ps ps-am tags tags-recursive \ ! uninstall uninstall-am # Use an explicit dependency for the bison generated header file. --- 1131,1138 ---- install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ ! mostlyclean-generic pdf pdf-am ps ps-am recheck recheck-html \ ! tags tags-recursive uninstall uninstall-am # Use an explicit dependency for the bison generated header file. diff -rcp ../binutils-2.20.51.0.10.original/gold/merge.cc gold/merge.cc *** ../binutils-2.20.51.0.10.original/gold/merge.cc 2010-08-10 15:11:43.000000000 +0100 --- gold/merge.cc 2010-08-10 15:14:03.000000000 +0100 *************** *** 1,6 **** // merge.cc -- handle section merging for gold ! // Copyright 2006, 2007, 2008 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. --- 1,6 ---- // merge.cc -- handle section merging for gold ! // Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. *************** *** 26,31 **** --- 26,32 ---- #include #include "merge.h" + #include "compressed_output.h" namespace gold { *************** bool *** 404,415 **** Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx) { section_size_type len; const unsigned char* p = object->section_contents(shndx, &len, false); section_size_type entsize = convert_to_section_size_type(this->entsize()); if (len % entsize != 0) ! return false; this->input_count_ += len / entsize; --- 405,433 ---- Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx) { section_size_type len; + section_size_type uncompressed_size = 0; + unsigned char* uncompressed_data = NULL; const unsigned char* p = object->section_contents(shndx, &len, false); + if (object->section_is_compressed(shndx, &uncompressed_size)) + { + uncompressed_data = new unsigned char[uncompressed_size]; + if (!decompress_input_section(p, len, uncompressed_data, + uncompressed_size)) + object->error(_("could not decompress section %s"), + object->section_name(shndx).c_str()); + p = uncompressed_data; + len = uncompressed_size; + } + section_size_type entsize = convert_to_section_size_type(this->entsize()); if (len % entsize != 0) ! { ! if (uncompressed_data != NULL) ! delete[] uncompressed_data; ! return false; ! } this->input_count_ += len / entsize; *************** Output_merge_data::do_add_input_section( *** 438,443 **** --- 456,464 ---- if (this->keeps_input_sections()) record_input_section(object, shndx); + if (uncompressed_data != NULL) + delete[] uncompressed_data; + return true; } *************** Output_merge_string::do_add_i *** 495,550 **** unsigned int shndx) { section_size_type len; const unsigned char* pdata = object->section_contents(shndx, &len, false); const Char_type* p = reinterpret_cast(pdata); const Char_type* pend = p + len / sizeof(Char_type); if (len % sizeof(Char_type) != 0) { object->error(_("mergeable string section length not multiple of " "character size")); return false; } size_t count = 0; // The index I is in bytes, not characters. section_size_type i = 0; ! while (i < len) { ! const Char_type* pl; ! for (pl = p; *pl != 0; ++pl) ! { ! if (pl >= pend) ! { ! gold_warning(_("%s: last entry in mergeable string section '%s' " ! "not null terminated"), ! object->name().c_str(), ! object->section_name(shndx).c_str()); ! break; ! } ! } Stringpool::Key key; ! const Char_type* str = this->stringpool_.add_with_length(p, pl - p, true, ! &key); ! section_size_type bytelen_with_null = ((pl - p) + 1) * sizeof(Char_type); ! this->merged_strings_.push_back(Merged_string(object, shndx, i, str, ! bytelen_with_null, key)); ! ! p = pl + 1; ! i += bytelen_with_null; ! ++count; } this->input_count_ += count; // For script processing, we keep the input sections. if (this->keeps_input_sections()) record_input_section(object, shndx); return true; } --- 516,613 ---- unsigned int shndx) { section_size_type len; + section_size_type uncompressed_size = 0; + unsigned char* uncompressed_data = NULL; const unsigned char* pdata = object->section_contents(shndx, &len, false); + if (object->section_is_compressed(shndx, &uncompressed_size)) + { + uncompressed_data = new unsigned char[uncompressed_size]; + if (!decompress_input_section(pdata, len, uncompressed_data, + uncompressed_size)) + object->error(_("could not decompress section %s"), + object->section_name(shndx).c_str()); + pdata = uncompressed_data; + len = uncompressed_size; + } + const Char_type* p = reinterpret_cast(pdata); const Char_type* pend = p + len / sizeof(Char_type); + const Char_type* pend0 = pend; if (len % sizeof(Char_type) != 0) { object->error(_("mergeable string section length not multiple of " "character size")); + if (uncompressed_data != NULL) + delete[] uncompressed_data; return false; } + if (pend[-1] != 0) + { + gold_warning(_("%s: last entry in mergeable string section '%s' " + "not null terminated"), + object->name().c_str(), + object->section_name(shndx).c_str()); + // Find the end of the last NULL-terminated string in the buffer. + while (pend0 > p && pend0[-1] != 0) + --pend0; + } + + Merged_strings_list* merged_strings_list = + new Merged_strings_list(object, shndx); + this->merged_strings_lists_.push_back(merged_strings_list); + Merged_strings& merged_strings = merged_strings_list->merged_strings; + + // Count the number of strings in the section and size the list. size_t count = 0; + for (const Char_type* pt = p; pt < pend0; pt += string_length(pt) + 1) + ++count; + if (pend0 < pend) + ++count; + merged_strings.reserve(count + 1); // The index I is in bytes, not characters. section_size_type i = 0; ! while (p < pend0) { ! size_t len = string_length(p); ! ! Stringpool::Key key; ! this->stringpool_.add_with_length(p, len, true, &key); ! ! merged_strings.push_back(Merged_string(i, key)); ! ! p += len + 1; ! i += (len + 1) * sizeof(Char_type); ! } ! if (p < pend) ! { ! size_t len = pend - p; Stringpool::Key key; ! this->stringpool_.add_with_length(p, len, true, &key); ! merged_strings.push_back(Merged_string(i, key)); ! ! i += (len + 1) * sizeof(Char_type); } + // Record the last offset in the input section so that we can + // compute the length of the last string. + merged_strings.push_back(Merged_string(i, 0)); + this->input_count_ += count; + this->input_size_ += len; // For script processing, we keep the input sections. if (this->keeps_input_sections()) record_input_section(object, shndx); + if (uncompressed_data != NULL) + delete[] uncompressed_data; + return true; } *************** Output_merge_string::finalize *** 557,576 **** { this->stringpool_.set_string_offsets(); ! for (typename Merged_strings::const_iterator p = ! this->merged_strings_.begin(); ! p != this->merged_strings_.end(); ! ++p) ! { ! section_offset_type offset = ! this->stringpool_.get_offset_from_key(p->stringpool_key); ! this->add_mapping(p->object, p->shndx, p->offset, p->length, offset); } // Save some memory. This also ensures that this function will work // if called twice, as may happen if Layout::set_segment_offsets // finds a better alignment. ! this->merged_strings_.clear(); return this->stringpool_.get_strtab_size(); } --- 620,653 ---- { this->stringpool_.set_string_offsets(); ! for (typename Merged_strings_lists::const_iterator l = ! this->merged_strings_lists_.begin(); ! l != this->merged_strings_lists_.end(); ! ++l) ! { ! section_offset_type last_input_offset = 0; ! section_offset_type last_output_offset = 0; ! for (typename Merged_strings::const_iterator p = ! (*l)->merged_strings.begin(); ! p != (*l)->merged_strings.end(); ! ++p) ! { ! section_size_type length = p->offset - last_input_offset; ! if (length > 0) ! this->add_mapping((*l)->object, (*l)->shndx, last_input_offset, ! length, last_output_offset); ! last_input_offset = p->offset; ! if (p->stringpool_key != 0) ! last_output_offset = ! this->stringpool_.get_offset_from_key(p->stringpool_key); ! } ! delete *l; } // Save some memory. This also ensures that this function will work // if called twice, as may happen if Layout::set_segment_offsets // finds a better alignment. ! this->merged_strings_lists_.clear(); return this->stringpool_.get_strtab_size(); } *************** Output_merge_string::do_print *** 641,647 **** { char buf[200]; snprintf(buf, sizeof buf, "%s merged %s", section_name, this->string_name()); ! fprintf(stderr, _("%s: %s input: %zu\n"), program_name, buf, this->input_count_); this->stringpool_.print_stats(buf); } --- 718,726 ---- { char buf[200]; snprintf(buf, sizeof buf, "%s merged %s", section_name, this->string_name()); ! fprintf(stderr, _("%s: %s input bytes: %zu\n"), ! program_name, buf, this->input_size_); ! fprintf(stderr, _("%s: %s input strings: %zu\n"), program_name, buf, this->input_count_); this->stringpool_.print_stats(buf); } diff -rcp ../binutils-2.20.51.0.10.original/gold/merge.h gold/merge.h *** ../binutils-2.20.51.0.10.original/gold/merge.h 2010-08-10 15:12:03.000000000 +0100 --- gold/merge.h 2010-08-10 15:14:03.000000000 +0100 *************** class Output_merge_string : public Outpu *** 462,468 **** public: Output_merge_string(uint64_t addralign) : Output_merge_base(sizeof(Char_type), addralign), stringpool_(), ! merged_strings_(), input_count_(0) { gold_assert(addralign <= sizeof(Char_type)); this->stringpool_.set_no_zero_null(); --- 462,468 ---- public: Output_merge_string(uint64_t addralign) : Output_merge_base(sizeof(Char_type), addralign), stringpool_(), ! merged_strings_lists_(), input_count_(0), input_size_(0) { gold_assert(addralign <= sizeof(Char_type)); this->stringpool_.set_no_zero_null(); *************** class Output_merge_string : public Outpu *** 531,566 **** // index and offset to strings. struct Merged_string { - // The input object where the string was found. - Relobj* object; - // The input section in the input object. - unsigned int shndx; // The offset in the input section. section_offset_type offset; - // The string itself, a pointer into a Stringpool. - const Char_type* string; - // The length of the string in bytes, including the null terminator. - size_t length; // The key in the Stringpool. Stringpool::Key stringpool_key; ! Merged_string(Relobj *objecta, unsigned int shndxa, ! section_offset_type offseta, const Char_type* stringa, ! size_t lengtha, Stringpool::Key stringpool_keya) ! : object(objecta), shndx(shndxa), offset(offseta), string(stringa), ! length(lengtha), stringpool_key(stringpool_keya) { } }; typedef std::vector Merged_strings; // As we see the strings, we add them to a Stringpool. Stringpool_template stringpool_; // Map from a location in an input object to an entry in the // Stringpool. ! Merged_strings merged_strings_; // The number of entries seen in input files. size_t input_count_; }; } // End namespace gold. --- 531,573 ---- // index and offset to strings. struct Merged_string { // The offset in the input section. section_offset_type offset; // The key in the Stringpool. Stringpool::Key stringpool_key; ! Merged_string(section_offset_type offseta, Stringpool::Key stringpool_keya) ! : offset(offseta), stringpool_key(stringpool_keya) { } }; typedef std::vector Merged_strings; + struct Merged_strings_list + { + // The input object where the strings were found. + Relobj* object; + // The input section in the input object. + unsigned int shndx; + // The list of merged strings. + Merged_strings merged_strings; + + Merged_strings_list(Relobj* objecta, unsigned int shndxa) + : object(objecta), shndx(shndxa), merged_strings() + { } + }; + + typedef std::vector Merged_strings_lists; + // As we see the strings, we add them to a Stringpool. Stringpool_template stringpool_; // Map from a location in an input object to an entry in the // Stringpool. ! Merged_strings_lists merged_strings_lists_; // The number of entries seen in input files. size_t input_count_; + // The total size of input sections. + size_t input_size_; }; } // End namespace gold. diff -rcp ../binutils-2.20.51.0.10.original/gold/object.cc gold/object.cc *** ../binutils-2.20.51.0.10.original/gold/object.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/object.cc 2010-08-10 15:14:03.000000000 +0100 *************** *** 39,44 **** --- 39,45 ---- #include "object.h" #include "dynobj.h" #include "plugin.h" + #include "compressed_output.h" namespace gold { *************** Sized_relobj::Sized_re *** 367,373 **** local_got_offsets_(), kept_comdat_sections_(), has_eh_frame_(false), ! discarded_eh_frame_shndx_(-1U) { } --- 368,377 ---- local_got_offsets_(), kept_comdat_sections_(), has_eh_frame_(false), ! discarded_eh_frame_shndx_(-1U), ! deferred_layout_(), ! deferred_layout_relocs_(), ! compressed_sections_() { } *************** Sized_relobj::find_eh_ *** 495,500 **** --- 499,548 ---- return false; } + // Build a table for any compressed debug sections, mapping each section index + // to the uncompressed size. + + template + Compressed_section_map* + build_compressed_section_map( + const unsigned char* pshdrs, + unsigned int shnum, + const char* names, + section_size_type names_size, + Sized_relobj* obj) + { + Compressed_section_map* uncompressed_sizes = new Compressed_section_map(); + const unsigned int shdr_size = elfcpp::Elf_sizes::shdr_size; + const unsigned char* p = pshdrs + shdr_size; + for (unsigned int i = 1; i < shnum; ++i, p += shdr_size) + { + typename elfcpp::Shdr shdr(p); + if (shdr.get_sh_type() == elfcpp::SHT_PROGBITS + && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + if (shdr.get_sh_name() >= names_size) + { + obj->error(_("bad section name offset for section %u: %lu"), + i, static_cast(shdr.get_sh_name())); + continue; + } + + const char* name = names + shdr.get_sh_name(); + if (is_compressed_debug_section(name)) + { + section_size_type len; + const unsigned char* contents = + obj->section_contents(i, &len, false); + uint64_t uncompressed_size = get_uncompressed_size(contents, len); + if (uncompressed_size != -1ULL) + (*uncompressed_sizes)[i] = + convert_to_section_size_type(uncompressed_size); + } + } + } + return uncompressed_sizes; + } + // Read the sections and symbols from an object file. template *************** Sized_relobj::do_read_ *** 514,519 **** --- 562,571 ---- if (this->find_eh_frame(pshdrs, names, sd->section_names_size)) this->has_eh_frame_ = true; } + if (memmem(names, sd->section_names_size, ".zdebug_", 8) != NULL) + this->compressed_sections_ = + build_compressed_section_map(pshdrs, this->shnum(), names, + sd->section_names_size, this); sd->symbols = NULL; sd->symbols_size = 0; *************** Sized_relobj::do_add_s *** 1562,1567 **** --- 1614,1620 ---- template Archive::Should_include Sized_relobj::do_should_include_member(Symbol_table* symtab, + Layout* layout, Read_symbols_data* sd, std::string* why) { *************** Sized_relobj::do_shoul *** 1587,1593 **** unsigned int st_name = sym.get_st_name(); const char* name = sym_names + st_name; Symbol* symbol; ! Archive::Should_include t = Archive::should_include_member(symtab, name, &symbol, why, &tmpbuf, &tmpbuflen); --- 1640,1648 ---- unsigned int st_name = sym.get_st_name(); const char* name = sym_names + st_name; Symbol* symbol; ! Archive::Should_include t = Archive::should_include_member(symtab, ! layout, ! name, &symbol, why, &tmpbuf, &tmpbuflen); diff -rcp ../binutils-2.20.51.0.10.original/gold/object.h gold/object.h *** ../binutils-2.20.51.0.10.original/gold/object.h 2010-08-10 15:11:43.000000000 +0100 --- gold/object.h 2010-08-10 15:14:03.000000000 +0100 *************** class Object *** 405,413 **** // Add symbol information to the global symbol table. Archive::Should_include ! should_include_member(Symbol_table* symtab, Read_symbols_data* sd, ! std::string* why) ! { return this->do_should_include_member(symtab, sd, why); } // Functions and types for the elfcpp::Elf_file interface. This // permit us to use Object as the File template parameter for --- 405,413 ---- // Add symbol information to the global symbol table. Archive::Should_include ! should_include_member(Symbol_table* symtab, Layout* layout, ! Read_symbols_data* sd, std::string* why) ! { return this->do_should_include_member(symtab, layout, sd, why); } // Functions and types for the elfcpp::Elf_file interface. This // permit us to use Object as the File template parameter for *************** class Object *** 518,523 **** --- 518,530 ---- set_no_export(bool value) { this->no_export_ = value; } + // Return TRUE if the section is a compressed debug section, and set + // *UNCOMPRESSED_SIZE to the size of the uncompressed data. + bool + section_is_compressed(unsigned int shndx, + section_size_type* uncompressed_size) const + { return this->do_section_is_compressed(shndx, uncompressed_size); } + protected: // Returns NULL for Objects that are not plugin objects. This method // is overridden in the Pluginobj class. *************** class Object *** 539,545 **** do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*) = 0; virtual Archive::Should_include ! do_should_include_member(Symbol_table* symtab, Read_symbols_data*, std::string* why) = 0; // Return the location of the contents of a section. Implemented by --- 546,552 ---- do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*) = 0; virtual Archive::Should_include ! do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, std::string* why) = 0; // Return the location of the contents of a section. Implemented by *************** class Object *** 628,633 **** --- 635,646 ---- bool handle_split_stack_section(const char* name); + // Return TRUE if the section is a compressed debug section, and set + // *UNCOMPRESSED_SIZE to the size of the uncompressed data. + virtual bool + do_section_is_compressed(unsigned int, section_size_type*) const + { return false; } + private: // This class may not be copied. Object(const Object&); *************** class Reloc_symbol_changes *** 1406,1411 **** --- 1419,1428 ---- std::vector vec_; }; + // Type for mapping section index to uncompressed size. + + typedef std::map Compressed_section_map; + // A regular object file. This is size and endian specific. template *************** class Sized_relobj : public Relobj *** 1606,1612 **** do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include ! do_should_include_member(Symbol_table* symtab, Read_symbols_data*, std::string* why); // Read the relocs. --- 1623,1629 ---- do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include ! do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, std::string* why); // Read the relocs. *************** class Sized_relobj : public Relobj *** 1781,1787 **** void set_output_local_symbol_count(unsigned int value) { this->output_local_symbol_count_ = value; } ! private: // For convenience. typedef Sized_relobj This; --- 1798,1823 ---- void set_output_local_symbol_count(unsigned int value) { this->output_local_symbol_count_ = value; } ! ! // Return TRUE if the section is a compressed debug section, and set ! // *UNCOMPRESSED_SIZE to the size of the uncompressed data. ! bool ! do_section_is_compressed(unsigned int shndx, ! section_size_type* uncompressed_size) const ! { ! if (this->compressed_sections_ == NULL) ! return false; ! Compressed_section_map::const_iterator p = ! this->compressed_sections_->find(shndx); ! if (p != this->compressed_sections_->end()) ! { ! if (uncompressed_size != NULL) ! *uncompressed_size = p->second; ! return true; ! } ! return false; ! } ! private: // For convenience. typedef Sized_relobj This; *************** class Sized_relobj : public Relobj *** 2024,2029 **** --- 2060,2067 ---- std::vector deferred_layout_; // The list of relocation sections whose layout was deferred. std::vector deferred_layout_relocs_; + // For compressed debug sections, map section index to uncompressed size. + Compressed_section_map* compressed_sections_; }; // A class to manage the list of all objects. diff -rcp ../binutils-2.20.51.0.10.original/gold/output.cc gold/output.cc *** ../binutils-2.20.51.0.10.original/gold/output.cc 2010-08-10 15:11:46.000000000 +0100 --- gold/output.cc 2010-08-10 15:14:03.000000000 +0100 *************** Output_section::Output_section(const cha *** 1917,1922 **** --- 1917,1923 ---- info_(0), type_(type), flags_(flags), + order_(ORDER_INVALID), out_shndx_(-1U), symtab_index_(0), dynsym_index_(0), *************** Output_section::Output_section(const cha *** 1938,1954 **** must_sort_attached_input_sections_(false), attached_input_sections_are_sorted_(false), is_relro_(false), - is_relro_local_(false), - is_last_relro_(false), - is_first_non_relro_(false), is_small_section_(false), is_large_section_(false), - is_interp_(false), - is_dynamic_linker_section_(false), generate_code_fills_at_write_(false), is_entsize_zero_(false), section_offsets_need_adjustment_(false), is_noload_(false), tls_offset_(0), checkpoint_(NULL), lookup_maps_(new Output_section_lookup_maps) --- 1939,1951 ---- must_sort_attached_input_sections_(false), attached_input_sections_are_sorted_(false), is_relro_(false), is_small_section_(false), is_large_section_(false), generate_code_fills_at_write_(false), is_entsize_zero_(false), section_offsets_need_adjustment_(false), is_noload_(false), + always_keeps_input_sections_(false), tls_offset_(0), checkpoint_(NULL), lookup_maps_(new Output_section_lookup_maps) *************** Output_section::add_input_section(Layout *** 2038,2045 **** { // Keep information about merged input sections for rebuilding fast // lookup maps if we have sections-script or we do relaxation. ! bool keeps_input_sections = ! have_sections_script || parameters->target().may_relax(); if (this->add_merge_input_section(object, shndx, sh_flags, entsize, addralign, keeps_input_sections)) { --- 2035,2044 ---- { // Keep information about merged input sections for rebuilding fast // lookup maps if we have sections-script or we do relaxation. ! bool keeps_input_sections = (this->always_keeps_input_sections_ ! || have_sections_script ! || parameters->target().may_relax()); ! if (this->add_merge_input_section(object, shndx, sh_flags, entsize, addralign, keeps_input_sections)) { *************** Output_section::add_input_section(Layout *** 2086,2093 **** } } this->set_current_data_size_for_child(aligned_offset_in_section ! + shdr.get_sh_size()); // We need to keep track of this section if we are already keeping // track of sections, or if we are relaxing. Also, if this is a --- 2085,2097 ---- } } + 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; + this->set_current_data_size_for_child(aligned_offset_in_section ! + input_section_size); // We need to keep track of this section if we are already keeping // track of sections, or if we are relaxing. Also, if this is a *************** Output_section::add_input_section(Layout *** 2095,2101 **** // the future, we keep track of the sections. If the // --section-ordering-file option is used to specify the order of // sections, we need to keep track of sections. ! if (have_sections_script || !this->input_sections_.empty() || this->may_sort_attached_input_sections() || this->must_sort_attached_input_sections() --- 2099,2106 ---- // the future, we keep track of the sections. If the // --section-ordering-file option is used to specify the order of // sections, we need to keep track of sections. ! if (this->always_keeps_input_sections_ ! || have_sections_script || !this->input_sections_.empty() || this->may_sort_attached_input_sections() || this->must_sort_attached_input_sections() *************** Output_section::print_merge_stats() *** 3400,3408 **** // Output segment methods. Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) ! : output_data_(), ! output_bss_(), ! vaddr_(0), paddr_(0), memsz_(0), max_align_(0), --- 3405,3411 ---- // Output segment methods. Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) ! : vaddr_(0), paddr_(0), memsz_(0), max_align_(0), *************** Output_segment::Output_segment(elfcpp::E *** 3421,3713 **** this->flags_ = elfcpp::PF_R; } ! // Add an Output_section to an Output_segment. void ! Output_segment::add_output_section(Output_section* os, ! elfcpp::Elf_Word seg_flags, ! bool do_sort) { gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0); gold_assert(!this->is_max_align_known_); gold_assert(os->is_large_data_section() == this->is_large_data_segment()); - gold_assert(this->type() == elfcpp::PT_LOAD || !do_sort); this->update_flags_for_output_section(seg_flags); ! Output_segment::Output_data_list* pdl; ! if (os->type() == elfcpp::SHT_NOBITS) ! pdl = &this->output_bss_; else ! pdl = &this->output_data_; ! ! // Note that while there may be many input sections in an output ! // section, there are normally only a few output sections in an ! // output segment. The loops below are expected to be fast. ! ! // So that PT_NOTE segments will work correctly, we need to ensure ! // that all SHT_NOTE sections are adjacent. ! if (os->type() == elfcpp::SHT_NOTE && !pdl->empty()) ! { ! Output_segment::Output_data_list::iterator p = pdl->end(); ! do ! { ! --p; ! if ((*p)->is_section_type(elfcpp::SHT_NOTE)) ! { ! ++p; ! pdl->insert(p, os); ! return; ! } ! } ! while (p != pdl->begin()); ! } ! ! // Similarly, so that PT_TLS segments will work, we need to group ! // SHF_TLS sections. An SHF_TLS/SHT_NOBITS section is a special ! // case: we group the SHF_TLS/SHT_NOBITS sections right after the ! // SHF_TLS/SHT_PROGBITS sections. This lets us set up PT_TLS ! // correctly. SHF_TLS sections get added to both a PT_LOAD segment ! // and the PT_TLS segment; we do this grouping only for the PT_LOAD ! // segment. ! if (this->type_ != elfcpp::PT_TLS ! && (os->flags() & elfcpp::SHF_TLS) != 0) ! { ! pdl = &this->output_data_; ! if (!pdl->empty()) ! { ! bool nobits = os->type() == elfcpp::SHT_NOBITS; ! bool sawtls = false; ! Output_segment::Output_data_list::iterator p = pdl->end(); ! gold_assert(p != pdl->begin()); ! do ! { ! --p; ! bool insert; ! if ((*p)->is_section_flag_set(elfcpp::SHF_TLS)) ! { ! sawtls = true; ! // Put a NOBITS section after the first TLS section. ! // Put a PROGBITS section after the first ! // TLS/PROGBITS section. ! insert = nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS); ! } ! else ! { ! // If we've gone past the TLS sections, but we've ! // seen a TLS section, then we need to insert this ! // section now. ! insert = sawtls; ! } ! ! if (insert) ! { ! ++p; ! pdl->insert(p, os); ! return; ! } ! } ! while (p != pdl->begin()); ! } ! ! // There are no TLS sections yet; put this one at the requested ! // location in the section list. ! } ! ! if (do_sort) ! { ! // For the PT_GNU_RELRO segment, we need to group relro ! // sections, and we need to put them before any non-relro ! // sections. Any relro local sections go before relro non-local ! // sections. One section may be marked as the last relro ! // section. ! if (os->is_relro()) ! { ! gold_assert(pdl == &this->output_data_); ! Output_segment::Output_data_list::iterator p; ! for (p = pdl->begin(); p != pdl->end(); ++p) ! { ! if (!(*p)->is_section()) ! break; ! Output_section* pos = (*p)->output_section(); ! if (!pos->is_relro() ! || (os->is_relro_local() && !pos->is_relro_local()) ! || (!os->is_last_relro() && pos->is_last_relro())) ! break; ! } ! ! pdl->insert(p, os); ! return; ! } ! // One section may be marked as the first section which follows ! // the relro sections. ! if (os->is_first_non_relro()) ! { ! gold_assert(pdl == &this->output_data_); ! Output_segment::Output_data_list::iterator p; ! for (p = pdl->begin(); p != pdl->end(); ++p) ! { ! if (!(*p)->is_section()) ! break; ! Output_section* pos = (*p)->output_section(); ! if (!pos->is_relro()) ! break; ! } ! pdl->insert(p, os); ! return; ! } ! } ! // Small data sections go at the end of the list of data sections. ! // If OS is not small, and there are small sections, we have to ! // insert it before the first small section. ! if (os->type() != elfcpp::SHT_NOBITS ! && !os->is_small_section() ! && !pdl->empty() ! && pdl->back()->is_section() ! && pdl->back()->output_section()->is_small_section()) ! { ! for (Output_segment::Output_data_list::iterator p = pdl->begin(); ! p != pdl->end(); ! ++p) ! { ! if ((*p)->is_section() ! && (*p)->output_section()->is_small_section()) ! { ! pdl->insert(p, os); ! return; ! } ! } ! gold_unreachable(); ! } ! // A small BSS section goes at the start of the BSS sections, after ! // other small BSS sections. ! if (os->type() == elfcpp::SHT_NOBITS && os->is_small_section()) ! { ! for (Output_segment::Output_data_list::iterator p = pdl->begin(); ! p != pdl->end(); ! ++p) ! { ! if (!(*p)->is_section() ! || !(*p)->output_section()->is_small_section()) ! { ! pdl->insert(p, os); ! return; ! } ! } ! } ! // A large BSS section goes at the end of the BSS sections, which ! // means that one that is not large must come before the first large ! // one. ! if (os->type() == elfcpp::SHT_NOBITS ! && !os->is_large_section() ! && !pdl->empty() ! && pdl->back()->is_section() ! && pdl->back()->output_section()->is_large_section()) { ! for (Output_segment::Output_data_list::iterator p = pdl->begin(); ! p != pdl->end(); ! ++p) { ! if ((*p)->is_section() ! && (*p)->output_section()->is_large_section()) { ! pdl->insert(p, os); return; } } - gold_unreachable(); } - - // We do some further output section sorting in order to make the - // generated program run more efficiently. We should only do this - // when not using a linker script, so it is controled by the DO_SORT - // parameter. - if (do_sort) - { - // FreeBSD requires the .interp section to be in the first page - // of the executable. That is a more efficient location anyhow - // for any OS, since it means that the kernel will have the data - // handy after it reads the program headers. - if (os->is_interp() && !pdl->empty()) - { - pdl->insert(pdl->begin(), os); - return; - } - - // Put loadable non-writable notes immediately after the .interp - // sections, so that the PT_NOTE segment is on the first page of - // the executable. - if (os->type() == elfcpp::SHT_NOTE - && (os->flags() & elfcpp::SHF_WRITE) == 0 - && !pdl->empty()) - { - Output_segment::Output_data_list::iterator p = pdl->begin(); - if ((*p)->is_section() && (*p)->output_section()->is_interp()) - ++p; - pdl->insert(p, os); - return; - } - - // If this section is used by the dynamic linker, and it is not - // writable, then put it first, after the .interp section and - // any loadable notes. This makes it more likely that the - // dynamic linker will have to read less data from the disk. - if (os->is_dynamic_linker_section() - && !pdl->empty() - && (os->flags() & elfcpp::SHF_WRITE) == 0) - { - bool is_reloc = (os->type() == elfcpp::SHT_REL - || os->type() == elfcpp::SHT_RELA); - Output_segment::Output_data_list::iterator p = pdl->begin(); - while (p != pdl->end() - && (*p)->is_section() - && ((*p)->output_section()->is_dynamic_linker_section() - || (*p)->output_section()->type() == elfcpp::SHT_NOTE)) - { - // Put reloc sections after the other ones. Putting the - // dynamic reloc sections first confuses BFD, notably - // objcopy and strip. - if (!is_reloc - && ((*p)->output_section()->type() == elfcpp::SHT_REL - || (*p)->output_section()->type() == elfcpp::SHT_RELA)) - break; - ++p; - } - pdl->insert(p, os); - return; - } - } - - // If there were no constraints on the output section, just add it - // to the end of the list. - pdl->push_back(os); - } - - // Remove an Output_section from this segment. It is an error if it - // is not present. - - void - Output_segment::remove_output_section(Output_section* os) - { - // We only need this for SHT_PROGBITS. - gold_assert(os->type() == elfcpp::SHT_PROGBITS); - for (Output_data_list::iterator p = this->output_data_.begin(); - p != this->output_data_.end(); - ++p) - { - if (*p == os) - { - this->output_data_.erase(p); - return; - } - } gold_unreachable(); } --- 3424,3487 ---- this->flags_ = elfcpp::PF_R; } ! // Add an Output_section to a PT_LOAD Output_segment. void ! Output_segment::add_output_section_to_load(Layout* layout, ! Output_section* os, ! elfcpp::Elf_Word seg_flags) { + gold_assert(this->type() == elfcpp::PT_LOAD); gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0); gold_assert(!this->is_max_align_known_); gold_assert(os->is_large_data_section() == this->is_large_data_segment()); this->update_flags_for_output_section(seg_flags); ! // We don't want to change the ordering if we have a linker script ! // with a SECTIONS clause. ! Output_section_order order = os->order(); ! if (layout->script_options()->saw_sections_clause()) ! order = static_cast(0); else ! gold_assert(order != ORDER_INVALID); ! this->output_lists_[order].push_back(os); ! } ! // Add an Output_section to a non-PT_LOAD Output_segment. ! void ! Output_segment::add_output_section_to_nonload(Output_section* os, ! elfcpp::Elf_Word seg_flags) ! { ! gold_assert(this->type() != elfcpp::PT_LOAD); ! gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0); ! gold_assert(!this->is_max_align_known_); ! this->update_flags_for_output_section(seg_flags); ! this->output_lists_[0].push_back(os); ! } ! // Remove an Output_section from this segment. It is an error if it ! // is not present. ! void ! Output_segment::remove_output_section(Output_section* os) ! { ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) { ! Output_data_list* pdl = &this->output_lists_[i]; ! for (Output_data_list::iterator p = pdl->begin(); p != pdl->end(); ++p) { ! if (*p == os) { ! pdl->erase(p); return; } } } gold_unreachable(); } *************** void *** 3718,3724 **** Output_segment::add_initial_output_data(Output_data* od) { gold_assert(!this->is_max_align_known_); ! this->output_data_.push_front(od); } // Return whether the first data section is a relro section. --- 3492,3521 ---- Output_segment::add_initial_output_data(Output_data* od) { gold_assert(!this->is_max_align_known_); ! Output_data_list::iterator p = this->output_lists_[0].begin(); ! this->output_lists_[0].insert(p, od); ! } ! ! // Return true if this segment has any sections which hold actual ! // data, rather than being a BSS section. ! ! bool ! Output_segment::has_any_data_sections() const ! { ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! { ! const Output_data_list* pdl = &this->output_lists_[i]; ! for (Output_data_list::const_iterator p = pdl->begin(); ! p != pdl->end(); ! ++p) ! { ! if (!(*p)->is_section()) ! return true; ! if ((*p)->output_section()->type() != elfcpp::SHT_NOBITS) ! return true; ! } ! } ! return false; } // Return whether the first data section is a relro section. *************** Output_segment::add_initial_output_data( *** 3726,3734 **** bool Output_segment::is_first_section_relro() const { ! return (!this->output_data_.empty() ! && this->output_data_.front()->is_section() ! && this->output_data_.front()->output_section()->is_relro()); } // Return the maximum alignment of the Output_data in Output_segment. --- 3523,3538 ---- bool Output_segment::is_first_section_relro() const { ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! { ! const Output_data_list* pdl = &this->output_lists_[i]; ! if (!pdl->empty()) ! { ! Output_data* p = pdl->front(); ! return p->is_section() && p->output_section()->is_relro(); ! } ! } ! return false; } // Return the maximum alignment of the Output_data in Output_segment. *************** Output_segment::maximum_alignment() *** 3738,3753 **** { if (!this->is_max_align_known_) { ! uint64_t addralign; ! ! addralign = Output_segment::maximum_alignment_list(&this->output_data_); ! if (addralign > this->max_align_) ! this->max_align_ = addralign; ! ! addralign = Output_segment::maximum_alignment_list(&this->output_bss_); ! if (addralign > this->max_align_) ! this->max_align_ = addralign; ! this->is_max_align_known_ = true; } --- 3542,3554 ---- { if (!this->is_max_align_known_) { ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! { ! const Output_data_list* pdl = &this->output_lists_[i]; ! uint64_t addralign = Output_segment::maximum_alignment_list(pdl); ! if (addralign > this->max_align_) ! this->max_align_ = addralign; ! } this->is_max_align_known_ = true; } *************** Output_segment::maximum_alignment_list(c *** 3771,3796 **** return ret; } ! // Return the number of dynamic relocs applied to this segment. ! unsigned int ! Output_segment::dynamic_reloc_count() const { ! return (this->dynamic_reloc_count_list(&this->output_data_) ! + this->dynamic_reloc_count_list(&this->output_bss_)); } ! // Return the number of dynamic relocs applied to an Output_data_list. ! unsigned int ! Output_segment::dynamic_reloc_count_list(const Output_data_list* pdl) const { - unsigned int count = 0; for (Output_data_list::const_iterator p = pdl->begin(); p != pdl->end(); ++p) ! count += (*p)->dynamic_reloc_count(); ! return count; } // Set the section addresses for an Output_segment. If RESET is true, --- 3572,3599 ---- return ret; } ! // Return whether this segment has any dynamic relocs. ! bool ! Output_segment::has_dynamic_reloc() const { ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! if (this->has_dynamic_reloc_list(&this->output_lists_[i])) ! return true; ! return false; } ! // Return whether this Output_data_list has any dynamic relocs. ! bool ! Output_segment::has_dynamic_reloc_list(const Output_data_list* pdl) const { for (Output_data_list::const_iterator p = pdl->begin(); p != pdl->end(); ++p) ! if ((*p)->has_dynamic_reloc()) ! return true; ! return false; } // Set the section addresses for an Output_segment. If RESET is true, *************** Output_segment::set_section_addresses(co *** 3818,3843 **** { uint64_t relro_size = 0; off_t off = *poff; ! for (Output_data_list::iterator p = this->output_data_.begin(); ! p != this->output_data_.end(); ! ++p) { ! if (!(*p)->is_section()) ! break; ! Output_section* pos = (*p)->output_section(); ! if (!pos->is_relro()) ! break; ! gold_assert(!(*p)->is_section_flag_set(elfcpp::SHF_TLS)); ! if ((*p)->is_address_valid()) ! relro_size += (*p)->data_size(); ! else { ! // FIXME: This could be faster. ! (*p)->set_address_and_file_offset(addr + relro_size, ! off + relro_size); ! relro_size += (*p)->data_size(); ! (*p)->reset_address_and_file_offset(); } } relro_size += increase_relro; --- 3621,3650 ---- { uint64_t relro_size = 0; off_t off = *poff; ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) { ! Output_data_list* pdl = &this->output_lists_[i]; ! Output_data_list::iterator p; ! for (p = pdl->begin(); p != pdl->end(); ++p) { ! if (!(*p)->is_section()) ! break; ! Output_section* pos = (*p)->output_section(); ! if (!pos->is_relro()) ! break; ! if ((*p)->is_address_valid()) ! relro_size += (*p)->data_size(); ! else ! { ! // FIXME: This could be faster. ! (*p)->set_address_and_file_offset(addr + relro_size, ! off + relro_size); ! relro_size += (*p)->data_size(); ! (*p)->reset_address_and_file_offset(); ! } } + if (p != pdl->end()) + break; } relro_size += increase_relro; *************** Output_segment::set_section_addresses(co *** 3868,3883 **** this->offset_ = orig_off; ! addr = this->set_section_list_addresses(layout, reset, &this->output_data_, ! addr, poff, pshndx, &in_tls); ! this->filesz_ = *poff - orig_off; ! ! off_t off = *poff; ! ! uint64_t ret = this->set_section_list_addresses(layout, reset, ! &this->output_bss_, ! addr, poff, pshndx, ! &in_tls); // If the last section was a TLS section, align upward to the // alignment of the TLS segment, so that the overall size of the TLS --- 3675,3695 ---- this->offset_ = orig_off; ! off_t off = 0; ! uint64_t ret; ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! { ! 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; ! } ! ! ret = addr; ! } // If the last section was a TLS section, align upward to the // alignment of the TLS segment, so that the overall size of the TLS *************** Output_segment::set_offset(unsigned int *** 4020,4026 **** gold_assert(!this->are_addresses_set_); ! if (this->output_data_.empty() && this->output_bss_.empty()) { gold_assert(increase == 0); this->vaddr_ = 0; --- 3832,3842 ---- gold_assert(!this->are_addresses_set_); ! // A non-load section only uses output_lists_[0]. ! ! Output_data_list* pdl = &this->output_lists_[0]; ! ! if (pdl->empty()) { gold_assert(increase == 0); this->vaddr_ = 0; *************** Output_segment::set_offset(unsigned int *** 4033,4043 **** return; } ! const Output_data* first; ! if (this->output_data_.empty()) ! first = this->output_bss_.front(); ! else ! first = this->output_data_.front(); this->vaddr_ = first->address(); this->paddr_ = (first->has_load_address() ? first->load_address() --- 3849,3880 ---- return; } ! // Find the first and last section by address. ! const Output_data* first = NULL; ! const Output_data* last_data = NULL; ! const Output_data* last_bss = NULL; ! for (Output_data_list::const_iterator p = pdl->begin(); ! p != pdl->end(); ! ++p) ! { ! if (first == NULL ! || (*p)->address() < first->address() ! || ((*p)->address() == first->address() ! && (*p)->data_size() < first->data_size())) ! first = *p; ! const Output_data** plast; ! if ((*p)->is_section() ! && (*p)->output_section()->type() == elfcpp::SHT_NOBITS) ! plast = &last_bss; ! else ! plast = &last_data; ! if (*plast == NULL ! || (*p)->address() > (*plast)->address() ! || ((*p)->address() == (*plast)->address() ! && (*p)->data_size() > (*plast)->data_size())) ! *plast = *p; ! } ! this->vaddr_ = first->address(); this->paddr_ = (first->has_load_address() ? first->load_address() *************** Output_segment::set_offset(unsigned int *** 4045,4065 **** this->are_addresses_set_ = true; this->offset_ = first->offset(); ! if (this->output_data_.empty()) this->filesz_ = 0; else ! { ! const Output_data* last_data = this->output_data_.back(); ! this->filesz_ = (last_data->address() ! + last_data->data_size() ! - this->vaddr_); ! } ! const Output_data* last; ! if (this->output_bss_.empty()) ! last = this->output_data_.back(); ! else ! last = this->output_bss_.back(); this->memsz_ = (last->address() + last->data_size() - this->vaddr_); --- 3882,3895 ---- this->are_addresses_set_ = true; this->offset_ = first->offset(); ! if (last_data == NULL) this->filesz_ = 0; else ! this->filesz_ = (last_data->address() ! + last_data->data_size() ! - this->vaddr_); ! const Output_data* last = last_bss != NULL ? last_bss : last_data; this->memsz_ = (last->address() + last->data_size() - this->vaddr_); *************** Output_segment::set_tls_offsets() *** 4085,4118 **** { gold_assert(this->type_ == elfcpp::PT_TLS); ! for (Output_data_list::iterator p = this->output_data_.begin(); ! p != this->output_data_.end(); ! ++p) ! (*p)->set_tls_offset(this->vaddr_); ! ! for (Output_data_list::iterator p = this->output_bss_.begin(); ! p != this->output_bss_.end(); ++p) (*p)->set_tls_offset(this->vaddr_); } ! // Return the address of the first section. uint64_t Output_segment::first_section_load_address() const { ! for (Output_data_list::const_iterator p = this->output_data_.begin(); ! p != this->output_data_.end(); ! ++p) ! if ((*p)->is_section()) ! return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address(); ! ! for (Output_data_list::const_iterator p = this->output_bss_.begin(); ! p != this->output_bss_.end(); ! ++p) ! if ((*p)->is_section()) ! return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address(); ! gold_unreachable(); } --- 3915,3944 ---- { gold_assert(this->type_ == elfcpp::PT_TLS); ! for (Output_data_list::iterator p = this->output_lists_[0].begin(); ! p != this->output_lists_[0].end(); ++p) (*p)->set_tls_offset(this->vaddr_); } ! // Return the load address of the first section. uint64_t Output_segment::first_section_load_address() const { ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! { ! const Output_data_list* pdl = &this->output_lists_[i]; ! for (Output_data_list::const_iterator p = pdl->begin(); ! p != pdl->end(); ! ++p) ! { ! if ((*p)->is_section()) ! return ((*p)->has_load_address() ! ? (*p)->load_address() ! : (*p)->address()); ! } ! } gold_unreachable(); } *************** Output_segment::first_section_load_addre *** 4121,4128 **** unsigned int Output_segment::output_section_count() const { ! return (this->output_section_count_list(&this->output_data_) ! + this->output_section_count_list(&this->output_bss_)); } // Return the number of Output_sections in an Output_data_list. --- 3947,3956 ---- unsigned int Output_segment::output_section_count() const { ! unsigned int ret = 0; ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! ret += this->output_section_count_list(&this->output_lists_[i]); ! return ret; } // Return the number of Output_sections in an Output_data_list. *************** Output_segment::section_with_lowest_load *** 4150,4167 **** { Output_section* found = NULL; uint64_t found_lma = 0; ! this->lowest_load_address_in_list(&this->output_data_, &found, &found_lma); ! ! Output_section* found_data = found; ! this->lowest_load_address_in_list(&this->output_bss_, &found, &found_lma); ! if (found != found_data && found_data != NULL) ! { ! gold_error(_("nobits section %s may not precede progbits section %s " ! "in same segment"), ! found->name(), found_data->name()); ! return NULL; ! } ! return found; } --- 3978,3986 ---- { Output_section* found = NULL; uint64_t found_lma = 0; ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! this->lowest_load_address_in_list(&this->output_lists_[i], &found, ! &found_lma); return found; } *************** Output_segment::write_section_headers(co *** 4221,4232 **** if (this->type_ != elfcpp::PT_LOAD) return v; ! v = this->write_section_headers_list(layout, secnamepool, ! &this->output_data_, ! v, pshndx); ! v = this->write_section_headers_list(layout, secnamepool, ! &this->output_bss_, ! v, pshndx); return v; } --- 4040,4054 ---- if (this->type_ != elfcpp::PT_LOAD) return v; ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! { ! const Output_data_list* pdl = &this->output_lists_[i]; ! v = this->write_section_headers_list(layout, ! secnamepool, ! pdl, ! v, pshndx); ! } ! return v; } *************** Output_segment::print_sections_to_mapfil *** 4263,4270 **** { if (this->type() != elfcpp::PT_LOAD) return; ! this->print_section_list_to_mapfile(mapfile, &this->output_data_); ! this->print_section_list_to_mapfile(mapfile, &this->output_bss_); } // Print an output section list to the map file. --- 4085,4092 ---- { if (this->type() != elfcpp::PT_LOAD) return; ! for (int i = 0; i < static_cast(ORDER_MAX); ++i) ! this->print_section_list_to_mapfile(mapfile, &this->output_lists_[i]); } // Print an output section list to the map file. diff -rcp ../binutils-2.20.51.0.10.original/gold/output.h gold/output.h *** ../binutils-2.20.51.0.10.original/gold/output.h 2010-08-10 15:11:28.000000000 +0100 --- gold/output.h 2010-08-10 15:14:03.000000000 +0100 *************** class Output_data *** 56,62 **** : address_(0), data_size_(0), offset_(-1), is_address_valid_(false), is_data_size_valid_(false), is_offset_valid_(false), is_data_size_fixed_(false), ! dynamic_reloc_count_(0) { } virtual --- 56,62 ---- : address_(0), data_size_(0), offset_(-1), is_address_valid_(false), is_data_size_valid_(false), is_offset_valid_(false), is_data_size_fixed_(false), ! has_dynamic_reloc_(false) { } virtual *************** class Output_data *** 233,247 **** is_layout_complete() { return Output_data::allocated_sizes_are_fixed; } ! // Count the number of dynamic relocations applied to this section. void add_dynamic_reloc() ! { ++this->dynamic_reloc_count_; } ! // Return the number of dynamic relocations applied to this section. ! unsigned int ! dynamic_reloc_count() const ! { return this->dynamic_reloc_count_; } // Whether the address is valid. bool --- 233,247 ---- is_layout_complete() { return Output_data::allocated_sizes_are_fixed; } ! // Note that a dynamic reloc has been applied to this data. void add_dynamic_reloc() ! { this->has_dynamic_reloc_ = true; } ! // Return whether a dynamic reloc has been applied. ! bool ! has_dynamic_reloc() const ! { return this->has_dynamic_reloc_; } // Whether the address is valid. bool *************** class Output_data *** 424,438 **** // File offset of contents in output file. off_t offset_; // Whether address_ is valid. ! bool is_address_valid_; // Whether data_size_ is valid. ! bool is_data_size_valid_; // Whether offset_ is valid. ! bool is_offset_valid_; // Whether data size is fixed. ! bool is_data_size_fixed_; ! // Count of dynamic relocations applied to this section. ! unsigned int dynamic_reloc_count_; }; // Output the section headers. --- 424,438 ---- // File offset of contents in output file. off_t offset_; // Whether address_ is valid. ! bool is_address_valid_ : 1; // Whether data_size_ is valid. ! bool is_data_size_valid_ : 1; // Whether offset_ is valid. ! bool is_offset_valid_ : 1; // Whether data size is fixed. ! bool is_data_size_fixed_ : 1; ! // Whether any dynamic relocs have been applied to this section. ! bool has_dynamic_reloc_ : 1; }; // Output the section headers. *************** class Output_section_lookup_maps *** 2432,2438 **** std::pair value(msp, pomb); std::pair result = this->merge_sections_by_properties_.insert(value); ! gold_assert(value.second); } // Add a mapping from a merged input section in OBJECT with index SHNDX --- 2432,2438 ---- std::pair value(msp, pomb); std::pair result = this->merge_sections_by_properties_.insert(value); ! gold_assert(result.second); } // Add a mapping from a merged input section in OBJECT with index SHNDX *************** class Output_section_lookup_maps *** 2445,2451 **** std::pair value(csid, pomb); std::pair result = this->merge_sections_by_id_.insert(value); ! gold_assert(value.second); } // Find a relaxed input section of OBJECT with index SHNDX. --- 2445,2451 ---- std::pair value(csid, pomb); std::pair result = this->merge_sections_by_id_.insert(value); ! gold_assert(result.second); } // Find a relaxed input section of OBJECT with index SHNDX. *************** class Output_section_lookup_maps *** 2469,2475 **** value(csid, poris); std::pair result = this->relaxed_input_sections_by_id_.insert(value); ! gold_assert(value.second); } private: --- 2469,2475 ---- value(csid, poris); std::pair result = this->relaxed_input_sections_by_id_.insert(value); ! gold_assert(result.second); } private: *************** class Output_section : public Output_dat *** 2761,2766 **** --- 2761,2777 ---- set_must_sort_attached_input_sections() { this->must_sort_attached_input_sections_ = true; } + // Get the order in which this section appears in the PT_LOAD output + // segment. + Output_section_order + order() const + { return this->order_; } + + // Set the order for this section. + void + set_order(Output_section_order order) + { this->order_ = order; } + // Return whether this section holds relro data--data which has // dynamic relocations but which may be marked read-only after the // dynamic relocations have been completed. *************** class Output_section : public Output_dat *** 2778,2823 **** clear_is_relro() { this->is_relro_ = false; } - // True if this section holds relro local data--relro data for which - // the dynamic relocations are all RELATIVE relocations. - bool - is_relro_local() const - { return this->is_relro_local_; } - - // Record that this section holds relro local data. - void - set_is_relro_local() - { this->is_relro_local_ = true; } - - // True if this must be the last relro section. - bool - is_last_relro() const - { return this->is_last_relro_; } - - // Record that this must be the last relro section. - void - set_is_last_relro() - { - gold_assert(this->is_relro_); - this->is_last_relro_ = true; - } - - // True if this must be the first section following the relro sections. - bool - is_first_non_relro() const - { - gold_assert(!this->is_relro_); - return this->is_first_non_relro_; - } - - // Record that this must be the first non-relro section. - void - set_is_first_non_relro() - { - gold_assert(!this->is_relro_); - this->is_first_non_relro_ = true; - } - // True if this is a small section: a section which holds small // variables. bool --- 2789,2794 ---- *************** class Output_section : public Output_dat *** 2845,2871 **** is_large_data_section() { return this->is_large_section_ && this->type_ != elfcpp::SHT_NOBITS; } - // True if this is the .interp section which goes into the PT_INTERP - // segment. - bool - is_interp() const - { return this->is_interp_; } - - // Record that this is the interp section. - void - set_is_interp() - { this->is_interp_ = true; } - - // True if this is a section used by the dynamic linker. - bool - is_dynamic_linker_section() const - { return this->is_dynamic_linker_section_; } - - // Record that this is a section used by the dynamic linker. - void - set_is_dynamic_linker_section() - { this->is_dynamic_linker_section_ = true; } - // Return whether this section should be written after all the input // sections are complete. bool --- 2816,2821 ---- *************** class Output_section : public Output_dat *** 3468,3473 **** --- 3418,3436 ---- input_sections() const { return this->input_sections_; } + // Whether this always keeps an input section list + bool + always_keeps_input_sections() const + { return this->always_keeps_input_sections_; } + + // Always keep an input section list. + void + set_always_keeps_input_sections() + { + gold_assert(this->current_data_size_for_child() == 0); + this->always_keeps_input_sections_ = true; + } + private: // We only save enough information to undo the effects of section layout. class Checkpoint_output_section *************** class Output_section : public Output_dat *** 3694,3699 **** --- 3657,3664 ---- const elfcpp::Elf_Word type_; // The section flags. elfcpp::Elf_Xword flags_; + // The order of this section in the output segment. + Output_section_order order_; // The section index. unsigned int out_shndx_; // If there is a STT_SECTION for this output section in the normal *************** class Output_section : public Output_dat *** 3761,3781 **** bool attached_input_sections_are_sorted_ : 1; // True if this section holds relro data. bool is_relro_ : 1; - // True if this section holds relro local data. - bool is_relro_local_ : 1; - // True if this must be the last relro section. - bool is_last_relro_ : 1; - // True if this must be the first section after the relro sections. - bool is_first_non_relro_ : 1; // True if this is a small section. bool is_small_section_ : 1; // True if this is a large section. bool is_large_section_ : 1; - // True if this is the .interp section going into the PT_INTERP - // segment. - bool is_interp_ : 1; - // True if this is section is read by the dynamic linker. - bool is_dynamic_linker_section_ : 1; // Whether code-fills are generated at write. bool generate_code_fills_at_write_ : 1; // Whether the entry size field should be zero. --- 3726,3735 ---- *************** class Output_section : public Output_dat *** 3784,3789 **** --- 3738,3745 ---- bool section_offsets_need_adjustment_ : 1; // Whether this is a NOLOAD section. bool is_noload_ : 1; + // Whether this always keeps input section. + bool always_keeps_input_sections_ : 1; // For SHT_TLS sections, the offset of this section relative to the base // of the TLS segment. uint64_t tls_offset_; *************** class Output_segment *** 3859,3870 **** uint64_t maximum_alignment(); ! // Add the Output_section OS to this segment. SEG_FLAGS is the ! // segment flags to use. DO_SORT is true if we should sort the ! // placement of the input section for more efficient generated code. void ! add_output_section(Output_section* os, elfcpp::Elf_Word seg_flags, ! bool do_sort); // Remove an Output_section from this segment. It is an error if it // is not present. --- 3815,3831 ---- uint64_t maximum_alignment(); ! // Add the Output_section OS to this PT_LOAD segment. SEG_FLAGS is ! // the segment flags to use. ! void ! add_output_section_to_load(Layout* layout, Output_section* os, ! elfcpp::Elf_Word seg_flags); ! ! // Add the Output_section OS to this non-PT_LOAD segment. SEG_FLAGS ! // is the segment flags to use. void ! add_output_section_to_nonload(Output_section* os, ! elfcpp::Elf_Word seg_flags); // Remove an Output_section from this segment. It is an error if it // is not present. *************** class Output_segment *** 3879,3890 **** // Return true if this segment has any sections which hold actual // data, rather than being a BSS section. bool ! has_any_data_sections() const ! { return !this->output_data_.empty(); } ! // Return the number of dynamic relocations applied to this segment. ! unsigned int ! dynamic_reloc_count() const; // Return the address of the first section. uint64_t --- 3840,3850 ---- // Return true if this segment has any sections which hold actual // data, rather than being a BSS section. bool ! has_any_data_sections() const; ! // Whether this segment has a dynamic relocs. ! bool ! has_dynamic_reloc() const; // Return the address of the first section. uint64_t *************** class Output_segment *** 3977,3983 **** print_sections_to_mapfile(Mapfile*) const; private: ! typedef std::list Output_data_list; // Find the maximum alignment in an Output_data_list. static uint64_t --- 3937,3943 ---- print_sections_to_mapfile(Mapfile*) const; private: ! typedef std::vector Output_data_list; // Find the maximum alignment in an Output_data_list. static uint64_t *************** class Output_segment *** 3997,4005 **** unsigned int output_section_count_list(const Output_data_list*) const; ! // Return the number of dynamic relocs in an Output_data_list. ! unsigned int ! dynamic_reloc_count_list(const Output_data_list*) const; // Find the section with the lowest load address in an // Output_data_list. --- 3957,3965 ---- unsigned int output_section_count_list(const Output_data_list*) const; ! // Return whether an Output_data_list has a dynamic reloc. ! bool ! has_dynamic_reloc_list(const Output_data_list*) const; // Find the section with the lowest load address in an // Output_data_list. *************** class Output_segment *** 4008,4013 **** --- 3968,3979 ---- Output_section** found, uint64_t* found_lma) const; + // Find the first and last entries by address. + void + find_first_and_last_list(const Output_data_list* pdl, + const Output_data** pfirst, + const Output_data** plast) const; + // Write the section headers in the list into V. template unsigned char* *************** class Output_segment *** 4022,4031 **** // NOTE: We want to use the copy constructor. Currently, shallow copy // works for us so we do not need to write our own copy constructor. ! // The list of output data with contents attached to this segment. ! Output_data_list output_data_; ! // The list of output data without contents attached to this segment. ! Output_data_list output_bss_; // The segment virtual address. uint64_t vaddr_; // The segment physical address. --- 3988,3995 ---- // NOTE: We want to use the copy constructor. Currently, shallow copy // works for us so we do not need to write our own copy constructor. ! // The list of output data attached to this segment. ! Output_data_list output_lists_[ORDER_MAX]; // The segment virtual address. uint64_t vaddr_; // The segment physical address. diff -rcp ../binutils-2.20.51.0.10.original/gold/plugin.cc gold/plugin.cc *** ../binutils-2.20.51.0.10.original/gold/plugin.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/plugin.cc 2010-08-10 15:14:03.000000000 +0100 *************** Sized_pluginobj::do_ad *** 705,730 **** template Archive::Should_include Sized_pluginobj::do_should_include_member( ! Symbol_table* symtab, Read_symbols_data*, std::string* why) { char* tmpbuf = NULL; size_t tmpbuflen = 0; ! for (int i = 0; i < this->nsyms_; ++i) { ! const struct ld_plugin_symbol& sym = this->syms_[i]; ! const char* name = sym.name; ! Symbol* symbol; ! Archive::Should_include t = Archive::should_include_member(symtab, name, ! &symbol, why, ! &tmpbuf, ! &tmpbuflen); if (t == Archive::SHOULD_INCLUDE_YES) { if (tmpbuf != NULL) free(tmpbuf); return t; } ! } if (tmpbuf != NULL) free(tmpbuf); return Archive::SHOULD_INCLUDE_UNKNOWN; --- 705,736 ---- template Archive::Should_include Sized_pluginobj::do_should_include_member( ! Symbol_table* symtab, ! Layout* layout, ! Read_symbols_data*, ! std::string* why) { char* tmpbuf = NULL; size_t tmpbuflen = 0; ! for (int i = 0; i < this->nsyms_; ++i) ! { ! const struct ld_plugin_symbol& sym = this->syms_[i]; ! const char* name = sym.name; ! Symbol* symbol; ! Archive::Should_include t = Archive::should_include_member(symtab, ! layout, ! name, ! &symbol, why, ! &tmpbuf, ! &tmpbuflen); if (t == Archive::SHOULD_INCLUDE_YES) { if (tmpbuf != NULL) free(tmpbuf); return t; } ! } if (tmpbuf != NULL) free(tmpbuf); return Archive::SHOULD_INCLUDE_UNKNOWN; *************** Sized_pluginobj::do_ge *** 862,868 **** } // Class Plugin_finish. This task runs after all replacement files have ! // been added. It calls each plugin's cleanup handler. class Plugin_finish : public Task { --- 868,877 ---- } // Class Plugin_finish. This task runs after all replacement files have ! // been added. For now, it's a placeholder for a possible plugin API ! // to allow the plugin to release most of its resources. The cleanup ! // handlers must be called later, because they can remove the temporary ! // object files that are needed until the end of the link. class Plugin_finish : public Task { *************** class Plugin_finish : public Task *** 892,900 **** void run(Workqueue*) { ! Plugin_manager* plugins = parameters->options().plugins(); ! gold_assert(plugins != NULL); ! plugins->cleanup(); } std::string --- 901,907 ---- void run(Workqueue*) { ! // We could call early cleanup handlers here. } std::string diff -rcp ../binutils-2.20.51.0.10.original/gold/plugin.h gold/plugin.h *** ../binutils-2.20.51.0.10.original/gold/plugin.h 2010-08-10 15:12:04.000000000 +0100 --- gold/plugin.h 2010-08-10 15:14:03.000000000 +0100 *************** class Sized_pluginobj : public Pluginobj *** 376,382 **** do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include ! do_should_include_member(Symbol_table* symtab, Read_symbols_data*, std::string* why); // Get the size of a section. --- 376,382 ---- do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include ! do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, std::string* why); // Get the size of a section. diff -rcp ../binutils-2.20.51.0.10.original/gold/powerpc.cc gold/powerpc.cc *** ../binutils-2.20.51.0.10.original/gold/powerpc.cc 2010-08-10 15:11:40.000000000 +0100 --- gold/powerpc.cc 2010-08-10 15:14:03.000000000 +0100 *************** Target_powerpc::got_se *** 738,744 **** layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! this->got_, false, false, false, false); // Create the GOT2 or TOC in the .got section. if (size == 32) --- 738,744 ---- layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! this->got_, ORDER_DATA, false); // Create the GOT2 or TOC in the .got section. if (size == 32) *************** Target_powerpc::got_se *** 747,754 **** layout->add_output_section_data(".got2", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! this->got2_, false, false, false, ! false); } else { --- 747,753 ---- layout->add_output_section_data(".got2", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! this->got2_, ORDER_DATA, false); } else { *************** Target_powerpc::got_se *** 756,763 **** layout->add_output_section_data(".toc", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! this->toc_, false, false, false, ! false); } // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section. --- 755,761 ---- layout->add_output_section_data(".toc", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! this->toc_, ORDER_DATA, false); } // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section. *************** Target_powerpc::rela_d *** 784,791 **** gold_assert(layout != NULL); this->rela_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rela_dyn_, true, ! false, false, false); } return this->rela_dyn_; } --- 782,789 ---- gold_assert(layout != NULL); this->rela_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rela_dyn_, ! ORDER_DYNAMIC_RELOCS, false); } return this->rela_dyn_; } *************** Output_data_plt_powerpcrel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rel_, true, false, ! false, false); } template --- 843,850 ---- { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rel_, ! ORDER_DYNAMIC_PLT_RELOCS, false); } template *************** Target_powerpc::make_p *** 980,986 **** (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR | elfcpp::SHF_WRITE), ! this->plt_, false, false, false, false); // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section. symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL, --- 978,984 ---- (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR | elfcpp::SHF_WRITE), ! this->plt_, ORDER_PLT, false); // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section. symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL, *************** Target_powerpc::gc_pro *** 1493,1499 **** typedef Target_powerpc Powerpc; typedef typename Target_powerpc::Scan Scan; ! gold::gc_process_relocs( symtab, layout, this, --- 1491,1498 ---- typedef Target_powerpc Powerpc; typedef typename Target_powerpc::Scan Scan; ! gold::gc_process_relocs( symtab, layout, this, *************** Target_powerpc::scan_r *** 1543,1550 **** Output_section* os = layout->add_output_section_data(".sdata", 0, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! sdata, false, ! false, false, false); symtab->define_in_output_data("_SDA_BASE_", NULL, Symbol_table::PREDEFINED, os, --- 1542,1550 ---- Output_section* os = layout->add_output_section_data(".sdata", 0, elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, ! sdata, ! ORDER_SMALL_DATA, ! false); symtab->define_in_output_data("_SDA_BASE_", NULL, Symbol_table::PREDEFINED, os, *************** Target_powerpc::Reloca *** 1636,1642 **** // Get the GOT offset if needed. Unlike i386 and x86_64, our GOT // pointer points to the beginning, not the end, of the table. // So we just use the plain offset. - bool have_got_offset = false; unsigned int got_offset = 0; unsigned int got2_offset = 0; switch (r_type) --- 1636,1641 ---- *************** Target_powerpc::Reloca *** 1668,1674 **** gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD)); got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD); } - have_got_offset = true; break; // R_PPC_PLTREL24 is rather special. If non-zero, --- 1667,1672 ---- *************** Target_powerpc::Reloca *** 1681,1687 **** got2_offset = got2->offset(); addend += got2_offset; } - have_got_offset = true; break; default: --- 1679,1684 ---- diff -rcp ../binutils-2.20.51.0.10.original/gold/reloc.cc gold/reloc.cc *** ../binutils-2.20.51.0.10.original/gold/reloc.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/reloc.cc 2010-08-10 15:14:03.000000000 +0100 *************** *** 32,37 **** --- 32,38 ---- #include "target-reloc.h" #include "reloc.h" #include "icf.h" + #include "compressed_output.h" namespace gold { *************** Sized_relobj::write_se *** 732,741 **** --- 733,749 ---- off_t view_start; section_size_type view_size; + bool must_decompress = false; if (output_offset != invalid_address) { view_start = output_section_offset + output_offset; view_size = convert_to_section_size_type(shdr.get_sh_size()); + section_size_type uncompressed_size; + if (this->section_is_compressed(i, &uncompressed_size)) + { + view_size = uncompressed_size; + must_decompress = true; + } } else { *************** Sized_relobj::write_se *** 754,760 **** { unsigned char* buffer = os->postprocessing_buffer(); view = buffer + view_start; ! if (output_offset != invalid_address) { off_t sh_offset = shdr.get_sh_offset(); if (!rm.empty() && rm.back().file_offset > sh_offset) --- 762,768 ---- { unsigned char* buffer = os->postprocessing_buffer(); view = buffer + view_start; ! if (output_offset != invalid_address && !must_decompress) { off_t sh_offset = shdr.get_sh_offset(); if (!rm.empty() && rm.back().file_offset > sh_offset) *************** Sized_relobj::write_se *** 770,783 **** else { view = of->get_output_view(view_start, view_size); ! off_t sh_offset = shdr.get_sh_offset(); ! if (!rm.empty() && rm.back().file_offset > sh_offset) ! is_sorted = false; ! rm.push_back(File_read::Read_multiple_entry(sh_offset, ! view_size, view)); } } pvs->view = view; pvs->address = os->address(); if (output_offset != invalid_address) --- 778,804 ---- else { view = of->get_output_view(view_start, view_size); ! if (!must_decompress) ! { ! off_t sh_offset = shdr.get_sh_offset(); ! if (!rm.empty() && rm.back().file_offset > sh_offset) ! is_sorted = false; ! rm.push_back(File_read::Read_multiple_entry(sh_offset, ! view_size, view)); ! } } } + if (must_decompress) + { + // Read and decompress the section. + section_size_type len; + const unsigned char* p = this->section_contents(i, &len, false); + if (!decompress_input_section(p, len, view, view_size)) + this->error(_("could not decompress section %s"), + this->section_name(i).c_str()); + } + pvs->view = view; pvs->address = os->address(); if (output_offset != invalid_address) diff -rcp ../binutils-2.20.51.0.10.original/gold/resolve.cc gold/resolve.cc *** ../binutils-2.20.51.0.10.original/gold/resolve.cc 2010-08-10 15:11:43.000000000 +0100 --- gold/resolve.cc 2010-08-10 15:14:03.000000000 +0100 *************** Symbol_table::resolve(Sized_symbol *** 335,352 **** sym.get_st_type()); bool adjust_common_sizes; typename Sized_symbol::Size_type tosize = to->symsize(); if (Symbol_table::should_override(to, frombits, OBJECT, object, ! &adjust_common_sizes)) { this->override(to, sym, st_shndx, is_ordinary, object, version); if (adjust_common_sizes && tosize > to->symsize()) to->set_symsize(tosize); } else { if (adjust_common_sizes && sym.get_st_size() > tosize) to->set_symsize(sym.get_st_size()); // The ELF ABI says that even for a reference to a symbol we // merge the visibility. to->override_visibility(sym.get_st_visibility()); --- 335,367 ---- sym.get_st_type()); bool adjust_common_sizes; + bool adjust_dyndef; typename Sized_symbol::Size_type tosize = to->symsize(); if (Symbol_table::should_override(to, frombits, OBJECT, object, ! &adjust_common_sizes, ! &adjust_dyndef)) { + elfcpp::STB tobinding = to->binding(); this->override(to, sym, st_shndx, is_ordinary, object, version); if (adjust_common_sizes && tosize > to->symsize()) to->set_symsize(tosize); + if (adjust_dyndef) + { + // We are overriding an UNDEF or WEAK UNDEF with a DYN DEF. + // Remember which kind of UNDEF it was for future reference. + to->set_undef_binding(tobinding); + } } else { if (adjust_common_sizes && sym.get_st_size() > tosize) to->set_symsize(sym.get_st_size()); + if (adjust_dyndef) + { + // We are keeping a DYN DEF after seeing an UNDEF or WEAK UNDEF. + // Remember which kind of UNDEF it was. + to->set_undef_binding(sym.get_st_bind()); + } // The ELF ABI says that even for a reference to a symbol we // merge the visibility. to->override_visibility(sym.get_st_visibility()); *************** Symbol_table::resolve(Sized_symbol *** 381,389 **** bool Symbol_table::should_override(const Symbol* to, unsigned int frombits, Defined defined, Object* object, ! bool* adjust_common_sizes) { *adjust_common_sizes = false; unsigned int tobits; if (to->source() == Symbol::IS_UNDEFINED) --- 396,406 ---- bool Symbol_table::should_override(const Symbol* to, unsigned int frombits, Defined defined, Object* object, ! bool* adjust_common_sizes, ! bool* adjust_dyndef) { *adjust_common_sizes = false; + *adjust_dyndef = false; unsigned int tobits; if (to->source() == Symbol::IS_UNDEFINED) *************** Symbol_table::should_override(const Symb *** 531,542 **** return false; case UNDEF * 16 + DYN_DEF: - case WEAK_UNDEF * 16 + DYN_DEF: case DYN_UNDEF * 16 + DYN_DEF: case DYN_WEAK_UNDEF * 16 + DYN_DEF: // Use a dynamic definition if we have a reference. return true; case COMMON * 16 + DYN_DEF: case WEAK_COMMON * 16 + DYN_DEF: case DYN_COMMON * 16 + DYN_DEF: --- 548,564 ---- return false; case UNDEF * 16 + DYN_DEF: case DYN_UNDEF * 16 + DYN_DEF: case DYN_WEAK_UNDEF * 16 + DYN_DEF: // Use a dynamic definition if we have a reference. return true; + case WEAK_UNDEF * 16 + DYN_DEF: + // When overriding a weak undef by a dynamic definition, + // we need to remember that the original undef was weak. + *adjust_dyndef = true; + return true; + case COMMON * 16 + DYN_DEF: case WEAK_COMMON * 16 + DYN_DEF: case DYN_COMMON * 16 + DYN_DEF: *************** Symbol_table::should_override(const Symb *** 554,565 **** return false; case UNDEF * 16 + DYN_WEAK_DEF: - case WEAK_UNDEF * 16 + DYN_WEAK_DEF: case DYN_UNDEF * 16 + DYN_WEAK_DEF: case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF: // Use a weak dynamic definition if we have a reference. return true; case COMMON * 16 + DYN_WEAK_DEF: case WEAK_COMMON * 16 + DYN_WEAK_DEF: case DYN_COMMON * 16 + DYN_WEAK_DEF: --- 576,592 ---- return false; case UNDEF * 16 + DYN_WEAK_DEF: case DYN_UNDEF * 16 + DYN_WEAK_DEF: case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF: // Use a weak dynamic definition if we have a reference. return true; + case WEAK_UNDEF * 16 + DYN_WEAK_DEF: + // When overriding a weak undef by a dynamic definition, + // we need to remember that the original undef was weak. + *adjust_dyndef = true; + return true; + case COMMON * 16 + DYN_WEAK_DEF: case WEAK_COMMON * 16 + DYN_WEAK_DEF: case DYN_COMMON * 16 + DYN_WEAK_DEF: *************** Symbol_table::should_override(const Symb *** 570,581 **** case DEF * 16 + UNDEF: case WEAK_DEF * 16 + UNDEF: - case DYN_DEF * 16 + UNDEF: - case DYN_WEAK_DEF * 16 + UNDEF: case UNDEF * 16 + UNDEF: // A new undefined reference tells us nothing. return false; case WEAK_UNDEF * 16 + UNDEF: case DYN_UNDEF * 16 + UNDEF: case DYN_WEAK_UNDEF * 16 + UNDEF: --- 597,612 ---- case DEF * 16 + UNDEF: case WEAK_DEF * 16 + UNDEF: case UNDEF * 16 + UNDEF: // A new undefined reference tells us nothing. return false; + case DYN_DEF * 16 + UNDEF: + case DYN_WEAK_DEF * 16 + UNDEF: + // For a dynamic def, we need to remember which kind of undef we see. + *adjust_dyndef = true; + return false; + case WEAK_UNDEF * 16 + UNDEF: case DYN_UNDEF * 16 + UNDEF: case DYN_WEAK_UNDEF * 16 + UNDEF: *************** Symbol_table::should_override(const Symb *** 591,598 **** case DEF * 16 + WEAK_UNDEF: case WEAK_DEF * 16 + WEAK_UNDEF: - case DYN_DEF * 16 + WEAK_UNDEF: - case DYN_WEAK_DEF * 16 + WEAK_UNDEF: case UNDEF * 16 + WEAK_UNDEF: case WEAK_UNDEF * 16 + WEAK_UNDEF: case DYN_UNDEF * 16 + WEAK_UNDEF: --- 622,627 ---- *************** Symbol_table::should_override(const Symb *** 604,609 **** --- 633,644 ---- // A new weak undefined reference tells us nothing. return false; + case DYN_DEF * 16 + WEAK_UNDEF: + case DYN_WEAK_DEF * 16 + WEAK_UNDEF: + // For a dynamic def, we need to remember which kind of undef we see. + *adjust_dyndef = true; + return false; + case DEF * 16 + DYN_UNDEF: case WEAK_DEF * 16 + DYN_UNDEF: case DYN_DEF * 16 + DYN_UNDEF: *************** bool *** 811,820 **** Symbol_table::should_override_with_special(const Symbol* to, Defined defined) { bool adjust_common_sizes; unsigned int frombits = global_flag | regular_flag | def_flag; bool ret = Symbol_table::should_override(to, frombits, defined, NULL, ! &adjust_common_sizes); ! gold_assert(!adjust_common_sizes); return ret; } --- 846,857 ---- Symbol_table::should_override_with_special(const Symbol* to, Defined defined) { bool adjust_common_sizes; + bool adjust_dyn_def; unsigned int frombits = global_flag | regular_flag | def_flag; bool ret = Symbol_table::should_override(to, frombits, defined, NULL, ! &adjust_common_sizes, ! &adjust_dyn_def); ! gold_assert(!adjust_common_sizes && !adjust_dyn_def); return ret; } diff -rcp ../binutils-2.20.51.0.10.original/gold/script.cc gold/script.cc *** ../binutils-2.20.51.0.10.original/gold/script.cc 2010-08-10 15:11:40.000000000 +0100 --- gold/script.cc 2010-08-10 15:14:03.000000000 +0100 *************** Script_assertion::print(FILE* f) const *** 1045,1052 **** // Class Script_options. Script_options::Script_options() ! : entry_(), symbol_assignments_(), version_script_info_(), ! script_sections_() { } --- 1045,1052 ---- // Class Script_options. Script_options::Script_options() ! : entry_(), symbol_assignments_(), symbol_definitions_(), ! symbol_references_(), version_script_info_(), script_sections_() { } *************** Script_options::add_symbol_assignment(co *** 1071,1076 **** --- 1071,1083 ---- value, provide, hidden); this->symbol_assignments_.push_back(p); } + + if (!provide) + { + std::string n(name, length); + this->symbol_definitions_.insert(n); + this->symbol_references_.erase(n); + } } else { *************** Script_options::add_symbol_assignment(co *** 1084,1089 **** --- 1091,1109 ---- } } + // Add a reference to a symbol. + + void + Script_options::add_symbol_reference(const char* name, size_t length) + { + if (length != 1 || name[0] != '.') + { + std::string n(name, length); + if (this->symbol_definitions_.find(n) == this->symbol_definitions_.end()) + this->symbol_references_.insert(n); + } + } + // Add an assertion. void *************** script_set_common_allocation(void* closu *** 2679,2684 **** --- 2699,2715 ---- script_parse_option(closurev, arg, strlen(arg)); } + // Called by the bison parser to refer to a symbol. + + extern "C" Expression* + script_symbol(void *closurev, const char* name, size_t length) + { + Parser_closure* closure = static_cast(closurev); + if (length != 1 || name[0] != '.') + closure->script_options()->add_symbol_reference(name, length); + return script_exp_string(name, length); + } + // Called by the bison parser to define a symbol. extern "C" void diff -rcp ../binutils-2.20.51.0.10.original/gold/script-c.h gold/script-c.h *** ../binutils-2.20.51.0.10.original/gold/script-c.h 2010-08-10 15:12:04.000000000 +0100 --- gold/script-c.h 2010-08-10 15:14:03.000000000 +0100 *************** script_push_lex_into_version_mode(void* *** 303,308 **** --- 303,316 ---- extern void script_pop_lex_mode(void* closure); + /* Called by the bison parser to get the value of a symbol. This is + called for a reference to a symbol, but is not called for something + like "sym += 10". Uses of the special symbol "." can just call + script_exp_string. */ + + extern Expression_ptr + script_symbol(void* closure, const char*, size_t); + /* Called by the bison parser to set a symbol to a value. PROVIDE is non-zero if the symbol should be provided--only defined if there is an undefined reference. HIDDEN is non-zero if the symbol should be diff -rcp ../binutils-2.20.51.0.10.original/gold/script.h gold/script.h *** ../binutils-2.20.51.0.10.original/gold/script.h 2010-08-10 15:12:03.000000000 +0100 --- gold/script.h 2010-08-10 15:14:03.000000000 +0100 *************** class Script_options *** 423,428 **** --- 423,432 ---- add_symbol_assignment(const char* name, size_t length, bool is_defsym, Expression* value, bool provide, bool hidden); + // Add a reference to a symbol. + void + add_symbol_reference(const char* name, size_t length); + // Add an assertion. void add_assertion(Expression* check, const char* message, size_t messagelen); *************** class Script_options *** 439,444 **** --- 443,474 ---- void add_symbols_to_table(Symbol_table*); + // Used to iterate over symbols which are referenced in expressions + // but not defined. + typedef Unordered_set::const_iterator referenced_const_iterator; + + referenced_const_iterator + referenced_begin() const + { return this->symbol_references_.begin(); } + + referenced_const_iterator + referenced_end() const + { return this->symbol_references_.end(); } + + // Return whether a symbol is referenced but not defined. + bool + is_referenced(const std::string& name) const + { + return (this->symbol_references_.find(name) + != this->symbol_references_.end()); + } + + // Return whether there are any symbols which were referenced but + // not defined. + bool + any_unreferenced() const + { return !this->symbol_references_.empty(); } + // Finalize the symbol values. Also check assertions. void finalize_symbols(Symbol_table*, const Layout*); *************** class Script_options *** 497,502 **** --- 527,536 ---- std::string entry_; // Symbols to set. Symbol_assignments symbol_assignments_; + // Symbols defined in an expression, for faster lookup. + Unordered_set symbol_definitions_; + // Symbols referenced in an expression. + Unordered_set symbol_references_; // Assertions to check. Assertions assertions_; // Version information parsed from a version script. diff -rcp ../binutils-2.20.51.0.10.original/gold/script-sections.cc gold/script-sections.cc *** ../binutils-2.20.51.0.10.original/gold/script-sections.cc 2010-08-10 15:12:03.000000000 +0100 --- gold/script-sections.cc 2010-08-10 15:14:03.000000000 +0100 *************** Script_sections::create_segments(Layout* *** 3212,3218 **** is_current_seg_readonly = true; } ! current_seg->add_output_section(*p, seg_flags, false); if (((*p)->flags() & elfcpp::SHF_WRITE) != 0) is_current_seg_readonly = false; --- 3212,3218 ---- is_current_seg_readonly = true; } ! current_seg->add_output_section_to_load(layout, *p, seg_flags); if (((*p)->flags() & elfcpp::SHF_WRITE) != 0) is_current_seg_readonly = false; *************** Script_sections::create_note_and_tls_seg *** 3291,3297 **** Layout::section_flags_to_segment((*p)->flags()); Output_segment* oseg = layout->make_output_segment(elfcpp::PT_NOTE, seg_flags); ! oseg->add_output_section(*p, seg_flags, false); // Incorporate any subsequent SHT_NOTE sections, in the // hopes that the script is sensible. --- 3291,3297 ---- Layout::section_flags_to_segment((*p)->flags()); Output_segment* oseg = layout->make_output_segment(elfcpp::PT_NOTE, seg_flags); ! oseg->add_output_section_to_nonload(*p, seg_flags); // Incorporate any subsequent SHT_NOTE sections, in the // hopes that the script is sensible. *************** Script_sections::create_note_and_tls_seg *** 3300,3306 **** && (*pnext)->type() == elfcpp::SHT_NOTE) { seg_flags = Layout::section_flags_to_segment((*pnext)->flags()); ! oseg->add_output_section(*pnext, seg_flags, false); p = pnext; ++pnext; } --- 3300,3306 ---- && (*pnext)->type() == elfcpp::SHT_NOTE) { seg_flags = Layout::section_flags_to_segment((*pnext)->flags()); ! oseg->add_output_section_to_nonload(*pnext, seg_flags); p = pnext; ++pnext; } *************** Script_sections::create_note_and_tls_seg *** 3315,3328 **** Layout::section_flags_to_segment((*p)->flags()); Output_segment* oseg = layout->make_output_segment(elfcpp::PT_TLS, seg_flags); ! oseg->add_output_section(*p, seg_flags, false); Layout::Section_list::const_iterator pnext = p + 1; while (pnext != sections->end() && ((*pnext)->flags() & elfcpp::SHF_TLS) != 0) { seg_flags = Layout::section_flags_to_segment((*pnext)->flags()); ! oseg->add_output_section(*pnext, seg_flags, false); p = pnext; ++pnext; } --- 3315,3328 ---- Layout::section_flags_to_segment((*p)->flags()); Output_segment* oseg = layout->make_output_segment(elfcpp::PT_TLS, seg_flags); ! oseg->add_output_section_to_nonload(*p, seg_flags); Layout::Section_list::const_iterator pnext = p + 1; while (pnext != sections->end() && ((*pnext)->flags() & elfcpp::SHF_TLS) != 0) { seg_flags = Layout::section_flags_to_segment((*pnext)->flags()); ! oseg->add_output_section_to_nonload(*pnext, seg_flags); p = pnext; ++pnext; } *************** Script_sections::attach_sections_using_p *** 3477,3486 **** elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(os->flags()); - r->second->add_output_section(os, seg_flags, false); ! if (r->second->type() == elfcpp::PT_LOAD) { if (in_load_segment) gold_error(_("section in two PT_LOAD segments")); in_load_segment = true; --- 3477,3488 ---- elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(os->flags()); ! if (r->second->type() != elfcpp::PT_LOAD) ! r->second->add_output_section_to_nonload(os, seg_flags); ! else { + r->second->add_output_section_to_load(layout, os, seg_flags); if (in_load_segment) gold_error(_("section in two PT_LOAD segments")); in_load_segment = true; diff -rcp ../binutils-2.20.51.0.10.original/gold/sparc.cc gold/sparc.cc *** ../binutils-2.20.51.0.10.original/gold/sparc.cc 2010-08-10 15:11:28.000000000 +0100 --- gold/sparc.cc 2010-08-10 15:14:03.000000000 +0100 *************** Target_sparc::got_sect *** 1045,1056 **** this->got_ = new Output_data_got(); ! Output_section* os; ! os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_, false, true, false, ! false); // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section. symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL, --- 1045,1054 ---- this->got_ = new Output_data_got(); ! layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_, ORDER_RELRO, true); // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section. symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL, *************** Target_sparc::rela_dyn *** 1076,1083 **** gold_assert(layout != NULL); this->rela_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rela_dyn_, true, ! false, false, false); } return this->rela_dyn_; } --- 1074,1081 ---- gold_assert(layout != NULL); this->rela_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rela_dyn_, ! ORDER_DYNAMIC_RELOCS, false); } return this->rela_dyn_; } *************** Output_data_plt_sparc: *** 1179,1186 **** { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rel_, true, ! false, false, false); } template --- 1177,1184 ---- { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rel_, ! ORDER_DYNAMIC_PLT_RELOCS, false); } template *************** Target_sparc::make_plt *** 1402,1408 **** (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR | elfcpp::SHF_WRITE), ! this->plt_, false, false, false, false); // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section. symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL, --- 1400,1406 ---- (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR | elfcpp::SHF_WRITE), ! this->plt_, ORDER_PLT, false); // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section. symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL, *************** Target_sparc::gc_proce *** 2332,2338 **** typedef Target_sparc Sparc; typedef typename Target_sparc::Scan Scan; ! gold::gc_process_relocs( symtab, layout, this, --- 2330,2337 ---- typedef Target_sparc Sparc; typedef typename Target_sparc::Scan Scan; ! gold::gc_process_relocs( symtab, layout, this, *************** Target_sparc::Relocate *** 2474,2480 **** // Get the GOT offset if needed. Unlike i386 and x86_64, our GOT // pointer points to the beginning, not the end, of the table. // So we just use the plain offset. - bool have_got_offset = false; unsigned int got_offset = 0; switch (r_type) { --- 2473,2478 ---- *************** Target_sparc::Relocate *** 2495,2501 **** gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD)); got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD); } - have_got_offset = true; break; default: --- 2493,2498 ---- diff -rcp ../binutils-2.20.51.0.10.original/gold/stringpool.cc gold/stringpool.cc *** ../binutils-2.20.51.0.10.original/gold/stringpool.cc 2010-08-10 15:11:43.000000000 +0100 --- gold/stringpool.cc 2010-08-10 15:14:03.000000000 +0100 *************** Stringpool_template::re *** 87,114 **** this->string_set_.swap(new_string_set); } - // Return the length of a string of arbitrary character type. - - template - size_t - Stringpool_template::string_length(const Stringpool_char* p) - { - size_t len = 0; - for (; *p != 0; ++p) - ++len; - return len; - } - - // Specialize string_length for char. Maybe we could just use - // std::char_traits<>::length? - - template<> - inline size_t - Stringpool_template::string_length(const char* p) - { - return strlen(p); - } - // Compare two strings of arbitrary character type for equality. template --- 87,92 ---- diff -rcp ../binutils-2.20.51.0.10.original/gold/stringpool.h gold/stringpool.h *** ../binutils-2.20.51.0.10.original/gold/stringpool.h 2010-08-10 15:11:43.000000000 +0100 --- gold/stringpool.h 2010-08-10 15:14:03.000000000 +0100 *************** namespace gold *** 32,37 **** --- 32,59 ---- class Output_file; + // Return the length of a string in units of Char_type. + + template + inline size_t + string_length(const Char_type* p) + { + size_t len = 0; + for (; *p != 0; ++p) + ++len; + return len; + } + + // Specialize string_length for char. Maybe we could just use + // std::char_traits<>::length? + + template<> + inline size_t + string_length(const char* p) + { + return strlen(p); + } + // A Stringpool is a pool of unique strings. It provides the // following features: *************** class Stringpool_template *** 266,275 **** Stringpool_template(const Stringpool_template&); Stringpool_template& operator=(const Stringpool_template&); - // Return the length of a string in units of Stringpool_char. - static size_t - string_length(const Stringpool_char*); - // Return whether two strings are equal. static bool string_equal(const Stringpool_char*, const Stringpool_char*); --- 288,293 ---- diff -rcp ../binutils-2.20.51.0.10.original/gold/symtab.cc gold/symtab.cc *** ../binutils-2.20.51.0.10.original/gold/symtab.cc 2010-08-10 15:12:04.000000000 +0100 --- gold/symtab.cc 2010-08-10 15:14:03.000000000 +0100 *************** *** 38,44 **** #include "target.h" #include "workqueue.h" #include "symtab.h" ! #include "demangle.h" // needed for --dynamic-list-cpp-new #include "plugin.h" namespace gold --- 38,44 ---- #include "target.h" #include "workqueue.h" #include "symtab.h" ! #include "script.h" #include "plugin.h" namespace gold *************** Symbol::init_fields(const char* name, co *** 76,81 **** --- 76,83 ---- this->is_ordinary_shndx_ = false; this->in_real_elf_ = false; this->is_defined_in_discarded_section_ = false; + this->undef_binding_set_ = false; + this->undef_binding_weak_ = false; } // Return the demangled version of the symbol's name, but only *************** Symbol_table::is_section_folded(Object* *** 528,534 **** // work list to avoid gc'ing them. void ! Symbol_table::gc_mark_undef_symbols() { for (options::String_set::const_iterator p = parameters->options().undefined_begin(); --- 530,536 ---- // work list to avoid gc'ing them. void ! Symbol_table::gc_mark_undef_symbols(Layout* layout) { for (options::String_set::const_iterator p = parameters->options().undefined_begin(); *************** Symbol_table::gc_mark_undef_symbols() *** 551,556 **** --- 553,579 ---- } } } + + for (Script_options::referenced_const_iterator p = + layout->script_options()->referenced_begin(); + p != layout->script_options()->referenced_end(); + ++p) + { + Symbol* sym = this->lookup(p->c_str()); + gold_assert(sym != NULL); + if (sym->source() == Symbol::FROM_OBJECT + && !sym->object()->is_dynamic()) + { + Relobj* obj = static_cast(sym->object()); + bool is_ordinary; + unsigned int shndx = sym->shndx(&is_ordinary); + if (is_ordinary) + { + gold_assert(this->gc_ != NULL); + this->gc_->worklist().push(Section_id(obj, shndx)); + } + } + } } void *************** Symbol_table::get_copy_source(const Symb *** 2161,2174 **** // Add any undefined symbols named on the command line. void ! Symbol_table::add_undefined_symbols_from_command_line() { ! if (parameters->options().any_undefined()) { if (parameters->target().get_size() == 32) { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) ! this->do_add_undefined_symbols_from_command_line<32>(); #else gold_unreachable(); #endif --- 2184,2198 ---- // Add any undefined symbols named on the command line. void ! Symbol_table::add_undefined_symbols_from_command_line(Layout* layout) { ! if (parameters->options().any_undefined() ! || layout->script_options()->any_unreferenced()) { if (parameters->target().get_size() == 32) { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) ! this->do_add_undefined_symbols_from_command_line<32>(layout); #else gold_unreachable(); #endif *************** Symbol_table::add_undefined_symbols_from *** 2176,2182 **** else if (parameters->target().get_size() == 64) { #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) ! this->do_add_undefined_symbols_from_command_line<64>(); #else gold_unreachable(); #endif --- 2200,2206 ---- else if (parameters->target().get_size() == 64) { #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) ! this->do_add_undefined_symbols_from_command_line<64>(layout); #else gold_unreachable(); #endif *************** Symbol_table::add_undefined_symbols_from *** 2188,2237 **** template void ! Symbol_table::do_add_undefined_symbols_from_command_line() { for (options::String_set::const_iterator p = parameters->options().undefined_begin(); p != parameters->options().undefined_end(); ++p) ! { ! const char* name = p->c_str(); ! if (this->lookup(name) != NULL) ! continue; ! const char* version = NULL; ! Sized_symbol* sym; ! Sized_symbol* oldsym; ! bool resolve_oldsym; ! if (parameters->target().is_big_endian()) ! { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) ! sym = this->define_special_symbol(&name, &version, ! false, &oldsym, ! &resolve_oldsym); #else ! gold_unreachable(); #endif ! } ! else ! { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) ! sym = this->define_special_symbol(&name, &version, ! false, &oldsym, ! &resolve_oldsym); #else ! gold_unreachable(); #endif ! } ! gold_assert(oldsym == NULL); ! sym->init_undefined(name, version, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, ! elfcpp::STV_DEFAULT, 0); ! ++this->saw_undefined_; ! } } // Set the dynamic symbol indexes. INDEX is the index of the first --- 2212,2270 ---- template void ! Symbol_table::do_add_undefined_symbols_from_command_line(Layout* layout) { for (options::String_set::const_iterator p = parameters->options().undefined_begin(); p != parameters->options().undefined_end(); ++p) ! this->add_undefined_symbol_from_command_line(p->c_str()); ! for (Script_options::referenced_const_iterator p = ! layout->script_options()->referenced_begin(); ! p != layout->script_options()->referenced_end(); ! ++p) ! this->add_undefined_symbol_from_command_line(p->c_str()); ! } ! ! template ! void ! Symbol_table::add_undefined_symbol_from_command_line(const char* name) ! { ! if (this->lookup(name) != NULL) ! return; ! const char* version = NULL; ! Sized_symbol* sym; ! Sized_symbol* oldsym; ! bool resolve_oldsym; ! if (parameters->target().is_big_endian()) ! { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) ! sym = this->define_special_symbol(&name, &version, ! false, &oldsym, ! &resolve_oldsym); #else ! gold_unreachable(); #endif ! } ! else ! { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) ! sym = this->define_special_symbol(&name, &version, ! false, &oldsym, ! &resolve_oldsym); #else ! gold_unreachable(); #endif ! } ! gold_assert(oldsym == NULL); ! sym->init_undefined(name, version, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, ! elfcpp::STV_DEFAULT, 0); ! ++this->saw_undefined_; } // Set the dynamic symbol indexes. INDEX is the index of the first *************** Symbol_table::sized_write_globals(const *** 2697,2702 **** --- 2730,2736 ---- unsigned int shndx; typename elfcpp::Elf_types::Elf_Addr sym_value = sym->value(); typename elfcpp::Elf_types::Elf_Addr dynsym_value = sym_value; + elfcpp::STB binding = sym->binding(); switch (sym->source()) { case Symbol::FROM_OBJECT: *************** Symbol_table::sized_write_globals(const *** 2720,2725 **** --- 2754,2761 ---- if (sym->needs_dynsym_value()) dynsym_value = target.dynsym_value(sym); shndx = elfcpp::SHN_UNDEF; + if (sym->is_undef_binding_weak()) + binding = elfcpp::STB_WEAK; } else if (symobj->pluginobj() != NULL) shndx = elfcpp::SHN_UNDEF; *************** Symbol_table::sized_write_globals(const *** 2800,2806 **** gold_assert(sym_index < output_count); unsigned char* ps = psyms + (sym_index * sym_size); this->sized_write_symbol(sym, sym_value, shndx, ! sympool, ps); } if (dynsym_index != -1U) --- 2836,2842 ---- gold_assert(sym_index < output_count); unsigned char* ps = psyms + (sym_index * sym_size); this->sized_write_symbol(sym, sym_value, shndx, ! binding, sympool, ps); } if (dynsym_index != -1U) *************** Symbol_table::sized_write_globals(const *** 2809,2815 **** gold_assert(dynsym_index < dynamic_count); unsigned char* pd = dynamic_view + (dynsym_index * sym_size); this->sized_write_symbol(sym, dynsym_value, shndx, ! dynpool, pd); } } --- 2845,2851 ---- gold_assert(dynsym_index < dynamic_count); unsigned char* pd = dynamic_view + (dynsym_index * sym_size); this->sized_write_symbol(sym, dynsym_value, shndx, ! binding, dynpool, pd); } } *************** Symbol_table::sized_write_symbol( *** 2827,2832 **** --- 2863,2869 ---- Sized_symbol* sym, typename elfcpp::Elf_types::Elf_Addr value, unsigned int shndx, + elfcpp::STB binding, const Stringpool* pool, unsigned char* p) const { *************** Symbol_table::sized_write_symbol( *** 2847,2853 **** if (sym->is_forced_local()) osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL, type)); else ! osym.put_st_info(elfcpp::elf_st_info(sym->binding(), type)); osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis())); osym.put_st_shndx(shndx); } --- 2884,2890 ---- if (sym->is_forced_local()) osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL, type)); else ! osym.put_st_info(elfcpp::elf_st_info(binding, type)); osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis())); osym.put_st_shndx(shndx); } diff -rcp ../binutils-2.20.51.0.10.original/gold/symtab.h gold/symtab.h *** ../binutils-2.20.51.0.10.original/gold/symtab.h 2010-08-10 15:11:43.000000000 +0100 --- gold/symtab.h 2010-08-10 15:14:03.000000000 +0100 *************** class Symbol *** 227,232 **** --- 227,249 ---- void override_visibility(elfcpp::STV); + // Set whether the symbol was originally a weak undef or a regular undef + // when resolved by a dynamic def. + inline void + set_undef_binding(elfcpp::STB bind) + { + if (!this->undef_binding_set_ || this->undef_binding_weak_) + { + this->undef_binding_weak_ = bind == elfcpp::STB_WEAK; + this->undef_binding_set_ = true; + } + } + + // Return TRUE if a weak undef was resolved by a dynamic def. + inline bool + is_undef_binding_weak() const + { return this->undef_binding_weak_; } + // Return the non-visibility part of the st_other field. unsigned char nonvis() const *************** class Symbol *** 949,954 **** --- 966,976 ---- // True if this symbol is defined in a section which was discarded // (bit 31). bool is_defined_in_discarded_section_ : 1; + // True if UNDEF_BINDING_WEAK_ has been set (bit 32). + bool undef_binding_set_ : 1; + // True if this symbol was a weak undef resolved by a dynamic def + // (bit 33). + bool undef_binding_weak_ : 1; }; // The parts of a symbol which are size specific. Using a template *************** class Symbol_table *** 1247,1253 **** // During garbage collection, this keeps undefined symbols. void ! gc_mark_undef_symbols(); // During garbage collection, this ensures externally visible symbols // are not treated as garbage while building shared objects. --- 1269,1275 ---- // During garbage collection, this keeps undefined symbols. void ! gc_mark_undef_symbols(Layout*); // During garbage collection, this ensures externally visible symbols // are not treated as garbage while building shared objects. *************** class Symbol_table *** 1397,1403 **** // Add any undefined symbols named on the command line to the symbol // table. void ! add_undefined_symbols_from_command_line(); // SYM is defined using a COPY reloc. Return the dynamic object // where the original definition was found. --- 1419,1425 ---- // Add any undefined symbols named on the command line to the symbol // table. void ! add_undefined_symbols_from_command_line(Layout*); // SYM is defined using a COPY reloc. Return the dynamic object // where the original definition was found. *************** class Symbol_table *** 1536,1542 **** // Whether we should override a symbol, based on flags in // resolve.cc. static bool ! should_override(const Symbol*, unsigned int, Defined, Object*, bool*); // Report a problem in symbol resolution. static void --- 1558,1564 ---- // Whether we should override a symbol, based on flags in // resolve.cc. static bool ! should_override(const Symbol*, unsigned int, Defined, Object*, bool*, bool*); // Report a problem in symbol resolution. static void *************** class Symbol_table *** 1611,1617 **** // table, sized version. template void ! do_add_undefined_symbols_from_command_line(); // Types of common symbols. --- 1633,1644 ---- // table, sized version. template void ! do_add_undefined_symbols_from_command_line(Layout*); ! ! // Add one undefined symbol. ! template ! void ! add_undefined_symbol_from_command_line(const char* name); // Types of common symbols. *************** class Symbol_table *** 1667,1673 **** void sized_write_symbol(Sized_symbol*, typename elfcpp::Elf_types::Elf_Addr value, ! unsigned int shndx, const Stringpool*, unsigned char* p) const; // Possibly warn about an undefined symbol from a dynamic object. --- 1694,1700 ---- void sized_write_symbol(Sized_symbol*, typename elfcpp::Elf_types::Elf_Addr value, ! unsigned int shndx, elfcpp::STB, const Stringpool*, unsigned char* p) const; // Possibly warn about an undefined symbol from a dynamic object. diff -rcp ../binutils-2.20.51.0.10.original/gold/version.cc gold/version.cc *** ../binutils-2.20.51.0.10.original/gold/version.cc 2010-08-10 15:11:43.000000000 +0100 --- gold/version.cc 2010-08-10 15:14:04.000000000 +0100 *************** namespace gold *** 37,43 **** // version number from configure.ac. But it's easier to just change // this file for now. ! static const char* version_string = "1.9"; // Report version information. --- 37,43 ---- // version number from configure.ac. But it's easier to just change // this file for now. ! static const char* version_string = "1.10"; // Report version information. diff -rcp ../binutils-2.20.51.0.10.original/gold/x86_64.cc gold/x86_64.cc *** ../binutils-2.20.51.0.10.original/gold/x86_64.cc 2010-08-10 15:12:03.000000000 +0100 --- gold/x86_64.cc 2010-08-10 15:14:04.000000000 +0100 *************** *** 1,6 **** // x86_64.cc -- x86_64 target support for gold. ! // Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. --- 1,6 ---- // x86_64.cc -- x86_64 target support for gold. ! // Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. *************** class Target_x86_64 : public Target_free *** 64,71 **** Target_x86_64() : Target_freebsd<64, false>(&x86_64_info), ! got_(NULL), plt_(NULL), got_plt_(NULL), global_offset_table_(NULL), ! rela_dyn_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL), got_mod_index_offset_(-1U), tlsdesc_reloc_info_(), tls_base_symbol_defined_(false) { } --- 64,72 ---- Target_x86_64() : Target_freebsd<64, false>(&x86_64_info), ! got_(NULL), plt_(NULL), got_plt_(NULL), got_tlsdesc_(NULL), ! global_offset_table_(NULL), rela_dyn_(NULL), ! copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL), got_mod_index_offset_(-1U), tlsdesc_reloc_info_(), tls_base_symbol_defined_(false) { } *************** class Target_x86_64 : public Target_free *** 403,408 **** --- 404,417 ---- return this->got_plt_; } + // Get the GOT section for TLSDESC entries. + Output_data_got<64, false>* + got_tlsdesc_section() const + { + gold_assert(this->got_tlsdesc_ != NULL); + return this->got_tlsdesc_; + } + // Create the PLT section. void make_plt_section(Symbol_table* symtab, Layout* layout); *************** class Target_x86_64 : public Target_free *** 486,491 **** --- 495,502 ---- Output_data_plt_x86_64* plt_; // The GOT PLT section. Output_data_space* got_plt_; + // The GOT section for TLSDESC relocations. + Output_data_got<64, false>* got_tlsdesc_; // The _GLOBAL_OFFSET_TABLE_ symbol. Symbol* global_offset_table_; // The dynamic reloc section. *************** Target_x86_64::got_section(Symbol_table* *** 547,565 **** this->got_ = new Output_data_got<64, false>(); ! Output_section* os; ! os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_, false, true, true, ! false); this->got_plt_ = new Output_data_space(8, "** GOT PLT"); ! os = layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_plt_, false, false, ! false, true); // The first three entries are reserved. this->got_plt_->set_current_data_size(3 * 8); --- 558,575 ---- this->got_ = new Output_data_got<64, false>(); ! layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_, ORDER_RELRO_LAST, ! true); this->got_plt_ = new Output_data_space(8, "** GOT PLT"); ! layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, ! (elfcpp::SHF_ALLOC ! | elfcpp::SHF_WRITE), ! this->got_plt_, ORDER_NON_RELRO_FIRST, ! false); // The first three entries are reserved. this->got_plt_->set_current_data_size(3 * 8); *************** Target_x86_64::got_section(Symbol_table* *** 576,581 **** --- 586,600 ---- elfcpp::STB_LOCAL, elfcpp::STV_HIDDEN, 0, false, false); + + // If there are any TLSDESC relocations, they get GOT entries in + // .got.plt after the jump slot entries. + this->got_tlsdesc_ = new Output_data_got<64, false>(); + layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + this->got_tlsdesc_, + ORDER_NON_RELRO_FIRST, false); } return this->got_; *************** Target_x86_64::rela_dyn_section(Layout* *** 591,598 **** gold_assert(layout != NULL); this->rela_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rela_dyn_, true, ! false, false, false); } return this->rela_dyn_; } --- 610,617 ---- gold_assert(layout != NULL); this->rela_dyn_ = new Reloc_section(parameters->options().combreloc()); layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rela_dyn_, ! ORDER_DYNAMIC_RELOCS, false); } return this->rela_dyn_; } *************** Output_data_plt_x86_64::Output_data_plt_ *** 699,706 **** { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rel_, true, ! false, false, false); } void --- 718,725 ---- { this->rel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, ! elfcpp::SHF_ALLOC, this->rel_, ! ORDER_DYNAMIC_PLT_RELOCS, false); } void *************** Output_data_plt_x86_64::rela_tlsdesc(Lay *** 750,756 **** this->tlsdesc_rel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, elfcpp::SHF_ALLOC, this->tlsdesc_rel_, ! true, false, false, false); gold_assert(this->tlsdesc_rel_->output_section() == this->rel_->output_section()); } --- 769,775 ---- this->tlsdesc_rel_ = new Reloc_section(false); layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA, elfcpp::SHF_ALLOC, this->tlsdesc_rel_, ! ORDER_DYNAMIC_PLT_RELOCS, false); gold_assert(this->tlsdesc_rel_->output_section() == this->rel_->output_section()); } *************** Target_x86_64::make_plt_section(Symbol_t *** 914,920 **** layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), ! this->plt_, false, false, false, false); } } --- 933,939 ---- layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS, (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR), ! this->plt_, ORDER_PLT, false); } } *************** Target_x86_64::Scan::local(Symbol_table* *** 1131,1138 **** switch (r_type) { case elfcpp::R_X86_64_NONE: ! case elfcpp::R_386_GNU_VTINHERIT: ! case elfcpp::R_386_GNU_VTENTRY: break; case elfcpp::R_X86_64_64: --- 1150,1157 ---- switch (r_type) { case elfcpp::R_X86_64_NONE: ! case elfcpp::R_X86_64_GNU_VTINHERIT: ! case elfcpp::R_X86_64_GNU_VTENTRY: break; case elfcpp::R_X86_64_64: *************** Target_x86_64::Scan::local(Symbol_table* *** 1308,1316 **** // Create reserved PLT and GOT entries for the resolver. target->reserve_tlsdesc_entries(symtab, layout); ! // Generate a double GOT entry with an R_X86_64_TLSDESC reloc. ! Output_data_got<64, false>* got ! = target->got_section(symtab, layout); unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info()); if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC)) { --- 1327,1339 ---- // Create reserved PLT and GOT entries for the resolver. target->reserve_tlsdesc_entries(symtab, layout); ! // Generate a double GOT entry with an ! // R_X86_64_TLSDESC reloc. The R_X86_64_TLSDESC reloc ! // is resolved lazily, so the GOT entry needs to be in ! // an area in .got.plt, not .got. Call got_section to ! // make sure the section has been created. ! target->got_section(symtab, layout); ! Output_data_got<64, false>* got = target->got_tlsdesc_section(); unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info()); if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC)) { *************** Target_x86_64::Scan::global(Symbol_table *** 1485,1492 **** switch (r_type) { case elfcpp::R_X86_64_NONE: ! case elfcpp::R_386_GNU_VTINHERIT: ! case elfcpp::R_386_GNU_VTENTRY: break; case elfcpp::R_X86_64_64: --- 1508,1515 ---- switch (r_type) { case elfcpp::R_X86_64_NONE: ! case elfcpp::R_X86_64_GNU_VTINHERIT: ! case elfcpp::R_X86_64_GNU_VTENTRY: break; case elfcpp::R_X86_64_64: *************** Target_x86_64::Scan::global(Symbol_table *** 1689,1697 **** // Create reserved PLT and GOT entries for the resolver. target->reserve_tlsdesc_entries(symtab, layout); ! // Create a double GOT entry with an R_X86_64_TLSDESC reloc. ! Output_data_got<64, false>* got ! = target->got_section(symtab, layout); Reloc_section *rt = target->rela_tlsdesc_section(layout); got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_DESC, rt, elfcpp::R_X86_64_TLSDESC, 0); --- 1712,1724 ---- // Create reserved PLT and GOT entries for the resolver. target->reserve_tlsdesc_entries(symtab, layout); ! // Create a double GOT entry with an R_X86_64_TLSDESC ! // reloc. The R_X86_64_TLSDESC reloc is resolved ! // lazily, so the GOT entry needs to be in an area in ! // .got.plt, not .got. Call got_section to make sure ! // the section has been created. ! target->got_section(symtab, layout); ! Output_data_got<64, false>* got = target->got_tlsdesc_section(); Reloc_section *rt = target->rela_tlsdesc_section(layout); got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_DESC, rt, elfcpp::R_X86_64_TLSDESC, 0); *************** Target_x86_64::gc_process_relocs(Symbol_ *** 1783,1789 **** } gold::gc_process_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA, ! Target_x86_64::Scan>( symtab, layout, this, --- 1810,1817 ---- } gold::gc_process_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA, ! Target_x86_64::Scan, ! Target_x86_64::Relocatable_size_for_reloc>( symtab, layout, this, *************** Target_x86_64::Relocate::relocate(const *** 1964,1971 **** switch (r_type) { case elfcpp::R_X86_64_NONE: ! case elfcpp::R_386_GNU_VTINHERIT: ! case elfcpp::R_386_GNU_VTENTRY: break; case elfcpp::R_X86_64_64: --- 1992,1999 ---- switch (r_type) { case elfcpp::R_X86_64_NONE: ! case elfcpp::R_X86_64_GNU_VTINHERIT: ! case elfcpp::R_X86_64_GNU_VTENTRY: break; case elfcpp::R_X86_64_64: *************** Target_x86_64::Relocate::relocate_tls(co *** 2230,2247 **** unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE ? GOT_TYPE_TLS_OFFSET : GOT_TYPE_TLS_DESC); ! unsigned int got_offset; if (gsym != NULL) { gold_assert(gsym->has_got_offset(got_type)); ! got_offset = gsym->got_offset(got_type) - target->got_size(); } else { unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info()); gold_assert(object->local_has_got_offset(r_sym, got_type)); ! got_offset = (object->local_got_offset(r_sym, got_type) ! - target->got_size()); } if (optimized_type == tls::TLSOPT_TO_IE) { --- 2258,2284 ---- unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE ? GOT_TYPE_TLS_OFFSET : GOT_TYPE_TLS_DESC); ! unsigned int got_offset = 0; ! if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC ! && optimized_type == tls::TLSOPT_NONE) ! { ! // We created GOT entries in the .got.tlsdesc portion of ! // the .got.plt section, but the offset stored in the ! // symbol is the offset within .got.tlsdesc. ! got_offset = (target->got_size() ! + target->got_plt_section()->data_size()); ! } if (gsym != NULL) { gold_assert(gsym->has_got_offset(got_type)); ! got_offset += gsym->got_offset(got_type) - target->got_size(); } else { unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info()); gold_assert(object->local_has_got_offset(r_sym, got_type)); ! got_offset += (object->local_got_offset(r_sym, got_type) ! - target->got_size()); } if (optimized_type == tls::TLSOPT_TO_IE) { *************** Target_x86_64::Relocatable_size_for_relo *** 2643,2650 **** switch (r_type) { case elfcpp::R_X86_64_NONE: ! case elfcpp::R_386_GNU_VTINHERIT: ! case elfcpp::R_386_GNU_VTENTRY: case elfcpp::R_X86_64_TLSGD: // Global-dynamic case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url) case elfcpp::R_X86_64_TLSDESC_CALL: --- 2680,2687 ---- switch (r_type) { case elfcpp::R_X86_64_NONE: ! case elfcpp::R_X86_64_GNU_VTINHERIT: ! case elfcpp::R_X86_64_GNU_VTENTRY: case elfcpp::R_X86_64_TLSGD: // Global-dynamic case elfcpp::R_X86_64_GOTPC32_TLSDESC: // Global-dynamic (from ~oliva url) case elfcpp::R_X86_64_TLSDESC_CALL: diff -rcp ../binutils-2.20.51.0.10.original/gold/yyscript.y gold/yyscript.y *** ../binutils-2.20.51.0.10.original/gold/yyscript.y 2010-08-10 15:11:40.000000000 +0100 --- gold/yyscript.y 2010-08-10 15:14:04.000000000 +0100 *************** exp: *** 867,873 **** | INTEGER { $$ = script_exp_integer($1); } | string ! { $$ = script_exp_string($1.value, $1.length); } | MAX_K '(' exp ',' exp ')' { $$ = script_exp_function_max($3, $5); } | MIN_K '(' exp ',' exp ')' --- 867,873 ---- | INTEGER { $$ = script_exp_integer($1); } | string ! { $$ = script_symbol(closure, $1.value, $1.length); } | MAX_K '(' exp ',' exp ')' { $$ = script_exp_function_max($3, $5); } | MIN_K '(' exp ',' exp ')'