|  | // target-select.h -- select a target for an object file  -*- C++ -*- | 
|  |  | 
|  | // Copyright (C) 2006-2023 Free Software Foundation, Inc. | 
|  | // Written by Ian Lance Taylor <iant@google.com>. | 
|  |  | 
|  | // This file is part of gold. | 
|  |  | 
|  | // This program is free software; you can redistribute it and/or modify | 
|  | // it under the terms of the GNU General Public License as published by | 
|  | // the Free Software Foundation; either version 3 of the License, or | 
|  | // (at your option) any later version. | 
|  |  | 
|  | // This program is distributed in the hope that it will be useful, | 
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | // GNU General Public License for more details. | 
|  |  | 
|  | // You should have received a copy of the GNU General Public License | 
|  | // along with this program; if not, write to the Free Software | 
|  | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | // MA 02110-1301, USA. | 
|  |  | 
|  | #ifndef GOLD_TARGET_SELECT_H | 
|  | #define GOLD_TARGET_SELECT_H | 
|  |  | 
|  | #include <vector> | 
|  |  | 
|  | #include "gold-threads.h" | 
|  |  | 
|  | namespace gold | 
|  | { | 
|  |  | 
|  | class Input_file; | 
|  | class Target; | 
|  | class Target_selector; | 
|  |  | 
|  | // Used to set the target only once. | 
|  |  | 
|  | class Set_target_once : public Once | 
|  | { | 
|  | public: | 
|  | Set_target_once(Target_selector* target_selector) | 
|  | : target_selector_(target_selector) | 
|  | { } | 
|  |  | 
|  | protected: | 
|  | void | 
|  | do_run_once(void*); | 
|  |  | 
|  | private: | 
|  | Target_selector* target_selector_; | 
|  | }; | 
|  |  | 
|  | // We want to avoid a master list of targets, which implies using a | 
|  | // global constructor.  And we also want the program to start up as | 
|  | // quickly as possible, which implies avoiding global constructors. | 
|  | // We compromise on a very simple global constructor.  We use a target | 
|  | // selector, which specifies an ELF machine number and a recognition | 
|  | // function.  We use global constructors to build a linked list of | 
|  | // target selectors--a simple pointer list, not a std::list. | 
|  |  | 
|  | class Target_selector | 
|  | { | 
|  | public: | 
|  | // Create a target selector for a specific machine number, size (32 | 
|  | // or 64), and endianness.  The machine number can be EM_NONE to | 
|  | // test for any machine number.  BFD_NAME is the name of the target | 
|  | // used by the GNU linker, for backward compatibility; it may be | 
|  | // NULL.  EMULATION is the name of the emulation used by the GNU | 
|  | // linker; it is similar to BFD_NAME. | 
|  | Target_selector(int machine, int size, bool is_big_endian, | 
|  | const char* bfd_name, const char* emulation); | 
|  |  | 
|  | virtual ~Target_selector() | 
|  | { } | 
|  |  | 
|  | // If we can handle this target, return a pointer to a target | 
|  | // structure.  The size and endianness are known. | 
|  | Target* | 
|  | recognize(Input_file* input_file, off_t offset, | 
|  | int machine, int osabi, int abiversion) | 
|  | { return this->do_recognize(input_file, offset, machine, osabi, abiversion); } | 
|  |  | 
|  | // If NAME matches the target, return a pointer to a target | 
|  | // structure. | 
|  | Target* | 
|  | recognize_by_bfd_name(const char* name) | 
|  | { return this->do_recognize_by_bfd_name(name); } | 
|  |  | 
|  | // Push all supported BFD names onto the vector.  This is only used | 
|  | // for help output. | 
|  | void | 
|  | supported_bfd_names(std::vector<const char*>* names) | 
|  | { this->do_supported_bfd_names(names); } | 
|  |  | 
|  | // If NAME matches the target emulation, return a pointer to a | 
|  | // target structure. | 
|  | Target* | 
|  | recognize_by_emulation(const char* name) | 
|  | { return this->do_recognize_by_emulation(name); } | 
|  |  | 
|  | // Push all supported emulations onto the vector.  This is only used | 
|  | // for help output. | 
|  | void | 
|  | supported_emulations(std::vector<const char*>* names) | 
|  | { this->do_supported_emulations(names); } | 
|  |  | 
|  | // Return the next Target_selector in the linked list. | 
|  | Target_selector* | 
|  | next() const | 
|  | { return this->next_; } | 
|  |  | 
|  | // Return the machine number this selector is looking for.  This can | 
|  | // be EM_NONE to match any machine number, in which case the | 
|  | // do_recognize hook will be responsible for matching the machine | 
|  | // number. | 
|  | int | 
|  | machine() const | 
|  | { return this->machine_; } | 
|  |  | 
|  | // Return the size this is looking for (32 or 64). | 
|  | int | 
|  | get_size() const | 
|  | { return this->size_; } | 
|  |  | 
|  | // Return the endianness this is looking for. | 
|  | bool | 
|  | is_big_endian() const | 
|  | { return this->is_big_endian_; } | 
|  |  | 
|  | // Return the BFD name.  This may return NULL, in which case the | 
|  | // do_recognize_by_bfd_name hook will be responsible for matching | 
|  | // the BFD name. | 
|  | const char* | 
|  | bfd_name() const | 
|  | { return this->bfd_name_; } | 
|  |  | 
|  | // Return the emulation.  This may return NULL, in which case the | 
|  | // do_recognize_by_emulation hook will be responsible for matching | 
|  | // the emulation. | 
|  | const char* | 
|  | emulation() const | 
|  | { return this->emulation_; } | 
|  |  | 
|  | // The reverse mapping, for --print-output-format: if we | 
|  | // instantiated TARGET, return our BFD_NAME.  If we did not | 
|  | // instantiate it, return NULL. | 
|  | const char* | 
|  | target_bfd_name(const Target* target) | 
|  | { return this->do_target_bfd_name(target); } | 
|  |  | 
|  | protected: | 
|  | // Return an instance of the real target.  This must be implemented | 
|  | // by the child class. | 
|  | virtual Target* | 
|  | do_instantiate_target() = 0; | 
|  |  | 
|  | // Recognize an object file given a machine code, OSABI code, and | 
|  | // ELF version value.  When this is called we already know that they | 
|  | // match the machine_, size_, and is_big_endian_ fields.  The child | 
|  | // class may implement a different version of this to do additional | 
|  | // checks, or to check for multiple machine codes if the machine_ | 
|  | // field is EM_NONE. | 
|  | virtual Target* | 
|  | do_recognize(Input_file*, off_t, int, int, int) | 
|  | { return this->instantiate_target(); } | 
|  |  | 
|  | // Recognize a target by name.  When this is called we already know | 
|  | // that the name matches (or that the bfd_name_ field is NULL).  The | 
|  | // child class may implement a different version of this to | 
|  | // recognize more than one name. | 
|  | virtual Target* | 
|  | do_recognize_by_bfd_name(const char*) | 
|  | { return this->instantiate_target(); } | 
|  |  | 
|  | // Return a list of supported BFD names.  The child class may | 
|  | // implement a different version of this to handle more than one | 
|  | // name. | 
|  | virtual void | 
|  | do_supported_bfd_names(std::vector<const char*>* names) | 
|  | { | 
|  | gold_assert(this->bfd_name_ != NULL); | 
|  | names->push_back(this->bfd_name_); | 
|  | } | 
|  |  | 
|  | // Recognize a target by emulation.  When this is called we already | 
|  | // know that the name matches (or that the emulation_ field is | 
|  | // NULL).  The child class may implement a different version of this | 
|  | // to recognize more than one emulation. | 
|  | virtual Target* | 
|  | do_recognize_by_emulation(const char*) | 
|  | { return this->instantiate_target(); } | 
|  |  | 
|  | // Return a list of supported emulations.  The child class may | 
|  | // implement a different version of this to handle more than one | 
|  | // emulation. | 
|  | virtual void | 
|  | do_supported_emulations(std::vector<const char*>* emulations) | 
|  | { | 
|  | gold_assert(this->emulation_ != NULL); | 
|  | emulations->push_back(this->emulation_); | 
|  | } | 
|  |  | 
|  | // Map from target to BFD name. | 
|  | virtual const char* | 
|  | do_target_bfd_name(const Target*); | 
|  |  | 
|  | // Instantiate the target and return it. | 
|  | Target* | 
|  | instantiate_target(); | 
|  |  | 
|  | // Return whether TARGET is the target we instantiated. | 
|  | bool | 
|  | is_our_target(const Target* target) | 
|  | { return target == this->instantiated_target_; } | 
|  |  | 
|  | private: | 
|  | // Set the target. | 
|  | void | 
|  | set_target(); | 
|  |  | 
|  | friend class Set_target_once; | 
|  |  | 
|  | // ELF machine code. | 
|  | const int machine_; | 
|  | // Target size--32 or 64. | 
|  | const int size_; | 
|  | // Whether the target is big endian. | 
|  | const bool is_big_endian_; | 
|  | // BFD name of target, for compatibility. | 
|  | const char* const bfd_name_; | 
|  | // GNU linker emulation for this target, for compatibility. | 
|  | const char* const emulation_; | 
|  | // Next entry in list built at global constructor time. | 
|  | Target_selector* next_; | 
|  | // The singleton Target structure--this points to an instance of the | 
|  | // real implementation. | 
|  | Target* instantiated_target_; | 
|  | // Used to set the target only once. | 
|  | Set_target_once set_target_once_; | 
|  | }; | 
|  |  | 
|  | // Select the target for an ELF file. | 
|  |  | 
|  | extern Target* | 
|  | select_target(Input_file*, off_t, | 
|  | int machine, int size, bool big_endian, int osabi, | 
|  | int abiversion); | 
|  |  | 
|  | // Select a target using a BFD name. | 
|  |  | 
|  | extern Target* | 
|  | select_target_by_bfd_name(const char* name); | 
|  |  | 
|  | // Select a target using a GNU linker emulation. | 
|  |  | 
|  | extern Target* | 
|  | select_target_by_emulation(const char* name); | 
|  |  | 
|  | // Fill in a vector with the list of supported targets.  This returns | 
|  | // a list of BFD names. | 
|  |  | 
|  | extern void | 
|  | supported_target_names(std::vector<const char*>*); | 
|  |  | 
|  | // Fill in a vector with the list of supported emulations. | 
|  |  | 
|  | extern void | 
|  | supported_emulation_names(std::vector<const char*>*); | 
|  |  | 
|  | // Print the output format, for the --print-output-format option. | 
|  |  | 
|  | extern void | 
|  | print_output_format(); | 
|  |  | 
|  | } // End namespace gold. | 
|  |  | 
|  | #endif // !defined(GOLD_TARGET_SELECT_H) |