diff --git a/llvm/include/llvm/Object/Archive.h b/llvm/include/llvm/Object/Archive.h --- a/llvm/include/llvm/Object/Archive.h +++ b/llvm/include/llvm/Object/Archive.h @@ -352,6 +352,12 @@ return make_range(symbol_begin(), symbol_end()); } + symbol_iterator ec_symbol_begin() const; + symbol_iterator ec_symbol_end() const; + iterator_range ec_symbols() const { + return make_range(ec_symbol_begin(), ec_symbol_end()); + } + static bool classof(Binary const *v) { return v->isArchive(); } // check if a symbol is in the archive @@ -362,6 +368,7 @@ StringRef getSymbolTable() const { return SymbolTable; } StringRef getStringTable() const { return StringTable; } uint32_t getNumberOfSymbols() const; + uint32_t getNumberOfECSymbols() const; virtual uint64_t getFirstChildOffset() const { return getArchiveMagicLen(); } std::vector> takeThinBuffers() { @@ -377,6 +384,7 @@ void setFirstRegular(const Child &C); StringRef SymbolTable; + StringRef ECSymbolTable; StringRef StringTable; private: diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp --- a/llvm/lib/Object/Archive.cpp +++ b/llvm/lib/Object/Archive.cpp @@ -933,6 +933,30 @@ StringTable = BufOrErr.get(); if (Increment()) return; + + if (I == E) { + setFirstRegular(*C); + Err = Error::success(); + return; + } + + NameOrErr = C->getRawName(); + if (!NameOrErr) { + Err = NameOrErr.takeError(); + return; + } + Name = NameOrErr.get(); + } + + if (Name.equals("//")) { + Expected BufOrErr = C->getBuffer(); + if (!BufOrErr) { + Err = BufOrErr.takeError(); + return; + } + ECSymbolTable = BufOrErr.get(); + if (Increment()) + return; } setFirstRegular(*C); @@ -968,6 +992,8 @@ } StringRef Archive::Symbol::getName() const { + if (Parent->getNumberOfSymbols() <= SymbolIndex) + return Parent->ECSymbolTable.begin() + StringIndex; return Parent->getSymbolTable().begin() + StringIndex; } @@ -1006,15 +1032,24 @@ Buf += MemberCount * 4 + 4; uint32_t SymbolCount = read32le(Buf); - if (SymbolIndex >= SymbolCount) + uint16_t OffsetIndex; + if (SymbolIndex < SymbolCount) { + // Skip SymbolCount to get to the indices table. + const char *Indices = Buf + 4; + + // Get the index of the offset in the file member offset table for this + // symbol. + OffsetIndex = read16le(Indices + SymbolIndex * 2); + } else if (SymbolIndex < SymbolCount + Parent->getNumberOfECSymbols()) { + // Skip SymbolCount to get to the indices table. + const char *Indices = Parent->ECSymbolTable.begin() + 4; + + // Get the index of the offset in the file member offset table for this + // symbol. + OffsetIndex = read16le(Indices + (SymbolIndex - SymbolCount) * 2); + } else { return errorCodeToError(object_error::parse_failed); - - // Skip SymbolCount to get to the indices table. - const char *Indices = Buf + 4; - - // Get the index of the offset in the file member offset table for this - // symbol. - uint16_t OffsetIndex = read16le(Indices + SymbolIndex * 2); + } // Subtract 1 since OffsetIndex is 1 based. --OffsetIndex; @@ -1063,11 +1098,18 @@ t.StringIndex -= CurRanStrx; t.StringIndex += NextRanStrx; } + } else if (!Parent->ECSymbolTable.empty() && + t.SymbolIndex >= Parent->getNumberOfSymbols()) { + // Go to one past next null. + t.StringIndex = Parent->ECSymbolTable.find('\0', t.StringIndex) + 1; } else { // Go to one past next null. t.StringIndex = Parent->getSymbolTable().find('\0', t.StringIndex) + 1; } ++t.SymbolIndex; + if (!Parent->ECSymbolTable.empty() && + t.SymbolIndex == Parent->getNumberOfSymbols()) + t.StringIndex = Parent->getNumberOfECSymbols() * 2 + 4; return t; } @@ -1133,6 +1175,15 @@ return symbol_iterator(Symbol(this, getNumberOfSymbols(), 0)); } +Archive::symbol_iterator Archive::ec_symbol_begin() const { + return symbol_iterator(Symbol(this, getNumberOfSymbols(), getNumberOfECSymbols() * 2 + 4)); +} + +Archive::symbol_iterator Archive::ec_symbol_end() const { + return symbol_iterator( + Symbol(this, getNumberOfSymbols() + getNumberOfECSymbols(), 0)); +} + uint32_t Archive::getNumberOfSymbols() const { if (!hasSymbolTable()) return 0; @@ -1151,6 +1202,10 @@ return read32le(buf); } +uint32_t Archive::getNumberOfECSymbols() const { + return ECSymbolTable.empty() ? 0 : read32le(ECSymbolTable.begin()); +} + Expected> Archive::findSym(StringRef name) const { Archive::symbol_iterator bs = symbol_begin(); Archive::symbol_iterator es = symbol_end(); diff --git a/llvm/test/tools/llvm-lib/ecsymbols.test b/llvm/test/tools/llvm-lib/ecsymbols.test --- a/llvm/test/tools/llvm-lib/ecsymbols.test +++ b/llvm/test/tools/llvm-lib/ecsymbols.test @@ -1,10 +1,9 @@ -# Check that llvm-lib can list the members of an archive which contains the +# Check that llvm-lib doesn't list the members of an archive which contains the # special member //. # RUN: yaml2obj %s -o %t.lib -# RUN: llvm-lib /list %t.lib | FileCheck %s - -# CHECK: // +# RUN: llvm-lib /list %t.lib | FileCheck --check-prefix=NOEC --allow-empty %s +# NOEC-NOT: ECSYMBOLS --- !Arch Members: @@ -23,3 +22,12 @@ # RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o x64-foo.o %S/Inputs/b.s # RUN: llvm-lib -machine:arm64ec -out:foo.lib arm64-foo.o arm64ec-foo.o x64-foo.o # RUN: grep -q '//' foo.lib + +# RUN: llvm-nm --print-armap foo.lib | FileCheck %s +# CHECK: Archive map +# CHECK-NEXT: a in arm64-foo.o +# CHECK-EMPTY: +# CHECK-NEXT: Archive EC map +# CHECK-NEXT: a in arm64ec-foo.o +# CHECK-NEXT: b in x64-foo.o +# CHECK-EMPTY: diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -1954,26 +1954,37 @@ return true; } +static void printArchiveMap(iterator_range &map, + StringRef Filename) { + for (auto I : map) { + Expected C = I.getMember(); + if (!C) { + error(C.takeError(), Filename); + break; + } + Expected FileNameOrErr = C->getName(); + if (!FileNameOrErr) { + error(FileNameOrErr.takeError(), Filename); + break; + } + StringRef SymName = I.getName(); + outs() << SymName << " in " << FileNameOrErr.get() << "\n"; + } + + outs() << "\n"; +} + static void dumpArchiveMap(Archive *A, StringRef Filename) { - Archive::symbol_iterator I = A->symbol_begin(); - Archive::symbol_iterator E = A->symbol_end(); - if (I != E) { + auto Map = A->symbols(); + if (!Map.empty()) { outs() << "Archive map\n"; - for (; I != E; ++I) { - Expected C = I->getMember(); - if (!C) { - error(C.takeError(), Filename); - break; - } - Expected FileNameOrErr = C->getName(); - if (!FileNameOrErr) { - error(FileNameOrErr.takeError(), Filename); - break; - } - StringRef SymName = I->getName(); - outs() << SymName << " in " << FileNameOrErr.get() << "\n"; - } - outs() << "\n"; + printArchiveMap(Map, Filename); + } + + Map = A->ec_symbols(); + if (!Map.empty()) { + outs() << "Archive EC map\n"; + printArchiveMap(Map, Filename); } }