diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py --- a/clang/test/lit.cfg.py +++ b/clang/test/lit.cfg.py @@ -273,16 +273,15 @@ elif platform.system() == 'AIX': config.environment['AIXTHREAD_STK'] = '4194304' -# The llvm-nm tool supports an environment variable "OBJECT_MODE" on AIX OS, which +# Some tools support an environment variable "OBJECT_MODE" on AIX OS, which # controls the kind of objects they will support. If there is no "OBJECT_MODE" # environment variable specified, the default behaviour is to support 32-bit # objects only. In order to not affect most test cases, which expect to support # 32-bit and 64-bit objects by default, set the environment variable -# "OBJECT_MODE" to 'any' for llvm-nm on AIX OS. +# "OBJECT_MODE" to '32_64' by default on AIX OS. if 'system-aix' in config.available_features: - config.substitutions.append(('llvm-nm', 'env OBJECT_MODE=any llvm-nm')) - config.substitutions.append(('llvm-ar', 'env OBJECT_MODE=any llvm-ar')) + config.environment['OBJECT_MODE'] = '32_64' # It is not realistically possible to account for all options that could # possibly be present in system and user configuration files, so disable diff --git a/llvm/include/llvm/Object/Archive.h b/llvm/include/llvm/Object/Archive.h --- a/llvm/include/llvm/Object/Archive.h +++ b/llvm/include/llvm/Object/Archive.h @@ -411,12 +411,17 @@ uint64_t FirstChildOffset = 0; uint64_t LastChildOffset = 0; std::string MergedGlobalSymtabBuf; + bool Has32BitGlobalSymtab = false; + bool Has64BitGlobalSymtab = false; public: BigArchive(MemoryBufferRef Source, Error &Err); uint64_t getFirstChildOffset() const override { return FirstChildOffset; } uint64_t getLastChildOffset() const { return LastChildOffset; } bool isEmpty() const override { return getFirstChildOffset() == 0; } + + bool has32BitGlobalSymtab() { return Has32BitGlobalSymtab; } + bool has64BitGlobalSymtab() { return Has64BitGlobalSymtab; } }; } // end namespace object diff --git a/llvm/include/llvm/Object/ArchiveWriter.h b/llvm/include/llvm/Object/ArchiveWriter.h --- a/llvm/include/llvm/Object/ArchiveWriter.h +++ b/llvm/include/llvm/Object/ArchiveWriter.h @@ -40,8 +40,27 @@ Expected computeArchiveRelativePath(StringRef From, StringRef To); +class WriteSymTabType { +public: + enum BitMode { + None, // Not write Symbol table. + Both, // Write both 32-bit and 64-bit symbol table. + Bit32, // Only write the 32-bit symbol table. + Bit64 // Only write the 64-bit symbol table. + }; + + WriteSymTabType(bool PrintSym) { Value = PrintSym ? Both : None; } + void operator=(bool PrintSym) { Value = PrintSym ? Both : None; } + operator bool() { return Value != None; } + void setBitMode(BitMode BM) { Value = BM; } + BitMode getBitMode() { return Value; } + +private: + BitMode Value; +}; + Error writeArchive(StringRef ArcName, ArrayRef NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, + WriteSymTabType WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr OldArchiveBuf = nullptr, bool IsEC = false); @@ -49,8 +68,9 @@ // writeArchiveToBuffer is similar to writeArchive but returns the Archive in a // buffer instead of writing it out to a file. Expected> -writeArchiveToBuffer(ArrayRef NewMembers, bool WriteSymtab, - object::Archive::Kind Kind, bool Deterministic, bool Thin); +writeArchiveToBuffer(ArrayRef NewMembers, + WriteSymTabType WriteSymtab, object::Archive::Kind Kind, + bool Deterministic, bool Thin); } #endif diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp --- a/llvm/lib/Object/Archive.cpp +++ b/llvm/lib/Object/Archive.cpp @@ -1392,6 +1392,8 @@ GlobSymtab32Loc, GlobSymtab32Size, "32-bit"); if (Err) return; + + Has32BitGlobalSymtab = true; } if (GlobSymtab64Offset) { @@ -1400,6 +1402,8 @@ GlobSymtab64Loc, GlobSymtab64Size, "64-bit"); if (Err) return; + + Has64BitGlobalSymtab = true; } SmallVector SymtabInfos; diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp --- a/llvm/lib/Object/ArchiveWriter.cpp +++ b/llvm/lib/Object/ArchiveWriter.cpp @@ -680,7 +680,7 @@ static Expected> computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, object::Archive::Kind Kind, bool Thin, bool Deterministic, - bool NeedSymbols, SymMap *SymMap, + WriteSymTabType NeedSymbols, SymMap *SymMap, ArrayRef NewMembers) { static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; @@ -860,7 +860,8 @@ static Error writeArchiveToStream(raw_ostream &Out, ArrayRef NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, + WriteSymTabType WriteSymtab, + object::Archive::Kind Kind, bool Deterministic, bool Thin, bool IsEC) { assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); @@ -1041,11 +1042,17 @@ // the offset to the 32-bit global symbol table, and the 'GlobSym64Offset' // contains the offset to the 64-bit global symbol table. uint64_t GlobalSymbolOffset = - (WriteSymtab && NumSyms32 > 0) ? MemberTableEndOffset : 0; + (WriteSymtab && + (WriteSymtab.getBitMode() != WriteSymTabType::BitMode::Bit64) && + NumSyms32 > 0) + ? MemberTableEndOffset + : 0; uint64_t GlobalSymbolOffset64 = 0; uint64_t NumSyms64 = NumSyms - NumSyms32; - if (WriteSymtab && NumSyms64 > 0) { + if (WriteSymtab && + (WriteSymtab.getBitMode() != WriteSymTabType::BitMode::Bit32) && + NumSyms64 > 0) { if (GlobalSymbolOffset == 0) GlobalSymbolOffset64 = MemberTableEndOffset; else @@ -1121,7 +1128,7 @@ } Error writeArchive(StringRef ArcName, ArrayRef NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, + WriteSymTabType WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, std::unique_ptr OldArchiveBuf, bool IsEC) { Expected Temp = @@ -1153,9 +1160,9 @@ } Expected> -writeArchiveToBuffer(ArrayRef NewMembers, bool WriteSymtab, - object::Archive::Kind Kind, bool Deterministic, - bool Thin) { +writeArchiveToBuffer(ArrayRef NewMembers, + WriteSymTabType WriteSymtab, object::Archive::Kind Kind, + bool Deterministic, bool Thin) { SmallVector ArchiveBufferVector; raw_svector_ostream ArchiveStream(ArchiveBufferVector); diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -641,6 +641,6 @@ # environment variable specified, the default behaviour is to support 32-bit # objects only. In order to not affect most test cases, which expect to support # 32-bit and 64-bit objects by default, set the environment variable -# "OBJECT_MODE" to 'any' by default on AIX OS. -if "system-aix" in config.available_features: - config.environment["OBJECT_MODE"] = "any" +# "OBJECT_MODE" to '32_64' by default on AIX OS. +if 'system-aix' in config.available_features: + config.environment['OBJECT_MODE'] = '32_64' diff --git a/llvm/test/tools/llvm-ranlib/aix-X-option.test b/llvm/test/tools/llvm-ranlib/aix-X-option.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ranlib/aix-X-option.test @@ -0,0 +1,123 @@ +## REQUIRES: system-aix +## Test the -X option. +## The option specifies the type of object file on which llvm-ranlib will operate. + +# RUN: rm -rf %t && mkdir %t && cd %t +# RUN: yaml2obj --docnum=1 -DFLAG=0x1DF %s -o t32_1.o +# RUN: yaml2obj --docnum=1 -DFLAG=0x1F7 %s -o t64_1.o +# RUN: yaml2obj --docnum=2 -DFLAG=0x1DF %s -o t32_2.o +# RUN: yaml2obj --docnum=2 -DFLAG=0x1F7 %s -o t64_2.o + +# RUN: llvm-ar qS t_all.a t32_1.o t64_1.o t32_2.o t64_2.o +# RUN: cp t_all.a t_X32.a +# RUN: cp t_all.a t_X64.a +# RUN: cp t_all.a t_X32_64.a + +## Test the OBJECT_MODE environment variable when adding symbol table. +# RUN: env OBJECT_MODE= llvm-ranlib t_X32.a +# RUN: llvm-nm --print-armap t_X32.a 2>&1 | FileCheck --check-prefixes=GLOB32 --implicit-check-not="in t64" %s +# RUN: cp t_all.a t_X32.a +# RUN: env OBJECT_MODE=32 llvm-ranlib t_X32.a +# RUN: llvm-nm --print-armap t_X32.a 2>&1 | FileCheck --check-prefixes=GLOB32 --implicit-check-not="in t64" %s + +# RUN: env OBJECT_MODE=64 llvm-ranlib t_X64.a +# RUN: llvm-nm --print-armap t_X64.a 2>&1 | FileCheck --check-prefixes=GLOB64 --implicit-check-not="in t32" %s + +# RUN: env OBJECT_MODE=32_64 llvm-ranlib t_X32_64.a +# RUN: llvm-nm --print-armap t_X32_64.a 2>&1 | FileCheck --check-prefixes=GLOB32,GLOB64 %s + +# RUN: cp t_all.a t_X32.a +# RUN: cp t_all.a t_X64.a +# RUN: cp t_all.a t_X32_64.a + +## Test -X option when adding symbol table. +# RUN: llvm-ranlib -X32 t_X32.a +# RUN: llvm-nm --print-armap t_X32.a 2>&1 | FileCheck --check-prefixes=GLOB32 --implicit-check-not="in t64" %s +# RUN: llvm-ranlib -X64 t_X32.a +# RUN: llvm-nm --print-armap t_X32.a 2>&1 | FileCheck --check-prefixes=GLOB32,GLOB64 %s + +# RUN: llvm-ranlib -X64 t_X64.a +# RUN: llvm-nm --print-armap t_X64.a 2>&1 | FileCheck --check-prefixes=GLOB64 --implicit-check-not="in t32" %s +# RUN: llvm-ranlib -X32 t_X64.a +# RUN: llvm-nm --print-armap t_X32.a 2>&1 | FileCheck --check-prefixes=GLOB32,GLOB64 %s + +# RUN: llvm-ranlib -X32_64 t_X32_64.a +# RUN: llvm-nm --print-armap t_X32_64.a 2>&1 | FileCheck --check-prefixes=GLOB32,GLOB64 %s + +# RUN: cp t_all.a t_X32.a +# RUN: cp t_all.a t_X64.a + +## Test that the -X option will override the "OBJECT_MODE" environment variable. +# RUN: env OBJECT_MODE=32_64 llvm-ranlib -X32 t_X32.a +# RUN: llvm-nm --print-armap t_X32.a 2>&1 | FileCheck --check-prefixes=GLOB32 --implicit-check-not="in t64" %s + +# RUN: env OBJECT_MODE=32 llvm-ranlib -X64 t_X64.a +# RUN: llvm-nm --print-armap t_X64.a 2>&1 | FileCheck --check-prefixes=GLOB64 --implicit-check-not="in t32" %s + +# GLOB32: sym1_0x1DF in t32_1.o +# GLOB32-NEXT: sym2_0x1DF in t32_1.o +# GLOB32-NEXT: sym3_0x1DF in t32_2.o +# GLOB32-NEXT: sym4_0x1DF in t32_2.o + +# GLOB64: sym1_0x1F7 in t64_1.o +# GLOB64-NEXT: sym2_0x1F7 in t64_1.o +# GLOB64-NEXT: sym3_0x1F7 in t64_2.o +# GLOB64-NEXT: sym4_0x1F7 in t64_2.o + +## Test invalid -X option and OBJECT_MODE enviornment var. +# RUN: not env OBJECT_MODE=any llvm-ranlib t_X64.a 2>&1 | FileCheck --implicit-check-not="error:" --check-prefixes=INVALID-OBJECT-MODE %s +# RUN: not env OBJECT_MODE=31 llvm-ranlib t_X64.a 2>&1 | FileCheck --implicit-check-not="error:" --check-prefixes=INVALID-OBJECT-MODE %s +# RUN: not llvm-ranlib -X t_X64.a 2>&1 | FileCheck --implicit-check-not="error:" --check-prefixes=INVALID-X-OPTION %s +# RUN: not llvm-ranlib -Xany t_X64.a 2>&1 | FileCheck --implicit-check-not="error:" --check-prefixes=INVALID-X-OPTION %s +# RUN: not llvm-ranlib -X31 t_X64.a 2>&1 | FileCheck --implicit-check-not="error:" --check-prefixes=INVALID-X-OPTION %s + +# INVALID-OBJECT-MODE: error: the OBJECT_MODE environment variable has an invalid value. OBJECT_MODE must be 32, 64, or 32_64 +# INVALID-X-OPTION: error: the specified object mode is not valid. Specify -X32, -X64, or -X32_64 + +--- !XCOFF +FileHeader: + MagicNumber: [[FLAG]] +Sections: + - Name: .data + Flags: [ STYP_DATA ] +Symbols: + - Name: sym1_[[FLAG]] + Section: .data + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + - Name: sym2_[[FLAG]] + Section: .data + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + +--- !XCOFF +FileHeader: + MagicNumber: [[FLAG]] +Sections: + - Name: .text + Flags: [ STYP_DATA ] +Symbols: + - Name: sym3_[[FLAG]] + Section: .text + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_PR + - Name: sym4_[[FLAG]] + Section: .text + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_PR 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 @@ -69,7 +69,10 @@ << " -v --version - Display the version of this program\n" << " -D - Use zero for timestamps and uids/gids " "(default)\n" - << " -U - Use actual timestamps and uids/gids\n"; + << " -U - Use actual timestamps and uids/gids\n" + << " -X{32|64|32_64} - Specifies which archive symbol tables " + "should " + "be generated if they do not already exist (AIX OS only)\n"; } static void printArHelp(StringRef ToolName) { @@ -225,7 +228,7 @@ static bool CompareFullPath = false; ///< 'P' modifier static bool OnlyUpdate = false; ///< 'u' modifier static bool Verbose = false; ///< 'v' modifier -static bool Symtab = true; ///< 's' modifier +static WriteSymTabType Symtab = true; ///< 's' modifier static bool Deterministic = true; ///< 'D' and 'U' modifiers static bool Thin = false; ///< 'T' modifier static bool AddLibrary = false; ///< 'L' modifier @@ -1074,9 +1077,27 @@ // In summary, we only need to update the symbol table if we have none. // This is actually very common because of broken build systems that think // they have to run ranlib. - if (OldArchive->hasSymbolTable()) - return; + if (OldArchive->hasSymbolTable()) { + if (OldArchive->kind() != object::Archive::K_AIXBIG) + return; + // For archives in the Big Archive format, the bit mode option specifies + // which symbol table to generate. The presence of a symbol table that does + // not match the specified bit mode does not prevent creation of the symbol + // table that has been requested. + if (OldArchive->kind() == object::Archive::K_AIXBIG) { + BigArchive *BigArc = dyn_cast(OldArchive); + if (BigArc->has32BitGlobalSymtab() && + Symtab.getBitMode() == WriteSymTabType::BitMode::Bit32) + return; + + if (BigArc->has64BitGlobalSymtab() && + Symtab.getBitMode() == WriteSymTabType::BitMode::Bit64) + return; + + Symtab.setBitMode(WriteSymTabType::BitMode::Both); + } + } if (OldArchive->isThin()) Thin = true; performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr); @@ -1250,6 +1271,7 @@ static BitModeTy getBitMode(const char *RawBitMode) { return StringSwitch(RawBitMode) + .Case("", BitModeTy::Bit32) .Case("32", BitModeTy::Bit32) .Case("64", BitModeTy::Bit64) .Case("32_64", BitModeTy::Bit32_64) @@ -1389,6 +1411,8 @@ static int ranlib_main(int argc, char **argv) { std::vector Archives; + + bool HasAIXXOption = false; for (int i = 1; i < argc; ++i) { StringRef arg(argv[i]); if (handleGenericOption(arg)) { @@ -1406,6 +1430,30 @@ } else if (arg.front() == 'v') { cl::PrintVersionMessage(); return 0; + } else if (arg.front() == 'X') { + if (object::Archive::getDefaultKindForHost() == + object::Archive::K_AIXBIG) { + HasAIXXOption = true; + arg.consume_front("X"); + const char *Xarg = arg.data(); + if (Xarg[0] == '\0') { + if (argv[i + 1][0] != '-') + BitMode = getBitMode(argv[++i]); + else + BitMode = BitModeTy::Unknown; + } else + BitMode = getBitMode(arg.data()); + + // -X option in ranlib do not accept "any" + if (BitMode == BitModeTy::Unknown || BitMode == BitModeTy::Any) + fail( + Twine("the specified object mode is not valid. Specify -X32, " + "-X64, or -X32_64")); + } else { + fail(Twine("-") + Twine(arg) + + " option not supported on non AIX OS"); + } + break; } else { // TODO: GNU ranlib also supports a -t flag fail("Invalid option: '-" + arg + "'"); @@ -1417,6 +1465,30 @@ } } + if (object::Archive::getDefaultKindForHost() == object::Archive::K_AIXBIG) { + // If not specify -X option, get BitMode from enviorment variable + // "OBJECT_MODE" for AIX OS if specify. + if (!HasAIXXOption) { + BitMode = getBitMode(getenv("OBJECT_MODE")); + // -X option in ranlib do not accept "any" + if (BitMode == BitModeTy::Any || BitMode == BitModeTy::Unknown) + fail("the OBJECT_MODE environment variable has an invalid value. " + "OBJECT_MODE must be 32, 64, or 32_64"); + } + + switch (BitMode) { + case BitModeTy::Bit32: + Symtab.setBitMode(WriteSymTabType::BitMode::Bit32); + break; + case BitModeTy::Bit64: + Symtab.setBitMode(WriteSymTabType::BitMode::Bit64); + break; + default: + Symtab = true; + break; + } + } + for (StringRef Archive : Archives) { ArchiveName = Archive.str(); performOperation(CreateSymTab);