| //===- 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()); |
| } |
| |