* ld-cris/asneed1.d: New test.
[deliverable/binutils-gdb.git] / gold / nacl.h
1 // nacl.h -- Native Client support for gold -*- C++ -*-
2
3 // Copyright 2012 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:
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:
44 Location(off_t file_offset, off_t data_size)
45 : offset_(file_offset), size_(data_size)
46 { }
47
48 inline off_t offset() const
49 { return this->offset_; }
50
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:
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
66 const unsigned char* data()
67 { return this->data_; }
68
69 private:
70 const unsigned char* data_;
71 };
72
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
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:
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*
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*
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*
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
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
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*
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
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
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)
This page took 0.035691 seconds and 4 git commands to generate.