[llvm] [llvm-ar][Object][COFF] Add support for EC symbols to llvm-ar. (PR #85230)
Jacek Caban via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 19 07:00:44 PDT 2024
https://github.com/cjacek updated https://github.com/llvm/llvm-project/pull/85230
>From 4415fd84ef2766773f74bd6b83ab1dbb4f7f6822 Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Sun, 18 Feb 2024 23:59:07 +0100
Subject: [PATCH 1/2] [llvm-ar][Object][COFF] Add support for EC symbols to
llvm-ar.
Make writeArchive IsEC argument optional and use EC symbol map when indicated by input object files.
---
llvm/include/llvm/Object/ArchiveWriter.h | 2 +-
llvm/lib/Object/ArchiveWriter.cpp | 65 +++++++++++++++----
llvm/test/tools/llvm-ar/ecsymbols.yaml | 83 ++++++++++++++++++++++++
llvm/test/tools/llvm-lib/empty.test | 27 ++++++++
4 files changed, 165 insertions(+), 12 deletions(-)
create mode 100644 llvm/test/tools/llvm-ar/ecsymbols.yaml
create mode 100644 llvm/test/tools/llvm-lib/empty.test
diff --git a/llvm/include/llvm/Object/ArchiveWriter.h b/llvm/include/llvm/Object/ArchiveWriter.h
index 7f915929cd7219..a19f8fcc79d741 100644
--- a/llvm/include/llvm/Object/ArchiveWriter.h
+++ b/llvm/include/llvm/Object/ArchiveWriter.h
@@ -52,7 +52,7 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
SymtabWritingMode WriteSymtab, object::Archive::Kind Kind,
bool Deterministic, bool Thin,
std::unique_ptr<MemoryBuffer> OldArchiveBuf = nullptr,
- bool IsEC = false);
+ std::optional<bool> IsEC = std::nullopt);
// writeArchiveToBuffer is similar to writeArchive but returns the Archive in a
// buffer instead of writing it out to a file.
diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp
index 97d0e4f75be8e0..ed312294bbb85a 100644
--- a/llvm/lib/Object/ArchiveWriter.cpp
+++ b/llvm/lib/Object/ArchiveWriter.cpp
@@ -48,7 +48,7 @@ using namespace llvm;
using namespace llvm::object;
struct SymMap {
- bool UseECMap;
+ bool UseECMap = false;
std::map<std::string, uint16_t> Map;
std::map<std::string, uint16_t> ECMap;
};
@@ -678,6 +678,25 @@ static bool isECObject(object::SymbolicFile &Obj) {
return false;
}
+static bool isAnyArm64COFF(object::SymbolicFile &Obj) {
+ if (Obj.isCOFF())
+ return COFF::isAnyArm64(cast<COFFObjectFile>(&Obj)->getMachine());
+
+ if (Obj.isCOFFImportFile())
+ return COFF::isAnyArm64(cast<COFFImportFile>(&Obj)->getMachine());
+
+ if (Obj.isIR()) {
+ Expected<std::string> TripleStr =
+ getBitcodeTargetTriple(Obj.getMemoryBufferRef());
+ if (!TripleStr)
+ return false;
+ Triple T(*TripleStr);
+ return T.isOSWindows() && T.getArch() == Triple::aarch64;
+ }
+
+ return false;
+}
+
bool isImportDescriptor(StringRef Name) {
return Name.starts_with(ImportDescriptorPrefix) ||
Name == StringRef{NullImportDescriptorSymbolName} ||
@@ -731,7 +750,8 @@ static Expected<std::vector<MemberData>>
computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
object::Archive::Kind Kind, bool Thin, bool Deterministic,
SymtabWritingMode NeedSymbols, SymMap *SymMap,
- LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers) {
+ LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers,
+ std::optional<bool> IsEC) {
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
uint64_t MemHeadPadSize = 0;
uint64_t Pos =
@@ -807,6 +827,30 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
}
}
+ if (SymMap) {
+ if (IsEC) {
+ SymMap->UseECMap = *IsEC;
+ } else {
+ // When IsEC is not specified by the caller, use it when we have both
+ // any ARM64 object (ARM64 or ARM64EC) and any EC object (ARM64EC or
+ // AMD64). This may be a single ARM64EC object, but may also be separated
+ // ARM64 and AMD64 objects.
+ bool HaveArm64 = false, HaveEC = false;
+ for (std::unique_ptr<SymbolicFile> &SymFile : SymFiles) {
+ if (!SymFile)
+ continue;
+ if (!HaveArm64)
+ HaveArm64 = isAnyArm64COFF(*SymFile);
+ if (!HaveEC)
+ HaveEC = isECObject(*SymFile);
+ if (HaveArm64 && HaveEC) {
+ SymMap->UseECMap = true;
+ break;
+ }
+ }
+ }
+ }
+
// The big archive format needs to know the offset of the previous member
// header.
uint64_t PrevOffset = 0;
@@ -953,11 +997,10 @@ Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
return std::string(Relative);
}
-static Error writeArchiveToStream(raw_ostream &Out,
- ArrayRef<NewArchiveMember> NewMembers,
- SymtabWritingMode WriteSymtab,
- object::Archive::Kind Kind,
- bool Deterministic, bool Thin, bool IsEC) {
+static Error
+writeArchiveToStream(raw_ostream &Out, ArrayRef<NewArchiveMember> NewMembers,
+ SymtabWritingMode WriteSymtab, object::Archive::Kind Kind,
+ bool Deterministic, bool Thin, std::optional<bool> IsEC) {
assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
SmallString<0> SymNamesBuf;
@@ -977,10 +1020,9 @@ static Error writeArchiveToStream(raw_ostream &Out,
// reference to it, thus SymbolicFile should be destroyed first.
LLVMContext Context;
- SymMap.UseECMap = IsEC;
Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab,
- isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers);
+ isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers, IsEC);
if (Error E = DataOrErr.takeError())
return E;
std::vector<MemberData> &Data = *DataOrErr;
@@ -1226,7 +1268,8 @@ static Error writeArchiveToStream(raw_ostream &Out,
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
SymtabWritingMode WriteSymtab, object::Archive::Kind Kind,
bool Deterministic, bool Thin,
- std::unique_ptr<MemoryBuffer> OldArchiveBuf, bool IsEC) {
+ std::unique_ptr<MemoryBuffer> OldArchiveBuf,
+ std::optional<bool> IsEC) {
Expected<sys::fs::TempFile> Temp =
sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a");
if (!Temp)
@@ -1263,7 +1306,7 @@ writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers,
raw_svector_ostream ArchiveStream(ArchiveBufferVector);
if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab,
- Kind, Deterministic, Thin, false))
+ Kind, Deterministic, Thin, std::nullopt))
return std::move(E);
return std::make_unique<SmallVectorMemoryBuffer>(
diff --git a/llvm/test/tools/llvm-ar/ecsymbols.yaml b/llvm/test/tools/llvm-ar/ecsymbols.yaml
new file mode 100644
index 00000000000000..1009ab278a978c
--- /dev/null
+++ b/llvm/test/tools/llvm-ar/ecsymbols.yaml
@@ -0,0 +1,83 @@
+## Test that ECSYMBOLS section is created when ARM64EC is used.
+
+# RUN: yaml2obj %s -o %t.arm64ec.obj -DMACHINE=IMAGE_FILE_MACHINE_ARM64EC
+# RUN: yaml2obj %s -o %t.arm64.obj -DMACHINE=IMAGE_FILE_MACHINE_ARM64
+# RUN: yaml2obj %s -o %t.amd64.obj -DMACHINE=IMAGE_FILE_MACHINE_AMD64
+
+## Create ARM64EC archive
+# RUN: rm -f %t.a
+# RUN: llvm-ar crs %t.a %t.arm64ec.obj
+# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=NOMAP,ECMAP %s
+
+## Add ARM64 object to the archive
+# RUN: llvm-ar rs %t.a %t.arm64.obj
+# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,ECMAP %s
+
+## Create ARM64 archive
+# RUN: rm -f %t.a
+# RUN: llvm-ar crs %t.a %t.arm64.obj
+# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,NOECMAP %s
+
+# Add ARM64EC object to the archive
+# RUN: llvm-ar rs %t.a %t.arm64ec.obj
+# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,ECMAP %s
+
+## Create mixed archive
+# RUN: rm -f %t.a
+# RUN: llvm-ar crs %t.a %t.arm64ec.obj %t.arm64.obj
+# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,ECMAP %s
+
+## Create mixed archive
+# RUN: rm -f %t.a
+# RUN: llvm-ar crs %t.a %t.amd64.obj %t.arm64.obj
+# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,AMDECMAP %s
+
+# MAP: Archive map
+# MAP-NEXT: a in ecsymbols.yaml.tmp.arm64.obj
+# MAP-NEXT: b in ecsymbols.yaml.tmp.arm64.obj
+# MAP-NEXT: c in ecsymbols.yaml.tmp.arm64.obj
+# MAP-EMPTY:
+# NOMAP-NOT: Archive map
+
+# ECMAP: Archive EC map
+# ECMAP-NEXT: a in ecsymbols.yaml.tmp.arm64ec.obj
+# ECMAP-NEXT: b in ecsymbols.yaml.tmp.arm64ec.obj
+# ECMAP-NEXT: c in ecsymbols.yaml.tmp.arm64ec.obj
+# ECMAP-EMPTY:
+# NOECMAP-NOT: Archive EC map
+
+# AMDECMAP: Archive EC map
+# AMDECMAP-NEXT: a in ecsymbols.yaml.tmp.amd64.obj
+# AMDECMAP-NEXT: b in ecsymbols.yaml.tmp.amd64.obj
+# AMDECMAP-NEXT: c in ecsymbols.yaml.tmp.amd64.obj
+# ECMAP-EMPTY:
+
+--- !COFF
+header:
+ Machine: [[MACHINE]]
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: ''
+symbols:
+ - Name: b
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: c
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: a
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/llvm/test/tools/llvm-lib/empty.test b/llvm/test/tools/llvm-lib/empty.test
new file mode 100644
index 00000000000000..37c841f8db46a4
--- /dev/null
+++ b/llvm/test/tools/llvm-lib/empty.test
@@ -0,0 +1,27 @@
+Create import libraries with empty exports and make sure that archive symbols
+are properly populated.
+
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-lib -machine:arm64 -out:arm64.lib -def:test.def
+RUN: llvm-nm --print-armap arm64.lib | FileCheck --check-prefixes=CHECK,NOECMAP %s
+
+RUN: llvm-lib -machine:arm64ec -out:arm64ec.lib -def:test.def
+RUN: llvm-nm --print-armap arm64ec.lib | FileCheck --check-prefixes=CHECK,ECMAP %s
+
+CHECK: Archive map
+CHECK-NEXT: __IMPORT_DESCRIPTOR_test in test.dll
+CHECK-NEXT: __NULL_IMPORT_DESCRIPTOR in test.dll
+CHECK-NEXT: test_NULL_THUNK_DATA in test.dll
+CHECK-EMPTY:
+
+ECMAP: Archive EC map
+ECMAP-NEXT: __IMPORT_DESCRIPTOR_test in test.dll
+ECMAP-NEXT: __NULL_IMPORT_DESCRIPTOR in test.dll
+ECMAP-NEXT: test_NULL_THUNK_DATA in test.dll
+
+NOECMAP-NOT: Archive EC map
+
+#--- test.def
+LIBRARY test.dll
+EXPORTS
>From d8ee0b9158c144e1089164d09c48a8cd8e560c9e Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek at codeweavers.com>
Date: Tue, 19 Mar 2024 14:04:32 +0100
Subject: [PATCH 2/2] Address review comments
---
llvm/lib/Object/ArchiveWriter.cpp | 2 +-
llvm/test/tools/llvm-ar/ecsymbols.ll | 57 ++++++++++++++++++++++++++
llvm/test/tools/llvm-ar/ecsymbols.yaml | 47 ++++++++++-----------
3 files changed, 82 insertions(+), 24 deletions(-)
create mode 100644 llvm/test/tools/llvm-ar/ecsymbols.ll
diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp
index ed312294bbb85a..913b74c110b364 100644
--- a/llvm/lib/Object/ArchiveWriter.cpp
+++ b/llvm/lib/Object/ArchiveWriter.cpp
@@ -833,7 +833,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
} else {
// When IsEC is not specified by the caller, use it when we have both
// any ARM64 object (ARM64 or ARM64EC) and any EC object (ARM64EC or
- // AMD64). This may be a single ARM64EC object, but may also be separated
+ // AMD64). This may be a single ARM64EC object, but may also be separate
// ARM64 and AMD64 objects.
bool HaveArm64 = false, HaveEC = false;
for (std::unique_ptr<SymbolicFile> &SymFile : SymFiles) {
diff --git a/llvm/test/tools/llvm-ar/ecsymbols.ll b/llvm/test/tools/llvm-ar/ecsymbols.ll
new file mode 100644
index 00000000000000..f7391c0bde19cc
--- /dev/null
+++ b/llvm/test/tools/llvm-ar/ecsymbols.ll
@@ -0,0 +1,57 @@
+;; Test that ECSYMBOLS section is created when ARM64EC bitcode is used.
+
+; RUN: llc -filetype=obj -mtriple=arm64ec-unknown-windows-msvc -o %t.arm64ec.obj %s
+; RUN: llc -filetype=obj -mtriple=aarch64-unknown-windows-msvc -o %t.arm64.obj %s
+; RUN: llc -filetype=obj -mtriple=x86_64-unknown-windows-msvc -o %t.amd64.obj %s
+
+;; Create ARM64EC archive.
+; RUN: rm -f %t*.a
+; RUN: llvm-ar cr %t1.a %t.arm64ec.obj
+; RUN: llvm-nm --print-armap %t1.a | FileCheck --check-prefixes=NOMAP,ECMAP %s
+
+;; Add ARM64 object to the archive.
+; RUN: llvm-ar r %t1.a %t.arm64.obj
+; RUN: llvm-nm --print-armap %t1.a | FileCheck --check-prefixes=MAP,ECMAP %s
+
+;; Create ARM64 archive.
+; RUN: llvm-ar cr %t2.a %t.arm64.obj
+; RUN: llvm-nm --print-armap %t2.a | FileCheck --check-prefixes=MAP,NOECMAP %s
+
+;; Add ARM64EC object to the archive.
+; RUN: llvm-ar r %t2.a %t.arm64ec.obj
+; RUN: llvm-nm --print-armap %t2.a | FileCheck --check-prefixes=MAP,ECMAP %s
+
+;; Create mixed archive with ARM64 and ARM64EC members.
+; RUN: llvm-ar cr %t3.a %t.arm64ec.obj %t.arm64.obj
+; RUN: llvm-nm --print-armap %t3.a | FileCheck --check-prefixes=MAP,ECMAP %s
+
+;; Create mixed archive with ARM64 and AMD64 members.
+; RUN: llvm-ar cr %t4.a %t.amd64.obj %t.arm64.obj
+; RUN: llvm-nm --print-armap %t4.a | FileCheck --check-prefixes=MAP,AMDECMAP %s
+
+;; Create an archive with no symbol table.
+; RUN: llvm-ar crS %t5.a %t.amd64.obj %t.arm64.obj
+; RUN: llvm-nm --print-armap %t5.a | FileCheck --check-prefixes=NOMAP,NOECMAP %s
+
+; MAP: Archive map
+; MAP-NEXT: a in ecsymbols.ll.tmp.arm64.obj
+; MAP-NEXT: b in ecsymbols.ll.tmp.arm64.obj
+; MAP-NEXT: c in ecsymbols.ll.tmp.arm64.obj
+; MAP-EMPTY:
+; NOMAP-NOT: Archive map
+
+; ECMAP: Archive EC map
+; ECMAP-NEXT: #a in ecsymbols.ll.tmp.arm64ec.obj
+; ECMAP-NEXT: #b in ecsymbols.ll.tmp.arm64ec.obj
+; ECMAP-NEXT: #c in ecsymbols.ll.tmp.arm64ec.obj
+; NOECMAP-NOT: Archive EC map
+
+; AMDECMAP: Archive EC map
+; AMDECMAP-NEXT: a in ecsymbols.ll.tmp.amd64.obj
+; AMDECMAP-NEXT: b in ecsymbols.ll.tmp.amd64.obj
+; AMDECMAP-NEXT: c in ecsymbols.ll.tmp.amd64.obj
+; AMDECMAP-EMPTY:
+
+define void @b() { ret void }
+define void @c() { ret void }
+define void @a() { ret void }
diff --git a/llvm/test/tools/llvm-ar/ecsymbols.yaml b/llvm/test/tools/llvm-ar/ecsymbols.yaml
index 1009ab278a978c..6cfe78d160ed70 100644
--- a/llvm/test/tools/llvm-ar/ecsymbols.yaml
+++ b/llvm/test/tools/llvm-ar/ecsymbols.yaml
@@ -4,33 +4,34 @@
# RUN: yaml2obj %s -o %t.arm64.obj -DMACHINE=IMAGE_FILE_MACHINE_ARM64
# RUN: yaml2obj %s -o %t.amd64.obj -DMACHINE=IMAGE_FILE_MACHINE_AMD64
-## Create ARM64EC archive
-# RUN: rm -f %t.a
-# RUN: llvm-ar crs %t.a %t.arm64ec.obj
-# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=NOMAP,ECMAP %s
+## Create ARM64EC archive.
+# RUN: rm -f %t*.a
+# RUN: llvm-ar cr %t1.a %t.arm64ec.obj
+# RUN: llvm-nm --print-armap %t1.a | FileCheck --check-prefixes=NOMAP,ECMAP %s
-## Add ARM64 object to the archive
-# RUN: llvm-ar rs %t.a %t.arm64.obj
-# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,ECMAP %s
+## Add ARM64 object to the archive.
+# RUN: llvm-ar r %t1.a %t.arm64.obj
+# RUN: llvm-nm --print-armap %t1.a | FileCheck --check-prefixes=MAP,ECMAP %s
-## Create ARM64 archive
-# RUN: rm -f %t.a
-# RUN: llvm-ar crs %t.a %t.arm64.obj
-# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,NOECMAP %s
+## Create ARM64 archive.
+# RUN: llvm-ar cr %t2.a %t.arm64.obj
+# RUN: llvm-nm --print-armap %t2.a | FileCheck --check-prefixes=MAP,NOECMAP %s
-# Add ARM64EC object to the archive
-# RUN: llvm-ar rs %t.a %t.arm64ec.obj
-# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,ECMAP %s
+## Add ARM64EC object to the archive.
+# RUN: llvm-ar r %t2.a %t.arm64ec.obj
+# RUN: llvm-nm --print-armap %t2.a | FileCheck --check-prefixes=MAP,ECMAP %s
-## Create mixed archive
-# RUN: rm -f %t.a
-# RUN: llvm-ar crs %t.a %t.arm64ec.obj %t.arm64.obj
-# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,ECMAP %s
+## Create mixed archive with ARM64 and ARM64EC members.
+# RUN: llvm-ar cr %t3.a %t.arm64ec.obj %t.arm64.obj
+# RUN: llvm-nm --print-armap %t3.a | FileCheck --check-prefixes=MAP,ECMAP %s
-## Create mixed archive
-# RUN: rm -f %t.a
-# RUN: llvm-ar crs %t.a %t.amd64.obj %t.arm64.obj
-# RUN: llvm-nm --print-armap %t.a | FileCheck --check-prefixes=MAP,AMDECMAP %s
+## Create mixed archive with ARM64 and AMD64 members.
+# RUN: llvm-ar cr %t4.a %t.amd64.obj %t.arm64.obj
+# RUN: llvm-nm --print-armap %t4.a | FileCheck --check-prefixes=MAP,AMDECMAP %s
+
+## Create an archive with no symbol table.
+# RUN: llvm-ar crS %t5.a %t.amd64.obj %t.arm64.obj
+# RUN: llvm-nm --print-armap %t5.a | FileCheck --check-prefixes=NOMAP,NOECMAP %s
# MAP: Archive map
# MAP-NEXT: a in ecsymbols.yaml.tmp.arm64.obj
@@ -50,7 +51,7 @@
# AMDECMAP-NEXT: a in ecsymbols.yaml.tmp.amd64.obj
# AMDECMAP-NEXT: b in ecsymbols.yaml.tmp.amd64.obj
# AMDECMAP-NEXT: c in ecsymbols.yaml.tmp.amd64.obj
-# ECMAP-EMPTY:
+# AMDECMAP-EMPTY:
--- !COFF
header:
More information about the llvm-commits
mailing list