Index: test/tools/llvm-objcopy/symbol-copy.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/symbol-copy.test @@ -0,0 +1,93 @@ +# 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: +#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 +#CHECK-NEXT: } +#CHECK-NEXT:] Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -111,6 +111,39 @@ } }; +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; +}; + +class SymbolTableSection : public SectionBase { +protected: + std::vector> Symbols; + StringTableSection *SymbolNames; + +public: + void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; } + void addSymbol(llvm::StringRef Name, uint8_t Bind, uint8_t Type, + SectionBase *DefinedIn, uint64_t Value, uint64_t Sz); + void addSymbolNames(); + const Symbol *getSymbolByIndex(uint32_t Index) const; + void finalize() override; + static bool classof(const SectionBase *S) { + return S->Type == llvm::ELF::SHT_SYMTAB; + } +}; + +// Only writeSection depends on the ELF type so we implement it in a subclass. +template class SymbolTableSectionImpl : public SymbolTableSection { + void writeSection(llvm::FileOutputBuffer &Out) const override; +}; + template class Object { private: typedef std::unique_ptr SecPtr; @@ -120,6 +153,8 @@ typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; + void initSymbolTable(const llvm::object::ELFFile &ElfFile, + SymbolTableSection *SymTab); SecPtr makeSection(const llvm::object::ELFFile &ElfFile, const Elf_Shdr &Shdr); void readProgramHeaders(const llvm::object::ELFFile &ElfFile); @@ -127,6 +162,7 @@ protected: StringTableSection *SectionNames; + SymbolTableSection *SymbolTable; std::vector Sections; std::vector Segments; Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -90,6 +90,70 @@ StrTabBuilder.write(Out.getBufferStart() + Offset); } +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(); + Symbols.emplace_back(llvm::make_unique(Sym)); + Size += this->EntrySize; +} + +void SymbolTableSection::finalize() { + // Make sure SymbolNames is finalized before getting name indexes. + SymbolNames->finalize(); + + uint32_t MaxLocalIndex = 0; + for (auto &Sym : Symbols) { + Sym->NameIndex = SymbolNames->findIndex(Sym->Name); + if (Sym->Binding == STB_LOCAL) + MaxLocalIndex = std::max(MaxLocalIndex, Sym->Index); + } + // Now we need to set the Link and Info fields. + Link = SymbolNames->Index; + Info = MaxLocalIndex + 1; +} + +void SymbolTableSection::addSymbolNames() { + // Add all of our strings to SymbolNames so that SymbolNames has the right + // size before layout is decided. + for (auto &Sym : Symbols) + SymbolNames->addString(Sym->Name); +} + +const Symbol *SymbolTableSection::getSymbolByIndex(uint32_t Index) const { + if (Symbols.size() <= Index) + error("Invalid symbol index: " + Twine(Index)); + return Symbols[Index].get(); +} + +template +void SymbolTableSectionImpl::writeSection( + llvm::FileOutputBuffer &Out) const { + uint8_t *Buf = Out.getBufferStart(); + Buf += Offset; + typename ELFT::Sym *Sym = reinterpret_cast(Buf); + // Loop though symbols setting each entry of the symbol table. + for (auto &Symbol : Symbols) { + 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; + } +} + // Returns true IFF a section is wholly inside the range of a segment static bool sectionWithinSegment(const SectionBase &Section, const Segment &Segment) { @@ -131,6 +195,40 @@ } } +template +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"); + + const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index)); + StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr)); + + for (const auto &Sym : unwrapOrError(ElfFile.symbols(&Shdr))) { + SectionBase *DefSection = nullptr; + StringRef Name = unwrapOrError(Sym.getName(StrTabData)); + if (Sym.st_shndx != SHN_UNDEF) { + if (Sym.st_shndx >= Sections.size()) + error("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_size); + } +} + template std::unique_ptr Object::makeSection(const llvm::object::ELFFile &ElfFile, @@ -139,6 +237,11 @@ switch (Shdr.sh_type) { case SHT_STRTAB: return llvm::make_unique(); + case SHT_SYMTAB: { + auto SymTab = llvm::make_unique>(); + SymbolTable = SymTab.get(); + return std::move(SymTab); + } case SHT_NOBITS: return llvm::make_unique
(Data); default: @@ -170,6 +273,11 @@ Sec->Index = Index++; Sections.push_back(std::move(Sec)); } + + // Now that all of the sections have been added we can fill out some extra + // details about symbol tables. + if (SymbolTable) + initSymbolTable(ElfFile, SymbolTable); } template Object::Object(const ELFObjectFile &Obj) { @@ -324,9 +432,12 @@ } template void ELFObject::finalize() { + // Make sure we add the names of all the sections. for (const auto &Section : this->Sections) { this->SectionNames->addString(Section->Name); } + // Make sure we add the names of all the symbols. + this->SymbolTable->addSymbolNames(); sortSections(); assignOffsets();