nacl.h 6.9 KB

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