//===- ELFReader.cpp ------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include <mcld/LD/ELFReaderIf.h> #include <mcld/IRBuilder.h> #include <mcld/Fragment/FillFragment.h> #include <mcld/LD/EhFrame.h> #include <mcld/LD/SectionData.h> #include <mcld/Target/GNULDBackend.h> //#include <mcld/Support/MemoryArea.h> //#include <mcld/Support/MemoryRegion.h> //#include <mcld/Support/MsgHandling.h> //#include <mcld/Object/ObjectBuilder.h> #include <cstring> #include <llvm/ADT/StringRef.h> #include <llvm/ADT/Twine.h> #include <llvm/Support/ELF.h> #include <llvm/Support/Host.h> using namespace mcld; //===----------------------------------------------------------------------===// // ELFReaderIF //===----------------------------------------------------------------------===// /// getSymType ResolveInfo::Type ELFReaderIF::getSymType(uint8_t pInfo, uint16_t pShndx) const { ResolveInfo::Type result = static_cast<ResolveInfo::Type>(pInfo & 0xF); if (llvm::ELF::SHN_ABS == pShndx && ResolveInfo::Section == result) { // In Mips, __gp_disp is a special section symbol. Its name comes from // .strtab, not .shstrtab. However, it is unique. Only it is also a ABS // symbol. So here is a tricky to identify __gp_disp and convert it to // Object symbol. return ResolveInfo::Object; } return result; } /// getSymDesc ResolveInfo::Desc ELFReaderIF::getSymDesc(uint16_t pShndx, const Input& pInput) const { if (pShndx == llvm::ELF::SHN_UNDEF) return ResolveInfo::Undefined; if (pShndx < llvm::ELF::SHN_LORESERVE) { // an ELF symbol defined in a section which we are not including // must be treated as an Undefined. // @ref Google gold linker: symtab.cc: 1086 if (NULL == pInput.context()->getSection(pShndx) || LDFileFormat::Ignore == pInput.context()->getSection(pShndx)->kind()) return ResolveInfo::Undefined; return ResolveInfo::Define; } if (pShndx == llvm::ELF::SHN_ABS) return ResolveInfo::Define; if (pShndx == llvm::ELF::SHN_COMMON) return ResolveInfo::Common; if (pShndx >= llvm::ELF::SHN_LOPROC && pShndx <= llvm::ELF::SHN_HIPROC) return target().getSymDesc(pShndx); // FIXME: ELF weak alias should be ResolveInfo::Indirect return ResolveInfo::NoneDesc; } /// getSymBinding ResolveInfo::Binding ELFReaderIF::getSymBinding(uint8_t pBinding, uint16_t pShndx, uint8_t pVis) const { // TODO: // if --just-symbols option is enabled, the symbol must covert to Absolute switch(pBinding) { case llvm::ELF::STB_LOCAL: return ResolveInfo::Local; case llvm::ELF::STB_GLOBAL: if (pShndx == llvm::ELF::SHN_ABS) return ResolveInfo::Absolute; return ResolveInfo::Global; case llvm::ELF::STB_WEAK: return ResolveInfo::Weak; } return ResolveInfo::NoneBinding; } /// getSymFragmentRef FragmentRef* ELFReaderIF::getSymFragmentRef(Input& pInput, uint16_t pShndx, uint32_t pOffset) const { if (Input::DynObj == pInput.type()) return FragmentRef::Null(); if (pShndx == llvm::ELF::SHN_UNDEF) return FragmentRef::Null(); if (pShndx >= llvm::ELF::SHN_LORESERVE) // including ABS and COMMON return FragmentRef::Null(); LDSection* sect_hdr = pInput.context()->getSection(pShndx); if (NULL == sect_hdr) unreachable(diag::unreachable_invalid_section_idx) << pShndx << pInput.path().native(); if (LDFileFormat::Ignore == sect_hdr->kind()) return FragmentRef::Null(); if (LDFileFormat::Group == sect_hdr->kind()) return FragmentRef::Null(); return FragmentRef::Create(*sect_hdr, pOffset); } /// getSymVisibility ResolveInfo::Visibility ELFReaderIF::getSymVisibility(uint8_t pVis) const { return static_cast<ResolveInfo::Visibility>(pVis); } /// getSymValue - get the section offset of the symbol. uint64_t ELFReaderIF::getSymValue(uint64_t pValue, uint16_t pShndx, const Input& pInput) const { if (Input::Object == pInput.type()) { // In relocatable files, st_value holds alignment constraints for a symbol // whose section index is SHN_COMMON if (pShndx == llvm::ELF::SHN_COMMON || pShndx == llvm::ELF::SHN_ABS) { return pValue; } // In relocatable files, st_value holds a section offset for a defined symbol. // TODO: // if --just-symbols option are enabled, convert the value from section offset // to virtual address by adding input section's virtual address. // The section's virtual address in relocatable files is normally zero, but // people can use link script to change it. return pValue; } // In executable and shared object files, st_value holds a virtual address. // the virtual address is needed for alias identification. return pValue; }