[PATCH] D36812: Add support for writing 64-bit symbol tables for archives when offsets become too large for 32-bit

Rafael Avila de Espindola via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 27 14:38:08 PDT 2017


LGTM

Jake Ehrlich via Phabricator <reviews at reviews.llvm.org> writes:

> jakehehrlich updated this revision to Diff 120669.
> jakehehrlich added a comment.
>
> This change adds --print-armap to the test. After https://reviews.llvm.org/D39379 lands this test will work. If the wrong index is used for "main" then the correct file is unlikely to show up making so this test should check that "main" is being looked up in the correct place.
>
>
> Repository:
>   rL LLVM
>
> https://reviews.llvm.org/D36812
>
> Files:
>   lib/Object/ArchiveWriter.cpp
>   test/Object/archive-SYM64-write.test
>
> Index: test/Object/archive-SYM64-write.test
> ===================================================================
> --- /dev/null
> +++ test/Object/archive-SYM64-write.test
> @@ -0,0 +1,31 @@
> +# RUN: yaml2obj %s > %t
> +# RUN: rm -f %t.lib
> +# RUN: cp %t %t2
> +# RUN: llvm-ar cr %t.lib %t %t2 %p/Inputs/trivial-object-test.elf-x86-64
> +# RUN: llvm-nm --print-armap %t.lib | FileCheck %s
> +
> +!ELF
> +FileHeader:
> +  Class:           ELFCLASS64
> +  Data:            ELFDATA2LSB
> +  Type:            ET_EXEC
> +  Machine:         EM_X86_64
> +Sections:
> +  - Name:            .data
> +    Type:            SHT_PROGBITS
> +    Flags:           [ SHF_ALLOC ]
> +    AddressAlign:    0x0000000000000001
> +    Content:         "00"
> +    Size:            2147483648
> +
> +# CHECK:      Archive map
> +# CHECK-NEXT: main in trivial-object-test.elf-x86-64
> +
> +# CHECK:    archive-SYM64-write.test.tmp:
> +
> +# CHECK:    archive-SYM64-write.test.tmp2:
> +
> +# CHECK:    trivial-object-test.elf-x86-64:
> +# CHECK-NEXT:                     U SomeOtherFunction
> +# CHECK-NEXT:    0000000000000000 T main
> +# CHECK-NEXT:                     U puts
> Index: lib/Object/ArchiveWriter.cpp
> ===================================================================
> --- lib/Object/ArchiveWriter.cpp
> +++ lib/Object/ArchiveWriter.cpp
> @@ -122,20 +122,20 @@
>  static bool isBSDLike(object::Archive::Kind Kind) {
>    switch (Kind) {
>    case object::Archive::K_GNU:
> +  case object::Archive::K_GNU64:
>      return false;
>    case object::Archive::K_BSD:
>    case object::Archive::K_DARWIN:
>      return true;
> -  case object::Archive::K_GNU64:
>    case object::Archive::K_DARWIN64:
>    case object::Archive::K_COFF:
>      break;
>    }
>    llvm_unreachable("not supported for writting");
>  }
>  
> -static void print32(raw_ostream &Out, object::Archive::Kind Kind,
> -                    uint32_t Val) {
> +template <class T>
> +static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
>    if (isBSDLike(Kind))
>      support::endian::Writer<support::little>(Out).write(Val);
>    else
> @@ -216,6 +216,20 @@
>    return Relative.str();
>  }
>  
> +static bool is64BitKind(object::Archive::Kind Kind) {
> +  switch (Kind) {
> +  case object::Archive::K_GNU:
> +  case object::Archive::K_BSD:
> +  case object::Archive::K_DARWIN:
> +  case object::Archive::K_COFF:
> +    return false;
> +  case object::Archive::K_DARWIN64:
> +  case object::Archive::K_GNU64:
> +    return true;
> +  }
> +  llvm_unreachable("not supported for writting");
> +}
> +
>  static void addToStringTable(raw_ostream &Out, StringRef ArcName,
>                               const NewArchiveMember &M, bool Thin) {
>    StringRef ID = M.Buf->getBufferIdentifier();
> @@ -288,6 +302,14 @@
>    return true;
>  }
>  
> +static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
> +                       uint64_t Val) {
> +  if (is64BitKind(Kind))
> +    print<uint64_t>(Out, Kind, Val);
> +  else
> +    print<uint32_t>(Out, Kind, Val);
> +}
> +
>  static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
>                               bool Deterministic, ArrayRef<MemberData> Members,
>                               StringRef StringTable) {
> @@ -299,9 +321,11 @@
>      NumSyms += M.Symbols.size();
>  
>    unsigned Size = 0;
> -  Size += 4; // Number of entries
> +  Size += is64BitKind(Kind) ? 8 : 4; // Number of entries
>    if (isBSDLike(Kind))
>      Size += NumSyms * 8; // Table
> +  else if (is64BitKind(Kind))
> +    Size += NumSyms * 8; // Table
>    else
>      Size += NumSyms * 4; // Table
>    if (isBSDLike(Kind))
> @@ -318,27 +342,30 @@
>    if (isBSDLike(Kind))
>      printBSDMemberHeader(Out, Out.tell(), "__.SYMDEF", now(Deterministic), 0, 0,
>                           0, Size);
> +  else if (is64BitKind(Kind))
> +    printGNUSmallMemberHeader(Out, "/SYM64", now(Deterministic), 0, 0, 0, Size);
>    else
>      printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size);
>  
>    uint64_t Pos = Out.tell() + Size;
>  
>    if (isBSDLike(Kind))
> -    print32(Out, Kind, NumSyms * 8);
> +    print<uint32_t>(Out, Kind, NumSyms * 8);
>    else
> -    print32(Out, Kind, NumSyms);
> +    printNBits(Out, Kind, NumSyms);
>  
>    for (const MemberData &M : Members) {
>      for (unsigned StringOffset : M.Symbols) {
>        if (isBSDLike(Kind))
> -        print32(Out, Kind, StringOffset);
> -      print32(Out, Kind, Pos); // member offset
> +        print<uint32_t>(Out, Kind, StringOffset);
> +      printNBits(Out, Kind, Pos); // member offset
>      }
>      Pos += M.Header.size() + M.Data.size() + M.Padding.size();
>    }
>  
>    if (isBSDLike(Kind))
> -    print32(Out, Kind, StringTable.size()); // byte count of the string table
> +    // byte count of the string table
> +    print<uint32_t>(Out, Kind, StringTable.size());
>    Out << StringTable;
>  
>    while (Pad--)
> @@ -442,6 +469,25 @@
>    if (!StringTableBuf.empty())
>      Data.insert(Data.begin(), computeStringTable(StringTableBuf));
>  
> +  // We would like to detect if we need to switch to a 64-bit symbol table.
> +  if (WriteSymtab) {
> +    uint64_t MaxOffset = 0;
> +    uint64_t LastOffset = MaxOffset;
> +    for (const auto& M : Data) {
> +      // Record the start of the member's offset
> +      LastOffset = MaxOffset;
> +      // Account for the size of each part associated with the member.
> +      MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
> +      // We assume 32-bit symbols to see if 32-bit symbols are possible or not.
> +      MaxOffset += M.Symbols.size() * 4;
> +    }
> +    // If LastOffset isn't going to fit in a 32-bit varible we need to switch
> +    // to 64-bit. Note that the file can be larger than 4GB as long as the last
> +    // member starts before the 4GB offset.
> +    if (LastOffset >> 32 != 0)
> +      Kind = object::Archive::K_GNU64;
> +  }
> +
>    SmallString<128> TmpArchive;
>    int TmpArchiveFD;
>    if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a",


More information about the llvm-commits mailing list