Home | History | Annotate | Download | only in LD
      1 //===- ELFReader.cpp ------------------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include <llvm/ADT/StringRef.h>
     11 #include <llvm/ADT/Twine.h>
     12 #include <llvm/Support/ELF.h>
     13 #include <llvm/Support/Host.h>
     14 
     15 #include <mcld/MC/MCLinker.h>
     16 #include <mcld/LD/ELFReader.h>
     17 #include <mcld/Target/GNULDBackend.h>
     18 #include <mcld/Support/MemoryArea.h>
     19 #include <mcld/Support/MemoryRegion.h>
     20 #include <mcld/Support/MsgHandling.h>
     21 #include <cstring>
     22 
     23 using namespace mcld;
     24 
     25 //===----------------------------------------------------------------------===//
     26 // ELFReaderIF
     27 /// getLDSectionKind
     28 LDFileFormat::Kind
     29 ELFReaderIF::getLDSectionKind(uint32_t pType, const char* pName) const
     30 {
     31   // name rules
     32   llvm::StringRef name(pName);
     33   if (name.startswith(".debug") ||
     34       name.startswith(".zdebug") ||
     35       name.startswith(".gnu.linkonce.wi.") ||
     36       name.startswith(".line") ||
     37       name.startswith(".stab"))
     38     return LDFileFormat::Debug;
     39   if (name.startswith(".comment"))
     40     return LDFileFormat::MetaData;
     41   if (name.startswith(".interp") || name.startswith(".dynamic"))
     42     return LDFileFormat::Note;
     43   if (name.startswith(".eh_frame"))
     44     return LDFileFormat::EhFrame;
     45   if (name.startswith(".eh_frame_hdr"))
     46     return LDFileFormat::EhFrameHdr;
     47   if (name.startswith(".gcc_except_table"))
     48     return LDFileFormat::GCCExceptTable;
     49 
     50   // type rules
     51   switch(pType) {
     52   case llvm::ELF::SHT_NULL:
     53     return LDFileFormat::Null;
     54   case llvm::ELF::SHT_INIT_ARRAY:
     55   case llvm::ELF::SHT_FINI_ARRAY:
     56   case llvm::ELF::SHT_PREINIT_ARRAY:
     57   case llvm::ELF::SHT_PROGBITS:
     58     return LDFileFormat::Regular;
     59   case llvm::ELF::SHT_SYMTAB:
     60   case llvm::ELF::SHT_DYNSYM:
     61   case llvm::ELF::SHT_STRTAB:
     62     return LDFileFormat::NamePool;
     63   case llvm::ELF::SHT_RELA:
     64   case llvm::ELF::SHT_REL:
     65     return LDFileFormat::Relocation;
     66   case llvm::ELF::SHT_NOBITS:
     67     return LDFileFormat::BSS;
     68   case llvm::ELF::SHT_DYNAMIC:
     69   case llvm::ELF::SHT_NOTE:
     70     return LDFileFormat::Note;
     71   case llvm::ELF::SHT_HASH:
     72   case llvm::ELF::SHT_SHLIB:
     73     return LDFileFormat::MetaData;
     74   case llvm::ELF::SHT_GROUP:
     75     return LDFileFormat::Group;
     76   case llvm::ELF::SHT_GNU_versym:
     77   case llvm::ELF::SHT_GNU_verdef:
     78   case llvm::ELF::SHT_GNU_verneed:
     79     return LDFileFormat::Version;
     80   default:
     81     if ((pType >= llvm::ELF::SHT_LOPROC && pType <= llvm::ELF::SHT_HIPROC) ||
     82         (pType >= llvm::ELF::SHT_LOOS && pType <= llvm::ELF::SHT_HIOS) ||
     83         (pType >= llvm::ELF::SHT_LOUSER && pType <= llvm::ELF::SHT_HIUSER))
     84       return LDFileFormat::Target;
     85     fatal(diag::err_unsupported_section) << pName << pType;
     86   }
     87   return LDFileFormat::MetaData;
     88 }
     89 
     90 /// getSymType
     91 ResolveInfo::Type ELFReaderIF::getSymType(uint8_t pInfo, uint16_t pShndx) const
     92 {
     93   ResolveInfo::Type result = static_cast<ResolveInfo::Type>(pInfo & 0xF);
     94   if (llvm::ELF::SHN_ABS == pShndx && ResolveInfo::Section == result) {
     95     // In Mips, __gp_disp is a special section symbol. Its name comes from
     96     // .strtab, not .shstrtab. However, it is unique. Only it is also a ABS
     97     // symbol. So here is a tricky to identify __gp_disp and convert it to
     98     // Object symbol.
     99     return ResolveInfo::Object;
    100   }
    101 
    102   return result;
    103 }
    104 
    105 /// getSymDesc
    106 ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx, const Input& pInput) const
    107 {
    108   if (pShndx == llvm::ELF::SHN_UNDEF)
    109     return ResolveInfo::Undefined;
    110 
    111   if (pShndx < llvm::ELF::SHN_LORESERVE) {
    112     // an ELF symbol defined in a section which we are not including
    113     // must be treated as an Undefined.
    114     // @ref Google gold linker: symtab.cc: 1086
    115     if (NULL == pInput.context()->getSection(pShndx))
    116       return ResolveInfo::Undefined;
    117     return ResolveInfo::Define;
    118   }
    119 
    120   if (pShndx == llvm::ELF::SHN_ABS)
    121     return ResolveInfo::Define;
    122 
    123   if (pShndx == llvm::ELF::SHN_COMMON)
    124     return ResolveInfo::Common;
    125 
    126   // FIXME: ELF weak alias should be ResolveInfo::Indirect
    127   return ResolveInfo::NoneDesc;
    128 }
    129 
    130 /// getSymBinding
    131 ResolveInfo::Binding
    132 ELFReaderIF::getSymBinding(uint8_t pBinding, uint16_t pShndx, uint8_t pVis) const
    133 {
    134 
    135   // TODO:
    136   // if --just-symbols option is enabled, the symbol must covert to Absolute
    137 
    138   switch(pBinding) {
    139   case llvm::ELF::STB_LOCAL:
    140     return ResolveInfo::Local;
    141   case llvm::ELF::STB_GLOBAL:
    142     return ResolveInfo::Global;
    143   case llvm::ELF::STB_WEAK:
    144     return ResolveInfo::Weak;
    145   }
    146 
    147   if (pShndx == llvm::ELF::SHN_ABS)
    148     return ResolveInfo::Absolute;
    149 
    150   return ResolveInfo::NoneBinding;
    151 }
    152 
    153 /// getSymFragmentRef
    154 FragmentRef*
    155 ELFReaderIF::getSymFragmentRef(Input& pInput,
    156                                MCLinker& pLinker,
    157                                uint16_t pShndx,
    158                                uint32_t pOffset) const
    159 {
    160 
    161   if (pShndx == llvm::ELF::SHN_UNDEF || pShndx >= llvm::ELF::SHN_LORESERVE)
    162     return NULL;
    163 
    164   LDSection* sect_hdr = pInput.context()->getSection(pShndx);
    165 
    166   if (NULL == sect_hdr)
    167     unreachable(diag::unreachable_invalid_section_idx) << pShndx
    168                                                        << pInput.path().native();
    169 
    170   FragmentRef* result = pLinker.getLayout().getFragmentRef(*sect_hdr, pOffset);
    171   return result;
    172 }
    173 
    174 /// getSymVisibility
    175 ResolveInfo::Visibility
    176 ELFReaderIF::getSymVisibility(uint8_t pVis) const
    177 {
    178   return static_cast<ResolveInfo::Visibility>(pVis);
    179 }
    180 
    181 /// getSymValue - get the section offset of the symbol.
    182 uint64_t ELFReaderIF::getSymValue(uint64_t pValue,
    183                                   uint16_t pShndx,
    184                                   const Input& pInput) const
    185 {
    186   if (Input::Object == pInput.type()) {
    187     // In relocatable files, st_value holds alignment constraints for a symbol
    188     // whose section index is SHN_COMMON
    189     if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) {
    190       return pValue;
    191     }
    192 
    193     // In relocatable files, st_value holds a section offset for a defined symbol.
    194     // TODO:
    195     // if --just-symbols option are enabled, convert the value from section offset
    196     // to virtual address by adding input section's virtual address.
    197     // The section's virtual address in relocatable files is normally zero, but
    198     // people can use link script to change it.
    199     return pValue;
    200   }
    201 
    202   // In executable and shared object files, st_value holds a virtual address.
    203   // the virtual address is useless during linking.
    204   return 0x0;
    205 }
    206 
    207 bool ELFReaderIF::readEhFrame(Input& pInput,
    208                               MCLinker& pLinker,
    209                               LDSection& pInputSectHdr) const
    210 {
    211   LDSection& out_sect = pLinker.getOrCreateOutputSectHdr(pInputSectHdr.name(),
    212                                                          pInputSectHdr.kind(),
    213                                                          pInputSectHdr.type(),
    214                                                          pInputSectHdr.flag());
    215 
    216   size_t size = pLinker.addEhFrame(pInput, pInputSectHdr, *pInput.memArea());
    217 
    218   out_sect.setSize(out_sect.size() + size);
    219   return true;
    220 }
    221