Index: llvm/tools/llvm-elfabi/ELFObjHandler.h =================================================================== --- llvm/tools/llvm-elfabi/ELFObjHandler.h +++ llvm/tools/llvm-elfabi/ELFObjHandler.h @@ -73,6 +73,9 @@ template class ELFBinaryWriterImpl { public: using Elf_Ehdr = typename ELFT::Ehdr; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Phdr = typename ELFT::Phdr; + using Elf_Dyn = typename ELFT::Dyn; ELFBinaryWriterImpl() {} @@ -96,6 +99,15 @@ /// @param ElfHeader Target ELFT::Ehdr to populate. /// @param Machine Target architecture (e_machine from ELF specifications). void initELFHeader(Elf_Ehdr &ElfHeader, uint16_t Machine); + +private: + void initDynamicShdr(Elf_Shdr &Dynamic, std::string &ShStrTab); + void initDynStrShdr(Elf_Shdr &DynStr, std::string &ShStrTab); + void initShStrTabShdr(Elf_Shdr &ShStrTabHdr, std::string &ShStrTab); + + size_t alignTo(size_t Offset, size_t Align); + size_t alignAndCopy(char *Dest, const void *Src, size_t DestOffset, + size_t Length, size_t Align); }; } // end namespace elfabi Index: llvm/tools/llvm-elfabi/ELFObjHandler.cpp =================================================================== --- llvm/tools/llvm-elfabi/ELFObjHandler.cpp +++ llvm/tools/llvm-elfabi/ELFObjHandler.cpp @@ -89,6 +89,60 @@ ElfHeader.e_entry = 0x00; ElfHeader.e_flags = 0u; ElfHeader.e_ehsize = sizeof(Elf_Ehdr); + + ElfHeader.e_phentsize = sizeof(Elf_Phdr); + ElfHeader.e_shentsize = sizeof(Elf_Shdr); +} + +template +void ELFBinaryWriterImpl::initDynamicShdr(Elf_Shdr &Dynamic, std::string &ShStrTab) { + Dynamic.sh_type = SHT_DYNAMIC; + Dynamic.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; + Dynamic.sh_addr = 0x4000; // TODO: check? + Dynamic.sh_info = 0; + Dynamic.sh_addralign = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); + Dynamic.sh_entsize = sizeof(Elf_Dyn); + + // These are populated/managed elsewhere, for now just initialize. + Dynamic.sh_name = ShStrTab.size(); + Dynamic.sh_offset = 0; + Dynamic.sh_size = 0; + Dynamic.sh_link = 0; + ShStrTab.append(".dynamic\0", 9); +} + +template +void ELFBinaryWriterImpl::initDynStrShdr(Elf_Shdr &DynStr, std::string &ShStrTab) { + DynStr.sh_type = SHT_STRTAB; + DynStr.sh_flags = SHF_ALLOC; + DynStr.sh_addr = 0x2000; // TODO: check? + DynStr.sh_info = 0; + DynStr.sh_addralign = 1; + DynStr.sh_entsize = 0; + + DynStr.sh_name = ShStrTab.size(); + // These are populated/managed elsewhere, for now just initialize. + DynStr.sh_offset = 0; + DynStr.sh_size = 0; + DynStr.sh_link = 0; + ShStrTab.append(".dynstr\0", 8); +} + +template +void ELFBinaryWriterImpl::initShStrTabShdr(Elf_Shdr &ShStrTabHdr, std::string &ShStrTab) { + ShStrTabHdr.sh_type = SHT_STRTAB; + ShStrTabHdr.sh_flags = SHF_ALLOC; + ShStrTabHdr.sh_addr = 0x0; // TODO: check? + ShStrTabHdr.sh_info = 0; + ShStrTabHdr.sh_addralign = 1; + ShStrTabHdr.sh_entsize = 0; + + ShStrTabHdr.sh_name = ShStrTab.size(); + // These are populated/managed elsewhere, for now just initialize. + ShStrTabHdr.sh_offset = 0; + ShStrTabHdr.sh_size = 0; + ShStrTabHdr.sh_link = 0; + ShStrTab.append(".shstrtab\0", 10); } template @@ -97,16 +151,190 @@ return createStringError(errc::invalid_argument, "Destination buffer too small"); } - // ELF Header. - Elf_Ehdr ElfHeader; - initELFHeader(ElfHeader, Stub.Arch); - std::memcpy(Buf, &ElfHeader, sizeof(Elf_Ehdr)); + Elf_Ehdr* ElfHeader = reinterpret_cast(Buf); + initELFHeader(*ElfHeader, Stub.Arch); + size_t WriteOffset = sizeof(Elf_Ehdr); + std::string DynStrTab; + DynStrTab.push_back('\0'); + std::string ShStrTab; + ShStrTab.push_back('\0'); + assert(DynStrTab.size() >= 1); + assert(ShStrTab.size() == 1); + // TODO: PT_LOAD + Elf_Phdr* PTDynPhdr = reinterpret_cast(Buf + WriteOffset); + ElfHeader->e_phoff = WriteOffset; + ElfHeader->e_phnum += 1; + WriteOffset += sizeof(Elf_Phdr); + PTDynPhdr->p_type = PT_DYNAMIC; + PTDynPhdr->p_flags = PF_W | PF_R; + PTDynPhdr->p_offset = 0; + PTDynPhdr->p_vaddr = 0x2000; // TODO: fix + PTDynPhdr->p_paddr = 0x2000; // TODO: fix + PTDynPhdr->p_filesz = 0; + PTDynPhdr->p_memsz = 0; + PTDynPhdr->p_align = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); + // Section headers: + // Undefined section. + Elf_Shdr* NullShdr = reinterpret_cast(Buf + WriteOffset); + memset(NullShdr, 0, sizeof(Elf_Shdr)); + ElfHeader->e_shnum += 1; + ElfHeader->e_shoff = WriteOffset; + WriteOffset += sizeof(Elf_Shdr); + // DynStr section. + Elf_Shdr *DynStr = reinterpret_cast(Buf + WriteOffset); + initDynStrShdr(*DynStr, ShStrTab); + uint64_t DynStrIdx = ElfHeader->e_shnum; + ElfHeader->e_shnum += 1; + WriteOffset += sizeof(Elf_Shdr); + // Dynamic section. + Elf_Shdr *Dynamic = reinterpret_cast(Buf + WriteOffset); + initDynamicShdr(*Dynamic, ShStrTab); + Dynamic->sh_link = DynStrIdx; + ElfHeader->e_shnum += 1; + WriteOffset += sizeof(Elf_Shdr); + // ShStrTab section. + Elf_Shdr *ShStrHdr = reinterpret_cast(Buf + WriteOffset); + initShStrTabShdr(*ShStrHdr, ShStrTab); + uint64_t ShStrTabIdx = ElfHeader->e_shnum; + NullShdr->sh_link = ShStrTabIdx; + ElfHeader->e_shstrndx = ShStrTabIdx; + ElfHeader->e_shnum += 1; + WriteOffset += sizeof(Elf_Shdr); + // Update SHT null: + NullShdr->sh_size = ElfHeader->e_shnum; + + // Warning sections. + // TODO: add warning sections. + // Finish populating .dynstr by adding SoName and building NeededLib list + std::vector DynEntries; + if (Stub.SoName.hasValue()) { + Elf_Dyn DynSOName; + DynSOName.d_tag = DT_SONAME; + DynSOName.d_un.d_val = DynStrTab.size(); + DynStrTab.append(Stub.SoName->c_str(), Stub.SoName->size() + 1); + DynEntries.push_back(DynSOName); + } + assert(DynStrTab.size() > 5); + for (const std::string &LibName : Stub.NeededLibs) { + Elf_Dyn NeededEntry; + NeededEntry.d_tag = DT_NEEDED; + NeededEntry.d_un.d_val = DynStrTab.size(); + DynStrTab.append(LibName.c_str(), LibName.size() + 1); + DynEntries.push_back(NeededEntry); + } + + // Write section contents: + // TODO: write .dynsym (mark offset in DT_SYMTAB) + // Write DynStr contents: + std::memcpy(Buf + WriteOffset, DynStrTab.c_str(), DynStrTab.size()); + DynStr->sh_offset = WriteOffset; + DynStr->sh_size = DynStrTab.size(); + WriteOffset += DynStrTab.size(); + + // Write Dynamic contents: + size_t DynAlign = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); + // Write DT_STRTAB. + Elf_Dyn DynStrTabEnt; + DynStrTabEnt.d_tag = DT_STRTAB; + DynStrTabEnt.d_un.d_ptr = DynStr->sh_offset; + WriteOffset = + alignAndCopy(Buf, &DynStrTabEnt, WriteOffset, sizeof(Elf_Dyn), DynAlign); + + Dynamic->sh_offset = WriteOffset - sizeof(Elf_Dyn); + PTDynPhdr->p_offset = WriteOffset - sizeof(Elf_Dyn); + Dynamic->sh_size += sizeof(Elf_Dyn); + + // Write DT_STRSZ. + Elf_Dyn DynStrSzEnt; + DynStrSzEnt.d_tag = DT_STRSZ; + DynStrSzEnt.d_un.d_val = DynStrTab.size(); + WriteOffset = + alignAndCopy(Buf, &DynStrSzEnt, WriteOffset, sizeof(Elf_Dyn), DynAlign); + Dynamic->sh_size += sizeof(Elf_Dyn); + + // Write DT_NEEDED and DT_SONAME. + WriteOffset = alignAndCopy(Buf, DynEntries.data(), WriteOffset, + sizeof(Elf_Dyn) * DynEntries.size(), DynAlign); + Dynamic->sh_size += sizeof(Elf_Dyn) * DynEntries.size(); + + // Write DT_NULL. + Elf_Dyn DynNullEnt; + DynNullEnt.d_tag = DT_NULL; + DynNullEnt.d_un.d_val = 0; + WriteOffset = + alignAndCopy(Buf, &DynNullEnt, WriteOffset, sizeof(Elf_Dyn), DynAlign); + Dynamic->sh_size += sizeof(Elf_Dyn); + PTDynPhdr->p_filesz = Dynamic->sh_size; + PTDynPhdr->p_memsz = Dynamic->sh_size; + + // Write ShStrTab contents: + ShStrHdr->sh_offset = WriteOffset; + std::memcpy(Buf + WriteOffset, ShStrTab.c_str(), ShStrTab.size()); + ShStrHdr->sh_offset = WriteOffset; + ShStrHdr->sh_size = ShStrTab.size(); + WriteOffset += ShStrTab.size(); + return Error::success(); } +size_t dynStrSize(const ELFStub &Stub) { + size_t Total = 1; // DynStr has a null character at minimum. + if (Stub.SoName.hasValue()) { + Total += Stub.SoName.getValue().size() + 1; // Include null terminator + } + for (const std::string &LibName : Stub.NeededLibs) { + Total += LibName.size() + 1; // Include null terminator + } + return Total; +} + template size_t ELFBinaryWriterImpl::getBinarySize(const ELFStub &Stub) { - return sizeof(Elf_Ehdr); + size_t AlignedSum = sizeof(Elf_Ehdr); + AlignedSum += sizeof(Elf_Phdr); + AlignedSum += 4 * sizeof(Elf_Shdr); + AlignedSum += dynStrSize(Stub); + size_t DynAlign = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); + AlignedSum = alignTo(AlignedSum, DynAlign); + AlignedSum += 3 * sizeof(Elf_Dyn); + if (Stub.SoName.hasValue()) + AlignedSum += sizeof(Elf_Dyn); + AlignedSum += Stub.NeededLibs.size() * sizeof(Elf_Dyn); + // ShStrTab contents size (fixed for now) + AlignedSum += 28; //0.dynstr0.shstrtab0.dynamic0 + return AlignedSum; +} + +template +size_t ELFBinaryWriterImpl::alignTo(size_t Offset, size_t Align) { + // Only allow powers of two. + assert((Align & (Align - 1)) == 0); + // Treat zero + if (Align == 0) + Align = 1; + + uint64_t BitMask = Align - 1;; + return (Offset + BitMask) & (~BitMask); +} + +template +size_t ELFBinaryWriterImpl::alignAndCopy(char *Dest, const void *Src, + size_t DestOffset, size_t Length, + size_t Align) { + if (Length == 0) + return DestOffset; + + uint64_t AlignedOffset = alignTo(DestOffset, Align); + uint64_t Pad = AlignedOffset - DestOffset; + + // Add padding, update destination offset. + if (Pad != 0) { + memset(Dest + DestOffset, 0, Pad); + } + + std::memcpy(Dest + AlignedOffset, Src, Length); + + return AlignedOffset + Length; } template class ELFBinaryWriterImpl;