//===- ELFWriter.cpp ------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include <cstdlib> #include <cstring> #include <llvm/Support/ELF.h> #include <llvm/Support/Casting.h> #include <mcld/ADT/SizeTraits.h> #include <mcld/MC/MCLDInfo.h> #include <mcld/MC/MCLinker.h> #include <mcld/LD/AlignFragment.h> #include <mcld/LD/FillFragment.h> #include <mcld/LD/RegionFragment.h> #include <mcld/LD/ELFWriter.h> #include <mcld/LD/LDSymbol.h> #include <mcld/LD/LDSection.h> #include <mcld/LD/Layout.h> #include <mcld/LD/ELFSegment.h> #include <mcld/LD/ELFSegmentFactory.h> #include <mcld/Target/GNULDBackend.h> #include <mcld/Support/MemoryRegion.h> using namespace llvm::ELF; using namespace mcld; /// writeELF32Header - write ELF header void ELFWriter::writeELF32Header(const MCLDInfo& pLDInfo, const Layout& pLayout, const GNULDBackend& pBackend, Output& pOutput) const { assert(pOutput.hasMemArea()); // ELF header must start from 0x0 MemoryRegion *region = pOutput.memArea()->request(0, sizeof(Elf32_Ehdr)); Elf32_Ehdr* header = (Elf32_Ehdr*)region->start(); memcpy(header->e_ident, ElfMagic, EI_MAG3+1); header->e_ident[EI_CLASS] = ELFCLASS32; header->e_ident[EI_DATA] = pBackend.isLittleEndian()? ELFDATA2LSB : ELFDATA2MSB; header->e_ident[EI_VERSION] = pBackend.ELFVersion(); header->e_ident[EI_OSABI] = pBackend.OSABI(); header->e_ident[EI_ABIVERSION] = pBackend.ABIVersion(); // FIXME: add processor-specific and core file types. switch(pOutput.type()) { case Output::Object: header->e_type = ET_REL; break; case Output::DynObj: header->e_type = ET_DYN; break; case Output::Exec: header->e_type = ET_EXEC; break; default: llvm::errs() << "unspported output file type: " << pOutput.type() << ".\n"; header->e_type = ET_NONE; } header->e_machine = pBackend.machine(); header->e_version = header->e_ident[EI_VERSION]; header->e_entry = getEntryPoint(pLDInfo, pLayout, pBackend, pOutput); header->e_phoff = sizeof(Elf32_Ehdr); header->e_shoff = getELF32LastStartOffset(pOutput); header->e_flags = pBackend.flags(); header->e_ehsize = sizeof(Elf32_Ehdr); header->e_phentsize = sizeof(Elf32_Phdr); header->e_phnum = pBackend.numOfSegments(); header->e_shentsize = sizeof(Elf32_Shdr); header->e_shnum = pOutput.context()->numOfSections(); header->e_shstrndx = pOutput.context()->getSectionIdx(".shstrtab"); } /// writeELF64Header - write ELF header void ELFWriter::writeELF64Header(const MCLDInfo& pLDInfo, const Layout& pLayout, const GNULDBackend& pBackend, Output& pOutput) const { assert(pOutput.hasMemArea()); // ELF header must start from 0x0 MemoryRegion *region = pOutput.memArea()->request(0, sizeof(Elf64_Ehdr)); Elf64_Ehdr* header = (Elf64_Ehdr*)region->start(); memcpy(header->e_ident, ElfMagic, EI_MAG3+1); header->e_ident[EI_CLASS] = ELFCLASS64; header->e_ident[EI_DATA] = pBackend.isLittleEndian()? ELFDATA2LSB : ELFDATA2MSB; header->e_ident[EI_VERSION] = pBackend.ELFVersion(); header->e_ident[EI_OSABI] = pBackend.OSABI(); header->e_ident[EI_ABIVERSION] = pBackend.ABIVersion(); // FIXME: add processor-specific and core file types. switch(pOutput.type()) { case Output::Object: header->e_type = ET_REL; break; case Output::DynObj: header->e_type = ET_DYN; break; case Output::Exec: header->e_type = ET_EXEC; break; default: llvm::errs() << "unspported output file type: " << pOutput.type() << ".\n"; header->e_type = ET_NONE; } header->e_machine = pBackend.machine(); header->e_version = header->e_ident[EI_VERSION]; header->e_entry = getEntryPoint(pLDInfo, pLayout, pBackend, pOutput); header->e_phoff = sizeof(Elf64_Ehdr); header->e_shoff = getELF64LastStartOffset(pOutput); header->e_flags = pBackend.flags(); header->e_ehsize = sizeof(Elf64_Ehdr); header->e_phentsize = sizeof(Elf64_Phdr); header->e_phnum = pBackend.numOfSegments(); header->e_shentsize = sizeof(Elf64_Shdr); header->e_shnum = pOutput.context()->numOfSections(); header->e_shstrndx = pOutput.context()->getSectionIdx(".shstrtab"); } /// getEntryPoint uint64_t ELFWriter::getEntryPoint(const MCLDInfo& pLDInfo, const Layout& pLayout, const GNULDBackend& pBackend, const Output& pOutput) const { llvm::StringRef entry_name; if (pLDInfo.options().hasEntry()) entry_name = pLDInfo.options().entry(); else entry_name = pBackend.entry(); uint64_t result = 0x0; bool issue_warning = (pLDInfo.options().hasEntry() && (pOutput.type() != Output::Object) && (pOutput.type() != Output::DynObj)); const LDSymbol* entry_symbol = pLDInfo.getNamePool().findSymbol(entry_name); // found the symbol if (NULL != entry_symbol) { if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) { llvm::errs() << "WARNING: entry symbol '" << entry_symbol->name() << "' exists but is not defined.\n"; } result = entry_symbol->value(); } // not in the symbol pool else { // We should parse entry as a number. // @ref GNU ld manual, Options -e. e.g., -e 0x1000. char* endptr; result = strtoull(entry_name.data(), &endptr, 0); if (*endptr != '\0') { if (issue_warning) { llvm::errs() << "cannot find entry symbol '" << entry_name.data() << "'.\n"; } result = 0x0; } } return result; } /// emitELF32SectionHeader - emit Elf32_Shdr void ELFWriter::emitELF32SectionHeader(Output& pOutput, MCLinker& pLinker) const { // emit section header unsigned int sectNum = pOutput.context()->numOfSections(); unsigned int header_size = sizeof(Elf32_Shdr) * sectNum; MemoryRegion* region = pOutput.memArea()->request( getELF32LastStartOffset(pOutput), header_size); Elf32_Shdr* shdr = (Elf32_Shdr*)region->start(); // Iterate the SectionTable in LDContext unsigned int sectIdx = 0; unsigned int shstridx = 0; // NULL section has empty name for (; sectIdx < sectNum; ++sectIdx) { const LDSection *ld_sect = pOutput.context()->getSection(sectIdx); shdr[sectIdx].sh_name = shstridx; shdr[sectIdx].sh_type = ld_sect->type(); shdr[sectIdx].sh_flags = ld_sect->flag(); shdr[sectIdx].sh_addr = ld_sect->addr(); shdr[sectIdx].sh_offset = ld_sect->offset(); shdr[sectIdx].sh_size = ld_sect->size(); shdr[sectIdx].sh_addralign = ld_sect->align(); shdr[sectIdx].sh_entsize = getELF32SectEntrySize(*ld_sect); shdr[sectIdx].sh_link = getSectLink(*ld_sect, pOutput); shdr[sectIdx].sh_info = getSectInfo(*ld_sect, pOutput); // adjust strshidx shstridx += ld_sect->name().size() + 1; } } /// emitELF64SectionHeader - emit Elf64_Shdr void ELFWriter::emitELF64SectionHeader(Output& pOutput, MCLinker& pLinker) const { // emit section header unsigned int sectNum = pOutput.context()->numOfSections(); unsigned int header_size = sizeof(Elf64_Shdr) * sectNum; MemoryRegion* region = pOutput.memArea()->request( getELF64LastStartOffset(pOutput), header_size); Elf64_Shdr* shdr = (Elf64_Shdr*)region->start(); // Iterate the SectionTable in LDContext unsigned int sectIdx = 0; unsigned int shstridx = 0; // NULL section has empty name for (; sectIdx < sectNum; ++sectIdx) { const LDSection *ld_sect = pOutput.context()->getSection(sectIdx); shdr[sectIdx].sh_name = shstridx; shdr[sectIdx].sh_type = ld_sect->type(); shdr[sectIdx].sh_flags = ld_sect->flag(); shdr[sectIdx].sh_addr = ld_sect->addr(); shdr[sectIdx].sh_offset = ld_sect->offset(); shdr[sectIdx].sh_size = ld_sect->size(); shdr[sectIdx].sh_addralign = (ld_sect->hasSectionData())? ld_sect->getSectionData()->getAlignment(): 0x0; shdr[sectIdx].sh_entsize = getELF64SectEntrySize(*ld_sect); shdr[sectIdx].sh_link = getSectLink(*ld_sect, pOutput); shdr[sectIdx].sh_info = getSectInfo(*ld_sect, pOutput); // adjust strshidx shstridx += ld_sect->name().size() + 1; } } /// emitELF32ProgramHeader - emit Elf32_Phdr void ELFWriter::emitELF32ProgramHeader(Output& pOutput, const GNULDBackend& pBackend) const { assert(pOutput.hasMemArea()); uint64_t start_offset, phdr_size; start_offset = sizeof(Elf32_Ehdr); phdr_size = sizeof(Elf32_Phdr); // Program header must start directly after ELF header MemoryRegion *region = pOutput.memArea()->request(start_offset, pBackend.numOfSegments() * phdr_size); Elf32_Phdr* phdr = (Elf32_Phdr*)region->start(); // Iterate the elf segment table in GNULDBackend size_t index = 0; ELFSegmentFactory::const_iterator seg = pBackend.elfSegmentTable().begin(), segEnd = pBackend.elfSegmentTable().end(); for (; seg != segEnd; ++seg, ++index) { phdr[index].p_type = (*seg).type(); phdr[index].p_flags = (*seg).flag(); phdr[index].p_offset = (*seg).offset(); phdr[index].p_vaddr = (*seg).vaddr(); phdr[index].p_paddr = (*seg).paddr(); phdr[index].p_filesz = (*seg).filesz(); phdr[index].p_memsz = (*seg).memsz(); phdr[index].p_align = (*seg).align(); } } /// emitELF64ProgramHeader - emit ElfR64Phdr void ELFWriter::emitELF64ProgramHeader(Output& pOutput, const GNULDBackend& pBackend) const { assert(pOutput.hasMemArea()); uint64_t start_offset, phdr_size; start_offset = sizeof(Elf64_Ehdr); phdr_size = sizeof(Elf64_Phdr); // Program header must start directly after ELF header MemoryRegion *region = pOutput.memArea()->request(start_offset, pBackend.numOfSegments() * phdr_size); Elf64_Phdr* phdr = (Elf64_Phdr*)region->start(); // Iterate the elf segment table in GNULDBackend size_t index = 0; ELFSegmentFactory::const_iterator seg = pBackend.elfSegmentTable().begin(), segEnd = pBackend.elfSegmentTable().end(); for (; seg != segEnd; ++seg, ++index) { phdr[index].p_type = (*seg).type(); phdr[index].p_flags = (*seg).flag(); phdr[index].p_offset = (*seg).offset(); phdr[index].p_vaddr = (*seg).vaddr(); phdr[index].p_paddr = (*seg).paddr(); phdr[index].p_filesz = (*seg).filesz(); phdr[index].p_memsz = (*seg).memsz(); phdr[index].p_align = (*seg).align(); } } /// emitELF32ShStrTab - emit section string table void ELFWriter::emitELF32ShStrTab(Output& pOutput, MCLinker& pLinker) const { uint64_t shstroffset = getELF32LastStartOffset(pOutput); // get shstrtab LDSection& shstrtab = pLinker.getOrCreateOutputSectHdr(".shstrtab", LDFileFormat::NamePool, SHT_STRTAB, 0x0); if (0 != shstrtab.size()) llvm::report_fatal_error(".shstrtab has been set.\n"); // compute size unsigned int shstrsize = 0; LDContext::const_sect_iterator section, sectEnd = pOutput.context()->sectEnd(); for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) { shstrsize += (*section)->name().size() + 1; } shstrtab.setSize(shstrsize); shstrtab.setOffset(shstroffset); // write out data MemoryRegion* region = pOutput.memArea()->request(shstrtab.offset(), shstrtab.size()); unsigned char* data = region->start(); shstrsize = 0; for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) { strcpy((char*)(data + shstrsize), (*section)->name().c_str()); shstrsize += (*section)->name().size() + 1; } shstrtab.setKind(LDFileFormat::NamePool); shstrtab.setType(llvm::ELF::SHT_STRTAB); shstrtab.setFlag(0x0); shstrtab.setAddr(0x0); } /// emitELF64ShStrTab - emit section string table void ELFWriter::emitELF64ShStrTab(Output& pOutput, MCLinker& pLinker) const { uint64_t shstroffset = getELF64LastStartOffset(pOutput); // get shstrtab LDSection& shstrtab = pLinker.getOrCreateOutputSectHdr(".shstrtab", LDFileFormat::NamePool, SHT_STRTAB, 0x0); if (0 != shstrtab.size()) llvm::report_fatal_error(".shstrtab has been set.\n"); // compute offset // compute size unsigned int shstrsize = 0; LDContext::const_sect_iterator section, sectEnd = pOutput.context()->sectEnd(); for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) { shstrsize += (*section)->name().size() + 1; } shstrtab.setSize(shstrsize); shstrtab.setOffset(shstroffset); // write out data MemoryRegion* region = pOutput.memArea()->request(shstrtab.offset(), shstrtab.size()); unsigned char* data = region->start(); shstrsize = 0; for (section = pOutput.context()->sectBegin(); section != sectEnd; ++section) { strcpy((char*)(data + shstrsize), (*section)->name().c_str()); shstrsize += (*section)->name().size() + 1; } shstrtab.setKind(LDFileFormat::NamePool); shstrtab.setType(llvm::ELF::SHT_STRTAB); shstrtab.setFlag(0x0); shstrtab.setAddr(0x0); } /// emitSectionData void ELFWriter::emitSectionData(const Layout& pLayout, const LDSection& pSection, MemoryRegion& pRegion) const { const SectionData* data = pSection.getSectionData(); SectionData::const_iterator fragIter, fragEnd = data->end(); size_t cur_offset = 0; for (fragIter = data->begin(); fragIter != fragEnd; ++fragIter) { size_t size = computeFragmentSize(pLayout, *fragIter); switch(fragIter->getKind()) { case Fragment::Region: { const RegionFragment& region_frag = llvm::cast<RegionFragment>(*fragIter); const uint8_t* from = region_frag.getRegion().start(); memcpy(pRegion.getBuffer(cur_offset), from, size); break; } case Fragment::Alignment: { // TODO: emit values with different sizes (> 1 byte), and emit nops AlignFragment& align_frag = llvm::cast<AlignFragment>(*fragIter); uint64_t count = size / align_frag.getValueSize(); switch (align_frag.getValueSize()) { case 1u: std::memset(pRegion.getBuffer(cur_offset), align_frag.getValue(), count); break; default: llvm::report_fatal_error("unsupported value size for align fragment emission yet.\n"); break; } break; } case Fragment::Fillment: { FillFragment& fill_frag = llvm::cast<FillFragment>(*fragIter); if (0 == size || 0 == fill_frag.getValueSize() || 0 == fill_frag.getSize()) { // ignore virtual fillment break; } uint64_t num_tiles = fill_frag.getSize() / fill_frag.getValueSize(); for (uint64_t i = 0; i != num_tiles; ++i) { std::memset(pRegion.getBuffer(cur_offset), fill_frag.getValue(), fill_frag.getValueSize()); } break; } case Fragment::Relocation: llvm::report_fatal_error("relocation fragment should not be in a regular section.\n"); break; case Fragment::Target: llvm::report_fatal_error("Target fragment should not be in a regular section.\n"); break; default: llvm::report_fatal_error("invalid fragment should not be in a regular section.\n"); break; } cur_offset += size; } } /// emitRelocation void ELFWriter::emitRelocation(const Layout& pLayout, const Output& pOutput, const LDSection& pSection, MemoryRegion& pRegion) const { const SectionData* sect_data = pSection.getSectionData(); assert(NULL != sect_data && "SectionData is NULL in emitRelocation!"); if (pSection.type() == SHT_REL) emitRel(pLayout, pOutput, *sect_data, pRegion); else if (pSection.type() == SHT_RELA) emitRela(pLayout, pOutput, *sect_data, pRegion); else llvm::report_fatal_error("unsupported relocation section type!"); } /// emitRel void ELFWriter::emitRel(const Layout& pLayout, const Output& pOutput, const SectionData& pSectionData, MemoryRegion& pRegion) const { Elf32_Rel* rel = reinterpret_cast<Elf32_Rel*>(pRegion.start()); Relocation* relocation = 0; FragmentRef* frag_ref = 0; for (SectionData::const_iterator it = pSectionData.begin(), ie = pSectionData.end(); it != ie; ++it, ++rel) { relocation = &(llvm::cast<Relocation>(*it)); frag_ref = &(relocation->targetRef()); if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec) { rel->r_offset = static_cast<Elf32_Addr>( frag_ref->frag()->getParent()->getSection().addr() + pLayout.getOutputOffset(*frag_ref)); } else { rel->r_offset = static_cast<Elf32_Addr>( frag_ref->frag()->getParent()->getSection().offset() + pLayout.getOutputOffset(*frag_ref)); } Elf32_Word Index; if( relocation->symInfo() == NULL ) Index = 0; else Index = static_cast<Elf32_Word>( f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol())); rel->setSymbolAndType(Index, relocation->type()); } } /// emitRela void ELFWriter::emitRela(const Layout& pLayout, const Output& pOutput, const SectionData& pSectionData, MemoryRegion& pRegion) const { Elf32_Rela* rel = reinterpret_cast<Elf32_Rela*>(pRegion.start()); Relocation* relocation = 0; FragmentRef* frag_ref = 0; for (SectionData::const_iterator it = pSectionData.begin(), ie = pSectionData.end(); it != ie; ++it, ++rel) { relocation = &(llvm::cast<Relocation>(*it)); frag_ref = &(relocation->targetRef()); if(pOutput.type() == Output::DynObj || pOutput.type() == Output::Exec) { rel->r_offset = static_cast<Elf32_Addr>( frag_ref->frag()->getParent()->getSection().addr() + pLayout.getOutputOffset(*frag_ref)); } else { rel->r_offset = static_cast<Elf32_Addr>( frag_ref->frag()->getParent()->getSection().offset() + pLayout.getOutputOffset(*frag_ref)); } Elf32_Word Index; if( relocation->symInfo() == NULL ) Index = 0; else Index = static_cast<Elf32_Word>( f_Backend.getSymbolIdx(relocation->symInfo()->outSymbol())); rel->setSymbolAndType(Index, relocation->type()); rel->r_addend = relocation->addend(); } } /// getELF32SectEntrySize - compute Elf32_Shdr::sh_entsize uint64_t ELFWriter::getELF32SectEntrySize(const LDSection& pSection) const { if (llvm::ELF::SHT_DYNSYM == pSection.type() || llvm::ELF::SHT_SYMTAB == pSection.type()) return sizeof(llvm::ELF::Elf32_Sym); if (llvm::ELF::SHT_REL == pSection.type()) return sizeof(llvm::ELF::Elf32_Rel); if (llvm::ELF::SHT_RELA == pSection.type()) return sizeof(llvm::ELF::Elf32_Rela); if (llvm::ELF::SHT_HASH == pSection.type()) return sizeof(llvm::ELF::Elf32_Word); if (llvm::ELF::SHT_DYNAMIC == pSection.type()) return sizeof(llvm::ELF::Elf32_Dyn); return 0x0; } /// getELF64SectEntrySize - compute Elf64_Shdr::sh_entsize uint64_t ELFWriter::getELF64SectEntrySize(const LDSection& pSection) const { if (llvm::ELF::SHT_DYNSYM == pSection.type() || llvm::ELF::SHT_SYMTAB == pSection.type()) return sizeof(llvm::ELF::Elf64_Sym); if (llvm::ELF::SHT_REL == pSection.type()) return sizeof(llvm::ELF::Elf64_Rel); if (llvm::ELF::SHT_RELA == pSection.type()) return sizeof(llvm::ELF::Elf64_Rela); if (llvm::ELF::SHT_HASH == pSection.type()) return sizeof(llvm::ELF::Elf64_Word); if (llvm::ELF::SHT_DYNAMIC == pSection.type()) return sizeof(llvm::ELF::Elf64_Dyn); return 0x0; } /// getSectLink - compute ElfXX_Shdr::sh_link uint64_t ELFWriter::getSectLink(const LDSection& pSection, const Output& pOutput) const { const LDContext* context = pOutput.context(); if (llvm::ELF::SHT_SYMTAB == pSection.type()) return context->getSectionIdx(".strtab"); if (llvm::ELF::SHT_DYNSYM == pSection.type()) return context->getSectionIdx(".dynstr"); if (llvm::ELF::SHT_DYNAMIC == pSection.type()) return context->getSectionIdx(".dynstr"); if (llvm::ELF::SHT_HASH == pSection.type()) return context->getSectionIdx(".dynsym"); if (llvm::ELF::SHT_REL == pSection.type() || llvm::ELF::SHT_RELA == pSection.type()) { if (pOutput.type() == Output::Object) return context->getSectionIdx(".symtab"); else return context->getSectionIdx(".dynsym"); } return llvm::ELF::SHN_UNDEF; } /// getSectInfo - compute ElfXX_Shdr::sh_info uint64_t ELFWriter::getSectInfo(const LDSection& pSection, const Output& pOutput) const { const LDSection* info_link = pSection.getLink(); if (NULL == info_link) return 0x0; return info_link->index(); } /// getELF32LastStartOffset uint64_t ELFWriter::getELF32LastStartOffset(const Output& pOutput) const { LDSection* lastSect = pOutput.context()->getSectionTable().back(); assert(lastSect != NULL); return Align<32>(lastSect->offset() + lastSect->size()); } /// getELF64LastStartOffset uint64_t ELFWriter::getELF64LastStartOffset(const Output& pOutput) const { LDSection* lastSect = pOutput.context()->getSectionTable().back(); assert(lastSect != NULL); return Align<64>(lastSect->offset() + lastSect->size()); }