1 // target-select.cc -- select a target for an object file 2 3 // Copyright (C) 2006-2016 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 33 namespace 34 { 35 36 // The start of the list of target selectors. 37 38 gold::Target_selector* target_selectors; 39 40 } // End anonymous namespace. 41 42 namespace gold 43 { 44 45 // Class Set_target_once. 46 47 void 48 Set_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 57 Target_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 70 Target* 71 Target_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 79 void 80 Target_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 88 const char* 89 Target_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 100 Target* 101 select_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 124 Target* 125 select_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 143 Target* 144 select_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 161 void 162 supported_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 170 void 171 supported_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 179 void 180 print_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