Index: elfcpp/elfcpp.h =================================================================== RCS file: /cvs/src/src/elfcpp/elfcpp.h,v retrieving revision 1.36 diff -u -p -r1.36 elfcpp.h --- elfcpp/elfcpp.h 15 Sep 2012 17:11:27 -0000 1.36 +++ elfcpp/elfcpp.h 11 Mar 2013 08:26:29 -0000 @@ -375,6 +375,8 @@ enum SHT SHT_GNU_HASH = 0x6ffffff6, // List of prelink dependencies. SHT_GNU_LIBLIST = 0x6ffffff7, + // Symbol information + SHT_SUNW_syminfo = 0x6ffffffc, // Versions defined by file. SHT_SUNW_verdef = 0x6ffffffd, SHT_GNU_verdef = 0x6ffffffd, @@ -963,6 +965,58 @@ enum ELF_NOTE_OS_SYLLABLE = 5 }; +// Syminfo flag values + +enum +{ + // symbol ref has direct association to object containing defn. + SYMINFO_FLG_DIRECT = 0x0001, + // symbol ref is associated to a standard filter. + SYMINFO_FLG_FILTER = 0x0002, + SYMINFO_FLG_PASSTHRU = 0x0002, // unused obsolete name + // symbol is a copy-reloc + SYMINFO_FLG_COPY = 0x0004, + // object containing defn. should be lazily-loaded + SYMINFO_FLG_LAZYLOAD = 0x0008, + // ref should be bound directly to object containing defn. + SYMINFO_FLG_DIRECTBIND = 0x0010, + // don't let an external reference directly bind to this symbol. + SYMINFO_FLG_NOEXTDIRECT = 0x0020, + // symbol ref is associated to a auxiliary filter. + SYMINFO_FLG_AUXILIARY = 0x0040, + // symbol defines an interposer. + SYMINFO_FLG_INTERPOSE = 0x0080, + // symbol is capabilities specific. + SYMINFO_FLG_CAP = 0x0100, + // symbol should not be included in BIND_NOW relocations. + SYMINFO_FLG_DEFERRED = 0x0200 +}; + +// Syminfo.si_boundto values + +enum +{ + // symbol bound to self + SYMINFO_BT_SELF = 0xffff, + // symbol bound to parent + SYMINFO_BT_PARENT = 0xfffe, + // no special symbol binding + SYMINFO_BT_NONE = 0xfffd, + // symbol defined as external + SYMINFO_BT_EXTERN = 0xfffc, + // beginning of reserved entries + SYMINFO_BT_LOWRESERVE = 0xff00 +}; + +// Syminfo version values + +enum +{ + SYMINFO_NONE = 0, + SYMINFO_CURRENT = 1, + SYMINFO_NUM = 2 +}; + } // End namespace elfcpp. // Include internal details after defining the types. @@ -1918,6 +1972,56 @@ class Vernaux_write internal::Vernaux_data* p_; }; +// Accessor classes for syminfo entries in the ELF SHT_SUNW_syminfo +// section. + +template +class Syminfo +{ + public: + Syminfo(const unsigned char* p) + : p_(reinterpret_cast(p)) + { } + + template + Syminfo(File* file, typename File::Location loc) + : p_(reinterpret_cast( + file->view(loc.file_offset, loc.data_size).data())) + { } + + Elf_Half + get_si_boundto() const + { return Convert<16, big_endian>::convert_host(this->p_->si_boundto); } + + Elf_Half + get_si_flags() const + { return Convert<16, big_endian>::convert_host(this->p_->si_flags); } + + private: + const internal::Syminfo_data* p_; +}; + +template +class Syminfo_write +{ + public: + Syminfo_write(unsigned char* p) + : p_(reinterpret_cast(p)) + { } + + void + set_si_boundto(Elf_Half v) + { this->p_->si_boundto = Convert<16, big_endian>::convert_host(v); } + + void + set_si_flags(Elf_Half v) + { this->p_->si_flags = Convert<16, big_endian>::convert_host(v); } + + private: + internal::Syminfo_data* p_; +}; + + } // End namespace elfcpp. #endif // !defined(ELFPCP_H) Index: elfcpp/elfcpp_internal.h =================================================================== RCS file: /cvs/src/src/elfcpp/elfcpp_internal.h,v retrieving revision 1.8 diff -u -p -r1.8 elfcpp_internal.h --- elfcpp/elfcpp_internal.h 22 Sep 2007 21:02:10 -0000 1.8 +++ elfcpp/elfcpp_internal.h 11 Mar 2013 08:26:29 -0000 @@ -233,6 +233,17 @@ struct Vernaux_data Elf_Word vna_next; }; +// An syminfo entry in a SHT_SUNW_syminfo section. This structure is +// the same in 32-bit and 64-bit ELF files. + +struct Syminfo_data +{ + // Direct bindings, symbol bound to + Elf_Half si_boundto; + // Per symbol flags + Elf_Half si_flags; +}; + } // End namespace internal. } // End namespace elfcpp. Index: gold/dynobj.cc =================================================================== RCS file: /cvs/src/src/gold/dynobj.cc,v retrieving revision 1.64 diff -u -p -r1.64 dynobj.cc --- gold/dynobj.cc 4 Jun 2012 20:00:31 -0000 1.64 +++ gold/dynobj.cc 11 Mar 2013 08:26:31 -0000 @@ -42,7 +42,8 @@ namespace gold Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset) : Object(name, input_file, true, offset), needed_(), - unknown_needed_(UNKNOWN_NEEDED_UNSET) + unknown_needed_(UNKNOWN_NEEDED_UNSET), + dtndx_(elfcpp::SYMINFO_BT_NONE) { // This will be overridden by a DT_SONAME entry, hopefully. But if // we never see a DT_SONAME entry, our rule is to use the dynamic Index: gold/dynobj.h =================================================================== RCS file: /cvs/src/src/gold/dynobj.h,v retrieving revision 1.47 diff -u -p -r1.47 dynobj.h --- gold/dynobj.h 21 Mar 2012 19:02:21 -0000 1.47 +++ gold/dynobj.h 11 Mar 2013 08:26:31 -0000 @@ -95,6 +95,16 @@ class Dynobj : public Object unsigned int local_dynsym_count, unsigned char** pphash, unsigned int* phashlen); + // Return the index of DT_NEEDED should be in the target shared object. + unsigned int + dtndx() const + { return this->dtndx_; } + + // Set the index of DT_NEEDED should be in the target shared object. + void + set_dtndx(unsigned int dtndx) + { this->dtndx_ = dtndx; } + protected: // Return a pointer to this object. virtual Dynobj* @@ -153,6 +163,8 @@ class Dynobj : public Object // Whether this dynamic object has any DT_NEEDED entries not seen // during the link. Unknown_needed unknown_needed_; + // the index of dynamic entry in target shared object + unsigned int dtndx_; }; // A dynamic object, size and endian specific version. Index: gold/layout.cc =================================================================== RCS file: /cvs/src/src/gold/layout.cc,v retrieving revision 1.246 diff -u -p -r1.246 layout.cc --- gold/layout.cc 10 Mar 2013 23:08:18 -0000 1.246 +++ gold/layout.cc 11 Mar 2013 08:26:31 -0000 @@ -1736,6 +1736,7 @@ Layout::default_section_order(Output_sec case elfcpp::SHT_SHLIB: case elfcpp::SHT_DYNSYM: case elfcpp::SHT_GNU_HASH: + case elfcpp::SHT_SUNW_syminfo: case elfcpp::SHT_GNU_verdef: case elfcpp::SHT_GNU_verneed: case elfcpp::SHT_GNU_versym: @@ -3841,6 +3842,7 @@ Layout::create_symtab_sections(const Inp off_t dynoff; size_t dyn_global_index; size_t dyncount; + off_t sioff = 0; if (this->dynsym_section_ == NULL) { dynoff = 0; @@ -3855,10 +3857,13 @@ Layout::create_symtab_sections(const Inp dyncount = (this->dynsym_section_->data_size() - locsize) / symsize; gold_assert(static_cast(dyncount * symsize) == this->dynsym_section_->data_size() - locsize); + Output_section* syminf = find_output_section(".syminfo"); + if (syminf) + sioff = syminf->offset() + 4; } off_t global_off = off; - off = symtab->finalize(off, dynoff, dyn_global_index, dyncount, + off = symtab->finalize(off, sioff, dynoff, dyn_global_index, dyncount, &this->sympool_, &local_symcount); if (!parameters->options().strip_all()) @@ -4246,6 +4251,49 @@ Layout::create_dynamic_symtab(const Inpu odyn->add_section_address(elfcpp::DT_GNU_HASH, hashsec); } } + + // Create the symbol information section. + + bool direct = false; + for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin(); + p != input_objects->dynobj_end(); + ++p) + { + if ((*p)->is_needed() && (*p)->input_file()->options().direct()) + { + direct = true; + break; + } + } + + if (parameters->options().Bdirect() || direct) + { + Output_section* syminf = + this->choose_output_section(NULL, ".syminfo", elfcpp::SHT_SUNW_syminfo, + elfcpp::SHF_ALLOC, false, + ORDER_DYNAMIC_LINKER, false); + + Output_section_data* sidata = new Output_data_fixed_space(index * 4, 4, + "** syminfo"); + if (syminf != NULL && sidata != NULL) + syminf->add_output_section_data(sidata); + + if (syminf != NULL) + { + syminf->set_should_link_to_dynsym(); + if (this->dynamic_section_ != NULL) + syminf->set_info_section(this->dynamic_section_); + syminf->set_entsize(4); + syminf->set_addralign(4); + + if (odyn != NULL) + { + odyn->add_section_address(elfcpp::DT_SYMINFO, syminf); + odyn->add_section_size(elfcpp::DT_SYMINSZ, syminf); + odyn->add_constant(elfcpp::DT_SYMINENT, 4); + } + } + } } // Assign offsets to each local portion of the dynamic symbol table. @@ -4586,6 +4634,7 @@ Layout::finish_dynamic_section(const Inp continue; } + (*p)->set_dtndx(odyn->dtnum()); odyn->add_string(elfcpp::DT_NEEDED, (*p)->soname()); } Index: gold/options.h =================================================================== RCS file: /cvs/src/src/gold/options.h,v retrieving revision 1.184 diff -u -p -r1.184 options.h --- gold/options.h 15 Feb 2013 15:44:03 -0000 1.184 +++ gold/options.h 11 Mar 2013 08:26:32 -0000 @@ -678,6 +678,11 @@ class General_options DEFINE_bool(Bsymbolic_functions, options::ONE_DASH, '\0', false, N_("Bind defined function symbols locally"), NULL); + DEFINE_bool(Bdirect, options::ONE_DASH, '\0', false, + N_("Establish direct bindings"), NULL); + DEFINE_bool_alias(Bnodirect, Bdirect, options::ONE_DASH, '\0', + N_("Inhibit direct bindings"), NULL, true); + DEFINE_optional_string(build_id, options::TWO_DASHES, '\0', "sha1", N_("Generate build ID note"), N_("[=STYLE]")); @@ -1247,6 +1252,10 @@ class General_options DEFINE_bool(defs, options::DASH_Z, '\0', false, N_("Report undefined symbols (even with --shared)"), NULL); + DEFINE_bool(direct, options::DASH_Z, '\0', false, + N_("Enable direct binding to shared object dependencies"), + N_("Disable direct binding to shared object dependencies" + " (default)")); DEFINE_bool(execstack, options::DASH_Z, '\0', false, N_("Mark output as requiring executable stack"), NULL); DEFINE_bool(initfirst, options::DASH_Z, '\0', false, @@ -1629,6 +1638,7 @@ class Position_dependent_options this->set_format_enum(options.format_enum()); this->set_whole_archive(options.whole_archive()); this->set_incremental_disposition(options.incremental_disposition()); + this->set_direct(options.direct()); } DEFINE_posdep(as_needed, bool); @@ -1636,6 +1646,7 @@ class Position_dependent_options DEFINE_posdep(format_enum, General_options::Object_format); DEFINE_posdep(whole_archive, bool); DEFINE_posdep(incremental_disposition, Incremental_disposition); + DEFINE_posdep(direct, bool); private: // This is a General_options with everything set to its default Index: gold/output.h =================================================================== RCS file: /cvs/src/src/gold/output.h,v retrieving revision 1.146 diff -u -p -r1.146 output.h --- gold/output.h 24 Jan 2013 18:49:54 -0000 1.146 +++ gold/output.h 11 Mar 2013 08:26:32 -0000 @@ -2574,6 +2574,11 @@ class Output_data_dynamic : public Outpu add_string(elfcpp::DT tag, const std::string& str) { this->add_string(tag, str.c_str()); } + // Number of DT entries. + unsigned int + dtnum() const + { return this->entries_.size(); } + protected: // Adjust the output section to set the entry size. void Index: gold/symtab.cc =================================================================== RCS file: /cvs/src/src/gold/symtab.cc,v retrieving revision 1.169 diff -u -p -r1.169 symtab.cc --- gold/symtab.cc 10 Mar 2013 23:08:18 -0000 1.169 +++ gold/symtab.cc 11 Mar 2013 08:26:37 -0000 @@ -2412,7 +2412,8 @@ Symbol_table::set_dynsym_indexes(unsigne // offset. Update *PLOCAL_SYMCOUNT if necessary. off_t -Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index, +Symbol_table::finalize(off_t off, off_t sioff, off_t dynoff, + size_t dyn_global_index, size_t dyncount, Stringpool* pool, unsigned int* plocal_symcount) { @@ -2422,6 +2423,7 @@ Symbol_table::finalize(off_t off, off_t this->first_global_index_ = *plocal_symcount; this->dynamic_offset_ = dynoff; + this->syminfo_offset_ = sioff; this->first_dynamic_global_index_ = dyn_global_index; this->dynamic_count_ = dyncount; @@ -2807,6 +2809,13 @@ Symbol_table::sized_write_globals(const else dynamic_view = of->get_output_view(this->dynamic_offset_, dynamic_size); + const section_size_type syminfo_size = dynamic_count * 4; + unsigned char* syminfo_view; + if (this->syminfo_offset_ == 0 || dynamic_count == 0) + syminfo_view = NULL; + else + syminfo_view = of->get_output_view(this->syminfo_offset_, syminfo_size); + for (Symbol_table_type::const_iterator p = this->table_.begin(); p != this->table_.end(); ++p) @@ -2829,6 +2838,8 @@ Symbol_table::sized_write_globals(const continue; } + elfcpp::Elf_Half si_boundto = elfcpp::SYMINFO_BT_NONE; + elfcpp::Elf_Half si_flags = elfcpp::SYMINFO_FLG_NOEXTDIRECT; unsigned int shndx; typename elfcpp::Elf_types::Elf_Addr sym_value = sym->value(); typename elfcpp::Elf_types::Elf_Addr dynsym_value = sym_value; @@ -2866,6 +2877,12 @@ Symbol_table::sized_write_globals(const binding = elfcpp::STB_WEAK; else binding = elfcpp::STB_GLOBAL; + + si_boundto = symobj->dynobj()->dtndx(); + si_flags = elfcpp::SYMINFO_FLG_DIRECT; + if (parameters->options().Bdirect() + || symobj->input_file()->options().direct()) + si_flags |= elfcpp::SYMINFO_FLG_DIRECTBIND; } else if (symobj->pluginobj() != NULL) shndx = elfcpp::SHN_UNDEF; @@ -2907,6 +2924,11 @@ Symbol_table::sized_write_globals(const // relative. if (parameters->options().relocatable()) sym_value -= os->address(); + + si_boundto = elfcpp::SYMINFO_BT_SELF; + si_flags = elfcpp::SYMINFO_FLG_DIRECT; + if (parameters->options().Bdirect()) + si_flags |= elfcpp::SYMINFO_FLG_DIRECTBIND; } } } @@ -2922,6 +2944,15 @@ Symbol_table::sized_write_globals(const dynsym_xindex->add(dynsym_index, shndx); shndx = elfcpp::SHN_XINDEX; } + if (sym->is_copied_from_dynobj()) + { + Dynobj* srcdso = this->get_copy_source(sym); + si_boundto = srcdso->dtndx(); + si_flags = elfcpp::SYMINFO_FLG_DIRECT | elfcpp::SYMINFO_FLG_COPY; + if (parameters->options().Bdirect() + || srcdso->input_file()->options().direct()) + si_flags |= elfcpp::SYMINFO_FLG_DIRECTBIND; + } break; case Symbol::IN_OUTPUT_SEGMENT: @@ -2956,12 +2987,22 @@ Symbol_table::sized_write_globals(const unsigned char* pd = dynamic_view + (dynsym_index * sym_size); this->sized_write_symbol(sym, dynsym_value, shndx, binding, dynpool, pd); + + if (syminfo_view) + { + unsigned char* pi = syminfo_view + (dynsym_index * 4); + elfcpp::Syminfo_write osi(pi); + osi.set_si_boundto(si_boundto); + osi.set_si_flags(si_flags); + } } } of->write_output_view(this->offset_, oview_size, psyms); if (dynamic_view != NULL) of->write_output_view(this->dynamic_offset_, dynamic_size, dynamic_view); + if (syminfo_view != NULL) + of->write_output_view(this->syminfo_offset_, syminfo_size, syminfo_view); } // Write out the symbol SYM, in section SHNDX, to P. POOL is the Index: gold/symtab.h =================================================================== RCS file: /cvs/src/src/gold/symtab.h,v retrieving revision 1.129 diff -u -p -r1.129 symtab.h --- gold/symtab.h 10 Mar 2013 23:08:18 -0000 1.129 +++ gold/symtab.h 11 Mar 2013 08:26:39 -0000 @@ -1505,14 +1505,16 @@ class Symbol_table // of all the input sections. This sets the final symbol indexes, // values and adds the names to *POOL. *PLOCAL_SYMCOUNT is the // index of the first global symbol. OFF is the file offset of the - // global symbol table, DYNOFF is the offset of the globals in the + // global symbol table, SIOFF is the file offset of the syminfo + // section (0 if none), DYNOFF is the offset of the globals in the // dynamic symbol table, DYN_GLOBAL_INDEX is the index of the first // global dynamic symbol, and DYNCOUNT is the number of global // dynamic symbols. This records the parameters, and returns the // new file offset. It updates *PLOCAL_SYMCOUNT if it created any // local symbols. off_t - finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount, + finalize(off_t off, off_t sioff, off_t dynoff, + size_t dyn_global_index, size_t dyncount, Stringpool* pool, unsigned int* plocal_symcount); // Set the final file offset of the symbol table. @@ -1847,6 +1849,8 @@ class Symbol_table unsigned int output_count_; // The file offset of the global dynamic symbols, or 0 if none. off_t dynamic_offset_; + // The file offset of the symbol information, or 0 if none. + off_t syminfo_offset_; // The index of the first global dynamic symbol. unsigned int first_dynamic_global_index_; // The number of global dynamic symbols, or 0 if none.