aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/Archive.cpp
diff options
context:
space:
mode:
authorzhijian <zhijian@ca.ibm.com>2023-05-18 10:54:14 -0400
committerzhijian <zhijian@ca.ibm.com>2023-05-18 10:54:14 -0400
commit38d3c6cb9b9dc67a8a5460aa241824be3240b81e (patch)
tree4b2a825f03d4987ef105ff260b848ce01896c6ed /llvm/lib/Object/Archive.cpp
parent6f28b0bb0ab3323c1c5c375db56b35c4933837e4 (diff)
downloadllvm-38d3c6cb9b9dc67a8a5460aa241824be3240b81e.zip
llvm-38d3c6cb9b9dc67a8a5460aa241824be3240b81e.tar.gz
llvm-38d3c6cb9b9dc67a8a5460aa241824be3240b81e.tar.bz2
[AIX] support 64bit global symbol table for big archive
Summary: In big archive , there is 32bit global symbol table and 64 bit global symbol table. llvm-ar only support 32bit global symbol table this moment, we need to support the 64 bit global symbol table. https://www.ibm.com/docs/en/aix/7.2?topic=formats-ar-file-format-big Global Symbol Tables Immediately following the member table, the archive file contains two global symbol tables. The first global symbol table locates 32-bit file members that define global symbols; the second global symbol table does the same for 64-bit file members. If the archive has no 32-bit or 64-bit file members, the respective global symbol table is omitted. The strip command can be used to delete one or both global symbol tables from the archive. The fl_gstoff field in the fixed-length header contains the offset to the 32-bit global symbol table, and the fl_gst64off contains the offset to the 64-bit global symbol table. Reviewers: James Henderson,Stephen Peckham Differential Revision: https://reviews.llvm.org/D142479
Diffstat (limited to 'llvm/lib/Object/Archive.cpp')
-rw-r--r--llvm/lib/Object/Archive.cpp162
1 files changed, 120 insertions, 42 deletions
diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp
index 081ff79..9920145 100644
--- a/llvm/lib/Object/Archive.cpp
+++ b/llvm/lib/Object/Archive.cpp
@@ -18,6 +18,7 @@
#include "llvm/Object/Error.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
@@ -1276,6 +1277,65 @@ bool Archive::isEmpty() const {
bool Archive::hasSymbolTable() const { return !SymbolTable.empty(); }
+static Error getGlobalSymtabLocAndSize(const MemoryBufferRef &Data,
+ uint64_t GlobalSymtabOffset,
+ const char *&GlobalSymtabLoc,
+ uint64_t &Size, const char *BitMessage) {
+ uint64_t BufferSize = Data.getBufferSize();
+ uint64_t GlobalSymtabContentOffset =
+ GlobalSymtabOffset + sizeof(BigArMemHdrType);
+ if (GlobalSymtabContentOffset > BufferSize)
+ return malformedError(
+ Twine(BitMessage) + " global symbol table header at offset 0x" +
+ Twine::utohexstr(GlobalSymtabOffset) + " and size 0x" +
+ Twine::utohexstr(sizeof(BigArMemHdrType)) +
+ " goes past the end of file");
+
+ GlobalSymtabLoc = Data.getBufferStart() + GlobalSymtabOffset;
+ const BigArMemHdrType *GlobalSymHdr =
+ reinterpret_cast<const BigArMemHdrType *>(GlobalSymtabLoc);
+ StringRef RawOffset = getFieldRawString(GlobalSymHdr->Size);
+ if (RawOffset.getAsInteger(10, Size))
+ return malformedError(Twine(BitMessage) + " global symbol table size \"" +
+ RawOffset + "\" is not a number");
+
+ if (GlobalSymtabContentOffset + Size > BufferSize)
+ return malformedError(
+ Twine(BitMessage) + " global symbol table content at offset 0x" +
+ Twine::utohexstr(GlobalSymtabContentOffset) + " and size 0x" +
+ Twine::utohexstr(Size) + " goes past the end of file");
+
+ return Error::success();
+}
+
+struct GlobalSymtabInfo {
+ uint64_t SymNum;
+ StringRef SymbolTable;
+ StringRef SymbolOffsetTable;
+ StringRef StringTable;
+};
+
+static void
+appendGlobalSymbolTableInfo(SmallVector<GlobalSymtabInfo> &SymtabInfos,
+ const char *GlobalSymtabLoc, uint64_t Size) {
+ // In a big archive, a global symbol table contains the following information:
+ // - The number of symbols.
+ // - The array of offsets into the archive file. The length is eight
+ // times the number of symbols.
+ // - The name-string table. The size is:
+ // Size-(8*(the number of symbols + 1)).
+
+ StringRef SymbolTable =
+ StringRef(GlobalSymtabLoc + sizeof(BigArMemHdrType), Size);
+ uint64_t SymNum = read64be(GlobalSymtabLoc + sizeof(BigArMemHdrType));
+ StringRef SymbolOffsetTable = StringRef(SymbolTable.data() + 8, 8 * SymNum);
+ unsigned SymOffsetsSize = 8 * (SymNum + 1);
+ uint64_t SymbolTableStringSize = Size - SymOffsetsSize;
+ StringRef StringTable =
+ StringRef(SymbolTable.data() + SymOffsetsSize, SymbolTableStringSize);
+ SymtabInfos.push_back({SymNum, SymbolTable, SymbolOffsetTable, StringTable});
+}
+
BigArchive::BigArchive(MemoryBufferRef Source, Error &Err)
: Archive(Source, Err) {
ErrorAsOutParameter ErrAsOutParam(&Err);
@@ -1302,55 +1362,73 @@ BigArchive::BigArchive(MemoryBufferRef Source, Error &Err)
Err = malformedError("malformed AIX big archive: last member offset \"" +
RawOffset + "\" is not a number");
- // Calculate the global symbol table.
- uint64_t GlobSymOffset = 0;
+ uint64_t GlobSymtab32Offset = 0;
RawOffset = getFieldRawString(ArFixLenHdr->GlobSymOffset);
- if (RawOffset.getAsInteger(10, GlobSymOffset))
- // TODO: add test case.
- Err = malformedError(
- "malformed AIX big archive: global symbol table offset \"" + RawOffset +
- "\" is not a number");
+ if (RawOffset.getAsInteger(10, GlobSymtab32Offset)) {
+ Err = malformedError("global symbol table "
+ "offset of 32-bit members \"" +
+ RawOffset + "\" is not a number");
+ return;
+ }
- if (Err)
+ uint64_t GlobSymtab64Offset = 0;
+ RawOffset = getFieldRawString(ArFixLenHdr->GlobSym64Offset);
+ if (RawOffset.getAsInteger(10, GlobSymtab64Offset)) {
+ Err = malformedError("global symbol table "
+ "offset of 64-bit members\"" +
+ RawOffset + "\" is not a number");
return;
+ }
- if (GlobSymOffset > 0) {
- uint64_t GlobalSymTblContentOffset =
- GlobSymOffset + sizeof(BigArMemHdrType);
- if (GlobalSymTblContentOffset > BufferSize) {
- Err = malformedError("global symbol table header at offset 0x" +
- Twine::utohexstr(GlobSymOffset) + " and size 0x" +
- Twine::utohexstr(sizeof(BigArMemHdrType)) +
- " goes past the end of file");
- return;
- }
+ const char *GlobSymtab32Loc = nullptr;
+ const char *GlobSymtab64Loc = nullptr;
+ uint64_t GlobSymtab32Size = 0;
+ uint64_t GlobSymtab64Size = 0;
+ const MemoryBufferRef &MemBuffRef = getMemoryBufferRef();
- const char *GlobSymTblLoc = Data.getBufferStart() + GlobSymOffset;
- const BigArMemHdrType *GlobalSymHdr =
- reinterpret_cast<const BigArMemHdrType *>(GlobSymTblLoc);
- RawOffset = getFieldRawString(GlobalSymHdr->Size);
- uint64_t Size;
- if (RawOffset.getAsInteger(10, Size)) {
- // TODO: add test case.
- Err = malformedError(
- "malformed AIX big archive: global symbol table size \"" + RawOffset +
- "\" is not a number");
+ if (GlobSymtab32Offset) {
+ Err =
+ getGlobalSymtabLocAndSize(MemBuffRef, GlobSymtab32Offset,
+ GlobSymtab32Loc, GlobSymtab32Size, "32-bit");
+ if (Err)
return;
- }
- if (GlobalSymTblContentOffset + Size > BufferSize) {
- Err = malformedError("global symbol table content at offset 0x" +
- Twine::utohexstr(GlobalSymTblContentOffset) +
- " and size 0x" + Twine::utohexstr(Size) +
- " goes past the end of file");
+ }
+
+ if (GlobSymtab64Offset) {
+ Err =
+ getGlobalSymtabLocAndSize(MemBuffRef, GlobSymtab64Offset,
+ GlobSymtab64Loc, GlobSymtab64Size, "64-bit");
+ if (Err)
return;
- }
- SymbolTable = StringRef(GlobSymTblLoc + sizeof(BigArMemHdrType), Size);
- unsigned SymNum = getNumberOfSymbols();
- unsigned SymOffsetsSize = 8 * (SymNum + 1);
- uint64_t SymbolTableStringSize = Size - SymOffsetsSize;
- StringTable =
- StringRef(GlobSymTblLoc + sizeof(BigArMemHdrType) + SymOffsetsSize,
- SymbolTableStringSize);
+ }
+
+ SmallVector<GlobalSymtabInfo> SymtabInfos;
+
+ if (GlobSymtab32Offset)
+ appendGlobalSymbolTableInfo(SymtabInfos, GlobSymtab32Loc, GlobSymtab32Size);
+ if (GlobSymtab64Offset)
+ appendGlobalSymbolTableInfo(SymtabInfos, GlobSymtab64Loc, GlobSymtab64Size);
+
+ if (SymtabInfos.size() == 1) {
+ SymbolTable = SymtabInfos[0].SymbolTable;
+ StringTable = SymtabInfos[0].StringTable;
+ } else if (SymtabInfos.size() == 2) {
+ // In order to let the Archive::Symbol::getNext() work for both 32-bit and
+ // 64-bit global symbol tables, we need to merge them into a single table.
+ raw_string_ostream Out(MergedGlobalSymtabBuf);
+ uint64_t SymNum = SymtabInfos[0].SymNum + SymtabInfos[1].SymNum;
+ write(Out, SymNum, support::big);
+ // Merge symbol offset.
+ Out << SymtabInfos[0].SymbolOffsetTable;
+ Out << SymtabInfos[1].SymbolOffsetTable;
+ // Merge string table.
+ Out << SymtabInfos[0].StringTable;
+ Out << SymtabInfos[1].StringTable;
+ SymbolTable = MergedGlobalSymtabBuf;
+ // The size of the symbol offset to the member file is 8 bytes.
+ StringTable = StringRef(SymbolTable.begin() + (SymNum + 1) * 8,
+ SymtabInfos[0].StringTable.size() +
+ SymtabInfos[1].StringTable.size());
}
child_iterator I = child_begin(Err, false);