Index: test/Object/X86/obj2yaml-dup-section-name.s =================================================================== --- test/Object/X86/obj2yaml-dup-section-name.s +++ test/Object/X86/obj2yaml-dup-section-name.s @@ -9,16 +9,16 @@ # CHECK: - Name: .text.foo{{$}} # CHECK: - Name: .rela.text.foo{{$}} # CHECK: Info: .text.foo{{$}} -# CHECK: - Name: .group1{{$}} +# CHECK: - Name: '.group [1]' # CHECK: Members: -# CHECK: - SectionOrType: .text.foo2{{$}} -# CHECK: - SectionOrType: .rela.text.foo3{{$}} -# CHECK: - Name: .text.foo2{{$}} -# CHECK: - Name: .rela.text.foo3{{$}} -# CHECK: Info: .text.foo2{{$}} +# CHECK: - SectionOrType: '.text.foo [2]' +# CHECK: - SectionOrType: '.rela.text.foo [3]' +# CHECK: - Name: '.text.foo [2]' +# CHECK: - Name: '.rela.text.foo [3]' +# CHECK: Info: '.text.foo [2]' # CHECK: Symbols: # CHECK: Section: .group{{$}} -# CHECK: Section: .group1{{$}} +# CHECK: Section: '.group [1]' .section .text.foo,"axG",@progbits,sym1,comdat Index: test/tools/obj2yaml/duplicate-symbol-names.test =================================================================== --- /dev/null +++ test/tools/obj2yaml/duplicate-symbol-names.test @@ -0,0 +1,105 @@ +## Check that obj2yaml is able to produce the YAML +## from the object containing symbols with duplicate names. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj -t %t1 | FileCheck %s + +# CHECK: Name: localfoo (1) +# CHECK: Name: localfoo (1) + +# RUN: obj2yaml %t1 | FileCheck %s --check-prefix=CASE1 + +# CASE1: --- !ELF +# CASE1-NEXT: FileHeader: +# CASE1-NEXT: Class: ELFCLASS64 +# CASE1-NEXT: Data: ELFDATA2LSB +# CASE1-NEXT: Type: ET_REL +# CASE1-NEXT: Machine: EM_X86_64 +# CASE1-NEXT: Symbols: +# CASE1-NEXT: - Name: localfoo +# CASE1-NEXT: - Name: 'localfoo [1]' +# CASE1-NEXT: ... + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Symbols: + - Name: 'localfoo [111]' + - Name: 'localfoo [222]' + +## Check we can refer to symbols with the same +## name from the relocations. + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=CASE2 + +# CASE2: Relocations: +# CASE2-NEXT: - Offset: 0x0000000000000000 +# CASE2-NEXT: Symbol: 'foo [1]' +# CASE2-NEXT: Type: R_X86_64_PC32 +# CASE2-NEXT: - Offset: 0x0000000000000004 +# CASE2-NEXT: Symbol: foo +# CASE2-NEXT: Type: R_X86_64_PC32 +# CASE2-NEXT: Symbols: +# CASE2-NEXT: - Name: foo +# CASE2-NEXT: - Name: 'foo [1]' + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Size: 8 + - Name: .rela.text + Type: SHT_RELA + Info: .text + Link: .symtab + Relocations: + - Type: R_X86_64_PC32 + Offset: 0 + Symbol: 'foo [1]' + - Type: R_X86_64_PC32 + Offset: 4 + Symbol: foo +Symbols: + - Name: foo + - Name: 'foo [1]' + +## Check obj2yaml does not add a suffix to name if the symbol +## is in .symtab and .dynsym at the same time. + +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: obj2yaml %t3 | FileCheck %s --check-prefix=CASE3 + +# CASE3: --- !ELF +# CASE3-NEXT: FileHeader: +# CASE3-NEXT: Class: ELFCLASS64 +# CASE3-NEXT: Data: ELFDATA2LSB +# CASE3-NEXT: Type: ET_DYN +# CASE3-NEXT: Machine: EM_X86_64 +# CASE3-NEXT: Symbols: +# CASE3-NEXT: - Name: foo +# CASE3-NEXT: Binding: STB_GLOBAL +# CASE3-NEXT: DynamicSymbols: +# CASE3-NEXT: - Name: foo +# CASE3-NEXT: Binding: STB_GLOBAL + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Symbols: + - Name: foo + Binding: STB_GLOBAL +DynamicSymbols: + - Name: foo + Binding: STB_GLOBAL Index: test/tools/yaml2obj/duplicate-section-names.test =================================================================== --- /dev/null +++ test/tools/yaml2obj/duplicate-section-names.test @@ -0,0 +1,63 @@ +## Check that yaml2obj is able to produce an object from the YAML +## containing section with duplicate names (but different name suffixes). + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj -s %t1 | FileCheck %s --check-prefix=CASE1 + +# CASE1: Name: .foo1 ( +# CASE1: Name: .foo ( +# CASE1: Name: .foo ( +# CASE1: Name: .foo2 ( + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .foo1 + Type: SHT_PROGBITS + - Name: .foo + Type: SHT_PROGBITS + - Name: '.foo [1]' + Type: SHT_PROGBITS + - Name: .foo2 + Type: SHT_PROGBITS + +## Check that yaml2obj reports an error in case we have +## sections with equal names and suffixes. + +# RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=CASE2 +# CASE2: error: Repeated section name: '.foo [1]' at YAML section number 1. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: '.foo [1]' + Type: SHT_PROGBITS + - Name: '.foo [1]' + Type: SHT_PROGBITS + +## Check that yaml2obj reports an error in case we have +## symbols without suffixes in the names and their +## names are equal. + +# RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=CASE3 +# CASE3: error: Repeated section name: '.foo' at YAML section number 1. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .foo + Type: SHT_PROGBITS Index: test/tools/yaml2obj/duplicate-symbol-names.test =================================================================== --- /dev/null +++ test/tools/yaml2obj/duplicate-symbol-names.test @@ -0,0 +1,53 @@ +## Check that yaml2obj is able to produce an object from the YAML +## containing symbols with duplicate names (but different name suffixes). + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj -t %t1 | FileCheck %s --check-prefix=CASE1 + +# CASE1: Name: localfoo (1) +# CASE1: Name: localfoo (1) + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Symbols: + - Name: localfoo + - Name: 'localfoo [1]' + +## Check that yaml2obj reports an error in case we have +## symbols with equal names and suffixes. + +# RUN: not yaml2obj --docnum=2 %s 2>&1| FileCheck %s --check-prefix=CASE2 +# CASE2: error: Repeated symbol name: 'localfoo [1]'. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Symbols: + - Name: 'localfoo [1]' + - Name: 'localfoo [1]' + +## Check that yaml2obj reports an error in case we have +## symbols without suffixes in the names and their +## names are equal. + +# RUN: not yaml2obj --docnum=3 %s 2>&1| FileCheck %s --check-prefix=CASE3 +# CASE3: error: Repeated symbol name: 'localfoo'. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Symbols: + - Name: localfoo + Section: .text.foo.1 + - Name: localfoo + Section: .text.foo.2 Index: tools/obj2yaml/elf2yaml.cpp =================================================================== --- tools/obj2yaml/elf2yaml.cpp +++ tools/obj2yaml/elf2yaml.cpp @@ -28,15 +28,22 @@ typedef typename ELFT::Rela Elf_Rela; ArrayRef Sections; + ArrayRef SymTable; - // If the file has multiple sections with the same name, we add a - // suffix to make them unique. + // If the file has multiple sections or symbols with the same name, + // we add a special suffix to make them unique. unsigned Suffix = 0; + DenseSet UsedSectionNames; std::vector SectionNames; + + DenseSet UsedSymbolNames; + std::vector SymbolNames; + Expected getUniquedSectionName(const Elf_Shdr *Sec); - Expected getSymbolName(const Elf_Sym *Sym, StringRef StrTable, - const Elf_Shdr *SymTab); + Expected getUniquedSymbolName(const Elf_Sym *Sym, + StringRef StrTable, + const Elf_Shdr *SymTab); const object::ELFFile &Obj; ArrayRef ShndxTable; @@ -87,16 +94,17 @@ return NameOrErr; StringRef Name = *NameOrErr; std::string &Ret = SectionNames[SecIndex]; - Ret = Name; - while (!UsedSectionNames.insert(Ret).second) - Ret = (Name + to_string(++Suffix)).str(); + if (!UsedSectionNames.insert(Name).second) + Ret = (Name + " [" + to_string(++Suffix) + "]").str(); + else + Ret = Name; return Ret; } template -Expected ELFDumper::getSymbolName(const Elf_Sym *Sym, - StringRef StrTable, - const Elf_Shdr *SymTab) { +Expected +ELFDumper::getUniquedSymbolName(const Elf_Sym *Sym, StringRef StrTable, + const Elf_Shdr *SymTab) { Expected SymbolNameOrErr = Sym->getName(StrTable); if (!SymbolNameOrErr) return SymbolNameOrErr; @@ -107,6 +115,22 @@ return ShdrOrErr.takeError(); return getUniquedSectionName(*ShdrOrErr); } + + // Symbols in .symtab can have duplicate names. For example, it is a common + // situation for local symbols in a relocatable object. Here we assign unique + // suffixes for such symbols so that we can differentiate them. + if (SymTab->sh_type == ELF::SHT_SYMTAB) { + unsigned Index = Sym - SymTable.data(); + if (!SymbolNames[Index].empty()) + return SymbolNames[Index]; + + if (UsedSymbolNames.insert(Name).second) + SymbolNames[Index] = Name; + else + SymbolNames[Index] = (Name + " [" + to_string(++Suffix) + "]").str(); + return SymbolNames[Index]; + } + return Name; } @@ -123,15 +147,24 @@ Y->Header.Flags = Obj.getHeader()->e_flags; Y->Header.Entry = Obj.getHeader()->e_entry; - const Elf_Shdr *Symtab = nullptr; - const Elf_Shdr *DynSymtab = nullptr; - // Dump sections auto SectionsOrErr = Obj.sections(); if (!SectionsOrErr) return errorToErrorCode(SectionsOrErr.takeError()); Sections = *SectionsOrErr; SectionNames.resize(Sections.size()); + + // Dump symbols. We need to do that early because another sections might want + // to access the deduplicated symbol names that we also create here. + for (const Elf_Shdr &Sec : Sections) { + if (Sec.sh_type == ELF::SHT_SYMTAB) + if (auto EC = dumpSymbols(&Sec, Y->Symbols)) + return EC; + if (Sec.sh_type == ELF::SHT_DYNSYM) + if (auto EC = dumpSymbols(&Sec, Y->DynamicSymbols)) + return EC; + } + for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { case ELF::SHT_DYNAMIC: { @@ -143,13 +176,9 @@ } case ELF::SHT_NULL: case ELF::SHT_STRTAB: - // Do not dump these sections. - break; case ELF::SHT_SYMTAB: - Symtab = &Sec; - break; case ELF::SHT_DYNSYM: - DynSymtab = &Sec; + // Do not dump these sections. break; case ELF::SHT_SYMTAB_SHNDX: { auto TableOrErr = Obj.getSHNDXTable(Sec); @@ -217,11 +246,6 @@ } } - if (auto EC = dumpSymbols(Symtab, Y->Symbols)) - return EC; - if (auto EC = dumpSymbols(DynSymtab, Y->DynamicSymbols)) - return EC; - return Y.release(); } @@ -241,6 +265,11 @@ if (!SymtabOrErr) return errorToErrorCode(SymtabOrErr.takeError()); + if (Symtab->sh_type == ELF::SHT_SYMTAB) { + SymTable = (*SymtabOrErr); + SymbolNames.resize(SymTable.size()); + } + for (const auto &Sym : (*SymtabOrErr).drop_front()) { ELFYAML::Symbol S; if (auto EC = dumpSymbol(&Sym, Symtab, StrTable, S)) @@ -261,7 +290,8 @@ S.Other = Sym->st_other; S.Binding = Sym->getBinding(); - Expected SymbolNameOrErr = getSymbolName(Sym, StrTable, SymTab); + Expected SymbolNameOrErr = + getUniquedSymbolName(Sym, StrTable, SymTab); if (!SymbolNameOrErr) return errorToErrorCode(SymbolNameOrErr.takeError()); S.Name = SymbolNameOrErr.get(); @@ -310,7 +340,7 @@ StringRef StrTab = *StrTabOrErr; if (Sym) { - Expected NameOrErr = getSymbolName(Sym, StrTab, SymTab); + Expected NameOrErr = getUniquedSymbolName(Sym, StrTab, SymTab); if (!NameOrErr) return errorToErrorCode(NameOrErr.takeError()); R.Symbol = NameOrErr.get(); @@ -603,7 +633,7 @@ return errorToErrorCode(StrTabOrErr.takeError()); Expected SymbolName = - getSymbolName(*SymOrErr, *StrTabOrErr, Symtab); + getUniquedSymbolName(*SymOrErr, *StrTabOrErr, Symtab); if (!SymbolName) return errorToErrorCode(SymbolName.takeError()); S->Signature = *SymbolName; Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -268,6 +268,13 @@ return true; } +static StringRef dropUniqueSuffix(StringRef S) { + size_t SuffixPos = S.rfind(" ["); + if (SuffixPos == StringRef::npos) + return S; + return S.slice(0, SuffixPos); +} + template bool ELFState::initSectionHeaders(ELFState &State, std::vector &SHeaders, @@ -301,7 +308,7 @@ assert(Sec && "It can't be null unless it is an implicit section. But all " "implicit sections should already have been handled above."); - SHeader.sh_name = DotShStrtab.getOffset(SecName); + SHeader.sh_name = DotShStrtab.getOffset(dropUniqueSuffix(SecName)); SHeader.sh_type = Sec->Type; if (Sec->Flags) SHeader.sh_flags = *Sec->Flags; @@ -591,7 +598,7 @@ if (Sym.NameIndex) Symbol.st_name = *Sym.NameIndex; else if (!Sym.Name.empty()) - Symbol.st_name = Strtab.getOffset(Sym.Name); + Symbol.st_name = Strtab.getOffset(dropUniqueSuffix(Sym.Name)); Symbol.setBindingAndType(Sym.Binding, Sym.Type); if (!Sym.Section.empty()) { @@ -904,7 +911,7 @@ template bool ELFState::buildSectionIndex() { for (unsigned i = 0, e = Doc.Sections.size(); i != e; ++i) { StringRef Name = Doc.Sections[i]->Name; - DotShStrtab.add(Name); + DotShStrtab.add(dropUniqueSuffix(Name)); // "+ 1" to take into account the SHT_NULL entry. if (!SN2I.addName(Name, i + 1)) { WithColor::error() << "Repeated section name: '" << Name @@ -953,12 +960,12 @@ template void ELFState::finalizeStrings() { // Add the regular symbol names to .strtab section. for (const ELFYAML::Symbol &Sym : Doc.Symbols) - DotStrtab.add(Sym.Name); + DotStrtab.add(dropUniqueSuffix(Sym.Name)); DotStrtab.finalize(); // Add the dynamic symbol names to .dynstr section. for (const ELFYAML::Symbol &Sym : Doc.DynamicSymbols) - DotDynstr.add(Sym.Name); + DotDynstr.add(dropUniqueSuffix(Sym.Name)); // SHT_GNU_verdef and SHT_GNU_verneed sections might also // add strings to .dynstr section.