//===- 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/LDContext.h" #include "mcld/LD/SectionData.h" #include "mcld/Target/GNULDBackend.h" #include <llvm/ADT/StringRef.h> #include <llvm/ADT/Twine.h> #include <llvm/Support/ELF.h> #include <llvm/Support/Host.h> #include <cstring> 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 (pShndx == llvm::ELF::SHN_ABS && result == ResolveInfo::Section) { // 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. if (pInput.context()->getSection(pShndx) == NULL || 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 (pInput.type() == Input::DynObj) 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 (sect_hdr == NULL) unreachable(diag::unreachable_invalid_section_idx) << pShndx << pInput.path().native(); if (sect_hdr->kind() == LDFileFormat::Ignore) return FragmentRef::Null(); if (sect_hdr->kind() == LDFileFormat::Group) 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 (pInput.type() == Input::Object) { // 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; } } // namespace mcld