1 // nacl.h -- Native Client support for gold -*- C++ -*- 2 3 // Copyright (C) 2012-2014 Free Software Foundation, Inc. 4 5 // This file is part of gold. 6 7 // This program is free software; you can redistribute it and/or modify 8 // it under the terms of the GNU General Public License as published by 9 // the Free Software Foundation; either version 3 of the License, or 10 // (at your option) any later version. 11 12 // This program is distributed in the hope that it will be useful, 13 // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 // GNU General Public License for more details. 16 17 // You should have received a copy of the GNU General Public License 18 // along with this program; if not, write to the Free Software 19 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 20 // MA 02110-1301, USA. 21 22 #include "elfcpp_file.h" 23 #include "fileread.h" 24 #include "layout.h" 25 #include "target-select.h" 26 #include "target.h" 27 28 #ifndef GOLD_NACL_H 29 #define GOLD_NACL_H 30 31 namespace gold 32 { 33 34 class Sniff_file 35 { 36 public: Sniff_file(Input_file * input_file,off_t offset)37 Sniff_file(Input_file* input_file, off_t offset) 38 : file_(input_file->file()), offset_(offset) 39 { } 40 41 class Location 42 { 43 public: Location(off_t file_offset,off_t data_size)44 Location(off_t file_offset, off_t data_size) 45 : offset_(file_offset), size_(data_size) 46 { } 47 offset()48 inline off_t offset() const 49 { return this->offset_; } 50 size()51 inline section_size_type size() const 52 { return this->size_; } 53 54 private: 55 off_t offset_; 56 section_size_type size_; 57 }; 58 59 class View 60 { 61 public: View(File_read & file,off_t file_offset,off_t data_size)62 View(File_read& file, off_t file_offset, off_t data_size) 63 : data_(file.get_view(0, file_offset, data_size, true, false)) 64 { } 65 data()66 const unsigned char* data() 67 { return this->data_; } 68 69 private: 70 const unsigned char* data_; 71 }; 72 view(off_t file_offset,off_t data_size)73 View view(off_t file_offset, off_t data_size) 74 { 75 return View(this->file_, this->offset_ + file_offset, data_size); 76 } 77 view(Location loc)78 View view(Location loc) 79 { 80 return this->view(loc.offset(), loc.size()); 81 } 82 83 // Report an error. 84 void 85 error(const char* format, ...) const ATTRIBUTE_PRINTF_2; 86 87 private: 88 File_read& file_; 89 off_t offset_; 90 }; 91 92 93 template<class base_selector, class nacl_target> 94 class Target_selector_nacl : public base_selector 95 { 96 public: Target_selector_nacl(const char * nacl_abi_name,const char * bfd_name,const char * emulation)97 Target_selector_nacl(const char* nacl_abi_name, 98 const char* bfd_name, const char* emulation) 99 : base_selector(), is_nacl_(false), nacl_abi_name_(nacl_abi_name), 100 bfd_name_(bfd_name), emulation_(emulation) 101 { } 102 103 protected: 104 virtual Target* do_instantiate_target()105 do_instantiate_target() 106 { 107 if (this->is_nacl_) 108 return new nacl_target(); 109 return this->base_selector::do_instantiate_target(); 110 } 111 112 virtual Target* do_recognize(Input_file * file,off_t offset,int machine,int osabi,int abiversion)113 do_recognize(Input_file* file, off_t offset, 114 int machine, int osabi, int abiversion) 115 { 116 this->is_nacl_ = file != NULL && this->recognize_nacl_file(file, offset); 117 if (this->is_nacl_) 118 return this->instantiate_target(); 119 return this->base_selector::do_recognize(file, offset, 120 machine, osabi, abiversion); 121 } 122 123 virtual Target* do_recognize_by_bfd_name(const char * name)124 do_recognize_by_bfd_name(const char* name) 125 { 126 gold_assert(this->bfd_name_ != NULL); 127 this->is_nacl_ = strcmp(name, this->bfd_name_) == 0; 128 if (this->is_nacl_) 129 return this->instantiate_target(); 130 return this->base_selector::do_recognize_by_bfd_name(name); 131 } 132 133 virtual void do_supported_bfd_names(std::vector<const char * > * names)134 do_supported_bfd_names(std::vector<const char*>* names) 135 { 136 gold_assert(this->bfd_name_ != NULL); 137 this->base_selector::do_supported_bfd_names(names); 138 names->push_back(this->bfd_name_); 139 } 140 141 virtual void do_supported_emulations(std::vector<const char * > * emulations)142 do_supported_emulations(std::vector<const char*>* emulations) 143 { 144 gold_assert(this->emulation_ != NULL); 145 this->base_selector::do_supported_emulations(emulations); 146 emulations->push_back(this->emulation_); 147 } 148 149 virtual const char* do_target_bfd_name(const Target * target)150 do_target_bfd_name(const Target* target) 151 { 152 return (!this->is_our_target(target) 153 ? NULL 154 : (this->is_nacl_ 155 ? this->bfd_name_ 156 : base_selector::do_target_bfd_name(target))); 157 } 158 159 private: 160 bool recognize_nacl_file(Input_file * input_file,off_t offset)161 recognize_nacl_file(Input_file* input_file, off_t offset) 162 { 163 if (this->is_big_endian()) 164 { 165 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) 166 # ifdef HAVE_TARGET_32_BIG 167 if (this->get_size() == 32) 168 return do_recognize_nacl_file<32, true>(input_file, offset); 169 # endif 170 # ifdef HAVE_TARGET_64_BIG 171 if (this->get_size() == 64) 172 return do_recognize_nacl_file<64, true>(input_file, offset); 173 # endif 174 #endif 175 gold_unreachable(); 176 } 177 else 178 { 179 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) 180 # ifdef HAVE_TARGET_32_LITTLE 181 if (this->get_size() == 32) 182 return do_recognize_nacl_file<32, false>(input_file, offset); 183 # endif 184 # ifdef HAVE_TARGET_64_LITTLE 185 if (this->get_size() == 64) 186 return do_recognize_nacl_file<64, false>(input_file, offset); 187 # endif 188 #endif 189 gold_unreachable(); 190 } 191 } 192 193 template<int size, bool big_endian> 194 bool do_recognize_nacl_file(Input_file * input_file,off_t offset)195 do_recognize_nacl_file(Input_file* input_file, off_t offset) 196 { 197 Sniff_file file(input_file, offset); 198 elfcpp::Elf_file<size, big_endian, Sniff_file> elf_file(&file); 199 const unsigned int shnum = elf_file.shnum(); 200 for (unsigned int shndx = 1; shndx < shnum; ++shndx) 201 { 202 if (elf_file.section_type(shndx) == elfcpp::SHT_NOTE) 203 { 204 Sniff_file::Location loc = elf_file.section_contents(shndx); 205 if (loc.size() < (3 * 4 206 + align_address(sizeof "NaCl", 4) 207 + align_address(nacl_abi_name_.size() + 1, 4))) 208 continue; 209 Sniff_file::View view(file.view(loc)); 210 const unsigned char* note_data = view.data(); 211 if ((elfcpp::Swap<32, big_endian>::readval(note_data + 0) 212 == sizeof "NaCl") 213 && (elfcpp::Swap<32, big_endian>::readval(note_data + 4) 214 == nacl_abi_name_.size() + 1) 215 && (elfcpp::Swap<32, big_endian>::readval(note_data + 8) 216 == elfcpp::NT_VERSION)) 217 { 218 const unsigned char* name = note_data + 12; 219 const unsigned char* desc = (name 220 + align_address(sizeof "NaCl", 4)); 221 if (memcmp(name, "NaCl", sizeof "NaCl") == 0 222 && memcmp(desc, nacl_abi_name_.c_str(), 223 nacl_abi_name_.size() + 1) == 0) 224 return true; 225 } 226 } 227 } 228 return false; 229 } 230 231 // Whether we decided this was the NaCl target variant. 232 bool is_nacl_; 233 // The string found in the NaCl ABI note. 234 std::string nacl_abi_name_; 235 // BFD name of NaCl target, for compatibility. 236 const char* const bfd_name_; 237 // GNU linker emulation for this NaCl target, for compatibility. 238 const char* const emulation_; 239 }; 240 241 } // end namespace gold 242 243 #endif // !defined(GOLD_NACL_H) 244