(root)/
binutils-2.41/
gold/
nacl.h
       1  // nacl.h -- Native Client support for gold    -*- C++ -*-
       2  
       3  // Copyright (C) 2012-2023 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)