Index: test/tools/llvm-objcopy/dynamic.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/dynamic.test @@ -0,0 +1,27 @@ +# RUN: llvm-objcopy %p/Inputs/dynamic.so %t +# RUN: llvm-readobj -dynamic-table %t | FileCheck %s +# RUN: llvm-readobj -sections %t | FileCheck -check-prefix=LINK %s + +#CHECK: DynamicSection [ +#CHECK-NEXT: Tag Type Name/Value +#CHECK-NEXT: 0x0000000000000006 SYMTAB 0x1C8 +#CHECK-NEXT: 0x000000000000000B SYMENT 24 +#CHECK-NEXT: 0x0000000000000005 STRTAB 0x210 +#CHECK-NEXT: 0x000000000000000A STRSZ 5 +#CHECK-NEXT: 0x0000000000000004 HASH 0x1F8 +#CHECK-NEXT: 0x0000000000000000 NULL 0x0 +#CHECK-NEXT:] + +#LINK: Index: 3 +#LINK-NEXT: Name: .dynstr + +#LINK: Name: .dynamic +#LINK-NEXT: Type: SHT_DYNAMIC +#LINK-NEXT: Flags [ +#LINK-NEXT: SHF_ALLOC +#LINK-NEXT: SHF_WRITE +#LINK-NEXT: ] +#LINK-NEXT: Address: +#LINK-NEXT: Offset: +#LINK-NEXT: Size: +#LINK-NEXT: Link: 3 Index: test/tools/llvm-objcopy/dynstr.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/dynstr.test @@ -0,0 +1,32 @@ +# RUN: yaml2obj %s > %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: ) Index: test/tools/llvm-objcopy/dynsym.test =================================================================== --- /dev/null +++ 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:] Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -194,6 +194,34 @@ } }; +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 @@ 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 ErrMsg, + llvm::Twine CastErrMsg); + protected: StringTableSection *SectionNames; SymbolTableSection *SymbolTable; Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -228,6 +228,12 @@ 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 @@ 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 @@ 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 @@ 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); } @@ -365,6 +368,22 @@ } } +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 ErrMsg, + Twine CastErrMsg) { + if (T *TSec = llvm::dyn_cast(getSection(Index, ErrMsg))) + return TSec; + error(CastErrMsg); +} + template std::unique_ptr Object::makeSection(const llvm::object::ELFFile &ElfFile, @@ -375,7 +394,26 @@ 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 @@ // 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 @@ 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