From f5c04b04ae30719d209a74762d0d3a7e0a811bb1 Mon Sep 17 00:00:00 2001 From: Jake Ehrlich Date: Tue, 19 Sep 2017 19:21:09 +0000 Subject: [PATCH] [llvm-objcopy] Add support for .dynamic, .dynsym, and .dynstr This change adds support for sections involved in dynamic loading such as SHT_DYNAMIC, SHT_DYNSYM, and allocated string tables. The two added binaries used for tests can be downloaded [[ https://drive.google.com/file/d/0B3gtIAmiMwZXOXE3T0RobFg4ZTg/view?usp=sharing | here ]] and [[ https://drive.google.com/file/d/0B3gtIAmiMwZXTFJSQUJZMGxNSXc/view?usp=sharing | here ]] Differential Revision: https://reviews.llvm.org/D36560 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@313663 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/tools/llvm-objcopy/Inputs/dynamic.so | Bin 0 -> 9112 bytes test/tools/llvm-objcopy/Inputs/dynsym.so | Bin 0 -> 13432 bytes test/tools/llvm-objcopy/dynamic.test | 27 ++++++++ test/tools/llvm-objcopy/dynstr.test | 32 +++++++++ test/tools/llvm-objcopy/dynsym.test | 64 +++++++++++++++++ tools/llvm-objcopy/Object.cpp | 111 +++++++++++++++++++++--------- tools/llvm-objcopy/Object.h | 34 +++++++++ 7 files changed, 237 insertions(+), 31 deletions(-) create mode 100755 test/tools/llvm-objcopy/Inputs/dynamic.so create mode 100755 test/tools/llvm-objcopy/Inputs/dynsym.so create mode 100644 test/tools/llvm-objcopy/dynamic.test create mode 100644 test/tools/llvm-objcopy/dynstr.test create mode 100644 test/tools/llvm-objcopy/dynsym.test diff --git a/test/tools/llvm-objcopy/Inputs/dynamic.so b/test/tools/llvm-objcopy/Inputs/dynamic.so new file mode 100755 index 0000000000000000000000000000000000000000..cf5757d5931cf46edfc1c7e5104a093ffd819f30 GIT binary patch literal 9112 zcmeI2O-n*i5QazXLk%i~$W3tEw7j(liWZ?{kzhgXTBVtxgbI2WxoX?b3flBX`VTFe zIcHweOD?Ki%mMFv=IeYs*WKKwllo~ol_HD`9g(-zgQu*4VhI^UWjdf`elOYC0Y zUs=OReb%L+STtiS_xR4=&*{PmZKxaj;M|v7=l4VWk1FdHgfw{RdU7vC{KZOQ_k)3^m>2;gU<8bS z5ikNqzz7%tBVYuKz&|4J`j75nS1|%czz7%tBVYuKfDtePM!*Od0V7}pz9)cQ^P4uH zS2V4t>U-@xU)N@FKH*0X{{szdjYI0){zH3s=<4;V+lzLiT?FQ+-!IKiH=8i8k4@3t zxIY^ADC#svonXa7isJTT?5$?6+oGs7==Iut_Hb(4yk+f-;$fHt^^NbF>h(qCymmah z_irpYudqaq9eknSkl`H3#dibXo@1Y|Kt1?Ektek>@E)LR?31-okM{?~dzD%lSSMIS zo9e^=WAgogen*hZ$G)iF;)&GC8T@dw+E5d5+#jDQY;#=p04GhSh6}R-9I7}Ebcg-8 x`*iA~3)Y!Bg|p;ge{kJrAI_$!US3?VYST`hV_&!{Jo&CZR|*-cNK{SMe**B;JLUiY literal 0 HcmV?d00001 diff --git a/test/tools/llvm-objcopy/Inputs/dynsym.so b/test/tools/llvm-objcopy/Inputs/dynsym.so new file mode 100755 index 0000000000000000000000000000000000000000..2f62627543a76a01ea2e1628988cd839f4a0a9ee GIT binary patch literal 13432 zcmeHOO=}cE5Ut(#v5BHdE(wS*;8lhw9wY}DO$-FafZ|0E+}UJxgY0hDnZw45;K^hD zQ!f4y|A$rG^@i9a7jenuHO#!O&#rzo$C~f2%e`)=BUnrFLV~m!HH91IPv9X^$aA@^ z@4K=hw^V&YpTf;4{`Azqp8J{F;;vdhy3qm@ugBtUn#tu9JxqYGTb$J@nZ0yn;oV~2 z^Yx&2+46+AE%#5b?`k0K_wILd6z-S!i_7r8Sf8bOt8w8x6aK@pd#`D?q=?B-pPjL; z9q6n^J>Dz2Su=(+Xd>QIFn`nwtMwxE!xc-4cIIWh4LuoDlP@x;X8L@S&(o>L5y$`; zAOmE843GgbKnBPF86X2>V6hCGpD#8)vy%ZbKnBPF86X2>fDDiUGC&5%02v?y*U!My z>o0*7kO4A42FL&zAOmE843GgbKnBPF86X1-W&pG1zien**PRHm>4@3x6CbFz`EXn7 z5!yNL!tJhZp*)^^9nQA1vfRy{E^8bL^5Iolff0vE-ww9!05{ zN!|?SjY?Hh1zj~hK9qb=*ODJj$K&BdjT+Td1I1C@%;GMhj<_eY?w@u)9K3w9zmr`0 zA4KEBdIj3iKj7SRVjdrJ|LE(o+O4;UNB@AJ-#?4C&zS4Kud$XJ@%TP~_&(GnEaZW_ zp&QfT`)mIz@c$8z7ydXG@g>MA)p#QJb*47?8 %t +# RUN: llvm-objcopy %t %t2 +# RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Address: 0x1000 + Content: "002EDEADBEEF002EBAADF00D00" + +#CHECK: Name: .dynstr +#CHECK-NEXT: Type: SHT_STRTAB +#CHECK-NEXT: Flags [ +#CHECK-NEXT: SHF_ALLOC +#CHECK-NEXT: ] +#CHECK-NEXT: Address: 0x1000 +#CHECK-NEXT: Offset: +#CHECK-NEXT: Size: 13 +#CHECK-NEXT: Link: +#CHECK-NEXT: Info: +#CHECK-NEXT: AddressAlignment: +#CHECK-NEXT: EntrySize: +#CHECK-NEXT: SectionData ( +#CHECK-NEXT: 0000: 002EDEAD BEEF002E BAADF00D 00 +#CHECK-NEXT: ) diff --git a/test/tools/llvm-objcopy/dynsym.test b/test/tools/llvm-objcopy/dynsym.test new file mode 100644 index 00000000000..b7d09536f69 --- /dev/null +++ b/test/tools/llvm-objcopy/dynsym.test @@ -0,0 +1,64 @@ +# RUN: llvm-objcopy %p/Inputs/dynsym.so %t +# RUN: llvm-readobj -dyn-symbols %t | FileCheck %s +# RUN: llvm-readobj -sections %t | FileCheck -check-prefix=LINK %s + +#LINK: Name: .dynsym +#LINK-NEXT: Type: SHT_DYNSYM +#LINK-NEXT: Flags [ +#LINK-NEXT: SHF_ALLOC +#LINK-NEXT: ] +#LINK-NEXT: Address: +#LINK-NEXT: Offset: +#LINK-NEXT: Size: +#LINK-NEXT: Link: 3 + +#LINK: Index: 3 +#LINK-NEXT: Name: .dynstr + +#CHECK: DynamicSymbols [ +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: @ (0) +#CHECK-NEXT: Value: 0x0 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Local +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Undefined (0x0) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: bang@ (1) +#CHECK-NEXT: Value: 0x4000 +#CHECK-NEXT: Size: 8 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: Object (0x1) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .bss (0x7) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: bar@ (6) +#CHECK-NEXT: Value: 0x1001 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: Function (0x2) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .text (0x4) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: baz@ (10) +#CHECK-NEXT: Value: 0x2000 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: Object (0x1) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .data (0x5) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: foo@ (14) +#CHECK-NEXT: Value: 0x1000 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: Function (0x2) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .text (0x4) +#CHECK-NEXT: } +#CHECK-NEXT:] diff --git a/tools/llvm-objcopy/Object.cpp b/tools/llvm-objcopy/Object.cpp index 16bfdfd140c..28323f47500 100644 --- a/tools/llvm-objcopy/Object.cpp +++ b/tools/llvm-objcopy/Object.cpp @@ -228,6 +228,12 @@ void RelocationSection::writeSection(llvm::FileOutputBuffer &Out) const { writeRel(reinterpret_cast(Buf)); } +bool SectionWithStrTab::classof(const SectionBase *S) { + return isa(S) || isa(S); +} + +void SectionWithStrTab::finalize() { this->Link = StrTab->Index; } + // Returns true IFF a section is wholly inside the range of a segment static bool sectionWithinSegment(const SectionBase &Section, const Segment &Segment) { @@ -308,16 +314,12 @@ void Object::initSymbolTable(const llvm::object::ELFFile &ElfFile, SymbolTableSection *SymTab) { SymTab->Size = 0; - if (SymbolTable->Link - 1 >= Sections.size()) - error("Symbol table has link index of " + Twine(SymbolTable->Link) + - " which is not a valid index"); - - if (auto StrTab = - dyn_cast(Sections[SymbolTable->Link - 1].get())) - SymTab->setStrTab(StrTab); - else - error("Symbol table has link index of " + Twine(SymbolTable->Link) + - "which is not a string table"); + SymTab->setStrTab(getSectionOfType( + SymbolTable->Link, + "Symbol table has link index of " + Twine(SymTab->Link) + + " which is not a valid index", + "Symbol table has link index of " + Twine(SymTab->Link) + + " which is not a string table")); const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index)); StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr)); @@ -325,6 +327,7 @@ void Object::initSymbolTable(const llvm::object::ELFFile &ElfFile, for (const auto &Sym : unwrapOrError(ElfFile.symbols(&Shdr))) { SectionBase *DefSection = nullptr; StringRef Name = unwrapOrError(Sym.getName(StrTabData)); + if (Sym.st_shndx >= SHN_LORESERVE) { if (!isValidReservedSectionIndex(Sym.st_shndx, Machine)) { error( @@ -333,12 +336,12 @@ void Object::initSymbolTable(const llvm::object::ELFFile &ElfFile, Twine(Sym.st_shndx)); } } else if (Sym.st_shndx != SHN_UNDEF) { - if (Sym.st_shndx >= Sections.size()) - error("Symbol '" + Name + - "' is defined in invalid section with index " + + DefSection = getSection( + Sym.st_shndx, + "Symbol '" + Name + "' is defined in invalid section with index " + Twine(Sym.st_shndx)); - DefSection = Sections[Sym.st_shndx - 1].get(); } + SymTab->addSymbol(Name, Sym.getBinding(), Sym.getType(), DefSection, Sym.getValue(), Sym.st_shndx, Sym.st_size); } @@ -366,6 +369,22 @@ void initRelocations(RelocationSection *Relocs, } template +SectionBase *Object::getSection(uint16_t Index, Twine ErrMsg) { + if (Index == SHN_UNDEF || Index > Sections.size()) + error(ErrMsg); + return Sections[Index - 1].get(); +} + +template +template +T *Object::getSectionOfType(uint16_t Index, Twine IndexErrMsg, + Twine TypeErrMsg) { + if (T *TSec = llvm::dyn_cast(getSection(Index, IndexErrMsg))) + return TSec; + error(TypeErrMsg); +} + +template std::unique_ptr Object::makeSection(const llvm::object::ELFFile &ElfFile, const Elf_Shdr &Shdr) { @@ -375,7 +394,26 @@ Object::makeSection(const llvm::object::ELFFile &ElfFile, case SHT_RELA: return llvm::make_unique>(); case SHT_STRTAB: + // If a string table is allocated we don't want to mess with it. That would + // mean altering the memory image. There are no special link types or + // anything so we can just use a Section. + if (Shdr.sh_flags & SHF_ALLOC) { + Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); + return llvm::make_unique
(Data); + } return llvm::make_unique(); + case SHT_HASH: + case SHT_GNU_HASH: + // Hash tables should refer to SHT_DYNSYM which we're not going to change. + // Because of this we don't need to mess with the hash tables either. + Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); + return llvm::make_unique
(Data); + case SHT_DYNSYM: + Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); + return llvm::make_unique(Data); + case SHT_DYNAMIC: + Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); + return llvm::make_unique(Data); case SHT_SYMTAB: { auto SymTab = llvm::make_unique>(); SymbolTable = SymTab.get(); @@ -423,28 +461,35 @@ void Object::readSectionHeaders(const ELFFile &ElfFile) { // relocation sections. for (auto &Section : Sections) { if (auto RelSec = dyn_cast>(Section.get())) { - if (RelSec->Link - 1 >= Sections.size() || RelSec->Link == 0) { - error("Link field value " + Twine(RelSec->Link) + " in section " + - RelSec->Name + " is invalid"); - } - if (RelSec->Info - 1 >= Sections.size() || RelSec->Info == 0) { - error("Info field value " + Twine(RelSec->Link) + " in section " + - RelSec->Name + " is invalid"); - } - auto SymTab = - dyn_cast(Sections[RelSec->Link - 1].get()); - if (SymTab == nullptr) { - error("Link field of relocation section " + RelSec->Name + - " is not a symbol table"); - } + + auto SymTab = getSectionOfType( + RelSec->Link, + "Link field value " + Twine(RelSec->Link) + " in section " + + RelSec->Name + " is invalid", + "Link field value " + Twine(RelSec->Link) + " in section " + + RelSec->Name + " is not a symbol table"); RelSec->setSymTab(SymTab); - RelSec->setSection(Sections[RelSec->Info - 1].get()); + + RelSec->setSection(getSection(RelSec->Info, + "Info field value " + Twine(RelSec->Link) + + " in section " + RelSec->Name + + " is invalid")); + auto Shdr = unwrapOrError(ElfFile.sections()).begin() + RelSec->Index; if (RelSec->Type == SHT_REL) initRelocations(RelSec, SymTab, unwrapOrError(ElfFile.rels(Shdr))); else initRelocations(RelSec, SymTab, unwrapOrError(ElfFile.relas(Shdr))); } + + if (auto Sec = dyn_cast(Section.get())) { + Sec->setStrTab(getSectionOfType( + Sec->Link, + "Link field value " + Twine(Sec->Link) + " in section " + Sec->Name + + " is invalid", + "Link field value " + Twine(Sec->Link) + " in section " + Sec->Name + + " is not a string table")); + } } } @@ -462,8 +507,12 @@ template Object::Object(const ELFObjectFile &Obj) { readSectionHeaders(ElfFile); readProgramHeaders(ElfFile); - SectionNames = - dyn_cast(Sections[Ehdr.e_shstrndx - 1].get()); + SectionNames = getSectionOfType( + Ehdr.e_shstrndx, + "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + " in elf header " + + " is invalid", + "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + " in elf header " + + " is not a string table"); } template diff --git a/tools/llvm-objcopy/Object.h b/tools/llvm-objcopy/Object.h index 1b7127e86da..7a6f0132a0e 100644 --- a/tools/llvm-objcopy/Object.h +++ b/tools/llvm-objcopy/Object.h @@ -194,6 +194,34 @@ public: } }; +class SectionWithStrTab : public Section { +private: + StringTableSection *StrTab; + +public: + SectionWithStrTab(llvm::ArrayRef Data) : Section(Data) {} + void setStrTab(StringTableSection *StringTable) { StrTab = StringTable; } + void finalize() override; + static bool classof(const SectionBase *S); +}; + +class DynamicSymbolTableSection : public SectionWithStrTab { +public: + DynamicSymbolTableSection(llvm::ArrayRef Data) + : SectionWithStrTab(Data) {} + static bool classof(const SectionBase *S) { + return S->Type == llvm::ELF::SHT_DYNSYM; + } +}; + +class DynamicSection : public SectionWithStrTab { +public: + DynamicSection(llvm::ArrayRef Data) : SectionWithStrTab(Data) {} + static bool classof(const SectionBase *S) { + return S->Type == llvm::ELF::SHT_DYNAMIC; + } +}; + template class Object { private: typedef std::unique_ptr SecPtr; @@ -210,6 +238,12 @@ private: void readProgramHeaders(const llvm::object::ELFFile &ElfFile); void readSectionHeaders(const llvm::object::ELFFile &ElfFile); + SectionBase *getSection(uint16_t Index, llvm::Twine ErrMsg); + + template + T *getSectionOfType(uint16_t Index, llvm::Twine IndexErrMsg, + llvm::Twine TypeErrMsg); + protected: StringTableSection *SectionNames; SymbolTableSection *SymbolTable; -- 2.11.0