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 23using namespace mcld; 24 25//===----------------------------------------------------------------------===// 26// ELFReaderIF 27/// getLDSectionKind 28LDFileFormat::Kind 29ELFReaderIF::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 91ResolveInfo::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 106ResolveInfo::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 131ResolveInfo::Binding 132ELFReaderIF::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 154FragmentRef* 155ELFReaderIF::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 175ResolveInfo::Visibility 176ELFReaderIF::getSymVisibility(uint8_t pVis) const 177{ 178 return static_cast<ResolveInfo::Visibility>(pVis); 179} 180 181/// getSymValue - get the section offset of the symbol. 182uint64_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 207bool 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