You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
5.0 KiB
155 lines
5.0 KiB
//===- 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
|