| //===- 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 |