C++程序  |  241行  |  6.48 KB

//===- MipsGOT.h ----------------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef TARGET_MIPS_MIPSGOT_H
#define TARGET_MIPS_MIPSGOT_H
#include <map>
#include <vector>


#include <mcld/ADT/SizeTraits.h>
#include <mcld/Target/GOT.h>
#include <mcld/Fragment/Relocation.h>
#include <mcld/Support/MemoryRegion.h>
#include <llvm/ADT/DenseMap.h>
#include <llvm/ADT/DenseSet.h>
#include <set>

namespace mcld {

class Input;
class LDSection;
class LDSymbol;
class OutputRelocSection;

/** \class MipsGOT
 *  \brief Mips Global Offset Table.
 */
class MipsGOT : public GOT
{
public:
  MipsGOT(LDSection& pSection);

  /// Assign value to the GOT entry.
  virtual void setEntryValue(Fragment* entry, uint64_t pValue) = 0;

  /// Emit the global offset table.
  virtual uint64_t emit(MemoryRegion& pRegion) = 0;

  /// Address of _gp_disp symbol.
  uint64_t getGPDispAddress() const;

  void initializeScan(const Input& pInput);
  void finalizeScan(const Input& pInput);

  bool reserveLocalEntry(ResolveInfo& pInfo, int reloc,
                         Relocation::DWord pAddend);
  bool reserveGlobalEntry(ResolveInfo& pInfo);

  size_t getLocalNum() const;   ///< number of local symbols in primary GOT
  size_t getGlobalNum() const;  ///< total number of global symbols

  bool isPrimaryGOTConsumed();

  Fragment* consumeLocal();
  Fragment* consumeGlobal();

  uint64_t getGPAddr(const Input& pInput) const;
  uint64_t getGPRelOffset(const Input& pInput, const Fragment& pEntry) const;

  void recordGlobalEntry(const ResolveInfo* pInfo, Fragment* pEntry);
  Fragment* lookupGlobalEntry(const ResolveInfo* pInfo);

  void recordLocalEntry(const ResolveInfo* pInfo,
                        Relocation::DWord pAddend,
                        Fragment* pEntry);
  Fragment* lookupLocalEntry(const ResolveInfo* pInfo,
                             Relocation::DWord pAddend);

  /// hasGOT1 - return if this got section has any GOT1 entry
  bool hasGOT1() const;

  bool hasMultipleGOT() const;

  /// Create GOT entries and reserve dynrel entries.
  void finalizeScanning(OutputRelocSection& pRelDyn);

  /// Compare two symbols to define order in the .dynsym.
  bool dynSymOrderCompare(const LDSymbol* pX, const LDSymbol* pY) const;

protected:
  /// Create GOT entry.
  virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent) = 0;

  /// Size of GOT entry.
  virtual size_t getEntrySize() const = 0;

  /// Reserve GOT header entries.
  virtual void reserveHeader() = 0;

private:
  /** \class GOTMultipart
   *  \brief GOTMultipart counts local and global entries in the GOT.
   */
  struct GOTMultipart
  {
    GOTMultipart(size_t local = 0, size_t global = 0);

    typedef llvm::DenseSet<const Input*> InputSetType;

    size_t m_LocalNum;  ///< number of reserved local entries
    size_t m_GlobalNum; ///< number of reserved global entries

    size_t m_ConsumedLocal;       ///< consumed local entries
    size_t m_ConsumedGlobal;      ///< consumed global entries

    Fragment* m_pLastLocal;   ///< the last consumed local entry
    Fragment* m_pLastGlobal;  ///< the last consumed global entry

    InputSetType m_Inputs;

    bool isConsumed() const;

    void consumeLocal();
    void consumeGlobal();
  };

  /** \class LocalEntry
   *  \brief LocalEntry local GOT entry descriptor.
   */
  struct LocalEntry
  {
    const ResolveInfo* m_pInfo;
    Relocation::DWord  m_Addend;
    bool               m_IsGot16;

    LocalEntry(const ResolveInfo* pInfo,
               Relocation::DWord addend, bool isGot16);

    bool operator<(const LocalEntry &O) const;
  };

  typedef std::vector<GOTMultipart> MultipartListType;

  // Set of global symbols.
  typedef llvm::DenseSet<const ResolveInfo*> SymbolSetType;
  // Map of symbols. If value is true, the symbol is referenced
  // in the current input only. If value is false, the symbol
  // is referenced in the other modules merged to the current GOT.
  typedef llvm::DenseMap<const ResolveInfo*, bool> SymbolUniqueMapType;

  // Set of local symbols.
  typedef std::set<LocalEntry> LocalSymbolSetType;

  MultipartListType m_MultipartList;  ///< list of GOT's descriptors
  const Input* m_pInput;              ///< current input

  // Global symbols merged to the current GOT
  // except symbols from the current input.
  SymbolSetType m_MergedGlobalSymbols;
  // Global symbols from the current input.
  SymbolUniqueMapType m_InputGlobalSymbols;
  // Local symbols merged to the current GOT
  // except symbols from the current input.
  LocalSymbolSetType m_MergedLocalSymbols;
  // Local symbols from the current input.
  LocalSymbolSetType m_InputLocalSymbols;

  size_t m_CurrentGOTPart;

  typedef llvm::DenseMap<const LDSymbol*, unsigned> SymbolOrderMapType;
  SymbolOrderMapType m_SymbolOrderMap;

  void initGOTList();

  void changeInput();
  bool isGOTFull() const;
  void split();
  void reserve(size_t pNum);

private:
  struct GotEntryKey
  {
    size_t m_GOTPage;
    const ResolveInfo* m_pInfo;
    Relocation::DWord m_Addend;

    bool operator<(const GotEntryKey& key) const
    {
      if (m_GOTPage != key.m_GOTPage)
        return m_GOTPage < key.m_GOTPage;

      if (m_pInfo != key.m_pInfo)
        return m_pInfo < key.m_pInfo;

      return m_Addend < key.m_Addend;
    }
  };

  typedef std::map<GotEntryKey, Fragment*> GotEntryMapType;
  GotEntryMapType m_GotLocalEntriesMap;
  GotEntryMapType m_GotGlobalEntriesMap;
};

/** \class Mips32GOT
 *  \brief Mips 32-bit Global Offset Table.
 */
class Mips32GOT : public MipsGOT
{
public:
  Mips32GOT(LDSection& pSection);

private:
  typedef GOT::Entry<4> Mips32GOTEntry;

  // MipsGOT
  virtual void setEntryValue(Fragment* entry, uint64_t pValue);
  virtual uint64_t emit(MemoryRegion& pRegion);
  virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent);
  virtual size_t getEntrySize() const;
  virtual void reserveHeader();
};

/** \class Mips64GOT
 *  \brief Mips 64-bit Global Offset Table.
 */
class Mips64GOT : public MipsGOT
{
public:
  Mips64GOT(LDSection& pSection);

private:
  typedef GOT::Entry<8> Mips64GOTEntry;

  // MipsGOT
  virtual void setEntryValue(Fragment* entry, uint64_t pValue);
  virtual uint64_t emit(MemoryRegion& pRegion);
  virtual Fragment* createEntry(uint64_t pValue, SectionData* pParent);
  virtual size_t getEntrySize() const;
  virtual void reserveHeader();
};

} // namespace of mcld

#endif