Index: test/tools/llvm-objcopy/basic-copy.test =================================================================== --- test/tools/llvm-objcopy/basic-copy.test +++ test/tools/llvm-objcopy/basic-copy.test @@ -17,11 +17,6 @@ # CHECK: Type: SHT_NULL -# CHECK: Name: .shstrtab -# CHECK-NEXT: Type: SHT_STRTAB -# CHECK-NEXT: Flags [ -# CHECK-NEXT: ] - # CHECK: Name: .text # CHECK-NEXT: Type: SHT_PROGBITS # CHECK-NEXT: Flags [ @@ -31,3 +26,18 @@ # CHECK-NEXT: Address: # CHECK-NEXT: Offset: # CHECK-NEXT: Size: 4 + +# CHECK: Name: .symtab +# CHECK-NEXT: Type: SHT_SYMTAB +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] + +# CHECK: Name: .strtab +# CHECK-NEXT: Type: SHT_STRTAB +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] + +# CHECK: Name: .shstrtab +# CHECK-NEXT: Type: SHT_STRTAB +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] Index: test/tools/llvm-objcopy/symbol-copy.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/symbol-copy.test @@ -0,0 +1,91 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy %t %t2 +# RUN: llvm-readobj -symbols %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000000010 + Content: "0000000000000000" + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x2000 + AddressAlign: 0x0000000000000010 + Content: "0000000000000000" +Symbols: + Global: + - Name: _start + Type: STT_FUNC + Section: .text + Value: 0x1000 + Size: 4 + - Name: foo + Type: STT_FUNC + Section: .text + Section: .text + Value: 0x1004 + - Name: bar + Type: STT_OBJECT + Section: .data + Value: 0x2000 + Size: 4 + - Name: baz + Type: STT_OBJECT + Section: .data + Value: 0x2004 + Size: 4 + +#CHECK: Symbols [ +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: (0) +#CHECK-NEXT: Value: 0x0 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Local +#CHECK-NEXT: Type: None +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Undefined +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: _start +#CHECK-NEXT: Value: 0x1000 +#CHECK-NEXT: Size: 4 +#CHECK-NEXT: Binding: Global +#CHECK-NEXT: Type: Function +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .text +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: foo +#CHECK-NEXT: Value: 0x1004 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global +#CHECK-NEXT: Type: Function +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .text +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: bar +#CHECK-NEXT: Value: 0x2000 +#CHECK-NEXT: Size: 4 +#CHECK-NEXT: Binding: Global +#CHECK-NEXT: Type: Object +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .data +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: baz +#CHECK-NEXT: Value: 0x2004 +#CHECK-NEXT: Size: 4 +#CHECK-NEXT: Binding: Global +#CHECK-NEXT: Type: Object +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: .data Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -106,6 +106,42 @@ } }; +struct Symbol { + uint8_t Binding; + SectionBase *DefinedIn; + uint32_t Index; + llvm::StringRef Name; + uint32_t NameIndex; + uint64_t Size; + uint8_t Type; + uint64_t Value; +}; + +// The symbol data changes from ELFT to ELFT so we need to template it. This +// lets us implement writeSection +template class SymbolTableSection : public SectionBase { +private: + std::vector FinalSymbols; + llvm::StringMap Symbols; + StringTableSection &SymbolNames; + +public: + SymbolTableSection(StringTableSection &SymNames) : SymbolNames(SymNames) { + Type = llvm::ELF::SHT_SYMTAB; + Align = sizeof(typename ELFT::Word); + EntrySize = sizeof(typename ELFT::Sym); + } + + void addSymbol(llvm::StringRef Name, uint8_t Bind, uint8_t Type, + SectionBase *DefinedIn, uint64_t Value, uint64_t Sz); + void removeSymbol(llvm::StringRef); + void finalize() override; + void writeSection(llvm::FileOutputBuffer &) const override; + static bool classof(const SectionBase *S) { + return S->Type == llvm::ELF::SHT_SYMTAB; + } +}; + template class Object { private: @@ -114,6 +150,8 @@ typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; + SymbolTableSection *SymbolTable; + StringTableSection *StringTable; StringTableSection *SectionNames; std::vector Sections; std::vector Segments; @@ -122,6 +160,8 @@ void assignOffsets(); void readProgramHeaders(const llvm::object::ELFFile &ElfFile); void readSectionHeaders(const llvm::object::ELFFile &ElfFile); + void readSymbolTable(const llvm::object::ELFFile &ElfFile, + const Elf_Shdr &SymTabShdr); void writeHeader(llvm::FileOutputBuffer &Out) const; void writeProgramHeaders(llvm::FileOutputBuffer &Out) const; void writeSectionData(llvm::FileOutputBuffer &Out) const; Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -103,6 +103,78 @@ } } +template +void SymbolTableSection::addSymbol(StringRef Name, uint8_t Bind, + uint8_t Type, SectionBase *DefinedIn, + uint64_t Value, uint64_t Sz) { + Symbol Sym; + Sym.Name = Name; + Sym.Binding = Bind; + Sym.Type = Type; + Sym.DefinedIn = DefinedIn; + Sym.Value = Value; + Sym.Size = Sz; + Sym.Index = Symbols.size(); + auto Res = Symbols.insert(std::make_pair(Name, Sym)); + if (Res.second) + Size += sizeof(typename ELFT::Sym); + SymbolNames.addString(Name); +} + +template +void SymbolTableSection::removeSymbol(StringRef Name) { + auto Iter = Symbols.find(Name); + if (Iter != std::end(Symbols)) { + Symbols.erase(Iter); + Size += sizeof(ELFT::Sym); + } + SymbolNames.removeString(Name); +} + +template void SymbolTableSection::finalize() { + auto CompareBinding = [](const Symbol &a, const Symbol &b) { + return a.Binding < b.Binding; + }; + auto CompareIndex = [](const Symbol &a, const Symbol &b) { + return a.Index < b.Index; + }; + // Make sure that SymbolNames is finalized first + SymbolNames.finalize(); + for (auto &Entry : Symbols) { + Entry.second.NameIndex = SymbolNames.findIndex(Entry.second.Name); + FinalSymbols.push_back(Entry.second); + } + Symbol DummyLocal; + DummyLocal.Binding = STB_LOCAL; + std::sort(std::begin(FinalSymbols), std::end(FinalSymbols), CompareIndex); + std::stable_sort(std::begin(FinalSymbols), std::end(FinalSymbols), + CompareBinding); + auto Iter = std::upper_bound(std::begin(FinalSymbols), std::end(FinalSymbols), + DummyLocal, CompareBinding); + Info = std::end(FinalSymbols) - Iter; + Link = SymbolNames.Index; +} + +template +void SymbolTableSection::writeSection(llvm::FileOutputBuffer &Out) const { + uint8_t *Buf = Out.getBufferStart(); + Buf += Offset; + typename ELFT::Sym *Sym = reinterpret_cast(Buf); + + for(auto &Symbol : FinalSymbols) { + Sym->st_name = Symbol.NameIndex; + Sym->st_value = Symbol.Value; + Sym->st_size = Symbol.Size; + Sym->setBinding(Symbol.Binding); + Sym->setType(Symbol.Type); + if(Symbol.DefinedIn) + Sym->st_shndx = Symbol.DefinedIn->Index; + else + Sym->st_shndx = SHN_UNDEF; + ++Sym; + } +} + template void Object::readProgramHeaders(const ELFFile &ElfFile) { uint32_t Index = 0; @@ -127,14 +199,64 @@ } } +template +void Object::readSymbolTable(const ELFFile &ElfFile, + const Elf_Shdr &SymTabShdr) { + + StringTableSection *StrTab = + dyn_cast(Sections[SymTabShdr.sh_link].get()); + + uint32_t SymTabIndex = + &SymTabShdr - unwrapOrError(ElfFile.sections()).begin(); + + SymbolTable = new SymbolTableSection(*StrTab); + SymbolTable->Name = unwrapOrError(ElfFile.getSectionName(&SymTabShdr)); + SymbolTable->Index = SymTabIndex; + SectionNames->addString(SymbolTable->Name); + + StringRef StrTabData = + unwrapOrError(ElfFile.getStringTableForSymtab(SymTabShdr)); + + for (const auto &Sym : unwrapOrError(ElfFile.symbols(&SymTabShdr))) { + SectionBase *DefSection = nullptr; + if (Sym.st_shndx != SHN_UNDEF) + DefSection = Sections[Sym.st_shndx].get(); + StringRef Name = unwrapOrError(Sym.getName(StrTabData)); + SymbolTable->addSymbol(Name, Sym.getBinding(), Sym.getType(), DefSection, + Sym.getValue(), Sym.st_size); + } + // Calculate where the SymbolTable belongs + Sections[SymTabIndex].reset(SymbolTable); +} + +template +static std::unique_ptr makeSection(ArrayRef Data, + uint64_t Type) { + if (Type == SHT_STRTAB) + return make_unique(); + return make_unique
(Data); +} + template void Object::readSectionHeaders(const ELFFile &ElfFile) { uint32_t Index = 0; + const Elf_Shdr *SymTabShdr = nullptr; for (const auto &Shdr : unwrapOrError(ElfFile.sections())) { - if (Shdr.sh_type == SHT_STRTAB) + if (Index == SectionNames->Index) { + Sections.emplace_back(SectionNames); + Index++; continue; + } + if (Shdr.sh_type == SHT_SYMTAB) { + // Put a placeholder in Sections so that Index corrasponds to the + // location in the array the symbol table should go + Sections.emplace_back(nullptr); + SymTabShdr = &Shdr; + Index++; + continue; + } ArrayRef Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); - SecPtr Sec = make_unique
(Data); + SecPtr Sec = makeSection(Data, Shdr.sh_type); Sec->Name = unwrapOrError(ElfFile.getSectionName(&Shdr)); Sec->Type = Shdr.sh_type; Sec->Flags = Shdr.sh_flags; @@ -145,11 +267,14 @@ Sec->Info = Shdr.sh_info; Sec->Align = Shdr.sh_addralign; Sec->EntrySize = Shdr.sh_entsize; - Sec->Index = Index; - Index++; + Sec->Index = Index++; SectionNames->addString(Sec->Name); Sections.push_back(std::move(Sec)); } + // If we encountered a symbol table construct it now that we should have + // every section + if (SymTabShdr) + readSymbolTable(ElfFile, *SymTabShdr); } template size_t Object::totalSize() const { @@ -168,26 +293,21 @@ Version = Ehdr.e_version; Entry = Ehdr.e_entry; Flags = Ehdr.e_flags; + SectionNames = new StringTableSection(); - SectionNames->Name = ".shstrtab"; + auto Shdr = unwrapOrError(ElfFile.getSection(Ehdr.e_shstrndx)); + SectionNames->Name = unwrapOrError(ElfFile.getSectionName(Shdr)); + SectionNames->Index = Ehdr.e_shstrndx; SectionNames->addString(SectionNames->Name); - Sections.emplace_back(SectionNames); readSectionHeaders(ElfFile); readProgramHeaders(ElfFile); } template void Object::sortSections() { - // Put allocated sections in address order. Maintain ordering as closely as - // possible while meeting that demand however. - auto CompareSections = [](const SecPtr &A, const SecPtr &B) { - if (A->Type == SHT_NULL) - return true; - if (A->Flags & SHF_ALLOC && B->Flags & SHF_ALLOC) - return A->Addr < B->Addr; - return A->Index < B->Index; - }; - std::sort(std::begin(Sections), std::end(Sections), CompareSections); + std::sort( + std::begin(Sections), std::end(Sections), + [](const SecPtr &A, const SecPtr &B) { return A->Index < B->Index; }); } uint64_t align(uint64_t Value, uint64_t Multiple) { @@ -221,7 +341,7 @@ // section header table offset to be exactly here. This spot might not be // aligned properlly however so we should align it as needed. This only takes // a little bit of tweaking to ensure that the sh_name is 4 byte aligned - Offset += 4 - Offset % 4; + Offset = align(Offset, 4); SHOffset = Offset; } @@ -231,6 +351,7 @@ // finalize SectionNames first so that we can assign name indexes. SectionNames->finalize(); + // Finally now that all offsets and indexes have been set we can finalize any // reamining issues. uint64_t Offset = SHOffset;