Index: llvm/trunk/test/tools/llvm-objcopy/abs-symbol.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/abs-symbol.test +++ llvm/trunk/test/tools/llvm-objcopy/abs-symbol.test @@ -0,0 +1,36 @@ +# 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 +Symbols: + Global: + - Name: test + Index: SHN_ABS + Value: 0x1234 + +#CHECK: Symbols [ +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: +#CHECK-NEXT: Value: 0x0 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Local (0x0) +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Undefined (0x0) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: test +#CHECK-NEXT: Value: 0x1234 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Absolute (0xFFF1) +#CHECK-NEXT: } +#CHECK-NEXT:] Index: llvm/trunk/test/tools/llvm-objcopy/common-symbol.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/common-symbol.test +++ llvm/trunk/test/tools/llvm-objcopy/common-symbol.test @@ -0,0 +1,84 @@ +# 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 +Symbols: + Global: + - Name: test + Index: SHN_COMMON + Value: 0x1234 + - Name: test2 + Index: SHN_HEXAGON_SCOMMON + Value: 0x1235 + - Name: test3 + Index: SHN_HEXAGON_SCOMMON_2 + Value: 0x1236 + - Name: test4 + Index: SHN_HEXAGON_SCOMMON_4 + Value: 0x1237 + - Name: test5 + Index: SHN_HEXAGON_SCOMMON_8 + Value: 0x1238 + +#CHECK: Symbols [ +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: +#CHECK-NEXT: Value: 0x0 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Local (0x0) +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Undefined (0x0) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: test +#CHECK-NEXT: Value: 0x1234 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Common (0xFFF2) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: test2 +#CHECK-NEXT: Value: 0x1235 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Processor Specific (0xFF00) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: test3 +#CHECK-NEXT: Value: 0x1236 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Processor Specific (0xFF02) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: test4 +#CHECK-NEXT: Value: 0x1237 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Processor Specific (0xFF03) +#CHECK-NEXT: } +#CHECK-NEXT: Symbol { +#CHECK-NEXT: Name: test5 +#CHECK-NEXT: Value: 0x1238 +#CHECK-NEXT: Size: 0 +#CHECK-NEXT: Binding: Global (0x1) +#CHECK-NEXT: Type: None (0x0) +#CHECK-NEXT: Other: 0 +#CHECK-NEXT: Section: Processor Specific (0xFF04) +#CHECK-NEXT: } +#CHECK-NEXT:] Index: llvm/trunk/test/tools/llvm-objcopy/section-index-unsupported.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/section-index-unsupported.test +++ llvm/trunk/test/tools/llvm-objcopy/section-index-unsupported.test @@ -0,0 +1,15 @@ +# RUN: yaml2obj %s > %t +# RUN: not llvm-objcopy %t %t2 2>&1 >/dev/null | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Symbols: + Global: + - Name: test + Index: 0xff05 + +# CHECK: [[_:.*]] Symbol 'test' has unsupported value greater than or equal to SHN_LORESERVE: 65285 Index: llvm/trunk/tools/llvm-objcopy/Object.h =================================================================== --- llvm/trunk/tools/llvm-objcopy/Object.h +++ llvm/trunk/tools/llvm-objcopy/Object.h @@ -113,15 +113,32 @@ } }; +// Symbols have a st_shndx field that normally stores an index but occasionally +// stores a different special value. This enum keeps track of what the st_shndx +// field means. Most of the values are just copies of the special SHN_* values. +// SYMBOL_SIMPLE_INDEX means that the st_shndx is just an index of a section. +enum SymbolShndxType { + SYMBOL_SIMPLE_INDEX = 0, + SYMBOL_ABS = llvm::ELF::SHN_ABS, + SYMBOL_COMMON = llvm::ELF::SHN_COMMON, + SYMBOL_HEXAGON_SCOMMON = llvm::ELF::SHN_HEXAGON_SCOMMON, + SYMBOL_HEXAGON_SCOMMON_2 = llvm::ELF::SHN_HEXAGON_SCOMMON_2, + SYMBOL_HEXAGON_SCOMMON_4 = llvm::ELF::SHN_HEXAGON_SCOMMON_4, + SYMBOL_HEXAGON_SCOMMON_8 = llvm::ELF::SHN_HEXAGON_SCOMMON_8, +}; + struct Symbol { uint8_t Binding; SectionBase *DefinedIn; + SymbolShndxType ShndxType; uint32_t Index; llvm::StringRef Name; uint32_t NameIndex; uint64_t Size; uint8_t Type; uint64_t Value; + + uint16_t getShndx() const; }; class SymbolTableSection : public SectionBase { @@ -132,7 +149,8 @@ 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); + SectionBase *DefinedIn, uint64_t Value, uint16_t Shndx, + uint64_t Sz); void addSymbolNames(); const Symbol *getSymbolByIndex(uint32_t Index) const; void finalize() override; Index: llvm/trunk/tools/llvm-objcopy/Object.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/Object.cpp +++ llvm/trunk/tools/llvm-objcopy/Object.cpp @@ -90,14 +90,54 @@ StrTabBuilder.write(Out.getBufferStart() + Offset); } +static bool isValidReservedSectionIndex(uint16_t Index) { + switch (Index) { + case SHN_ABS: + case SHN_COMMON: + case SHN_HEXAGON_SCOMMON: + case SHN_HEXAGON_SCOMMON_2: + case SHN_HEXAGON_SCOMMON_4: + case SHN_HEXAGON_SCOMMON_8: + return true; + default: + return false; + } +} + +uint16_t Symbol::getShndx() const { + if (DefinedIn != nullptr) { + return DefinedIn->Index; + } + switch (ShndxType) { + // This means that we don't have a defined section but we do need to + // output a legitimate section index. + case SYMBOL_SIMPLE_INDEX: + return SHN_UNDEF; + case SYMBOL_ABS: + case SYMBOL_COMMON: + case SYMBOL_HEXAGON_SCOMMON: + case SYMBOL_HEXAGON_SCOMMON_2: + case SYMBOL_HEXAGON_SCOMMON_4: + case SYMBOL_HEXAGON_SCOMMON_8: + return static_cast(ShndxType); + } + llvm_unreachable("Symbol with invalid ShndxType encountered"); +} + void SymbolTableSection::addSymbol(StringRef Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, uint64_t Value, - uint64_t Sz) { + uint16_t Shndx, uint64_t Sz) { Symbol Sym; Sym.Name = Name; Sym.Binding = Bind; Sym.Type = Type; Sym.DefinedIn = DefinedIn; + if (DefinedIn == nullptr) { + if (isValidReservedSectionIndex(Shndx)) + Sym.ShndxType = static_cast(Shndx); + else + Sym.ShndxType = SYMBOL_SIMPLE_INDEX; + } Sym.Value = Value; Sym.Size = Sz; Sym.Index = Symbols.size(); @@ -146,10 +186,7 @@ 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->st_shndx = Symbol->getShndx(); ++Sym; } } @@ -251,7 +288,14 @@ 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 >= SHN_LORESERVE) { + if (!isValidReservedSectionIndex(Sym.st_shndx)) { + error( + "Symbol '" + Name + + "' has unsupported value greater than or equal to SHN_LORESERVE: " + + 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 " + @@ -259,7 +303,7 @@ DefSection = Sections[Sym.st_shndx - 1].get(); } SymTab->addSymbol(Name, Sym.getBinding(), Sym.getType(), DefSection, - Sym.getValue(), Sym.st_size); + Sym.getValue(), Sym.st_shndx, Sym.st_size); } }