//===- 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/ELFReader.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/Object/ObjectBuilder.h" #include "mcld/Support/MemoryArea.h" #include "mcld/Support/MsgHandling.h" #include "mcld/Target/GNUInfo.h" #include "mcld/Target/GNULDBackend.h" #include #include #include #include #include #include namespace mcld { //===----------------------------------------------------------------------===// // ELFReader<32, true> //===----------------------------------------------------------------------===// /// constructor ELFReader<32, true>::ELFReader(GNULDBackend& pBackend) : ELFReaderIF(pBackend) { } /// destructor ELFReader<32, true>::~ELFReader() { } /// isELF - is this a ELF file bool ELFReader<32, true>::isELF(const void* pELFHeader) const { const llvm::ELF::Elf32_Ehdr* hdr = reinterpret_cast(pELFHeader); if (memcmp(llvm::ELF::ElfMagic, hdr, 4) == 0) return true; return false; } /// readRegularSection - read a regular section and create fragments. bool ELFReader<32, true>::readRegularSection(Input& pInput, SectionData& pSD) const { uint32_t offset = pInput.fileOffset() + pSD.getSection().offset(); uint32_t size = pSD.getSection().size(); Fragment* frag = IRBuilder::CreateRegion(pInput, offset, size); ObjectBuilder::AppendFragment(*frag, pSD); return true; } /// readSymbols - read ELF symbols and create LDSymbol bool ELFReader<32, true>::readSymbols(Input& pInput, IRBuilder& pBuilder, llvm::StringRef pRegion, const char* pStrTab) const { // get number of symbols size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Sym); const llvm::ELF::Elf32_Sym* symtab = reinterpret_cast(pRegion.begin()); uint32_t st_name = 0x0; uint32_t st_value = 0x0; uint32_t st_size = 0x0; uint8_t st_info = 0x0; uint8_t st_other = 0x0; uint16_t st_shndx = 0x0; // skip the first NULL symbol pInput.context()->addSymbol(LDSymbol::Null()); /// recording symbols added from DynObj to analyze weak alias std::vector potential_aliases; bool is_dyn_obj = (pInput.type() == Input::DynObj); for (size_t idx = 1; idx < entsize; ++idx) { st_info = symtab[idx].st_info; st_other = symtab[idx].st_other; if (llvm::sys::IsLittleEndianHost) { st_name = symtab[idx].st_name; st_value = symtab[idx].st_value; st_size = symtab[idx].st_size; st_shndx = symtab[idx].st_shndx; } else { st_name = mcld::bswap32(symtab[idx].st_name); st_value = mcld::bswap32(symtab[idx].st_value); st_size = mcld::bswap32(symtab[idx].st_size); st_shndx = mcld::bswap16(symtab[idx].st_shndx); } // If the section should not be included, set the st_shndx SHN_UNDEF // - A section in interrelated groups are not included. if (pInput.type() == Input::Object && st_shndx < llvm::ELF::SHN_LORESERVE && st_shndx != llvm::ELF::SHN_UNDEF) { if (pInput.context()->getSection(st_shndx) == NULL) st_shndx = llvm::ELF::SHN_UNDEF; } // get ld_type ResolveInfo::Type ld_type = getSymType(st_info, st_shndx); // get ld_desc ResolveInfo::Desc ld_desc = getSymDesc(st_shndx, pInput); // get ld_binding ResolveInfo::Binding ld_binding = getSymBinding((st_info >> 4), st_shndx, st_other); // get ld_value - ld_value must be section relative. uint64_t ld_value = getSymValue(st_value, st_shndx, pInput); // get ld_vis ResolveInfo::Visibility ld_vis = getSymVisibility(st_other); // get section LDSection* section = NULL; if (st_shndx < llvm::ELF::SHN_LORESERVE) // including ABS and COMMON section = pInput.context()->getSection(st_shndx); // get ld_name std::string ld_name; if (ResolveInfo::Section == ld_type) { // Section symbol's st_name is the section index. assert(section != NULL && "get a invalid section"); ld_name = section->name(); } else { ld_name = std::string(pStrTab + st_name); } LDSymbol* psym = pBuilder.AddSymbol(pInput, ld_name, ld_type, ld_desc, ld_binding, st_size, ld_value, section, ld_vis); if (is_dyn_obj && psym != NULL && ResolveInfo::Undefined != ld_desc && (ResolveInfo::Global == ld_binding || ResolveInfo::Weak == ld_binding) && ResolveInfo::Object == ld_type) { AliasInfo p; p.pt_alias = psym; p.ld_binding = ld_binding; p.ld_value = ld_value; potential_aliases.push_back(p); } } // end of for loop // analyze weak alias // FIXME: it is better to let IRBuilder handle alias anlysis. // 1. eliminate code duplication // 2. easy to know if a symbol is from .so // (so that it may be a potential alias) if (is_dyn_obj) { // sort symbols by symbol value and then weak before strong std::sort(potential_aliases.begin(), potential_aliases.end(), less); // for each weak symbol, find out all its aliases, and // then link them as a circular list in Module std::vector::iterator sym_it, sym_e; sym_e = potential_aliases.end(); for (sym_it = potential_aliases.begin(); sym_it != sym_e; ++sym_it) { if (ResolveInfo::Weak != sym_it->ld_binding) continue; Module& pModule = pBuilder.getModule(); std::vector::iterator alias_it = sym_it + 1; while (alias_it != sym_e) { if (sym_it->ld_value != alias_it->ld_value) break; if (sym_it + 1 == alias_it) pModule.CreateAliasList(*sym_it->pt_alias->resolveInfo()); pModule.addAlias(*alias_it->pt_alias->resolveInfo()); ++alias_it; } sym_it = alias_it - 1; } // end of for loop } return true; } //===----------------------------------------------------------------------===// // ELFReader::read relocations - read ELF rela and rel, and create Relocation //===----------------------------------------------------------------------===// /// ELFReader::readRela - read ELF rela and create Relocation bool ELFReader<32, true>::readRela(Input& pInput, LDSection& pSection, llvm::StringRef pRegion) const { // get the number of rela size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rela); const llvm::ELF::Elf32_Rela* relaTab = reinterpret_cast(pRegion.begin()); for (size_t idx = 0; idx < entsize; ++idx) { Relocation::Type r_type = 0x0; uint32_t r_sym = 0x0; uint32_t r_offset = 0x0; int32_t r_addend = 0; if (!target() .readRelocation(relaTab[idx], r_type, r_sym, r_offset, r_addend)) { return false; } LDSymbol* symbol = pInput.context()->getSymbol(r_sym); if (symbol == NULL) { fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path(); } IRBuilder::AddRelocation(pSection, r_type, *symbol, r_offset, r_addend); } // end of for return true; } /// readRel - read ELF rel and create Relocation bool ELFReader<32, true>::readRel(Input& pInput, LDSection& pSection, llvm::StringRef pRegion) const { // get the number of rel size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf32_Rel); const llvm::ELF::Elf32_Rel* relTab = reinterpret_cast(pRegion.begin()); for (size_t idx = 0; idx < entsize; ++idx) { Relocation::Type r_type = 0x0; uint32_t r_sym = 0x0; uint32_t r_offset = 0x0; if (!target().readRelocation(relTab[idx], r_type, r_sym, r_offset)) return false; LDSymbol* symbol = pInput.context()->getSymbol(r_sym); if (symbol == NULL) { fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path(); } IRBuilder::AddRelocation(pSection, r_type, *symbol, r_offset); } // end of for return true; } /// isMyEndian - is this ELF file in the same endian to me? bool ELFReader<32, true>::isMyEndian(const void* pELFHeader) const { const llvm::ELF::Elf32_Ehdr* hdr = reinterpret_cast(pELFHeader); return (hdr->e_ident[llvm::ELF::EI_DATA] == llvm::ELF::ELFDATA2LSB); } /// isMyMachine - is this ELF file generated for the same machine. bool ELFReader<32, true>::isMyMachine(const void* pELFHeader) const { const llvm::ELF::Elf32_Ehdr* hdr = reinterpret_cast(pELFHeader); if (llvm::sys::IsLittleEndianHost) return (hdr->e_machine == target().getInfo().machine()); return (mcld::bswap16(hdr->e_machine) == target().getInfo().machine()); } /// fileType - return the file type Input::Type ELFReader<32, true>::fileType(const void* pELFHeader) const { const llvm::ELF::Elf32_Ehdr* hdr = reinterpret_cast(pELFHeader); uint32_t type = 0x0; if (llvm::sys::IsLittleEndianHost) type = hdr->e_type; else type = mcld::bswap16(hdr->e_type); switch (type) { case llvm::ELF::ET_REL: return Input::Object; case llvm::ELF::ET_EXEC: return Input::Exec; case llvm::ELF::ET_DYN: return Input::DynObj; case llvm::ELF::ET_CORE: return Input::CoreFile; case llvm::ELF::ET_NONE: default: return Input::Unknown; } } /// readSectionHeaders - read ELF section header table and create LDSections bool ELFReader<32, true>::readSectionHeaders(Input& pInput, const void* pELFHeader) const { const llvm::ELF::Elf32_Ehdr* ehdr = reinterpret_cast(pELFHeader); uint32_t shoff = 0x0; uint16_t shentsize = 0x0; uint32_t shnum = 0x0; uint32_t shstrtab = 0x0; if (llvm::sys::IsLittleEndianHost) { shoff = ehdr->e_shoff; shentsize = ehdr->e_shentsize; shnum = ehdr->e_shnum; shstrtab = ehdr->e_shstrndx; } else { shoff = mcld::bswap32(ehdr->e_shoff); shentsize = mcld::bswap16(ehdr->e_shentsize); shnum = mcld::bswap16(ehdr->e_shnum); shstrtab = mcld::bswap16(ehdr->e_shstrndx); } // If the file has no section header table, e_shoff holds zero. if (shoff == 0x0) return true; const llvm::ELF::Elf32_Shdr* shdr = NULL; llvm::StringRef shdr_region; uint32_t sh_name = 0x0; uint32_t sh_type = 0x0; uint32_t sh_flags = 0x0; uint32_t sh_offset = 0x0; uint32_t sh_size = 0x0; uint32_t sh_link = 0x0; uint32_t sh_info = 0x0; uint32_t sh_addralign = 0x0; // if shnum and shstrtab overflow, the actual values are in the 1st shdr if (shnum == llvm::ELF::SHN_UNDEF || shstrtab == llvm::ELF::SHN_XINDEX) { shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff, shentsize); shdr = reinterpret_cast(shdr_region.begin()); if (llvm::sys::IsLittleEndianHost) { sh_size = shdr->sh_size; sh_link = shdr->sh_link; } else { sh_size = mcld::bswap32(shdr->sh_size); sh_link = mcld::bswap32(shdr->sh_link); } if (shnum == llvm::ELF::SHN_UNDEF) shnum = sh_size; if (shstrtab == llvm::ELF::SHN_XINDEX) shstrtab = sh_link; shoff += shentsize; } shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff, shnum * shentsize); const llvm::ELF::Elf32_Shdr* shdrTab = reinterpret_cast(shdr_region.begin()); // get .shstrtab first shdr = &shdrTab[shstrtab]; if (llvm::sys::IsLittleEndianHost) { sh_offset = shdr->sh_offset; sh_size = shdr->sh_size; } else { sh_offset = mcld::bswap32(shdr->sh_offset); sh_size = mcld::bswap32(shdr->sh_size); } llvm::StringRef sect_name_region = pInput.memArea()->request(pInput.fileOffset() + sh_offset, sh_size); const char* sect_name = sect_name_region.begin(); LinkInfoList link_info_list; // create all LDSections, including first NULL section. for (size_t idx = 0; idx < shnum; ++idx) { if (llvm::sys::IsLittleEndianHost) { sh_name = shdrTab[idx].sh_name; sh_type = shdrTab[idx].sh_type; sh_flags = shdrTab[idx].sh_flags; sh_offset = shdrTab[idx].sh_offset; sh_size = shdrTab[idx].sh_size; sh_link = shdrTab[idx].sh_link; sh_info = shdrTab[idx].sh_info; sh_addralign = shdrTab[idx].sh_addralign; } else { sh_name = mcld::bswap32(shdrTab[idx].sh_name); sh_type = mcld::bswap32(shdrTab[idx].sh_type); sh_flags = mcld::bswap32(shdrTab[idx].sh_flags); sh_offset = mcld::bswap32(shdrTab[idx].sh_offset); sh_size = mcld::bswap32(shdrTab[idx].sh_size); sh_link = mcld::bswap32(shdrTab[idx].sh_link); sh_info = mcld::bswap32(shdrTab[idx].sh_info); sh_addralign = mcld::bswap32(shdrTab[idx].sh_addralign); } LDSection* section = IRBuilder::CreateELFHeader( pInput, sect_name + sh_name, sh_type, sh_flags, sh_addralign); section->setSize(sh_size); section->setOffset(sh_offset); section->setInfo(sh_info); if (sh_link != 0x0 || sh_info != 0x0) { LinkInfo link_info = {section, sh_link, sh_info}; link_info_list.push_back(link_info); } } // end of for // set up InfoLink LinkInfoList::iterator info, infoEnd = link_info_list.end(); for (info = link_info_list.begin(); info != infoEnd; ++info) { if (LDFileFormat::Relocation == info->section->kind()) info->section->setLink(pInput.context()->getSection(info->sh_info)); else info->section->setLink(pInput.context()->getSection(info->sh_link)); } return true; } /// readSignature - read a symbol from the given Input and index in symtab /// This is used to get the signature of a group section. ResolveInfo* ELFReader<32, true>::readSignature(Input& pInput, LDSection& pSymTab, uint32_t pSymIdx) const { LDSection* symtab = &pSymTab; LDSection* strtab = symtab->getLink(); assert(symtab != NULL && strtab != NULL); uint32_t offset = pInput.fileOffset() + symtab->offset() + sizeof(llvm::ELF::Elf32_Sym) * pSymIdx; llvm::StringRef symbol_region = pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf32_Sym)); const llvm::ELF::Elf32_Sym* entry = reinterpret_cast(symbol_region.begin()); uint32_t st_name = 0x0; uint8_t st_info = 0x0; uint8_t st_other = 0x0; uint16_t st_shndx = 0x0; st_info = entry->st_info; st_other = entry->st_other; if (llvm::sys::IsLittleEndianHost) { st_name = entry->st_name; st_shndx = entry->st_shndx; } else { st_name = mcld::bswap32(entry->st_name); st_shndx = mcld::bswap16(entry->st_shndx); } llvm::StringRef strtab_region = pInput.memArea()->request( pInput.fileOffset() + strtab->offset(), strtab->size()); // get ld_name llvm::StringRef ld_name(strtab_region.begin() + st_name); ResolveInfo* result = ResolveInfo::Create(ld_name); result->setSource(pInput.type() == Input::DynObj); result->setType(static_cast(st_info & 0xF)); result->setDesc(getSymDesc(st_shndx, pInput)); result->setBinding(getSymBinding((st_info >> 4), st_shndx, st_other)); result->setVisibility(getSymVisibility(st_other)); return result; } /// readDynamic - read ELF .dynamic in input dynobj bool ELFReader<32, true>::readDynamic(Input& pInput) const { assert(pInput.type() == Input::DynObj); const LDSection* dynamic_sect = pInput.context()->getSection(".dynamic"); if (dynamic_sect == NULL) { fatal(diag::err_cannot_read_section) << ".dynamic"; } const LDSection* dynstr_sect = dynamic_sect->getLink(); if (dynstr_sect == NULL) { fatal(diag::err_cannot_read_section) << ".dynstr"; } llvm::StringRef dynamic_region = pInput.memArea()->request( pInput.fileOffset() + dynamic_sect->offset(), dynamic_sect->size()); llvm::StringRef dynstr_region = pInput.memArea()->request( pInput.fileOffset() + dynstr_sect->offset(), dynstr_sect->size()); const llvm::ELF::Elf32_Dyn* dynamic = reinterpret_cast(dynamic_region.begin()); const char* dynstr = dynstr_region.begin(); bool hasSOName = false; size_t numOfEntries = dynamic_sect->size() / sizeof(llvm::ELF::Elf32_Dyn); for (size_t idx = 0; idx < numOfEntries; ++idx) { llvm::ELF::Elf32_Sword d_tag = 0x0; llvm::ELF::Elf32_Word d_val = 0x0; if (llvm::sys::IsLittleEndianHost) { d_tag = dynamic[idx].d_tag; d_val = dynamic[idx].d_un.d_val; } else { d_tag = mcld::bswap32(dynamic[idx].d_tag); d_val = mcld::bswap32(dynamic[idx].d_un.d_val); } switch (d_tag) { case llvm::ELF::DT_SONAME: assert(d_val < dynstr_sect->size()); pInput.setName(sys::fs::Path(dynstr + d_val).filename().native()); hasSOName = true; break; case llvm::ELF::DT_NEEDED: // TODO: break; case llvm::ELF::DT_NULL: default: break; } } // if there is no SONAME in .dynamic, then set it from input path if (!hasSOName) pInput.setName(pInput.path().filename().native()); return true; } //===----------------------------------------------------------------------===// // ELFReader<64, true> //===----------------------------------------------------------------------===// /// constructor ELFReader<64, true>::ELFReader(GNULDBackend& pBackend) : ELFReaderIF(pBackend) { } /// destructor ELFReader<64, true>::~ELFReader() { } /// isELF - is this a ELF file bool ELFReader<64, true>::isELF(const void* pELFHeader) const { const llvm::ELF::Elf64_Ehdr* hdr = reinterpret_cast(pELFHeader); if (memcmp(llvm::ELF::ElfMagic, hdr, 4) == 0) return true; return false; } /// readRegularSection - read a regular section and create fragments. bool ELFReader<64, true>::readRegularSection(Input& pInput, SectionData& pSD) const { uint64_t offset = pInput.fileOffset() + pSD.getSection().offset(); uint64_t size = pSD.getSection().size(); Fragment* frag = IRBuilder::CreateRegion(pInput, offset, size); ObjectBuilder::AppendFragment(*frag, pSD); return true; } /// readSymbols - read ELF symbols and create LDSymbol bool ELFReader<64, true>::readSymbols(Input& pInput, IRBuilder& pBuilder, llvm::StringRef pRegion, const char* pStrTab) const { // get number of symbols size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Sym); const llvm::ELF::Elf64_Sym* symtab = reinterpret_cast(pRegion.begin()); uint32_t st_name = 0x0; uint64_t st_value = 0x0; uint64_t st_size = 0x0; uint8_t st_info = 0x0; uint8_t st_other = 0x0; uint16_t st_shndx = 0x0; // skip the first NULL symbol pInput.context()->addSymbol(LDSymbol::Null()); /// recording symbols added from DynObj to analyze weak alias std::vector potential_aliases; bool is_dyn_obj = (pInput.type() == Input::DynObj); for (size_t idx = 1; idx < entsize; ++idx) { st_info = symtab[idx].st_info; st_other = symtab[idx].st_other; if (llvm::sys::IsLittleEndianHost) { st_name = symtab[idx].st_name; st_value = symtab[idx].st_value; st_size = symtab[idx].st_size; st_shndx = symtab[idx].st_shndx; } else { st_name = mcld::bswap32(symtab[idx].st_name); st_value = mcld::bswap64(symtab[idx].st_value); st_size = mcld::bswap64(symtab[idx].st_size); st_shndx = mcld::bswap16(symtab[idx].st_shndx); } // If the section should not be included, set the st_shndx SHN_UNDEF // - A section in interrelated groups are not included. if (pInput.type() == Input::Object && st_shndx < llvm::ELF::SHN_LORESERVE && st_shndx != llvm::ELF::SHN_UNDEF) { if (pInput.context()->getSection(st_shndx) == NULL) st_shndx = llvm::ELF::SHN_UNDEF; } // get ld_type ResolveInfo::Type ld_type = getSymType(st_info, st_shndx); // get ld_desc ResolveInfo::Desc ld_desc = getSymDesc(st_shndx, pInput); // get ld_binding ResolveInfo::Binding ld_binding = getSymBinding((st_info >> 4), st_shndx, st_other); // get ld_value - ld_value must be section relative. uint64_t ld_value = getSymValue(st_value, st_shndx, pInput); // get ld_vis ResolveInfo::Visibility ld_vis = getSymVisibility(st_other); // get section LDSection* section = NULL; if (st_shndx < llvm::ELF::SHN_LORESERVE) // including ABS and COMMON section = pInput.context()->getSection(st_shndx); // get ld_name std::string ld_name; if (ResolveInfo::Section == ld_type) { // Section symbol's st_name is the section index. assert(section != NULL && "get a invalid section"); ld_name = section->name(); } else { ld_name = std::string(pStrTab + st_name); } LDSymbol* psym = pBuilder.AddSymbol(pInput, ld_name, ld_type, ld_desc, ld_binding, st_size, ld_value, section, ld_vis); if (is_dyn_obj && psym != NULL && ResolveInfo::Undefined != ld_desc && (ResolveInfo::Global == ld_binding || ResolveInfo::Weak == ld_binding) && ResolveInfo::Object == ld_type) { AliasInfo p; p.pt_alias = psym; p.ld_binding = ld_binding; p.ld_value = ld_value; potential_aliases.push_back(p); } } // end of for loop // analyze weak alias here if (is_dyn_obj) { // sort symbols by symbol value and then weak before strong std::sort(potential_aliases.begin(), potential_aliases.end(), less); // for each weak symbol, find out all its aliases, and // then link them as a circular list in Module std::vector::iterator sym_it, sym_e; sym_e = potential_aliases.end(); for (sym_it = potential_aliases.begin(); sym_it != sym_e; ++sym_it) { if (ResolveInfo::Weak != sym_it->ld_binding) continue; Module& pModule = pBuilder.getModule(); std::vector::iterator alias_it = sym_it + 1; while (alias_it != sym_e) { if (sym_it->ld_value != alias_it->ld_value) break; if (sym_it + 1 == alias_it) pModule.CreateAliasList(*sym_it->pt_alias->resolveInfo()); pModule.addAlias(*alias_it->pt_alias->resolveInfo()); ++alias_it; } sym_it = alias_it - 1; } // end of for loop } return true; } //===----------------------------------------------------------------------===// // ELFReader::read relocations - read ELF rela and rel, and create Relocation //===----------------------------------------------------------------------===// /// ELFReader::readRela - read ELF rela and create Relocation bool ELFReader<64, true>::readRela(Input& pInput, LDSection& pSection, llvm::StringRef pRegion) const { // get the number of rela size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Rela); const llvm::ELF::Elf64_Rela* relaTab = reinterpret_cast(pRegion.begin()); for (size_t idx = 0; idx < entsize; ++idx) { Relocation::Type r_type = 0x0; uint32_t r_sym = 0x0; uint64_t r_offset = 0x0; int64_t r_addend = 0; if (!target() .readRelocation(relaTab[idx], r_type, r_sym, r_offset, r_addend)) { return false; } LDSymbol* symbol = pInput.context()->getSymbol(r_sym); if (symbol == NULL) { fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path(); } IRBuilder::AddRelocation(pSection, r_type, *symbol, r_offset, r_addend); } // end of for return true; } /// readRel - read ELF rel and create Relocation bool ELFReader<64, true>::readRel(Input& pInput, LDSection& pSection, llvm::StringRef pRegion) const { // get the number of rel size_t entsize = pRegion.size() / sizeof(llvm::ELF::Elf64_Rel); const llvm::ELF::Elf64_Rel* relTab = reinterpret_cast(pRegion.begin()); for (size_t idx = 0; idx < entsize; ++idx) { Relocation::Type r_type = 0x0; uint32_t r_sym = 0x0; uint64_t r_offset = 0x0; if (!target().readRelocation(relTab[idx], r_type, r_sym, r_offset)) return false; LDSymbol* symbol = pInput.context()->getSymbol(r_sym); if (symbol == NULL) { fatal(diag::err_cannot_read_symbol) << r_sym << pInput.path(); } IRBuilder::AddRelocation(pSection, r_type, *symbol, r_offset); } // end of for return true; } /// isMyEndian - is this ELF file in the same endian to me? bool ELFReader<64, true>::isMyEndian(const void* pELFHeader) const { const llvm::ELF::Elf64_Ehdr* hdr = reinterpret_cast(pELFHeader); return (hdr->e_ident[llvm::ELF::EI_DATA] == llvm::ELF::ELFDATA2LSB); } /// isMyMachine - is this ELF file generated for the same machine. bool ELFReader<64, true>::isMyMachine(const void* pELFHeader) const { const llvm::ELF::Elf64_Ehdr* hdr = reinterpret_cast(pELFHeader); if (llvm::sys::IsLittleEndianHost) return (hdr->e_machine == target().getInfo().machine()); return (mcld::bswap16(hdr->e_machine) == target().getInfo().machine()); } /// fileType - return the file type Input::Type ELFReader<64, true>::fileType(const void* pELFHeader) const { const llvm::ELF::Elf64_Ehdr* hdr = reinterpret_cast(pELFHeader); uint32_t type = 0x0; if (llvm::sys::IsLittleEndianHost) type = hdr->e_type; else type = mcld::bswap16(hdr->e_type); switch (type) { case llvm::ELF::ET_REL: return Input::Object; case llvm::ELF::ET_EXEC: return Input::Exec; case llvm::ELF::ET_DYN: return Input::DynObj; case llvm::ELF::ET_CORE: return Input::CoreFile; case llvm::ELF::ET_NONE: default: return Input::Unknown; } } /// readSectionHeaders - read ELF section header table and create LDSections bool ELFReader<64, true>::readSectionHeaders(Input& pInput, const void* pELFHeader) const { const llvm::ELF::Elf64_Ehdr* ehdr = reinterpret_cast(pELFHeader); uint64_t shoff = 0x0; uint16_t shentsize = 0x0; uint32_t shnum = 0x0; uint32_t shstrtab = 0x0; if (llvm::sys::IsLittleEndianHost) { shoff = ehdr->e_shoff; shentsize = ehdr->e_shentsize; shnum = ehdr->e_shnum; shstrtab = ehdr->e_shstrndx; } else { shoff = mcld::bswap64(ehdr->e_shoff); shentsize = mcld::bswap16(ehdr->e_shentsize); shnum = mcld::bswap16(ehdr->e_shnum); shstrtab = mcld::bswap16(ehdr->e_shstrndx); } // If the file has no section header table, e_shoff holds zero. if (shoff == 0x0) return true; const llvm::ELF::Elf64_Shdr* shdr = NULL; llvm::StringRef shdr_region; uint32_t sh_name = 0x0; uint32_t sh_type = 0x0; uint64_t sh_flags = 0x0; uint64_t sh_offset = 0x0; uint64_t sh_size = 0x0; uint32_t sh_link = 0x0; uint32_t sh_info = 0x0; uint64_t sh_addralign = 0x0; // if shnum and shstrtab overflow, the actual values are in the 1st shdr if (shnum == llvm::ELF::SHN_UNDEF || shstrtab == llvm::ELF::SHN_XINDEX) { shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff, shentsize); shdr = reinterpret_cast(shdr_region.begin()); if (llvm::sys::IsLittleEndianHost) { sh_size = shdr->sh_size; sh_link = shdr->sh_link; } else { sh_size = mcld::bswap64(shdr->sh_size); sh_link = mcld::bswap32(shdr->sh_link); } if (shnum == llvm::ELF::SHN_UNDEF) shnum = sh_size; if (shstrtab == llvm::ELF::SHN_XINDEX) shstrtab = sh_link; shoff += shentsize; } shdr_region = pInput.memArea()->request(pInput.fileOffset() + shoff, shnum * shentsize); const llvm::ELF::Elf64_Shdr* shdrTab = reinterpret_cast(shdr_region.begin()); // get .shstrtab first shdr = &shdrTab[shstrtab]; if (llvm::sys::IsLittleEndianHost) { sh_offset = shdr->sh_offset; sh_size = shdr->sh_size; } else { sh_offset = mcld::bswap64(shdr->sh_offset); sh_size = mcld::bswap64(shdr->sh_size); } llvm::StringRef sect_name_region = pInput.memArea()->request(pInput.fileOffset() + sh_offset, sh_size); const char* sect_name = sect_name_region.begin(); LinkInfoList link_info_list; // create all LDSections, including first NULL section. for (size_t idx = 0; idx < shnum; ++idx) { if (llvm::sys::IsLittleEndianHost) { sh_name = shdrTab[idx].sh_name; sh_type = shdrTab[idx].sh_type; sh_flags = shdrTab[idx].sh_flags; sh_offset = shdrTab[idx].sh_offset; sh_size = shdrTab[idx].sh_size; sh_link = shdrTab[idx].sh_link; sh_info = shdrTab[idx].sh_info; sh_addralign = shdrTab[idx].sh_addralign; } else { sh_name = mcld::bswap32(shdrTab[idx].sh_name); sh_type = mcld::bswap32(shdrTab[idx].sh_type); sh_flags = mcld::bswap64(shdrTab[idx].sh_flags); sh_offset = mcld::bswap64(shdrTab[idx].sh_offset); sh_size = mcld::bswap64(shdrTab[idx].sh_size); sh_link = mcld::bswap32(shdrTab[idx].sh_link); sh_info = mcld::bswap32(shdrTab[idx].sh_info); sh_addralign = mcld::bswap64(shdrTab[idx].sh_addralign); } LDSection* section = IRBuilder::CreateELFHeader( pInput, sect_name + sh_name, sh_type, sh_flags, sh_addralign); section->setSize(sh_size); section->setOffset(sh_offset); section->setInfo(sh_info); if (sh_link != 0x0 || sh_info != 0x0) { LinkInfo link_info = {section, sh_link, sh_info}; link_info_list.push_back(link_info); } } // end of for // set up InfoLink LinkInfoList::iterator info, infoEnd = link_info_list.end(); for (info = link_info_list.begin(); info != infoEnd; ++info) { if (LDFileFormat::Relocation == info->section->kind()) info->section->setLink(pInput.context()->getSection(info->sh_info)); else info->section->setLink(pInput.context()->getSection(info->sh_link)); } return true; } /// readSignature - read a symbol from the given Input and index in symtab /// This is used to get the signature of a group section. ResolveInfo* ELFReader<64, true>::readSignature(Input& pInput, LDSection& pSymTab, uint32_t pSymIdx) const { LDSection* symtab = &pSymTab; LDSection* strtab = symtab->getLink(); assert(symtab != NULL && strtab != NULL); uint64_t offset = pInput.fileOffset() + symtab->offset() + sizeof(llvm::ELF::Elf64_Sym) * pSymIdx; llvm::StringRef symbol_region = pInput.memArea()->request(offset, sizeof(llvm::ELF::Elf64_Sym)); const llvm::ELF::Elf64_Sym* entry = reinterpret_cast(symbol_region.begin()); uint32_t st_name = 0x0; uint8_t st_info = 0x0; uint8_t st_other = 0x0; uint16_t st_shndx = 0x0; st_info = entry->st_info; st_other = entry->st_other; if (llvm::sys::IsLittleEndianHost) { st_name = entry->st_name; st_shndx = entry->st_shndx; } else { st_name = mcld::bswap32(entry->st_name); st_shndx = mcld::bswap16(entry->st_shndx); } llvm::StringRef strtab_region = pInput.memArea()->request( pInput.fileOffset() + strtab->offset(), strtab->size()); // get ld_name llvm::StringRef ld_name(strtab_region.begin() + st_name); ResolveInfo* result = ResolveInfo::Create(ld_name); result->setSource(pInput.type() == Input::DynObj); result->setType(static_cast(st_info & 0xF)); result->setDesc(getSymDesc(st_shndx, pInput)); result->setBinding(getSymBinding((st_info >> 4), st_shndx, st_other)); result->setVisibility(getSymVisibility(st_other)); return result; } /// readDynamic - read ELF .dynamic in input dynobj bool ELFReader<64, true>::readDynamic(Input& pInput) const { assert(pInput.type() == Input::DynObj); const LDSection* dynamic_sect = pInput.context()->getSection(".dynamic"); if (dynamic_sect == NULL) { fatal(diag::err_cannot_read_section) << ".dynamic"; } const LDSection* dynstr_sect = dynamic_sect->getLink(); if (dynstr_sect == NULL) { fatal(diag::err_cannot_read_section) << ".dynstr"; } llvm::StringRef dynamic_region = pInput.memArea()->request( pInput.fileOffset() + dynamic_sect->offset(), dynamic_sect->size()); llvm::StringRef dynstr_region = pInput.memArea()->request( pInput.fileOffset() + dynstr_sect->offset(), dynstr_sect->size()); const llvm::ELF::Elf64_Dyn* dynamic = reinterpret_cast(dynamic_region.begin()); const char* dynstr = dynstr_region.begin(); bool hasSOName = false; size_t numOfEntries = dynamic_sect->size() / sizeof(llvm::ELF::Elf64_Dyn); for (size_t idx = 0; idx < numOfEntries; ++idx) { llvm::ELF::Elf64_Sxword d_tag = 0x0; llvm::ELF::Elf64_Xword d_val = 0x0; if (llvm::sys::IsLittleEndianHost) { d_tag = dynamic[idx].d_tag; d_val = dynamic[idx].d_un.d_val; } else { d_tag = mcld::bswap64(dynamic[idx].d_tag); d_val = mcld::bswap64(dynamic[idx].d_un.d_val); } switch (d_tag) { case llvm::ELF::DT_SONAME: assert(d_val < dynstr_sect->size()); pInput.setName(sys::fs::Path(dynstr + d_val).filename().native()); hasSOName = true; break; case llvm::ELF::DT_NEEDED: // TODO: break; case llvm::ELF::DT_NULL: default: break; } } // if there is no SONAME in .dynamic, then set it from input path if (!hasSOName) pInput.setName(pInput.path().filename().native()); return true; } } // namespace mcld