1 // nacl.h -- Native Client support for gold -*- C++ -*-
3 // Copyright (C) 2012-2015 Free Software Foundation, Inc.
5 // This file is part of gold.
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.
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.
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.
22 #include "elfcpp_file.h"
25 #include "target-select.h"
37 Sniff_file(Input_file* input_file, off_t offset)
38 : file_(input_file->file()), offset_(offset)
44 Location(off_t file_offset, off_t data_size)
45 : offset_(file_offset), size_(data_size)
48 inline off_t offset() const
49 { return this->offset_; }
51 inline section_size_type size() const
52 { return this->size_; }
56 section_size_type size_;
62 View(File_read& file, off_t file_offset, off_t data_size)
63 : data_(file.get_view(file_offset, 0, data_size, true, false))
66 const unsigned char* data()
67 { return this->data_; }
70 const unsigned char* data_;
73 View view(off_t file_offset, off_t data_size)
75 return View(this->file_, this->offset_ + file_offset, data_size);
78 View view(Location loc)
80 return this->view(loc.offset(), loc.size());
85 error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
93 template<class base_selector, class nacl_target>
94 class Target_selector_nacl : public base_selector
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)
105 do_instantiate_target()
108 return new nacl_target();
109 return this->base_selector::do_instantiate_target();
113 do_recognize(Input_file* file, off_t offset,
114 int machine, int osabi, int abiversion)
116 this->is_nacl_ = file != NULL && this->recognize_nacl_file(file, offset);
118 return this->instantiate_target();
119 return this->base_selector::do_recognize(file, offset,
120 machine, osabi, abiversion);
124 do_recognize_by_bfd_name(const char* name)
126 gold_assert(this->bfd_name_ != NULL);
127 this->is_nacl_ = strcmp(name, this->bfd_name_) == 0;
129 return this->instantiate_target();
130 return this->base_selector::do_recognize_by_bfd_name(name);
134 do_supported_bfd_names(std::vector<const char*>* names)
136 gold_assert(this->bfd_name_ != NULL);
137 this->base_selector::do_supported_bfd_names(names);
138 names->push_back(this->bfd_name_);
142 do_supported_emulations(std::vector<const char*>* emulations)
144 gold_assert(this->emulation_ != NULL);
145 this->base_selector::do_supported_emulations(emulations);
146 emulations->push_back(this->emulation_);
150 do_target_bfd_name(const Target* target)
152 return (!this->is_our_target(target)
156 : base_selector::do_target_bfd_name(target)));
161 recognize_nacl_file(Input_file* input_file, off_t offset)
163 if (this->is_big_endian())
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);
170 # ifdef HAVE_TARGET_64_BIG
171 if (this->get_size() == 64)
172 return do_recognize_nacl_file<64, true>(input_file, offset);
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);
184 # ifdef HAVE_TARGET_64_LITTLE
185 if (this->get_size() == 64)
186 return do_recognize_nacl_file<64, false>(input_file, offset);
193 template<int size, bool big_endian>
195 do_recognize_nacl_file(Input_file* input_file, off_t offset)
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)
202 if (elf_file.section_type(shndx) == elfcpp::SHT_NOTE)
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)))
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)
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))
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)
231 // Whether we decided this was the NaCl target variant.
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_;
241 } // end namespace gold
243 #endif // !defined(GOLD_NACL_H)