Index: llvm/lib/Object/ArchiveWriter.cpp =================================================================== --- llvm/lib/Object/ArchiveWriter.cpp +++ llvm/lib/Object/ArchiveWriter.cpp @@ -46,6 +46,7 @@ struct SymMap { std::map Map; + std::map ECMap; }; NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef) @@ -414,6 +415,20 @@ return Size; } +static uint64_t computeECSymbolsSize(SymMap &SymMap, + uint32_t *Padding = nullptr) { + uint64_t Size = sizeof(uint32_t); // Number of symbols + + for (auto S : SymMap.ECMap) + Size += sizeof(uint16_t) + S.first.length() + 1; + + uint32_t Pad = offsetToAlignment(Size, Align(2)); + Size += Pad; + if (Padding) + *Padding = Pad; + return Size; +} + static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, uint64_t Size, uint64_t PrevMemberOffset = 0) { @@ -448,8 +463,11 @@ uint64_t Size = sizeof("!\n") - 1; Size += HeaderSize + SymtabSize; - if (SymMap) + if (SymMap) { Size += HeaderSize + computeSymbolMapSize(NumMembers, *SymMap); + if (SymMap->ECMap.size()) + Size += HeaderSize + computeECSymbolsSize(*SymMap); + } return Size + StringMemberSize; } @@ -523,6 +541,38 @@ Out.write(uint8_t(0)); } +static void writeECSymbols(raw_ostream &Out, object::Archive::Kind Kind, + bool Deterministic, ArrayRef Members, + SymMap &SymMap) { + uint32_t Pad; + uint64_t Size = computeECSymbolsSize(SymMap, &Pad); + printGNUSmallMemberHeader(Out, "/", now(Deterministic), 0, 0, 0, + Size); + + printLE(Out, SymMap.ECMap.size()); + + for (auto S : SymMap.ECMap) + printLE(Out, S.second); + for (auto S : SymMap.ECMap) + Out << S.first << '\0'; + while (Pad--) + Out.write(uint8_t(0)); +} + +static bool isECObject(object::SymbolicFile &Obj) { + if (Obj.isCOFF()) + return cast(&Obj)->getMachine() == + COFF::IMAGE_FILE_MACHINE_ARM64EC; + + if (Obj.isIR()) { + Expected TripleStr = + getBitcodeTargetTriple(Obj.getMemoryBufferRef()); + return TripleStr && Triple(*TripleStr).isWindowsArm64EC(); + } + + return false; +} + static Expected> getSymbols(MemoryBufferRef Buf, uint16_t Index, raw_ostream &SymNames, SymMap *SymMap, bool &HasObject) { @@ -550,20 +600,25 @@ Obj = std::move(*ObjOrErr); } + std::map *Map = nullptr; + if (SymMap) + Map = isECObject(*Obj) ? &SymMap->ECMap : &SymMap->Map; HasObject = true; for (const object::BasicSymbolRef &S : Obj->symbols()) { if (!isArchiveSymbol(S)) continue; - if (SymMap) { + if (Map) { std::string Name; raw_string_ostream NameStream(Name); if (Error E = S.printName(NameStream)) return std::move(E); - if (SymMap->Map.find(Name) != SymMap->Map.end()) + if (Map->find(Name) != Map->end()) continue; // ignore duplicated symbol - SymMap->Map[Name] = Index; - Ret.push_back(SymNames.tell()); - SymNames << Name << '\0'; + (*Map)[Name] = Index; + if (Map == &SymMap->Map) { + Ret.push_back(SymNames.tell()); + SymNames << Name << '\0'; + } } else { Ret.push_back(SymNames.tell()); if (Error E = S.printName(SymNames)) @@ -858,6 +913,9 @@ Out << StringTableMember.Header << StringTableMember.Data << StringTableMember.Padding; + if (WriteSymtab && SymMap.ECMap.size()) + writeECSymbols(Out, Kind, Deterministic, Data, SymMap); + for (const MemberData &M : Data) Out << M.Header << M.Data << M.Padding; } else { Index: llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp =================================================================== --- llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -154,7 +154,8 @@ if (Machine != COFF::IMAGE_FILE_MACHINE_I386 && Machine != COFF::IMAGE_FILE_MACHINE_AMD64 && Machine != COFF::IMAGE_FILE_MACHINE_ARMNT && - Machine != COFF::IMAGE_FILE_MACHINE_ARM64) { + Machine != COFF::IMAGE_FILE_MACHINE_ARM64 && + Machine != COFF::IMAGE_FILE_MACHINE_ARM64EC) { return createStringError(inconvertibleErrorCode(), "unknown machine: " + std::to_string(Machine)); } @@ -182,8 +183,19 @@ } } +static bool machineMatches(COFF::MachineTypes LibMachine, + COFF::MachineTypes FileMachine) { + if (LibMachine == FileMachine) + return true; + // ARM64EC mode allows both pure ARM64 and ARM64EC objects to be mixed in the + // archive. + return LibMachine == COFF::IMAGE_FILE_MACHINE_ARM64EC && + FileMachine == COFF::IMAGE_FILE_MACHINE_ARM64; +} + static void appendFile(std::vector &Members, COFF::MachineTypes &LibMachine, + COFF::MachineTypes &InferredMachine, std::string &LibMachineSource, MemoryBufferRef MB) { file_magic Magic = identify_magic(MB.getBuffer()); @@ -215,7 +227,8 @@ exit(1); } - appendFile(Members, LibMachine, LibMachineSource, *ChildMB); + appendFile(Members, LibMachine, InferredMachine, LibMachineSource, + *ChildMB); } fatalOpenError(std::move(Err), MB.getBufferIdentifier()); @@ -248,12 +261,14 @@ // COFF file to the .lib output instead of adding the .res file, and remove // this check. See PR42180. if (FileMachine != COFF::IMAGE_FILE_MACHINE_UNKNOWN) { - if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) { - LibMachine = FileMachine; + if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN || + (InferredMachine == COFF::IMAGE_FILE_MACHINE_ARM64 && + FileMachine == COFF::IMAGE_FILE_MACHINE_ARM64EC)) { + LibMachine = InferredMachine = FileMachine; LibMachineSource = (" (inferred from earlier file '" + MB.getBufferIdentifier() + "')") .str(); - } else if (LibMachine != FileMachine) { + } else if (!machineMatches(LibMachine, FileMachine)) { llvm::errs() << MB.getBufferIdentifier() << ": file machine type " << machineToStr(FileMachine) << " conflicts with library machine type " @@ -339,6 +354,7 @@ std::vector> MBs; StringSet<> Seen; std::vector Members; + COFF::MachineTypes InferredMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; // Create a NewArchiveMember for each input file. for (auto *Arg : Args.filtered(OPT_INPUT)) { @@ -366,7 +382,7 @@ MemoryBufferRef MBRef = (*MOrErr)->getMemBufferRef(); // Append a file. - appendFile(Members, LibMachine, LibMachineSource, MBRef); + appendFile(Members, LibMachine, InferredMachine, LibMachineSource, MBRef); // Take the ownership of the file buffer to keep the file open. MBs.push_back(std::move(*MOrErr)); Index: llvm/test/tools/llvm-lib/ecsymbols.test =================================================================== --- llvm/test/tools/llvm-lib/ecsymbols.test +++ llvm/test/tools/llvm-lib/ecsymbols.test @@ -15,3 +15,10 @@ - Name: '//' Size: '0' ... + +# Check that llvm-lib produces // members for ARM64EC libraries. +RUN: rm -rf %t +RUN: mkdir -p %t +RUN: llvm-mc -triple=arm64ec-pc-windows-msvc -filetype=obj -o %t/foo.o %S/Inputs/a.s +RUN: llvm-lib -machine:arm64ec -out:%t/foo.lib %t/foo.o +RUN: grep -q '//' %t/foo.lib