Commit | Line | Data |
---|---|---|
2e702c99 RM |
1 | // nacl.h -- Native Client support for gold -*- C++ -*- |
2 | ||
b90efa5b | 3 | // Copyright (C) 2012-2015 Free Software Foundation, Inc. |
2e702c99 RM |
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) | |
775ed62e | 63 | : data_(file.get_view(file_offset, 0, data_size, true, false)) |
2e702c99 RM |
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) |