Index: llvm/include/llvm/Object/Archive.h =================================================================== --- llvm/include/llvm/Object/Archive.h +++ llvm/include/llvm/Object/Archive.h @@ -302,6 +302,7 @@ StringRef getName() const; Expected getMember() const; Symbol getNext() const; + bool isECSymbol() const; }; class symbol_iterator { @@ -352,6 +353,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 +369,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 +385,7 @@ void setFirstRegular(const Child &C); StringRef SymbolTable; + StringRef ECSymbolTable; StringRef StringTable; private: @@ -386,6 +395,8 @@ unsigned Format : 3; unsigned IsThin : 1; mutable std::vector> ThinBuffers; + + bool validateECSymbolsMap(const StringRef &Map) const; }; class BigArchive : public Archive { Index: llvm/lib/Object/Archive.cpp =================================================================== --- llvm/lib/Object/Archive.cpp +++ llvm/lib/Object/Archive.cpp @@ -933,12 +933,65 @@ 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 == "//") { + // ARM64EC-aware libraries contain an additional special member with + // EC symbol map after string table. Its format is similar to regular + // symbol map, except it doesn't contain member offsets. Its + // indexes refer to member offsets from the regular symbol table instead. + Expected BufOrErr = C->getBuffer(); + if (!BufOrErr) { + Err = BufOrErr.takeError(); + return; + } + if (validateECSymbolsMap(BufOrErr.get())) + ECSymbolTable = BufOrErr.get(); + if (Increment()) + return; } setFirstRegular(*C); Err = Error::success(); } +bool Archive::validateECSymbolsMap(const StringRef &Map) const { + if (Map.size() < sizeof(uint32_t) || SymbolTable.size() < sizeof(uint32_t)) + return false; + + uint32_t Count = read32le(Map.begin()); + if (Map.size() < sizeof(uint32_t) + Count * sizeof(uint16_t)) + return false; + + uint32_t MemberCount = read32le(SymbolTable.begin()); + const char *Indexes = Map.begin() + sizeof(uint32_t); + uint32_t StringIndex = sizeof(uint32_t) + Count * sizeof(uint16_t); + + for (uint32_t i = 0; i < Count; i++) { + uint16_t Index = read16le(Indexes + i * sizeof(uint16_t)); + if (Index >= MemberCount) + return false; + StringIndex = Map.find('\0', StringIndex) + 1; + if (StringIndex > Map.size()) + return false; + } + + return true; +} + object::Archive::Kind Archive::getDefaultKindForHost() { Triple HostTriple(sys::getProcessTriple()); return HostTriple.isOSDarwin() @@ -967,7 +1020,17 @@ return child_iterator::end(Child(nullptr, nullptr, nullptr)); } +bool Archive::Symbol::isECSymbol() const { + // symbols use SymbolCount..SymbolCount+getNumberOfECSymbols() for EC symbol + // indexes + uint32_t SymbolCount = Parent->getNumberOfSymbols(); + return SymbolCount <= SymbolIndex && + SymbolIndex < SymbolCount + Parent->getNumberOfECSymbols(); +} + StringRef Archive::Symbol::getName() const { + if (isECSymbol()) + return Parent->ECSymbolTable.begin() + StringIndex; return Parent->getSymbolTable().begin() + StringIndex; } @@ -1006,15 +1069,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 (isECSymbol()) { + // 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,6 +1135,9 @@ t.StringIndex -= CurRanStrx; t.StringIndex += NextRanStrx; } + } else if (t.isECSymbol()) { + // 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; @@ -1133,6 +1208,17 @@ return symbol_iterator(Symbol(this, getNumberOfSymbols(), 0)); } +Archive::symbol_iterator Archive::ec_symbol_begin() const { + return symbol_iterator( + Symbol(this, getNumberOfSymbols(), + sizeof(uint32_t) + getNumberOfECSymbols() * sizeof(uint16_t))); +} + +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 +1237,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(); Index: llvm/test/tools/llvm-lib/ecsymbols.test =================================================================== --- llvm/test/tools/llvm-lib/ecsymbols.test +++ 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: Index: llvm/tools/llvm-nm/llvm-nm.cpp =================================================================== --- llvm/tools/llvm-nm/llvm-nm.cpp +++ 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); } }