1// target-select.cc -- select a target for an object file 2 3// Copyright (C) 2006-2017 Free Software Foundation, Inc. 4// Written by Ian Lance Taylor <iant@google.com>. 5 6// This file is part of gold. 7 8// This program is free software; you can redistribute it and/or modify 9// it under the terms of the GNU General Public License as published by 10// the Free Software Foundation; either version 3 of the License, or 11// (at your option) any later version. 12 13// This program is distributed in the hope that it will be useful, 14// but WITHOUT ANY WARRANTY; without even the implied warranty of 15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16// GNU General Public License for more details. 17 18// You should have received a copy of the GNU General Public License 19// along with this program; if not, write to the Free Software 20// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21// MA 02110-1301, USA. 22 23#include "gold.h" 24 25#include <cstdio> 26#include <cstring> 27 28#include "elfcpp.h" 29#include "options.h" 30#include "parameters.h" 31#include "target-select.h" 32 33namespace 34{ 35 36// The start of the list of target selectors. 37 38gold::Target_selector* target_selectors; 39 40} // End anonymous namespace. 41 42namespace gold 43{ 44 45// Class Set_target_once. 46 47void 48Set_target_once::do_run_once(void*) 49{ 50 this->target_selector_->set_target(); 51} 52 53// Construct a Target_selector, which means adding it to the linked 54// list. This runs at global constructor time, so we want it to be 55// fast. 56 57Target_selector::Target_selector(int machine, int size, bool is_big_endian, 58 const char* bfd_name, const char* emulation) 59 : machine_(machine), size_(size), is_big_endian_(is_big_endian), 60 bfd_name_(bfd_name), emulation_(emulation), instantiated_target_(NULL), 61 set_target_once_(this) 62{ 63 this->next_ = target_selectors; 64 target_selectors = this; 65} 66 67// Instantiate the target and return it. Use SET_TARGET_ONCE_ to 68// avoid instantiating two instances of the same target. 69 70Target* 71Target_selector::instantiate_target() 72{ 73 this->set_target_once_.run_once(NULL); 74 return this->instantiated_target_; 75} 76 77// Instantiate the target. This is called at most once. 78 79void 80Target_selector::set_target() 81{ 82 gold_assert(this->instantiated_target_ == NULL); 83 this->instantiated_target_ = this->do_instantiate_target(); 84} 85 86// If we instantiated TARGET, return the corresponding BFD name. 87 88const char* 89Target_selector::do_target_bfd_name(const Target* target) 90{ 91 if (!this->is_our_target(target)) 92 return NULL; 93 const char* my_bfd_name = this->bfd_name(); 94 gold_assert(my_bfd_name != NULL); 95 return my_bfd_name; 96} 97 98// Find the target for an ELF file. 99 100Target* 101select_target(Input_file* input_file, off_t offset, 102 int machine, int size, bool is_big_endian, 103 int osabi, int abiversion) 104{ 105 for (Target_selector* p = target_selectors; p != NULL; p = p->next()) 106 { 107 int pmach = p->machine(); 108 if ((pmach == machine || pmach == elfcpp::EM_NONE) 109 && p->get_size() == size 110 && (p->is_big_endian() ? is_big_endian : !is_big_endian)) 111 { 112 Target* ret = p->recognize(input_file, offset, 113 machine, osabi, abiversion); 114 if (ret != NULL) 115 return ret; 116 } 117 } 118 return NULL; 119} 120 121// Find a target using a BFD name. This is used to support the 122// --oformat option. 123 124Target* 125select_target_by_bfd_name(const char* name) 126{ 127 for (Target_selector* p = target_selectors; p != NULL; p = p->next()) 128 { 129 const char* pname = p->bfd_name(); 130 if (pname == NULL || strcmp(pname, name) == 0) 131 { 132 Target* ret = p->recognize_by_bfd_name(name); 133 if (ret != NULL) 134 return ret; 135 } 136 } 137 return NULL; 138} 139 140// Find a target using a GNU linker emulation. This is used to 141// support the -m option. 142 143Target* 144select_target_by_emulation(const char* name) 145{ 146 for (Target_selector* p = target_selectors; p != NULL; p = p->next()) 147 { 148 const char* pname = p->emulation(); 149 if (pname == NULL || strcmp(pname, name) == 0) 150 { 151 Target* ret = p->recognize_by_emulation(name); 152 if (ret != NULL) 153 return ret; 154 } 155 } 156 return NULL; 157} 158 159// Push all the supported BFD names onto a vector. 160 161void 162supported_target_names(std::vector<const char*>* names) 163{ 164 for (Target_selector* p = target_selectors; p != NULL; p = p->next()) 165 p->supported_bfd_names(names); 166} 167 168// Push all the supported emulations onto a vector. 169 170void 171supported_emulation_names(std::vector<const char*>* names) 172{ 173 for (Target_selector* p = target_selectors; p != NULL; p = p->next()) 174 p->supported_emulations(names); 175} 176 177// Implement the --print-output-format option. 178 179void 180print_output_format() 181{ 182 if (!parameters->target_valid()) 183 { 184 // This case arises when --print-output-format is used with no 185 // input files. We need to come up with the right string to 186 // print based on the other options. If the user specified the 187 // format using a --oformat option, use that. That saves each 188 // target from having to remember the name that was used to 189 // select it. In other cases, we will just have to ask the 190 // target. 191 if (parameters->options().user_set_oformat()) 192 { 193 const char* bfd_name = parameters->options().oformat(); 194 Target* target = select_target_by_bfd_name(bfd_name); 195 if (target != NULL) 196 printf("%s\n", bfd_name); 197 else 198 gold_error(_("unrecognized output format %s"), bfd_name); 199 return; 200 } 201 202 parameters_force_valid_target(); 203 } 204 205 const Target* target = ¶meters->target(); 206 for (Target_selector* p = target_selectors; p != NULL; p = p->next()) 207 { 208 const char* bfd_name = p->target_bfd_name(target); 209 if (bfd_name != NULL) 210 { 211 printf("%s\n", bfd_name); 212 return; 213 } 214 } 215 216 gold_unreachable(); 217} 218 219} // End namespace gold. 220