From 602706ee583decf5d0f9be3da91ef027201bff16 Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Tue, 17 Feb 2015 18:54:22 +0000 Subject: [PATCH] [Object] Support reading 64-bit MIPS ELF archives The 64-bit MIPS ELF archive file format is used by MIPS64 targets. The main difference from a regular archive file is the symbol table format: 1. ar_name is equal to "/SYM64/" 2. number of symbols and offsets are 64-bit integers http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf Page 96 The patch allows reading of such archive files by llvm-nm, llvm-objdump and other tools. But it does not support archive files with number of symbols and/or offsets exceed 2^32. I think it is a rather rare case requires more significant modification of `Archive` class code. http://reviews.llvm.org/D7546 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229520 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/Archive.h | 1 + lib/Object/Archive.cpp | 30 +++++++++++++++--- .../Inputs/archive-test.a-irix6-mips64el | Bin 0 -> 6608 bytes test/Object/nm-irix6.test | 27 ++++++++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 test/Object/Inputs/archive-test.a-irix6-mips64el create mode 100644 test/Object/nm-irix6.test diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index e3b7a2a1fca..4f8e28172c8 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -178,6 +178,7 @@ public: enum Kind { K_GNU, + K_MIPS64, K_BSD, K_COFF }; diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 305dab06fd3..43b0771a4a4 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -162,7 +162,7 @@ ErrorOr Archive::Child::getName() const { return object_error::parse_failed; // GNU long file names end with a /. - if (Parent->kind() == K_GNU) { + if (Parent->kind() == K_GNU || Parent->kind() == K_MIPS64) { StringRef::size_type End = StringRef(addr).find('/'); return StringRef(addr, End); } @@ -273,8 +273,16 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) return; } - if (Name == "/") { + // MIPS 64-bit ELF archives use a special format of a symbol table. + // This format is marked by `ar_name` field equals to "/SYM64/". + // For detailed description see page 96 in the following document: + // http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf + + bool has64SymTable = false; + if (Name == "/" || Name == "/SYM64/") { SymbolTable = i; + if (Name == "/SYM64/") + has64SymTable = true; ++i; if (i == e) { @@ -285,7 +293,7 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) } if (Name == "//") { - Format = K_GNU; + Format = has64SymTable ? K_MIPS64 : K_GNU; StringTable = i; ++i; FirstRegular = i; @@ -294,7 +302,7 @@ Archive::Archive(MemoryBufferRef Source, std::error_code &ec) } if (Name[0] != '/') { - Format = K_GNU; + Format = has64SymTable ? K_MIPS64 : K_GNU; FirstRegular = i; ec = object_error::success; return; @@ -348,11 +356,18 @@ StringRef Archive::Symbol::getName() const { ErrorOr Archive::Symbol::getMember() const { const char *Buf = Parent->SymbolTable->getBuffer().begin(); - const char *Offsets = Buf + 4; + const char *Offsets = Buf; + if (Parent->kind() == K_MIPS64) + Offsets += sizeof(uint64_t); + else + Offsets += sizeof(uint32_t); uint32_t Offset = 0; if (Parent->kind() == K_GNU) { Offset = *(reinterpret_cast(Offsets) + SymbolIndex); + } else if (Parent->kind() == K_MIPS64) { + Offset = + *(reinterpret_cast(Offsets) + SymbolIndex); } else if (Parent->kind() == K_BSD) { // The SymbolIndex is an index into the ranlib structs that start at // Offsets (the first uint32_t is the number of bytes of the ranlib @@ -449,6 +464,9 @@ Archive::symbol_iterator Archive::symbol_begin() const { uint32_t symbol_count = 0; symbol_count = *reinterpret_cast(buf); buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); + } else if (kind() == K_MIPS64) { + uint64_t symbol_count = *reinterpret_cast(buf); + buf += sizeof(uint64_t) + (symbol_count * (sizeof(uint64_t))); } else if (kind() == K_BSD) { // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t // which is the number of bytes of ranlib structs that follow. The ranlib @@ -486,6 +504,8 @@ Archive::symbol_iterator Archive::symbol_end() const { uint32_t symbol_count = 0; if (kind() == K_GNU) { symbol_count = *reinterpret_cast(buf); + } else if (kind() == K_MIPS64) { + symbol_count = *reinterpret_cast(buf); } else if (kind() == K_BSD) { symbol_count = (*reinterpret_cast(buf)) / (sizeof(uint32_t) * 2); diff --git a/test/Object/Inputs/archive-test.a-irix6-mips64el b/test/Object/Inputs/archive-test.a-irix6-mips64el new file mode 100644 index 0000000000000000000000000000000000000000..ccc2634be7a2fe88ff128e2ef292d7ac33076b95 GIT binary patch literal 6608 zcmeHMJ8u&~5T3K0V9X;AQ6M3~ra(!ASbVQ2K>>wCK$9X86&3O0F0mB*qVriI75M>3 zQ1Am%q@bfsK@cS+1wSAqB@{?0kjyu}+w(=(a+^py(%d|E_ICE}^V*(Su7tJi$E642 zESZjFyGyR+xi|7!>*c9zMz3?1erz4wT>0DWc9p*f z?^au5xVKVMsWDCS-Sov`MGdtxo9d#hfnwk_5hkteLOX-m_*Z!gRXM=nZ}o=l+X zR;xqCB`5`hWP7g}RjQCt7|U&?h2D;gyw?%QdL^omthU=ELvO3m@&i_OetVB`RsCFW+-CxT{jn~cn8&5Jox;wNifzEjI^QP~=b1e%zHp5BCHPOb8^m6s zc{tS?*~d9dQ()B-wwDlSu#%935qQ?`;> ze}R6d?+eHC>D|WJ`7<+coM-P-9y`sT#KaK;8EOyaVCVj;r?Pnj*HcfYvejs1mx$jq zt|h?JT+f#^YQL(3{U89`!OwjeLo>K9<4IF;Xrh3fL(sPdV&a3YmJFL9N>#SC&sPNn0PTTk$=Y53?DvE