Home | History | Annotate | Download | only in gold
      1 // nacl.h -- Native Client support for gold    -*- C++ -*-
      2 
      3 // Copyright (C) 2012-2016 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(file_offset, 0, 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)
    244