[AIX] support write operation of big archive.

SUMMARY

1. Enable supporting the write operation of big archive.
2. the first commit come from https://reviews.llvm.org/D104367
3. refactor the first commit and implement writing symbol table.
4. fixed the bugs and add more test cases in the second commit.

Reviewers: James Henderson
Differential Revision: https://reviews.llvm.org/D123949
This commit is contained in:
zhijian 2022-05-13 10:40:15 -04:00
parent 98f82d69bd
commit fe3b621f05
40 changed files with 202 additions and 99 deletions

View File

@ -391,6 +391,7 @@ private:
};
class BigArchive : public Archive {
public:
/// Fixed-Length Header.
struct FixLenHdr {
char Magic[sizeof(BigArchiveMagic) - 1]; ///< Big archive magic string.

View File

@ -25,6 +25,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SmallVectorMemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
@ -127,16 +128,20 @@ static bool isDarwin(object::Archive::Kind Kind) {
Kind == object::Archive::K_DARWIN64;
}
static bool isAIXBigArchive(object::Archive::Kind Kind) {
return Kind == object::Archive::K_AIXBIG;
}
static bool isBSDLike(object::Archive::Kind Kind) {
switch (Kind) {
case object::Archive::K_GNU:
case object::Archive::K_GNU64:
case object::Archive::K_AIXBIG:
return false;
case object::Archive::K_BSD:
case object::Archive::K_DARWIN:
case object::Archive::K_DARWIN64:
return true;
case object::Archive::K_AIXBIG:
case object::Archive::K_COFF:
break;
}
@ -189,6 +194,31 @@ printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
Out.write(uint8_t(0));
}
static void
printBigArchiveMemberHeader(raw_ostream &Out, StringRef Name,
const sys::TimePoint<std::chrono::seconds> &ModTime,
unsigned UID, unsigned GID, unsigned Perms,
uint64_t Size, unsigned PrevOffset,
unsigned NextOffset) {
unsigned NameLen = Name.size();
printWithSpacePadding(Out, Size, 20); // File member size
printWithSpacePadding(Out, NextOffset, 20); // Next member header offset
printWithSpacePadding(Out, PrevOffset, 20); // Previous member header offset
printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); // File member date
// The big archive format has 12 chars for uid and gid.
printWithSpacePadding(Out, UID % 1000000000000, 12); // UID
printWithSpacePadding(Out, GID % 1000000000000, 12); // GID
printWithSpacePadding(Out, format("%o", Perms), 12); // Permission
printWithSpacePadding(Out, NameLen, 4); // Name length
if (NameLen) {
printWithSpacePadding(Out, Name, NameLen); // Name
if (NameLen % 2)
Out.write(uint8_t(0)); // Null byte padding
}
Out << "`\n"; // Terminator
}
static bool useStringTable(bool Thin, StringRef Name) {
return Thin || Name.size() >= 16 || Name.contains('/');
}
@ -199,8 +229,8 @@ static bool is64BitKind(object::Archive::Kind Kind) {
case object::Archive::K_BSD:
case object::Archive::K_DARWIN:
case object::Archive::K_COFF:
case object::Archive::K_AIXBIG:
return false;
case object::Archive::K_AIXBIG:
case object::Archive::K_DARWIN64:
case object::Archive::K_GNU64:
return true;
@ -304,7 +334,11 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
// uniformly.
// We do this for all bsd formats because it simplifies aligning members.
uint32_t Pad = offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
// For the big archive format, the symbol table is the last member, so there
// is no need to align.
uint32_t Pad = isAIXBigArchive(Kind)
? 0
: offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
Size += Pad;
if (Padding)
*Padding = Pad;
@ -312,11 +346,15 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
}
static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
bool Deterministic, uint64_t Size) {
bool Deterministic, uint64_t Size,
uint64_t PrevMemberOffset = 0) {
if (isBSDLike(Kind)) {
const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
Size);
} else if (isAIXBigArchive(Kind)) {
printBigArchiveMemberHeader(Out, "", now(Deterministic), 0, 0,
0, Size, PrevMemberOffset, 0);
} else {
const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
@ -325,7 +363,8 @@ static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
bool Deterministic, ArrayRef<MemberData> Members,
StringRef StringTable) {
StringRef StringTable,
uint64_t PrevMemberOffset = 0) {
// We don't write a symbol table on an archive with no members -- except on
// Darwin, where the linker will abort unless the archive has a symbol table.
if (StringTable.empty() && !isDarwin(Kind))
@ -338,9 +377,10 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
uint32_t Pad;
uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize, StringTable, &Pad);
writeSymbolTableHeader(Out, Kind, Deterministic, Size);
writeSymbolTableHeader(Out, Kind, Deterministic, Size, PrevMemberOffset);
uint64_t Pos = Out.tell() + Size;
uint64_t Pos = isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr)
: Out.tell() + Size;
if (isBSDLike(Kind))
printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
@ -409,9 +449,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
bool NeedSymbols, ArrayRef<NewArchiveMember> NewMembers) {
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
// This ignores the symbol table, but we only need the value mod 8 and the
// symbol table is aligned to be a multiple of 8 bytes
uint64_t Pos = 0;
uint64_t Pos =
isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 0;
std::vector<MemberData> Ret;
bool HasObject = false;
@ -471,6 +510,9 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
Entry.second = Entry.second > 1 ? 1 : 0;
}
// The big archive format needs to know the offset of the previous member
// header.
unsigned PrevOffset = 0;
for (const NewArchiveMember &M : NewMembers) {
std::string Header;
raw_string_ostream Out(Header);
@ -503,8 +545,16 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
std::move(StringMsg), object::object_error::parse_failed);
}
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
ModTime, Size);
if (isAIXBigArchive(Kind)) {
unsigned NextOffset = Pos + sizeof(object::BigArMemHdrType) +
alignTo(M.MemberName.size(), 2) + alignTo(Size, 2);
printBigArchiveMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
M.Perms, Size, PrevOffset, NextOffset);
PrevOffset = Pos;
} else {
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
ModTime, Size);
}
Out.flush();
std::vector<unsigned> Symbols;
@ -588,22 +638,25 @@ static Error writeArchiveToStream(raw_ostream &Out,
return E;
std::vector<MemberData> &Data = *DataOrErr;
if (!StringTableBuf.empty())
if (!StringTableBuf.empty() && !isAIXBigArchive(Kind))
Data.insert(Data.begin(), computeStringTable(StringTableBuf));
// We would like to detect if we need to switch to a 64-bit symbol table.
if (WriteSymtab) {
uint64_t MaxOffset = 8; // For the file signature.
uint64_t LastOffset = MaxOffset;
uint64_t NumSyms = 0;
for (const auto &M : Data) {
// Record the start of the member's offset
LastOffset = MaxOffset;
// Account for the size of each part associated with the member.
MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
NumSyms += M.Symbols.size();
}
uint64_t LastMemberEndOffset =
isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 8;
uint64_t LastMemberHeaderOffset = LastMemberEndOffset;
uint64_t NumSyms = 0;
for (const auto &M : Data) {
// Record the start of the member's offset
LastMemberHeaderOffset = LastMemberEndOffset;
// Account for the size of each part associated with the member.
LastMemberEndOffset += M.Header.size() + M.Data.size() + M.Padding.size();
NumSyms += M.Symbols.size();
}
// The symbol table is put at the end of the big archive file. The symbol
// table is at the start of the archive file for other archive formats.
if (WriteSymtab && !isAIXBigArchive(Kind)) {
// We assume 32-bit offsets to see if 32-bit symbols are possible or not.
uint64_t SymtabSize = computeSymbolTableSize(Kind, NumSyms, 4, SymNamesBuf);
auto computeSymbolTableHeaderSize =
@ -613,7 +666,7 @@ static Error writeArchiveToStream(raw_ostream &Out,
writeSymbolTableHeader(Tmp, Kind, Deterministic, SymtabSize);
return TmpBuf.size();
};
LastOffset += computeSymbolTableHeaderSize() + SymtabSize;
LastMemberHeaderOffset += computeSymbolTableHeaderSize() + SymtabSize;
// The SYM64 format is used when an archive's member offsets are larger than
// 32-bits can hold. The need for this shift in format is detected by
@ -627,10 +680,10 @@ static Error writeArchiveToStream(raw_ostream &Out,
if (Sym64Env)
StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
// If LastOffset isn't going to fit in a 32-bit varible we need to switch
// to 64-bit. Note that the file can be larger than 4GB as long as the last
// member starts before the 4GB offset.
if (LastOffset >= Sym64Threshold) {
// If LastMemberHeaderOffset isn't going to fit in a 32-bit varible we need
// to switch to 64-bit. Note that the file can be larger than 4GB as long as
// the last member starts before the 4GB offset.
if (LastMemberHeaderOffset >= Sym64Threshold) {
if (Kind == object::Archive::K_DARWIN)
Kind = object::Archive::K_DARWIN64;
else
@ -640,15 +693,92 @@ static Error writeArchiveToStream(raw_ostream &Out,
if (Thin)
Out << "!<thin>\n";
else if (isAIXBigArchive(Kind))
Out << "<bigaf>\n";
else
Out << "!<arch>\n";
if (WriteSymtab)
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf);
if (!isAIXBigArchive(Kind)) {
if (WriteSymtab)
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf);
for (const MemberData &M : Data)
Out << M.Header << M.Data << M.Padding;
} else {
// For the big archive (AIX) format, compute a table of member names and
// offsets, used in the member table.
uint64_t MemberTableNameStrTblSize = 0;
std::vector<size_t> MemberOffsets;
std::vector<StringRef> MemberNames;
// Loop across object to find offset and names.
uint64_t MemberEndOffset = sizeof(object::BigArchive::FixLenHdr);
for (size_t I = 0, Size = NewMembers.size(); I != Size; ++I) {
const NewArchiveMember &Member = NewMembers[I];
MemberTableNameStrTblSize += Member.MemberName.size() + 1;
MemberOffsets.push_back(MemberEndOffset);
MemberNames.push_back(Member.MemberName);
// File member name ended with "`\n". The length is included in
// BigArMemHdrType.
MemberEndOffset += sizeof(object::BigArMemHdrType) +
alignTo(Data[I].Data.size(), 2) +
alignTo(Member.MemberName.size(), 2);
}
for (const MemberData &M : Data)
Out << M.Header << M.Data << M.Padding;
// AIX member table size.
unsigned MemberTableSize = 20 + // Number of members field
20 * MemberOffsets.size() +
MemberTableNameStrTblSize;
unsigned GlobalSymbolOffset =
(WriteSymtab && NumSyms > 0)
? LastMemberEndOffset +
alignTo(sizeof(object::BigArMemHdrType) + MemberTableSize, 2)
: 0;
// Fixed Sized Header.
printWithSpacePadding(Out, NewMembers.size() ? LastMemberEndOffset : 0,
20); // Offset to member table
// If there are no file members in the archive, there will be no global
// symbol table.
printWithSpacePadding(Out, NewMembers.size() ? GlobalSymbolOffset : 0, 20);
printWithSpacePadding(
Out, 0,
20); // Offset to 64 bits global symbol table - Not supported yet
printWithSpacePadding(
Out, NewMembers.size() ? sizeof(object::BigArchive::FixLenHdr) : 0,
20); // Offset to first archive member
printWithSpacePadding(Out, NewMembers.size() ? LastMemberHeaderOffset : 0,
20); // Offset to last archive member
printWithSpacePadding(
Out, 0,
20); // Offset to first member of free list - Not supported yet
for (const MemberData &M : Data) {
Out << M.Header << M.Data;
if (M.Data.size() % 2)
Out << '\0';
}
if (NewMembers.size()) {
// Member table.
printBigArchiveMemberHeader(Out, "", sys::toTimePoint(0), 0, 0, 0,
MemberTableSize, LastMemberHeaderOffset,
GlobalSymbolOffset);
printWithSpacePadding(Out, MemberOffsets.size(), 20); // Number of members
for (uint64_t MemberOffset : MemberOffsets)
printWithSpacePadding(Out, MemberOffset,
20); // Offset to member file header.
for (StringRef MemberName : MemberNames)
Out << MemberName << '\0'; // Member file name, null byte padding.
if (MemberTableNameStrTblSize % 2)
Out << '\0'; // Name table must be tail padded to an even number of
// bytes.
if (WriteSymtab && NumSyms > 0)
writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf,
LastMemberEndOffset);
}
}
Out.flush();
return Error::success();
}

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
Test which operations create an archive and which don't.
RUN: touch %t

View File

@ -1,5 +1,3 @@
XFAIL: system-aix
RUN: mkdir -p %t
RUN: cd %t
RUN: rm -rf foo

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## Show that the archive library emits error messages when adding malformed
## objects.

View File

@ -1,5 +1,3 @@
XFAIL: system-aix
Test adding a member to a particular position
RUN: touch %t.foo

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## Show that the archive library does not emit an error or add any symbols to
## the archive symbol table, when it encounters an unknown file type, but still
## adds the file to the archive.

View File

@ -1,5 +1,3 @@
XFAIL: system-aix
Test the 'u' option of llvm-ar
RUN: rm -rf %t && mkdir -p %t && cd %t

View File

@ -1,5 +1,3 @@
; XFAIL: system-aix
;RUN: rm -rf %t && mkdir -p %t
;RUN: not llvm-ar r %t/test.a . 2>&1 | FileCheck -DMSG=%errc_EISDIR %s
;CHECK: .: [[MSG]]

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
# Test the 'N' count parameter.
# Get a temp clean cwd to extract into.

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
## Test the creation warning and supression of that warning.
RUN: touch %t1.txt

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
# Test the use of dash before key letters.
RUN: touch %t1.txt

View File

@ -1,10 +1,7 @@
; REQUIRES: system-aix
;; Test llvm-ar does not support Big AIX archive write operation.
;; Test llvm-ar uses the big archive format for XCOFF object files by default.
; RUN: yaml2obj %S/Inputs/xcoff.yaml -o %t.obj
; RUN: rm -f %t.ar
; RUN: not llvm-ar cr %t.ar %t.obj 2>&1 | FileCheck %s
; RUN: echo "test big archive" > %t.txt
; RUN: not llvm-ar cr %t.ar %t.txt 2>&1 | FileCheck %s
; RUN: llvm-ar cr %t.ar %t.obj
; RUN: FileCheck %s --input-file=%t.ar
; CHECK: big archive writer operation on AIX not yet supported
; CHECK: bigaf

View File

@ -1,10 +1,9 @@
# XFAIL: system-aix
## Test Display of empty archives.
# RUN: rm -rf %t && mkdir -p %t
## Display empty archive:
# RUN: llvm-ar cr %t/empty.a
# RUN: llvm-ar cr --format=gnu %t/empty.a
# RUN: llvm-ar tv %t/empty.a 2>&1 | count 0
## Display empty thin archive:

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## Test the use of "--" on the commandline
# RUN: echo contents > %t.txt

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## Unsupported on windows as marking files "unreadable"
## is non-trivial on windows.
# UNSUPPORTED: system-windows

View File

@ -1,10 +1,10 @@
## Test extract operation.
# XFAIL: system-darwin,system-aix
# XFAIL: system-darwin
# RUN: rm -rf %t && mkdir -p %t/extracted/
## Extracting from an empty archive should not warn or error:
# RUN: llvm-ar cr %t/empty.a
# RUN: llvm-ar cr --format=gnu %t/empty.a
# RUN: llvm-ar xv %t/empty.a 2>&1 | count 0
# RUN: echo filea > %t/a.txt

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## This test creates a thin archive that contains a thin archive, a regular
## archive, and a file.
##

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
# Note: many of these tests depend on relative paths, so we have to cd to a
# test directory first.
RUN: mkdir -p %t && cd %t
@ -28,7 +27,7 @@ DISPLAY-NOT-FOUND: 'a/foo.txt' was not found
# Deleting will fail with P because the members exist as foo.txt, not a/foo.txt.
RUN: rm -f del1.a
RUN: llvm-ar rcS del1.a foo.txt
RUN: llvm-ar rcS --format=gnu del1.a foo.txt
RUN: llvm-ar dP del1.a a/foo.txt
RUN: llvm-ar t del1.a a/foo.txt | FileCheck %s --check-prefix=DISPLAY-FOUND --match-full-lines
RUN: llvm-ar d del1.a a/foo.txt

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
## Test inserting files after a file.
RUN: touch %t1.txt

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
## Test inserting files before a file.
RUN: touch %t1.txt

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
## Test moving files after a file.
RUN: touch %t1.txt

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
## Test moving files after a file.
RUN: touch %t1.txt

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
RUN: yaml2obj %S/Inputs/elf.yaml -o %t.o
RUN: rm -f %t.ar

View File

@ -1,4 +1,3 @@
XFAIL: system-aix
# Test non-ascii archive members
RUN: rm -rf %t && mkdir -p %t/extracted

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## Test that on windows, members are case insensitive.
# UNSUPPORTED: system-windows

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## Test that --plugin is ignored.
# RUN: rm -f %t.a

View File

@ -1,5 +1,5 @@
## Test Print output
# XFAIL: system-darwin,system-aix
# XFAIL: system-darwin
# RUN: rm -rf %t && mkdir -p %t
# RUN: echo file1 > %t/1.txt
@ -9,7 +9,7 @@
# RUN: llvm-ar -rc %t/archive.a %t/1.txt %t/2.txt %t/3.txt
## Print empty archive:
# RUN: llvm-ar cr %t/empty.a
# RUN: llvm-ar --format=gnu cr %t/empty.a
# RUN: llvm-ar p %t/empty.a 2>&1 | count 0
# RUN: llvm-ar pv %t/empty.a 2>&1 | count 0

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## Test that read-only archives cannot be edited
# RUN: rm -rf %t && mkdir -p %t

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## Check that response files can cope with non-ascii characters.
# RUN: echo 'contents' > %t-£.txt

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## llvm-ar should be able to consume response files.
# RUN: echo 'contents' > %t.txt

View File

@ -1,4 +1,3 @@
# XFAIL: system-aix
## This test checks that an archive is flattened correctly.
# RUN: yaml2obj %S/Inputs/input1.yaml -o %t-input1.o

View File

@ -1,7 +1,7 @@
# RUN: llvm-as %S/Inputs/f.ll -o %t.f.bc
# RUN: llvm-as %S/Inputs/g.ll -o %t.g.bc
# RUN: llvm-ar cr --format=gnu %t.fg.a %t.f.bc %t.g.bc
# RUN: llvm-ar cr --format=gnu %t.empty.lib
# RUN: llvm-ar cr %t.fg.a %t.f.bc %t.g.bc
# RUN: llvm-ar cr --format=gnu %t.empty.lib
# RUN: llvm-link %S/Inputs/h.ll %t.fg.a %t.empty.lib -o %t.linked.bc
# RUN: llvm-nm %t.linked.bc | FileCheck %s

View File

@ -1,4 +1,5 @@
# RUN: llvm-ar --format=gnu cr %t.fg.a %S/Inputs/f.ll %S/Inputs/g.ll
# XFAIL: system-aix
# RUN: llvm-ar cr %t.fg.a %S/Inputs/f.ll %S/Inputs/g.ll
# RUN: not llvm-link %S/Inputs/h.ll %t.fg.a -o %t.linked.bc 2>&1 | FileCheck %s
# RUN: rm -f %t.fg.a

View File

@ -4,16 +4,16 @@
# RUN: llvm-as %p/Inputs/armv7-ios.ll -o %t-ir-armv7.o
# RUN: llvm-as %p/Inputs/x64-osx.ll -o %t-ir-x86_64.o
# RUN: llvm-ar --format=gnu cr %t.empty.a
# RUN: llvm-ar cr --format=gnu %t.empty.a
# RUN: not llvm-lipo %t.empty.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=EMPTY-ARCHIVE %s
# RUN: llvm-ar --format=gnu cr %t.different_architectures.a %t-i386.o %t-x86_64.o
# RUN: llvm-ar cr %t.different_architectures.a %t-i386.o %t-x86_64.o
# RUN: not llvm-lipo %t.different_architectures.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-DIFFERENT-ARCHS %s
# RUN: llvm-ar --format=gnu cr %t.contains_fat_binary.a %t-universal.o
# RUN: llvm-ar cr %t.contains_fat_binary.a %t-universal.o
# RUN: not llvm-lipo %t.contains_fat_binary.a -create -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-FAT-BINARY %s
# RUN: llvm-ar --format=gnu cr %t-i386-lib.a %t-i386.o
# RUN: llvm-ar cr %t-i386-lib.a %t-i386.o
# RUN: llvm-lipo %t-i386-lib.a %t-x86_64.o -create -output %t-i386-x86_64-universal.o
# RUN: llvm-lipo %t-i386-x86_64-universal.o -info | FileCheck --check-prefix=INFO-i386-x86_64 %s
# RUN: llvm-lipo %t-i386-x86_64-universal.o -thin i386 -output %t-extracted-i386-lib.a
@ -21,18 +21,18 @@
# RUN: llvm-lipo %t-i386-x86_64-universal.o -thin x86_64 -output %t-extracted-x86_64.o
# RUN: cmp %t-extracted-x86_64.o %t-x86_64.o
# RUN: llvm-ar --format=gnu cr %t-ir-armv7-lib.a %t-ir-armv7.o
# RUN: llvm-ar cr %t-ir-armv7-lib.a %t-ir-armv7.o
# RUN: llvm-lipo %t-ir-armv7-lib.a %t-ir-x86_64.o -create -output %t-ir-armv7-x86_64-universal.o
# RUN: llvm-lipo %t-ir-armv7-x86_64-universal.o -thin armv7 -output %t-ir-extracted-armv7-lib.a
# RUN: cmp %t-ir-extracted-armv7-lib.a %t-ir-armv7-lib.a
# RUN: llvm-lipo %t-ir-armv7-x86_64-universal.o -thin x86_64 -output %t-ir-extracted-x86_64.o
# RUN: cmp %t-ir-extracted-x86_64.o %t-ir-x86_64.o
# RUN: llvm-ar --format=gnu cr %t.different_types0.a %t-i386.o %t-ir-x86_64.o
# RUN: llvm-ar cr %t.different_types0.a %t-i386.o %t-ir-x86_64.o
# RUN: not llvm-lipo -create %t.different_types0.a -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-MACHO-AND-IR %s
# RUN: llvm-ar --format=gnu cr %t.different_types1.a %t-ir-x86_64.o %t-i386.o
# RUN: llvm-ar cr %t.different_types1.a %t-ir-x86_64.o %t-i386.o
# RUN: not llvm-lipo -create %t.different_types1.a -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-IR-AND-MACHO %s
# RUN: llvm-ar --format=gnu cr %t.different_architectures_ir.a %t-ir-x86_64.o %t-ir-armv7.o
# RUN: llvm-ar cr %t.different_architectures_ir.a %t-ir-x86_64.o %t-ir-armv7.o
# RUN: not llvm-lipo -create %t.different_architectures_ir.a -output /dev/null 2>&1 | FileCheck --check-prefix=ARCHIVE-WITH-DIFFERENT-ARCHS %s
# EMPTY-ARCHIVE: empty archive

View File

@ -56,7 +56,7 @@ Symbols:
# RUN: yaml2obj --docnum=2 -DFLAG=0x1DF %s -o %t_xcoff32.o
# RUN: yaml2obj --docnum=2 -DFLAG=0x1F7 %s -o %t_xcoff64.o
# RUN: rm -f %t.a
# RUN: llvm-ar --format=gnu -q -c %t.a %t_xcoff32.o %t_xcoff64.o
# RUN: llvm-ar -q -c %t.a %t_xcoff32.o %t_xcoff64.o
# RUN: llvm-nm --format=just-symbols -X32 %t_xcoff32.o | \
# RUN: FileCheck --check-prefixes=XCOFF32 %s --implicit-check-not={{.}}

View File

@ -14,7 +14,7 @@
## Case 2: copy a universal object file containing an archive.
# RUN: rm -f %t.archive.i386
# RUN: llvm-ar --format=gnu cr %t.archive.i386 %t.i386
# RUN: llvm-ar cr %t.archive.i386 %t.i386
# RUN: llvm-lipo %t.archive.i386 %t.x86_64 -create -output %t.universal.containing.archive
# RUN: llvm-objcopy %t.universal.containing.archive %t.universal.containing.archive.copy
# RUN: llvm-lipo %t.universal.containing.archive.copy -archs | FileCheck --check-prefix=VERIFY_ARCHS %s
@ -24,7 +24,7 @@
# RUN: cmp %t.x86_64 %t.archive.x86_64.copy
## Case 3: copy an archive containing a universal object.
# RUN: llvm-ar --format=gnu cr %t.archive.containing.universal %t.universal
# RUN: llvm-ar cr %t.archive.containing.universal %t.universal
# RUN: llvm-objcopy %t.archive.containing.universal %t.archive.containing.universal.copy
## Case 4: try to copy a universal object file contaning a bitcode slice.
@ -34,7 +34,7 @@
# RUN: | FileCheck --check-prefix=UNSUPPORTED_UNIVERSAL_OBJECT %s
## Case 5: try to copy an archive containing an unsupported universal object.
# RUN: llvm-ar --format=gnu cr %t.archive.universal.bitcode %t.universal.containing.bitcode
# RUN: llvm-ar cr %t.archive.universal.bitcode %t.universal.containing.bitcode
# RUN: not llvm-objcopy %t.archive.universal.bitcode %t.archive.universal.bitcode.copy 2>&1 \
# RUN: | FileCheck --check-prefix=UNSUPPORTED_UNIVERSAL_OBJECT %s

View File

@ -16,7 +16,7 @@ EMPTY: '{{.*}}.empty': The file was not recognized as a valid object file
# Test that unrecognised files in archives are ignored.
RUN: rm -f %t.a
RUN: llvm-ar --format=gnu rc %t.a %t.empty
RUN: llvm-ar rc %t.a %t.empty
RUN: llvm-readobj --all %t.a 2>&1 | FileCheck --check-prefix=NO-OUTPUT --allow-empty %s
NO-OUTPUT-NOT: {{.}}

View File

@ -5,21 +5,21 @@
## Case 1: Empty archive. No output expected.
# RUN: rm -f %t1.a
# RUN: llvm-ar --format=gnu rc %t1.a
# RUN: llvm-ar rc --format=gnu %t1.a
# RUN: llvm-size -B %t1.a | count 0
# RUN: llvm-size -A %t1.a | count 0
## Case 2: Single member.
# RUN: rm -f %t2.a
# RUN: llvm-ar --format=gnu rc %t2.a %t1
# RUN: llvm-ar rc %t2.a %t1
# RUN: llvm-size -B %t2.a | FileCheck %s -DARCHIVE=%t2.a --check-prefix=BERKELEY-1
# RUN: llvm-size -A %t2.a | FileCheck %s -DARCHIVE=%t2.a --check-prefix=SYSV-1
## Case 3: Multiple members.
# RUN: rm -f %t3.a
# RUN: llvm-ar --format=gnu rc %t3.a %t1 %t2
# RUN: llvm-ar rc %t3.a %t1 %t2
# RUN: llvm-size -B %t3.a | FileCheck %s -DARCHIVE=%t3.a --check-prefixes=BERKELEY-1,BERKELEY-2
# RUN: llvm-size -A %t3.a | FileCheck %s -DARCHIVE=%t3.a --check-prefixes=SYSV-1,SYSV-2

View File

@ -82,6 +82,7 @@ static void printArHelp(StringRef ToolName) {
=gnu - gnu
=darwin - darwin
=bsd - bsd
=aix - aix (big archive)
--plugin=<string> - ignored for compatibility
-h --help - display this help and exit
--rsp-quoting - quoting style for response files
@ -187,7 +188,7 @@ static SmallVector<const char *, 256> PositionalArgs;
static bool MRI;
namespace {
enum Format { Default, GNU, BSD, DARWIN, Unknown };
enum Format { Default, GNU, BSD, DARWIN, BIGARCHIVE, Unknown };
}
static Format FormatType = Default;
@ -950,8 +951,6 @@ static void performWriteOperation(ArchiveOperation Operation,
else
Kind = !NewMembers.empty() ? getKindFromMember(NewMembers.front())
: getDefaultForHost();
if (Kind == object::Archive::K_AIXBIG)
fail("big archive writer operation on AIX not yet supported");
break;
case GNU:
Kind = object::Archive::K_GNU;
@ -966,6 +965,11 @@ static void performWriteOperation(ArchiveOperation Operation,
fail("only the gnu format has a thin mode");
Kind = object::Archive::K_DARWIN;
break;
case BIGARCHIVE:
if (Thin)
fail("only the gnu format has a thin mode");
Kind = object::Archive::K_AIXBIG;
break;
case Unknown:
llvm_unreachable("");
}
@ -1237,6 +1241,7 @@ static int ar_main(int argc, char **argv) {
.Case("gnu", GNU)
.Case("darwin", DARWIN)
.Case("bsd", BSD)
.Case("bigarchive", BIGARCHIVE)
.Default(Unknown);
if (FormatType == Unknown)
fail(std::string("Invalid format ") + Match);