[llvm] 2037577 - [llvm-ar] Use COFF archive format for COFF targets. (#82898)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 13 05:27:25 PDT 2024
Author: Jacek Caban
Date: 2024-03-13T13:27:20+01:00
New Revision: 203757776826cfd164c537048ec90f5ada50cae2
URL: https://github.com/llvm/llvm-project/commit/203757776826cfd164c537048ec90f5ada50cae2
DIFF: https://github.com/llvm/llvm-project/commit/203757776826cfd164c537048ec90f5ada50cae2.diff
LOG: [llvm-ar] Use COFF archive format for COFF targets. (#82898)
Detect COFF files by default and allow specifying it with --format
argument.
This is important for ARM64EC, which uses a separated symbol map for EC
symbols. Since K_COFF is mostly compatible with K_GNU, this shouldn't
really make a difference for other targets.
This originally landed as #82642, but was reverted due to test failures
in tests using no symbol table. Since COFF symbol can't express it,
fallback to GNU format in that case.
Added:
llvm/test/tools/llvm-ar/coff-symtab.test
llvm/test/tools/llvm-ar/no-symtab.yaml
Modified:
llvm/docs/CommandGuide/llvm-ar.rst
llvm/docs/ReleaseNotes.rst
llvm/include/llvm/Object/Archive.h
llvm/lib/Object/Archive.cpp
llvm/lib/Object/ArchiveWriter.cpp
llvm/tools/llvm-ar/llvm-ar.cpp
Removed:
################################################################################
diff --git a/llvm/docs/CommandGuide/llvm-ar.rst b/llvm/docs/CommandGuide/llvm-ar.rst
index 03d5b9e41ada38..63b3a519550bc0 100644
--- a/llvm/docs/CommandGuide/llvm-ar.rst
+++ b/llvm/docs/CommandGuide/llvm-ar.rst
@@ -261,7 +261,7 @@ Other
.. option:: --format=<type>
- This option allows for default, gnu, darwin or bsd ``<type>`` to be selected.
+ This option allows for default, gnu, darwin, bsd or coff ``<type>`` to be selected.
When creating an ``archive`` with the default ``<type>``, :program:``llvm-ar``
will attempt to infer it from the input files and fallback to the default
toolchain target if unable to do so.
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index b34a5f31c5eb0a..7be51730663bd1 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -153,6 +153,9 @@ Changes to the LLVM tools
if it's not specified with the ``--format`` argument and cannot be inferred from
input files.
+* llvm-ar now allows specifying COFF archive format with ``--format`` argument
+ and uses it by default for COFF targets.
+
* llvm-objcopy now supports ``--set-symbol-visibility`` and
``--set-symbols-visibility`` options for ELF input to change the
visibility of symbols.
diff --git a/llvm/include/llvm/Object/Archive.h b/llvm/include/llvm/Object/Archive.h
index f71630054dc637..a3165c3235e0ed 100644
--- a/llvm/include/llvm/Object/Archive.h
+++ b/llvm/include/llvm/Object/Archive.h
@@ -339,6 +339,7 @@ class Archive : public Binary {
Kind kind() const { return (Kind)Format; }
bool isThin() const { return IsThin; }
static object::Archive::Kind getDefaultKind();
+ static object::Archive::Kind getDefaultKindForTriple(Triple &T);
child_iterator child_begin(Error &Err, bool SkipInternal = true) const;
child_iterator child_end() const;
diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp
index 9000e9aa81ff41..6139d9996bdad3 100644
--- a/llvm/lib/Object/Archive.cpp
+++ b/llvm/lib/Object/Archive.cpp
@@ -969,12 +969,19 @@ Archive::Archive(MemoryBufferRef Source, Error &Err)
Err = Error::success();
}
+object::Archive::Kind Archive::getDefaultKindForTriple(Triple &T) {
+ if (T.isOSDarwin())
+ return object::Archive::K_DARWIN;
+ if (T.isOSAIX())
+ return object::Archive::K_AIXBIG;
+ if (T.isOSWindows())
+ return object::Archive::K_COFF;
+ return object::Archive::K_GNU;
+}
+
object::Archive::Kind Archive::getDefaultKind() {
Triple HostTriple(sys::getDefaultTargetTriple());
- return HostTriple.isOSDarwin()
- ? object::Archive::K_DARWIN
- : (HostTriple.isOSAIX() ? object::Archive::K_AIXBIG
- : object::Archive::K_GNU);
+ return getDefaultKindForTriple(HostTriple);
}
Archive::child_iterator Archive::child_begin(Error &Err,
diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp
index e0629747b40cd7..aa57e55de70c8d 100644
--- a/llvm/lib/Object/ArchiveWriter.cpp
+++ b/llvm/lib/Object/ArchiveWriter.cpp
@@ -62,12 +62,16 @@ object::Archive::Kind NewArchiveMember::detectKindFromObject() const {
Expected<std::unique_ptr<object::ObjectFile>> OptionalObject =
object::ObjectFile::createObjectFile(MemBufferRef);
- if (OptionalObject)
- return isa<object::MachOObjectFile>(**OptionalObject)
- ? object::Archive::K_DARWIN
- : (isa<object::XCOFFObjectFile>(**OptionalObject)
- ? object::Archive::K_AIXBIG
- : object::Archive::K_GNU);
+ if (OptionalObject) {
+ if (isa<object::MachOObjectFile>(**OptionalObject))
+ return object::Archive::K_DARWIN;
+ if (isa<object::XCOFFObjectFile>(**OptionalObject))
+ return object::Archive::K_AIXBIG;
+ if (isa<object::COFFObjectFile>(**OptionalObject) ||
+ isa<object::COFFImportFile>(**OptionalObject))
+ return object::Archive::K_COFF;
+ return object::Archive::K_GNU;
+ }
// Squelch the error in case we had a non-object file.
consumeError(OptionalObject.takeError());
@@ -80,10 +84,7 @@ object::Archive::Kind NewArchiveMember::detectKindFromObject() const {
MemBufferRef, file_magic::bitcode, &Context)) {
auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr);
auto TargetTriple = Triple(IRObject.getTargetTriple());
- return TargetTriple.isOSDarwin()
- ? object::Archive::K_DARWIN
- : (TargetTriple.isOSAIX() ? object::Archive::K_AIXBIG
- : object::Archive::K_GNU);
+ return object::Archive::getDefaultKindForTriple(TargetTriple);
} else {
// Squelch the error in case this was not a SymbolicFile.
consumeError(ObjOrErr.takeError());
@@ -976,10 +977,12 @@ static Error writeArchiveToStream(raw_ostream &Out,
SmallString<0> StringTableBuf;
raw_svector_ostream StringTable(StringTableBuf);
SymMap SymMap;
+ bool ShouldWriteSymtab = WriteSymtab != SymtabWritingMode::NoSymtab;
// COFF symbol map uses 16-bit indexes, so we can't use it if there are too
- // many members.
- if (isCOFFArchive(Kind) && NewMembers.size() > 0xfffe)
+ // many members. COFF format also requires symbol table presence, so use
+ // GNU format when NoSymtab is requested.
+ if (isCOFFArchive(Kind) && (NewMembers.size() > 0xfffe || !ShouldWriteSymtab))
Kind = object::Archive::K_GNU;
// In the scenario when LLVMContext is populated SymbolicFile will contain a
@@ -1008,7 +1011,6 @@ static Error writeArchiveToStream(raw_ostream &Out,
uint64_t LastMemberHeaderOffset = 0;
uint64_t NumSyms = 0;
uint64_t NumSyms32 = 0; // Store symbol number of 32-bit member files.
- bool ShouldWriteSymtab = WriteSymtab != SymtabWritingMode::NoSymtab;
for (const auto &M : Data) {
// Record the start of the member's offset
diff --git a/llvm/test/tools/llvm-ar/coff-symtab.test b/llvm/test/tools/llvm-ar/coff-symtab.test
new file mode 100644
index 00000000000000..4f7270d9e2c6e7
--- /dev/null
+++ b/llvm/test/tools/llvm-ar/coff-symtab.test
@@ -0,0 +1,91 @@
+Verify that llvm-ar uses COFF archive format by ensuring that archive map is sorted.
+
+RUN: rm -rf %t.dir && split-file %s %t.dir && cd %t.dir
+
+RUN: yaml2obj coff-symtab.yaml -o coff-symtab.obj
+RUN: llvm-ar crs out.a coff-symtab.obj
+RUN: llvm-nm --print-armap out.a | FileCheck %s
+
+RUN: llvm-as coff-symtab.ll -o coff-symtab.bc
+RUN: llvm-ar crs out2.a coff-symtab.bc
+RUN: llvm-nm --print-armap out2.a | FileCheck %s
+
+RUN: yaml2obj elf.yaml -o coff-symtab.o
+RUN: llvm-ar crs --format coff out3.a coff-symtab.o
+RUN: llvm-nm --print-armap out3.a | FileCheck %s
+
+Create an empty archive with no symbol map, add a COFF file to it and check that the output archive is a COFF archive.
+
+RUN: llvm-ar rcS out4.a
+RUN: llvm-ar rs out4.a coff-symtab.obj
+RUN: llvm-nm --print-armap out4.a | FileCheck %s
+
+CHECK: Archive map
+CHECK-NEXT: a in coff-symtab
+CHECK-NEXT: b in coff-symtab
+CHECK-NEXT: c in coff-symtab
+CHECK-EMPTY:
+
+#--- coff-symtab.yaml
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_UNKNOWN
+ 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
+...
+
+
+#--- coff-symtab.ll
+target triple = "x86_64-unknown-windows-msvc"
+
+define void @b() { ret void }
+define void @c() { ret void }
+define void @a() { ret void }
+
+#--- elf.yaml
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data : ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ - Name: b
+ Binding: STB_GLOBAL
+ Section: .text
+ - Name: c
+ Binding: STB_GLOBAL
+ Section: .text
+ - Name: a
+ Binding: STB_GLOBAL
+ Section: .text
+...
diff --git a/llvm/test/tools/llvm-ar/no-symtab.yaml b/llvm/test/tools/llvm-ar/no-symtab.yaml
new file mode 100644
index 00000000000000..7370c9b3235522
--- /dev/null
+++ b/llvm/test/tools/llvm-ar/no-symtab.yaml
@@ -0,0 +1,32 @@
+## Create archives with no symtab in various formats and check that we can read them.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: rm -f %t.*.a
+
+# RUN: llvm-ar --format=gnu rcS %t.gnu.a %t.o
+# RUN: llvm-ar --format=coff rcS %t.coff.a %t.o
+# RUN: llvm-ar --format=darwin rcS %t.darwin.a %t.o
+# RUN: llvm-ar --format=bsd rcS %t.bsd.a %t.o
+# RUN: llvm-ar --format=bigarchive rcS %t.bigarchive.a %t.o
+
+# RUN: llvm-nm --print-armap %t.gnu.a | FileCheck %s
+# RUN: llvm-nm --print-armap %t.coff.a | FileCheck %s
+# RUN: llvm-nm --print-armap %t.darwin.a | FileCheck %s
+# RUN: llvm-nm --print-armap %t.bsd.a | FileCheck %s
+# RUN: llvm-nm --print-armap %t.bigarchive.a | FileCheck %s
+
+# CHECK-NOT: Archive map
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+Symbols:
+ - Name: symbol
+ Binding: STB_GLOBAL
+ Section: .text
diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp
index 81cb2a21daf1f2..294b8531b08f13 100644
--- a/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -82,6 +82,7 @@ static void printArHelp(StringRef ToolName) {
=darwin - darwin
=bsd - bsd
=bigarchive - big archive (AIX OS)
+ =coff - coff
--plugin=<string> - ignored for compatibility
-h --help - display this help and exit
--output - the directory to extract archive members to
@@ -193,7 +194,7 @@ static SmallVector<const char *, 256> PositionalArgs;
static bool MRI;
namespace {
-enum Format { Default, GNU, BSD, DARWIN, BIGARCHIVE, Unknown };
+enum Format { Default, GNU, COFF, BSD, DARWIN, BIGARCHIVE, Unknown };
}
static Format FormatType = Default;
@@ -1025,14 +1026,21 @@ static void performWriteOperation(ArchiveOperation Operation,
Kind = object::Archive::K_GNU;
else if (OldArchive) {
Kind = OldArchive->kind();
- if (Kind == object::Archive::K_BSD) {
- auto InferredKind = object::Archive::K_BSD;
+ std::optional<object::Archive::Kind> AltKind;
+ if (Kind == object::Archive::K_BSD)
+ AltKind = object::Archive::K_DARWIN;
+ else if (Kind == object::Archive::K_GNU && !OldArchive->hasSymbolTable())
+ // If there is no symbol table, we can't tell GNU from COFF format
+ // from the old archive type.
+ AltKind = object::Archive::K_COFF;
+ if (AltKind) {
+ auto InferredKind = Kind;
if (NewMembersP && !NewMembersP->empty())
InferredKind = NewMembersP->front().detectKindFromObject();
else if (!NewMembers.empty())
InferredKind = NewMembers.front().detectKindFromObject();
- if (InferredKind == object::Archive::K_DARWIN)
- Kind = object::Archive::K_DARWIN;
+ if (InferredKind == AltKind)
+ Kind = *AltKind;
}
} else if (NewMembersP)
Kind = !NewMembersP->empty() ? NewMembersP->front().detectKindFromObject()
@@ -1044,6 +1052,9 @@ static void performWriteOperation(ArchiveOperation Operation,
case GNU:
Kind = object::Archive::K_GNU;
break;
+ case COFF:
+ Kind = object::Archive::K_COFF;
+ break;
case BSD:
if (Thin)
fail("only the gnu format has a thin mode");
@@ -1376,6 +1387,7 @@ static int ar_main(int argc, char **argv) {
.Case("darwin", DARWIN)
.Case("bsd", BSD)
.Case("bigarchive", BIGARCHIVE)
+ .Case("coff", COFF)
.Default(Unknown);
if (FormatType == Unknown)
fail(std::string("Invalid format ") + Match);
More information about the llvm-commits
mailing list