From d2ae11527af77939ccbdc3f2d1b862ccc5d1fc23 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Tue, 8 Jul 2014 22:10:02 +0000 Subject: [PATCH] Add support for BSD format Archive map symbols (aka the table of contents from a __.SYMDEF or "__.SYMDEF SORTED" archive member). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212568 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Object/Archive.cpp | 69 ++++++++++++++++++++++++++++++--- test/Object/archive-symtab.test | 6 +++ 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 2393ade562d..6d09bdbac06 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -339,7 +339,14 @@ ErrorOr Archive::Symbol::getMember() const { Offset = *(reinterpret_cast(Offsets) + SymbolIndex); } else if (Parent->kind() == K_BSD) { - llvm_unreachable("BSD format is not supported"); + // 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 + // structs). The ranlib structs are a pair of uint32_t's the first + // being a string table offset and the second being the offset into + // the archive of the member that defines the symbol. Which is what + // is needed here. + Offset = *(reinterpret_cast(Offsets) + + (SymbolIndex * 2) + 1); } else { uint32_t MemberCount = *reinterpret_cast(Buf); @@ -377,9 +384,43 @@ ErrorOr Archive::Symbol::getMember() const { Archive::Symbol Archive::Symbol::getNext() const { Symbol t(*this); - // Go to one past next null. - t.StringIndex = - Parent->SymbolTable->getBuffer().find('\0', t.StringIndex) + 1; + if (Parent->kind() == K_BSD) { + // t.StringIndex is an offset from the start of the __.SYMDEF or + // "__.SYMDEF SORTED" member into the string table for the ranlib + // struct indexed by t.SymbolIndex . To change t.StringIndex to the + // offset in the string table for t.SymbolIndex+1 we subtract the + // its offset from the start of the string table for t.SymbolIndex + // and add the offset of the string table for t.SymbolIndex+1. + + // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t + // which is the number of bytes of ranlib structs that follow. The ranlib + // structs are a pair of uint32_t's the first being a string table offset + // and the second being the offset into the archive of the member that + // define the symbol. After that the next uint32_t is the byte count of + // the string table followed by the string table. + const char *Buf = Parent->SymbolTable->getBuffer().begin(); + uint32_t RanlibCount = 0; + RanlibCount = (*reinterpret_cast(Buf)) / + (sizeof(uint32_t) * 2); + // If t.SymbolIndex + 1 will be past the count of symbols (the RanlibCount) + // don't change the t.StringIndex as we don't want to reference a ranlib + // past RanlibCount. + if (t.SymbolIndex + 1 < RanlibCount) { + const char *Ranlibs = Buf + 4; + uint32_t CurRanStrx = 0; + uint32_t NextRanStrx = 0; + CurRanStrx = *(reinterpret_cast(Ranlibs) + + (t.SymbolIndex * 2)); + NextRanStrx = *(reinterpret_cast(Ranlibs) + + ((t.SymbolIndex + 1) * 2)); + t.StringIndex -= CurRanStrx; + t.StringIndex += NextRanStrx; + } + } else { + // Go to one past next null. + t.StringIndex = + Parent->SymbolTable->getBuffer().find('\0', t.StringIndex) + 1; + } ++t.SymbolIndex; return t; } @@ -394,7 +435,22 @@ Archive::symbol_iterator Archive::symbol_begin() const { symbol_count = *reinterpret_cast(buf); buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); } else if (kind() == K_BSD) { - llvm_unreachable("BSD archive format is not supported"); + // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t + // which is the number of bytes of ranlib structs that follow. The ranlib + // structs are a pair of uint32_t's the first being a string table offset + // and the second being the offset into the archive of the member that + // define the symbol. After that the next uint32_t is the byte count of + // the string table followed by the string table. + uint32_t ranlib_count = 0; + ranlib_count = (*reinterpret_cast(buf)) / + (sizeof(uint32_t) * 2); + const char *ranlibs = buf + 4; + uint32_t ran_strx = 0; + ran_strx = *(reinterpret_cast(ranlibs)); + buf += sizeof(uint32_t) + (ranlib_count * (2 * (sizeof(uint32_t)))); + // Skip the byte count of the string table. + buf += sizeof(uint32_t); + buf += ran_strx; } else { uint32_t member_count = 0; uint32_t symbol_count = 0; @@ -416,7 +472,8 @@ Archive::symbol_iterator Archive::symbol_end() const { if (kind() == K_GNU) { symbol_count = *reinterpret_cast(buf); } else if (kind() == K_BSD) { - llvm_unreachable("BSD archive format is not supported"); + symbol_count = (*reinterpret_cast(buf)) / + (sizeof(uint32_t) * 2); } else { uint32_t member_count = 0; member_count = *reinterpret_cast(buf); diff --git a/test/Object/archive-symtab.test b/test/Object/archive-symtab.test index 5e5292c86e1..683d5f3337b 100644 --- a/test/Object/archive-symtab.test +++ b/test/Object/archive-symtab.test @@ -59,3 +59,9 @@ RUN: llvm-nm -s %t.a | FileCheck %s --check-prefix=NOMAP RUN: llvm-ranlib %t.a RUN: llvm-nm -s %t.a | FileCheck %s + +RUN: llvm-nm -s %p/Inputs/macho-archive-x86_64.a | FileCheck %s --check-prefix=BSD-MachO + +BSD-MachO: Archive map +BSD-MachO: _bar in bar.o +BSD-MachO: _foo in foo.o -- 2.34.1