diff --git a/llvm/docs/CommandGuide/llvm-ar.rst b/llvm/docs/CommandGuide/llvm-ar.rst --- a/llvm/docs/CommandGuide/llvm-ar.rst +++ b/llvm/docs/CommandGuide/llvm-ar.rst @@ -289,6 +289,25 @@ Display the version of the :program:`llvm-ar` executable. +.. option:: -X mode + + Specifies the type of object file :program:`llvm-ar` will recognise. The mode must be + one of the following: + + 32 + Process only 32-bit object files. + 64 + Process only 64-bit object files. + 32_64 + Process both 32-bit and 64-bit object files. + any + Process all object files. + + The default is to process 32-bit object files (ignore 64-bit objects). The mode can also + be set with the OBJECT_MODE environment variable. For example, OBJECT_MODE=64 causes ar to + process any 64-bit objects and ignore 32-bit objects. The -X flag overrides the OBJECT_MODE + variable. + .. option:: @ Read command-line options and commands from response file ````. diff --git a/llvm/test/Object/lit.local.cfg b/llvm/test/Object/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/Object/lit.local.cfg @@ -0,0 +1,2 @@ +if 'system-aix' in config.available_features: + config.environment['OBJECT_MODE'] = 'any' diff --git a/llvm/test/tools/lit.local.cfg b/llvm/test/tools/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/tools/lit.local.cfg @@ -0,0 +1,2 @@ +if 'system-aix' in config.available_features: + config.environment['OBJECT_MODE'] = 'any' diff --git a/llvm/test/tools/llvm-ar/Inputs/bitcode-sym32.ll b/llvm/test/tools/llvm-ar/Inputs/bitcode-sym32.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/Inputs/bitcode-sym32.ll @@ -0,0 +1,14 @@ +target triple = "powerpcle-unknown-linux-gnu" + +@C32 = dso_local global i32 5, align 4 +@undef_var32 = external dso_local global i32, align 4 + +define dso_local i32 @foo32(i32 %i) #0 { +entry: + %i.addr = alloca i32, align 4 + store i32 %i, i32* %i.addr, align 4 + %0 = load i32, i32* %i.addr, align 4 + %1 = load i32, i32* @undef_var32, align 4 + %add = add nsw i32 %0, %1 + ret i32 %add +} diff --git a/llvm/test/tools/llvm-ar/Inputs/bitcode-sym64.ll b/llvm/test/tools/llvm-ar/Inputs/bitcode-sym64.ll new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/Inputs/bitcode-sym64.ll @@ -0,0 +1,12 @@ +target triple = "powerpc64le-unknown-linux-gnu" + +@C64 = dso_local global i32 5, align 4 +@static_var64 = internal global i32 2, align 4 + +define dso_local signext i32 @bar64() #0 { +entry: + %0 = load i32, i32* @static_var64, align 4 + %1 = load i32, i32* @C64, align 4 + %add = add nsw i32 %0, %1 + ret i32 %add +} diff --git a/llvm/test/tools/llvm-ar/invalid-option-X.test b/llvm/test/tools/llvm-ar/invalid-option-X.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/invalid-option-X.test @@ -0,0 +1,5 @@ +# REQUIRES: !system-aix +## Test not support "-X" option in non AIX OS + +# RUN: not llvm-ar -q -X32 %t.a xcoff32.o 2>&1 | FileCheck %s +# CHECK: error: -X32 option not supported on non AIX OS diff --git a/llvm/test/tools/llvm-ar/option-X.test b/llvm/test/tools/llvm-ar/option-X.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ar/option-X.test @@ -0,0 +1,275 @@ +# REQUIRES: system-aix +## Test the "-X" option. +## The option specifies the type of object file llvm-ar will operate on. + +# RUN: rm -rf %t && mkdir %t && cd %t +# RUN: unset OBJECT_MODE +# RUN: yaml2obj --docnum=1 -DCLASS=ELFCLASS32 %s -o elf32.o +# RUN: yaml2obj --docnum=1 -DCLASS=ELFCLASS64 %s -o elf64.o + +# RUN: yaml2obj --docnum=2 -DFLAG=0x1DF %s -o xcoff32.o +# RUN: yaml2obj --docnum=2 -DFLAG=0x1F7 %s -o xcoff64.o + +## Test default -X option when creating a new archive. +# RUN: llvm-ar -q -c archive.a xcoff32.o elf32.o xcoff64.o elf64.o 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN-64 +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32 + +# WARN-64: xcoff64.o is not valid with the current object file mode +# WARN-64: elf64.o is not valid with the current object file mode + +## Test -X32 option when creating a new archive. +# RUN: rm -f archive32.a +# RUN: llvm-ar -q -c -X 32 archive32.a xcoff32.o elf32.o xcoff64.o elf64.o 2>&1 +# RUN: llvm-ar -t -Xany archive32.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32 + +## Test -X option will override the envionment "OBJECT_MODE" +# RUN: rm -f archive.a +# RUN: env OBJECT_MODE=64 llvm-ar -q -c -X32 archive.a xcoff32.o elf32.o xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32 + +## Test -X64 option when creating a new archive. +# RUN: rm -f archive.a +# RUN: llvm-ar -q -c -X 64 archive.a xcoff32.o elf32.o xcoff64.o elf64.o 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN-32 +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ64 + +# WARN-32: xcoff32.o is not valid with the current object file mode +# WARN-32-NEXT: elf32.o is not valid with the current object file mode + +## Test -Xany option when creating a new archive. +# RUN: rm -f archive.a +# RUN: llvm-ar -q -c -Xany archive.a xcoff32.o elf32.o xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32_64 + +## Test -X32_64 option when creating a new archive. +# RUN: rm -f archive.a +# RUN: llvm-ar -q -c -X32_64 archive.a xcoff32.o elf32.o xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32_64 + +## Test envionment "OBJECT_MODE" when creating a new archive. +# RUN: rm -f archive.a +# RUN: env OBJECT_MODE=64 llvm-ar -q -c archive.a xcoff32.o elf32.o xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ64 + +# RUN: rm -f archive.a +# RUN: env OBJECT_MODE=32_64 llvm-ar -q -c archive.a xcoff32.o elf32.o xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32_64 + +# RUN: rm -f archive.a +# RUN: env OBJECT_MODE=any llvm-ar -q -c archive.a xcoff32.o elf32.o xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32_64 + +## Test -X option for print operation. +# RUN: llvm-ar -t -X32 archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32 + +# RUN: llvm-ar -t -X64 archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ64 + +# RUN: llvm-ar -t -X32_64 archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32_64 + +## Test -X option for extract operation. +# RUN: rm -rf *.o +# RUN: llvm-ar -x -X32 archive.a +# RUN: test -f xcoff32.o +# RUN: test -f elf32.o +# RUN: not test -f xcoff64.o +# RUN: not test -f elf64.o + +# RUN: rm -rf *.o +# RUN: llvm-ar -x -X64 archive.a +# RUN: test -f xcoff64.o +# RUN: test -f elf64.o +# RUN: not test -f xcoff32.o +# RUN: not test -f elf32.o + +# RUN: rm -rf *.o +# RUN: llvm-ar -x -X32_64 archive.a +# RUN: test -f xcoff32.o +# RUN: test -f elf32.o +# RUN: test -f xcoff64.o +# RUN: test -f elf64.o + +# RUN: rm -rf *.o +# RUN: llvm-ar -x -Xany archive.a +# RUN: test -f xcoff32.o +# RUN: test -f elf32.o +# RUN: test -f xcoff64.o +# RUN: test -f elf64.o + +## Extract a 64bit object file with option -X32 +# RUN: rm -rf *.o +# RUN: not llvm-ar -x archive.a xcoff64.o 2>&1 | \ +# RUN: FileCheck %s -DFILE=xcoff64.o --check-prefixes=ERR64 +# RUN: not llvm-ar -x -X32 archive.a xcoff64.o 2>&1 | \ +# RUN: FileCheck %s -DFILE=xcoff64.o --check-prefixes=ERR64 + +# ERR64: llvm-ar: error: '[[FILE]]' was not found +# RUN: not test -f xcoff64.o + +## Test deleting a object file from big archive file. +# RUN: cp archive.a %t_bak.a +# RUN: llvm-ar -d -X32 archive.a xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32_64 + +# RUN: cp %t_bak.a archive.a +# RUN: llvm-ar -d -X64 archive.a xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32 + +# RUN: cp %t_bak.a archive.a +# RUN: llvm-ar -d -Xany archive.a xcoff64.o elf64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32 + +## Test replace/insert a object file from big archive file. +## xcoff32.o is 64 bits object file here. +# RUN: rm -rf *.o +# RUN: yaml2obj --docnum=2 -DFLAG=0x1F7 %s -o xcoff32.o + +## Without -X64, -X32_64 or -Xany, nothing changed here, +## since xcoff32.o is 64 bits object file. +# RUN: llvm-ar -ru archive32.a xcoff32.o +# RUN: llvm-ar -t -Xany archive32.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32 +# RUN: llvm-nm -Xany --format=just-symbols archive32.a | \ +# RUN: FileCheck %s --check-prefixes=SYM32 + +## With option -X64, -X32_64 or -Xany, +## the old 32bit xcoff32.o is still in the archive +## and a new 64bits object file is added into the archive. +# RUN: llvm-ar -ru -X64 archive32.a xcoff32.o +# RUN: llvm-ar -t -Xany archive32.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32,OBJ32_DUP +# RUN: llvm-nm -Xany --format=just-symbols archive32.a | \ +# RUN: FileCheck %s --check-prefixes=SYM32_64 + +## Test move mumber +# RUN: cp %t_bak.a archive.a +## Not move 64bits object without -X64 +# RUN: not llvm-ar -ma elf64.o archive.a xcoff64.o 2>&1| \ +# RUN: FileCheck %s --check-prefixes=MOVE_ERR + +# MOVE_ERR: llvm-ar: error: xcoff64.o: No such file or directory + +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OBJ32_64 + +# RUN: llvm-ar -ma -X64 elf64.o archive.a xcoff64.o +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=MOVE +# MOVE: xcoff32.o +# MOVE-NEXT: elf32.o +# MOVE-NEXT: elf64.o +# MOVE-NEXT: xcoff64.o +# MOVE-EMPTY: + +#OBJ32: xcoff32.o +#OBJ32-NEXT: elf32.o +#OBJ32_DUP-NEXT: xcoff32.o +#OBJ32-EMPTY: + +#OBJ64: xcoff64.o +#OBJ64-NEXT: elf64.o +#OBJ64-EMPTY: + +#OBJ32_64: xcoff32.o +#OBJ32_64-NEXT: elf32.o +#OBJ32_64-NEXT: xcoff64.o +#OBJ32_64-NEXT: elf64.o +#OBJ32_64-EMPTY: + +#SYM32: var_0x1DF +#SYM32-NOT: var_0x1F7 + +#SYM32_64: var_0x1DF +#SYM32_64: var_0x1F7 + +## Test -X option for object file bit code,mach-O,coff,wasm + +# RUN: llvm-as -o t32.bc %p/Inputs/bitcode-sym32.ll +# RUN: llvm-as -o t64.bc %p/Inputs/bitcode-sym64.ll +# RUN: yaml2obj --docnum=3 %s -o macho32.o +# RUN: yaml2obj --docnum=4 %s -o macho64.o +# RUN: yaml2obj --docnum=5 %s -o wasm.o +# RUN: yaml2obj --docnum=6 %s -o coff.o + +# RUN: rm -rf archive.a +# RUN: llvm-ar -q -c archive.a coff.o t32.bc t64.bc wasm.o macho32.o macho64.o 2>&1 +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OTHER32 + +# OTHER32: coff.o +# OTHER32-NEXT: t32.bc +# OTHER32-NEXT: wasm.o +# OTHER32-NEXT: macho32.o +# OTHER32-EMPTY: + +# RUN: rm -rf archive.a +# RUN: llvm-ar -q -c -X64 archive.a coff.o t32.bc t64.bc wasm.o macho32.o macho64.o 2>&1 +# RUN: llvm-ar -t -Xany archive.a | \ +# RUN: FileCheck %s --check-prefixes=OTHER64 + +# OTHER64: t64.bc +# OTHER64-NEXT: macho64.o +# OTHER64-EMPTY: + + +--- !ELF +FileHeader: + Class: [[CLASS]] + Data: ELFDATA2LSB + Type: ET_REL +Symbols: + - Name: [[CLASS]]_var + +--- !XCOFF +FileHeader: + MagicNumber: [[FLAG]] +Symbols: + - Name: var_[[FLAG]] + +--- !mach-o +FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00002000 + +## mach-o 64 bit +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x0100000C + cpusubtype: 0x00000000 + filetype: 0x00000001 + ncmds: 0 + sizeofcmds: 0 + flags: 0x00000000 + reserved: 0x00000000 + +--- !WASM +FileHeader: + Version: 0x00000001 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARMNT + Characteristics: [ ] +sections: +symbols: diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/tools/llvm-ar/llvm-ar.cpp @@ -18,10 +18,14 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" +#include "llvm/Object/TapiFile.h" +#include "llvm/Object/Wasm.h" #include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/CommandLine.h" @@ -55,6 +59,7 @@ #endif using namespace llvm; +using namespace llvm::object; // The name this program was invoked as. static StringRef ToolName; @@ -90,6 +95,7 @@ =windows - windows --thin - create a thin archive --version - print the version and exit + -X{32|64|32_64|any} - object mode (only for AIX OS) @ - read options from OPERATIONS: @@ -208,6 +214,10 @@ CreateSymTab ///< Create a symbol table in an existing archive }; +enum class BitModeTy { Bit32, Bit64, Bit32_64, Any, Unknown }; + +static BitModeTy BitMode = BitModeTy::Bit32; + // Modifiers to follow operation to vary behavior static bool AddAfter = false; ///< 'a' modifier static bool AddBefore = false; ///< 'b' modifier @@ -607,6 +617,68 @@ llvm_unreachable("Missing entry in covered switch."); } +static bool is64BitSymbolicFile(SymbolicFile &Obj) { + if (auto *IRObj = dyn_cast(&Obj)) + return Triple(IRObj->getTargetTriple()).isArch64Bit(); + if (isa(Obj) || isa(Obj)) + return false; + if (XCOFFObjectFile *XCOFFObj = dyn_cast(&Obj)) + return XCOFFObj->is64Bit(); + if (isa(Obj)) + return false; + if (TapiFile *Tapi = dyn_cast(&Obj)) + return Tapi->is64Bit(); + if (MachOObjectFile *MachO = dyn_cast(&Obj)) + return MachO->is64Bit(); + if (ELFObjectFileBase *ElfO = dyn_cast(&Obj)) + return ElfO->getBytesInAddress() == 8; + + fail("unsupported file format"); +} + +static bool isValidInBitMode(Binary &Bin) { + if (BitMode == BitModeTy::Bit32_64 || BitMode == BitModeTy::Any) + return true; + + if (SymbolicFile *SymFile = dyn_cast(&Bin)) { + bool Is64Bit = is64BitSymbolicFile(*SymFile); + if ((Is64Bit && (BitMode == BitModeTy::Bit32)) || + (!Is64Bit && (BitMode == BitModeTy::Bit64))) + return false; + } + // In AIX "ar", non-object files are always considered to have a valid bit + // mode. + return true; +} + +Expected> getAsBinary(const NewArchiveMember &NM, + LLVMContext *Context) { + auto BinaryOrErr = createBinary(NM.Buf->getMemBufferRef(), Context); + if (BinaryOrErr) + return std::move(*BinaryOrErr); + return BinaryOrErr.takeError(); +} + +Expected> getAsBinary(const Archive::Child &C, + LLVMContext *Context) { + return C.getAsBinary(Context); +} + +template static bool isValidInBitMode(const A &Member) { + if (object::Archive::getDefaultKindForHost() != object::Archive::K_AIXBIG) + return true; + LLVMContext Context; + Context.setOpaquePointers(true); + Expected> BinOrErr = getAsBinary(Member, &Context); + // In AIX "ar", if there is a non-object file member, it is never ignored due + // to the bit mode setting. + if (!BinOrErr) { + consumeError(BinOrErr.takeError()); + return true; + } + return isValidInBitMode(*BinOrErr.get()); +} + static void performReadOperation(ArchiveOperation Operation, object::Archive *OldArchive) { if (Operation == Extract && OldArchive->isThin()) @@ -621,6 +693,10 @@ failIfError(NameOrErr.takeError()); StringRef Name = NameOrErr.get(); + // Check whether to ignore this object due to its bitness. + if (!isValidInBitMode(C)) + continue; + if (Filter) { auto I = find_if(Members, [Name](StringRef Path) { return comparePaths(Name, Path); @@ -697,8 +773,7 @@ Members.push_back(std::move(*NMOrErr)); } -static void addMember(std::vector &Members, - StringRef FileName, bool FlattenArchive = false) { +static NewArchiveMember getArchiveMember(StringRef FileName) { Expected NMOrErr = NewArchiveMember::getFile(FileName, Deterministic); failIfError(NMOrErr.takeError(), FileName); @@ -718,9 +793,25 @@ PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName)); } } + return std::move(*NMOrErr); +} + +static void addMember(std::vector &Members, + NewArchiveMember &NM) { + Members.push_back(std::move(NM)); +} + +static void addMember(std::vector &Members, + StringRef FileName, bool FlattenArchive = false) { + NewArchiveMember NM = getArchiveMember(FileName); + if (!isValidInBitMode(NM)) { + WithColor::warning() << FileName + << " is not valid with the current object file mode\n"; + return; + } if (FlattenArchive && - identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { + identify_magic(NM.Buf->getBuffer()) == file_magic::archive) { object::Archive &Lib = readLibrary(FileName); // When creating thin archives, only flatten if the member is also thin. if (!Thin || Lib.isThin()) { @@ -732,7 +823,7 @@ return; } } - Members.push_back(std::move(*NMOrErr)); + Members.push_back(std::move(NM)); } enum InsertAction { @@ -748,6 +839,9 @@ StringRef Name, std::vector::iterator &Pos, StringMap &MemberCount) { + if (!isValidInBitMode(Member)) + return IA_AddOldMember; + if (Operation == QuickAppend || Members.empty()) return IA_AddOldMember; auto MI = find_if( @@ -824,17 +918,37 @@ case IA_AddOldMember: addChildMember(Ret, Child, /*FlattenArchive=*/Thin); break; - case IA_AddNewMember: - addMember(Ret, *MemberI); - break; + case IA_AddNewMember: { + NewArchiveMember NM = getArchiveMember(*MemberI); + if (isValidInBitMode(NM)) + addMember(Ret, NM); + else { + // If a new member is not a valid object for the bit mode, add the old + // member back. + WithColor::warning() + << *MemberI + << " is not valid with the current object file mode\n"; + addChildMember(Ret, Child, /*FlattenArchive=*/Thin); + } + } break; case IA_Delete: break; case IA_MoveOldMember: addChildMember(Moved, Child, /*FlattenArchive=*/Thin); break; - case IA_MoveNewMember: - addMember(Moved, *MemberI); - break; + case IA_MoveNewMember: { + NewArchiveMember NM = getArchiveMember(*MemberI); + if (isValidInBitMode(NM)) + addMember(Moved, NM); + else { + // If a new member is not a valid object for the bit mode, add the old + // member back. + WithColor::warning() + << *MemberI + << " is not valid with the current object file mode\n"; + addChildMember(Moved, Child, /*FlattenArchive=*/Thin); + } + } break; } // When processing elements with the count param, we need to preserve the // full members list when iterating over all archive members. For @@ -1122,6 +1236,15 @@ return false; } +static BitModeTy getBitMode(const char *RawBitMode) { + return StringSwitch(RawBitMode) + .Case("32", BitModeTy::Bit32) + .Case("64", BitModeTy::Bit64) + .Case("32_64", BitModeTy::Bit32_64) + .Case("any", BitModeTy::Any) + .Default(BitModeTy::Unknown); +} + static const char *matchFlagWithArg(StringRef Expected, ArrayRef::iterator &ArgIt, ArrayRef Args) { @@ -1171,6 +1294,14 @@ cl::ExpandResponseFiles(Saver, getRspQuoting(makeArrayRef(argv, argc)), Argv); + // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if + // specified. + if (object::Archive::getDefaultKindForHost() == object::Archive::K_AIXBIG) { + BitMode = getBitMode(getenv("OBJECT_MODE")); + if (BitMode == BitModeTy::Unknown) + BitMode = BitModeTy::Bit32; + } + for (ArrayRef::iterator ArgIt = Argv.begin(); ArgIt != Argv.end(); ++ArgIt) { const char *Match = nullptr; @@ -1220,6 +1351,19 @@ matchFlagWithArg("rsp-quoting", ArgIt, Argv)) continue; + if (strncmp(*ArgIt, "-X", 2) == 0) { + if (object::Archive::getDefaultKindForHost() == + object::Archive::K_AIXBIG) { + Match = *(*ArgIt + 2) != '\0' ? *ArgIt + 2 : *(++ArgIt); + BitMode = getBitMode(Match); + if (BitMode == BitModeTy::Unknown) + fail(Twine("invalid bit mode: ") + Match); + continue; + } else { + fail(Twine(*ArgIt) + " option not supported on non AIX OS"); + } + } + Options += *ArgIt + 1; }