+// A class to handle the PLT data.
+
+class Output_data_plt_i386 : public Output_section_data
+{
+ public:
+ typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
+
+ Output_data_plt_i386(Symbol_table*, Layout*, Output_data_space*);
+
+ // Add an entry to the PLT.
+ void
+ add_entry(Symbol* gsym);
+
+ // Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
+ unsigned int
+ add_local_ifunc_entry(Sized_relobj_file<32, false>* relobj,
+ unsigned int local_sym_index);
+
+ // Return the .rel.plt section data.
+ Reloc_section*
+ rel_plt() const
+ { return this->rel_; }
+
+ // Return where the TLS_DESC relocations should go.
+ Reloc_section*
+ rel_tls_desc(Layout*);
+
+ // Return the number of PLT entries.
+ unsigned int
+ entry_count() const
+ { return this->count_; }
+
+ // Return the offset of the first non-reserved PLT entry.
+ static unsigned int
+ first_plt_entry_offset()
+ { return plt_entry_size; }
+
+ // Return the size of a PLT entry.
+ static unsigned int
+ get_plt_entry_size()
+ { return plt_entry_size; }
+
+ protected:
+ void
+ do_adjust_output_section(Output_section* os);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** PLT")); }
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 16;
+
+ // The first entry in the PLT for an executable.
+ static const unsigned char exec_first_plt_entry[plt_entry_size];
+
+ // The first entry in the PLT for a shared object.
+ static const unsigned char dyn_first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char exec_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for a shared object.
+ static const unsigned char dyn_plt_entry[plt_entry_size];
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_cie_size = 16;
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+
+ // Set the final size.
+ void
+ set_final_data_size()
+ { this->set_data_size((this->count_ + 1) * plt_entry_size); }
+
+ // Write out the PLT data.
+ void
+ do_write(Output_file*);
+
+ // We keep a list of global STT_GNU_IFUNC symbols, each with its
+ // offset in the GOT.
+ struct Global_ifunc
+ {
+ Symbol* sym;
+ unsigned int got_offset;
+ };
+
+ // We keep a list of local STT_GNU_IFUNC symbols, each with its
+ // offset in the GOT.
+ struct Local_ifunc
+ {
+ Sized_relobj_file<32, false>* object;
+ unsigned int local_sym_index;
+ unsigned int got_offset;
+ };
+
+ // The reloc section.
+ Reloc_section* rel_;
+ // The TLS_DESC relocations, if necessary. These must follow the
+ // regular PLT relocs.
+ Reloc_section* tls_desc_rel_;
+ // The .got.plt section.
+ Output_data_space* got_plt_;
+ // The number of PLT entries.
+ unsigned int count_;
+ // Global STT_GNU_IFUNC symbols.
+ std::vector<Global_ifunc> global_ifuncs_;
+ // Local STT_GNU_IFUNC symbols.
+ std::vector<Local_ifunc> local_ifuncs_;
+};