123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // target-select.cc -- select a target for an object file
- // Copyright (C) 2006-2015 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.
- #include "gold.h"
- #include <cstdio>
- #include <cstring>
- #include "elfcpp.h"
- #include "options.h"
- #include "parameters.h"
- #include "target-select.h"
- namespace
- {
- // The start of the list of target selectors.
- gold::Target_selector* target_selectors;
- } // End anonymous namespace.
- namespace gold
- {
- // Class Set_target_once.
- void
- Set_target_once::do_run_once(void*)
- {
- this->target_selector_->set_target();
- }
- // Construct a Target_selector, which means adding it to the linked
- // list. This runs at global constructor time, so we want it to be
- // fast.
- Target_selector::Target_selector(int machine, int size, bool is_big_endian,
- const char* bfd_name, const char* emulation)
- : machine_(machine), size_(size), is_big_endian_(is_big_endian),
- bfd_name_(bfd_name), emulation_(emulation), instantiated_target_(NULL),
- set_target_once_(this)
- {
- this->next_ = target_selectors;
- target_selectors = this;
- }
- // Instantiate the target and return it. Use SET_TARGET_ONCE_ to
- // avoid instantiating two instances of the same target.
- Target*
- Target_selector::instantiate_target()
- {
- this->set_target_once_.run_once(NULL);
- return this->instantiated_target_;
- }
- // Instantiate the target. This is called at most once.
- void
- Target_selector::set_target()
- {
- gold_assert(this->instantiated_target_ == NULL);
- this->instantiated_target_ = this->do_instantiate_target();
- }
- // If we instantiated TARGET, return the corresponding BFD name.
- const char*
- Target_selector::do_target_bfd_name(const Target* target)
- {
- if (!this->is_our_target(target))
- return NULL;
- const char* my_bfd_name = this->bfd_name();
- gold_assert(my_bfd_name != NULL);
- return my_bfd_name;
- }
- // Find the target for an ELF file.
- Target*
- select_target(Input_file* input_file, off_t offset,
- int machine, int size, bool is_big_endian,
- int osabi, int abiversion)
- {
- for (Target_selector* p = target_selectors; p != NULL; p = p->next())
- {
- int pmach = p->machine();
- if ((pmach == machine || pmach == elfcpp::EM_NONE)
- && p->get_size() == size
- && (p->is_big_endian() ? is_big_endian : !is_big_endian))
- {
- Target* ret = p->recognize(input_file, offset,
- machine, osabi, abiversion);
- if (ret != NULL)
- return ret;
- }
- }
- return NULL;
- }
- // Find a target using a BFD name. This is used to support the
- // --oformat option.
- Target*
- select_target_by_bfd_name(const char* name)
- {
- for (Target_selector* p = target_selectors; p != NULL; p = p->next())
- {
- const char* pname = p->bfd_name();
- if (pname == NULL || strcmp(pname, name) == 0)
- {
- Target* ret = p->recognize_by_bfd_name(name);
- if (ret != NULL)
- return ret;
- }
- }
- return NULL;
- }
- // Find a target using a GNU linker emulation. This is used to
- // support the -m option.
- Target*
- select_target_by_emulation(const char* name)
- {
- for (Target_selector* p = target_selectors; p != NULL; p = p->next())
- {
- const char* pname = p->emulation();
- if (pname == NULL || strcmp(pname, name) == 0)
- {
- Target* ret = p->recognize_by_emulation(name);
- if (ret != NULL)
- return ret;
- }
- }
- return NULL;
- }
- // Push all the supported BFD names onto a vector.
- void
- supported_target_names(std::vector<const char*>* names)
- {
- for (Target_selector* p = target_selectors; p != NULL; p = p->next())
- p->supported_bfd_names(names);
- }
- // Push all the supported emulations onto a vector.
- void
- supported_emulation_names(std::vector<const char*>* names)
- {
- for (Target_selector* p = target_selectors; p != NULL; p = p->next())
- p->supported_emulations(names);
- }
- // Implement the --print-output-format option.
- void
- print_output_format()
- {
- if (!parameters->target_valid())
- {
- // This case arises when --print-output-format is used with no
- // input files. We need to come up with the right string to
- // print based on the other options. If the user specified the
- // format using a --oformat option, use that. That saves each
- // target from having to remember the name that was used to
- // select it. In other cases, we will just have to ask the
- // target.
- if (parameters->options().user_set_oformat())
- {
- const char* bfd_name = parameters->options().oformat();
- Target* target = select_target_by_bfd_name(bfd_name);
- if (target != NULL)
- printf("%s\n", bfd_name);
- else
- gold_error(_("unrecognized output format %s"), bfd_name);
- return;
- }
- parameters_force_valid_target();
- }
- const Target* target = ¶meters->target();
- for (Target_selector* p = target_selectors; p != NULL; p = p->next())
- {
- const char* bfd_name = p->target_bfd_name(target);
- if (bfd_name != NULL)
- {
- printf("%s\n", bfd_name);
- return;
- }
- }
- gold_unreachable();
- }
- } // End namespace gold.
|