//===- lib/ReaderWriter/ELF/HeaderChunks.cpp --------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "HeaderChunks.h" #include "TargetLayout.h" #include "llvm/ADT/STLExtras.h" namespace lld { namespace elf { template void ELFHeader::finalize() { _eh.e_ident[llvm::ELF::EI_CLASS] = (ELFT::Is64Bits) ? llvm::ELF::ELFCLASS64 : llvm::ELF::ELFCLASS32; _eh.e_ident[llvm::ELF::EI_DATA] = (ELFT::TargetEndianness == llvm::support::little) ? llvm::ELF::ELFDATA2LSB : llvm::ELF::ELFDATA2MSB; _eh.e_type = this->_ctx.getOutputELFType(); _eh.e_machine = this->_ctx.getOutputMachine(); } template ELFHeader::ELFHeader(const ELFLinkingContext &ctx) : Chunk("elfhdr", Chunk::Kind::ELFHeader, ctx) { this->_alignment = ELFT::Is64Bits ? 8 : 4; this->_fsize = sizeof(Elf_Ehdr); this->_msize = sizeof(Elf_Ehdr); memset(_eh.e_ident, 0, llvm::ELF::EI_NIDENT); e_ident(llvm::ELF::EI_MAG0, 0x7f); e_ident(llvm::ELF::EI_MAG1, 'E'); e_ident(llvm::ELF::EI_MAG2, 'L'); e_ident(llvm::ELF::EI_MAG3, 'F'); e_ehsize(sizeof(Elf_Ehdr)); e_flags(0); } template void ELFHeader::write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) { uint8_t *chunkBuffer = buffer.getBufferStart(); uint8_t *atomContent = chunkBuffer + this->fileOffset(); memcpy(atomContent, &_eh, fileSize()); } template bool ProgramHeader::addSegment(Segment *segment) { bool allocatedNew = false; ELFLinkingContext::OutputMagic outputMagic = this->_ctx.getOutputMagic(); // For segments that are not a loadable segment, we // just pick the values directly from the segment as there // wouldnt be any slices within that if (segment->segmentType() != llvm::ELF::PT_LOAD) { Elf_Phdr *phdr = allocateProgramHeader(allocatedNew); phdr->p_type = segment->segmentType(); phdr->p_offset = segment->fileOffset(); phdr->p_vaddr = segment->virtualAddr(); phdr->p_paddr = segment->virtualAddr(); phdr->p_filesz = segment->fileSize(); phdr->p_memsz = segment->memSize(); phdr->p_flags = segment->flags(); phdr->p_align = segment->alignment(); this->_fsize = fileSize(); this->_msize = this->_fsize; return allocatedNew; } // For all other segments, use the slice // to derive program headers for (auto slice : segment->slices()) { Elf_Phdr *phdr = allocateProgramHeader(allocatedNew); phdr->p_type = segment->segmentType(); phdr->p_offset = slice->fileOffset(); phdr->p_vaddr = slice->virtualAddr(); phdr->p_paddr = slice->virtualAddr(); phdr->p_filesz = slice->fileSize(); phdr->p_memsz = slice->memSize(); phdr->p_flags = segment->flags(); phdr->p_align = slice->alignment(); uint64_t segPageSize = segment->pageSize(); uint64_t sliceAlign = slice->alignment(); // Alignment of PT_LOAD segments are set to the page size, but if the // alignment of the slice is greater than the page size, set the alignment // of the segment appropriately. if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC && outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) { phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ? (segPageSize < sliceAlign) ? sliceAlign : segPageSize : sliceAlign; } else phdr->p_align = slice->alignment(); } this->_fsize = fileSize(); this->_msize = this->_fsize; return allocatedNew; } template void ProgramHeader::write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) { uint8_t *chunkBuffer = buffer.getBufferStart(); uint8_t *dest = chunkBuffer + this->fileOffset(); for (auto phi : _ph) { memcpy(dest, phi, sizeof(Elf_Phdr)); dest += sizeof(Elf_Phdr); } } template typename ProgramHeader::Elf_Phdr * ProgramHeader::allocateProgramHeader(bool &allocatedNew) { Elf_Phdr *phdr; if (_phi == _ph.end()) { phdr = new (_allocator) Elf_Phdr; _ph.push_back(phdr); _phi = _ph.end(); allocatedNew = true; } else { phdr = (*_phi); ++_phi; } return phdr; } template SectionHeader::SectionHeader(const ELFLinkingContext &ctx, int32_t order) : Chunk("shdr", Chunk::Kind::SectionHeader, ctx) { this->_fsize = 0; this->_alignment = 8; this->setOrder(order); // The first element in the list is always NULL auto *nullshdr = new (_sectionAllocate.Allocate()) Elf_Shdr; ::memset(nullshdr, 0, sizeof(Elf_Shdr)); _sectionInfo.push_back(nullshdr); this->_fsize += sizeof(Elf_Shdr); } template void SectionHeader::appendSection(OutputSection *section) { auto *shdr = new (_sectionAllocate.Allocate()) Elf_Shdr; shdr->sh_name = _stringSection->addString(section->name()); shdr->sh_type = section->type(); shdr->sh_flags = section->flags(); shdr->sh_offset = section->fileOffset(); shdr->sh_addr = section->virtualAddr(); if (section->isLoadableSection()) shdr->sh_size = section->memSize(); else shdr->sh_size = section->fileSize(); shdr->sh_link = section->link(); shdr->sh_info = section->shinfo(); shdr->sh_addralign = section->alignment(); shdr->sh_entsize = section->entsize(); _sectionInfo.push_back(shdr); } template void SectionHeader::updateSection(Section *section) { Elf_Shdr *shdr = _sectionInfo[section->ordinal()]; shdr->sh_type = section->getType(); shdr->sh_flags = section->getFlags(); shdr->sh_offset = section->fileOffset(); shdr->sh_addr = section->virtualAddr(); shdr->sh_size = section->fileSize(); shdr->sh_link = section->getLink(); shdr->sh_info = section->getInfo(); shdr->sh_addralign = section->alignment(); shdr->sh_entsize = section->getEntSize(); } template void SectionHeader::write(ELFWriter *writer, TargetLayout &layout, llvm::FileOutputBuffer &buffer) { uint8_t *chunkBuffer = buffer.getBufferStart(); uint8_t *dest = chunkBuffer + this->fileOffset(); for (auto shi : _sectionInfo) { memcpy(dest, shi, sizeof(Elf_Shdr)); dest += sizeof(Elf_Shdr); } _stringSection->write(writer, layout, buffer); } template class ELFHeader; template class ELFHeader; template class ELFHeader; template class ELFHeader; template class ProgramHeader; template class ProgramHeader; template class ProgramHeader; template class ProgramHeader; template class SectionHeader; template class SectionHeader; template class SectionHeader; template class SectionHeader; } // end namespace elf } // end namespace lld