Index: include/llvm/Object/Archive.h =================================================================== --- include/llvm/Object/Archive.h +++ include/llvm/Object/Archive.h @@ -229,7 +229,7 @@ enum Kind { K_GNU, - K_MIPS64, + K_GNU64, K_BSD, K_DARWIN, K_DARWIN64, Index: lib/Object/Archive.cpp =================================================================== --- lib/Object/Archive.cpp +++ lib/Object/Archive.cpp @@ -179,7 +179,7 @@ // GNU long file names end with a "/\n". if (Parent->kind() == Archive::K_GNU || - Parent->kind() == Archive::K_MIPS64) { + Parent->kind() == Archive::K_GNU64) { StringRef::size_type End = StringRef(addr).find('\n'); return StringRef(addr, End - 1); } @@ -338,7 +338,7 @@ ErrorAsOutParameter ErrAsOutParam(Err); - // If there was an error in the construction of the Header + // If there was an error in the construction of the Header // then just return with the error now set. if (*Err) return; @@ -698,7 +698,7 @@ } if (Name == "//") { - Format = has64SymTable ? K_MIPS64 : K_GNU; + Format = has64SymTable ? K_GNU64 : K_GNU; // The string table is never an external member, but we still // must check any Expected<> return value. Expected BufOrErr = C->getBuffer(); @@ -715,7 +715,7 @@ } if (Name[0] != '/') { - Format = has64SymTable ? K_MIPS64 : K_GNU; + Format = has64SymTable ? K_GNU64 : K_GNU; setFirstRegular(*C); Err = Error::success(); return; @@ -797,14 +797,14 @@ Expected Archive::Symbol::getMember() const { const char *Buf = Parent->getSymbolTable().begin(); const char *Offsets = Buf; - if (Parent->kind() == K_MIPS64 || Parent->kind() == K_DARWIN64) + if (Parent->kind() == K_GNU64 || Parent->kind() == K_DARWIN64) Offsets += sizeof(uint64_t); else Offsets += sizeof(uint32_t); uint32_t Offset = 0; if (Parent->kind() == K_GNU) { Offset = read32be(Offsets + SymbolIndex * 4); - } else if (Parent->kind() == K_MIPS64) { + } else if (Parent->kind() == K_GNU64) { Offset = read64be(Offsets + SymbolIndex * 8); } else if (Parent->kind() == K_BSD) { // The SymbolIndex is an index into the ranlib structs that start at @@ -902,7 +902,7 @@ uint32_t symbol_count = 0; symbol_count = read32be(buf); buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); - } else if (kind() == K_MIPS64) { + } else if (kind() == K_GNU64) { uint64_t symbol_count = read64be(buf); buf += sizeof(uint64_t) + (symbol_count * (sizeof(uint64_t))); } else if (kind() == K_BSD) { @@ -959,7 +959,7 @@ const char *buf = getSymbolTable().begin(); if (kind() == K_GNU) return read32be(buf); - if (kind() == K_MIPS64) + if (kind() == K_GNU64) return read64be(buf); if (kind() == K_BSD) return read32le(buf) / 8; Index: lib/Object/ArchiveWriter.cpp =================================================================== --- lib/Object/ArchiveWriter.cpp +++ lib/Object/ArchiveWriter.cpp @@ -115,7 +115,7 @@ bool MayTruncate = false) { uint64_t OldPos = OS.tell(); OS << Data; - unsigned SizeSoFar = OS.tell() - OldPos; + uint64_t SizeSoFar = OS.tell() - OldPos; if (Size > SizeSoFar) { OS.indent(Size - SizeSoFar); } else if (Size < SizeSoFar) { @@ -129,11 +129,11 @@ 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_MIPS64: case object::Archive::K_DARWIN64: case object::Archive::K_COFF: break; @@ -141,14 +141,36 @@ llvm_unreachable("not supported for writting"); } -static void print32(raw_ostream &Out, object::Archive::Kind Kind, - uint32_t Val) { +template +static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) { if (isBSDLike(Kind)) support::endian::Writer(Out).write(Val); else support::endian::Writer(Out).write(Val); } +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 printNBits(raw_ostream &Out, object::Archive::Kind Kind, + uint64_t Val) { + if (is64BitKind(Kind)) + print(Out, Kind, Val); + else + print(Out, Kind, Val); +} + static void printRestOfMemberHeader( raw_fd_ostream &Out, const sys::TimePoint &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { @@ -280,13 +302,25 @@ return sys::TimePoint(); } +bool isArchiveSymbol(const object::BasicSymbolRef &S) { + uint32_t Symflags = S.getFlags(); + if (Symflags & object::SymbolRef::SF_FormatSpecific) + return false; + if (!(Symflags & object::SymbolRef::SF_Global)) + return false; + if (Symflags & object::SymbolRef::SF_Undefined && + !(Symflags & object::SymbolRef::SF_Indirect)) + return false; + return true; +} + // Returns the offset of the first reference to a member offset. -static ErrorOr +static ErrorOr writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, ArrayRef Members, std::vector &MemberOffsetRefs, bool Deterministic) { - unsigned HeaderStartOffset = 0; - unsigned BodyStartOffset = 0; + uint64_t HeaderStartOffset = 0; + uint64_t BodyStartOffset = 0; SmallString<128> NameBuf; raw_svector_ostream NameOS(NameBuf); LLVMContext Context; @@ -306,30 +340,27 @@ HeaderStartOffset = Out.tell(); if (isBSDLike(Kind)) printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0); + else if (is64BitKind(Kind)) + printGNUSmallMemberHeader(Out, "/SYM64", now(Deterministic), 0, 0, 0, + 0); else printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0); BodyStartOffset = Out.tell(); - print32(Out, Kind, 0); // number of entries or bytes + printNBits(Out, Kind, 0); // number of entries or bytes } for (const object::BasicSymbolRef &S : Obj.symbols()) { - uint32_t Symflags = S.getFlags(); - if (Symflags & object::SymbolRef::SF_FormatSpecific) - continue; - if (!(Symflags & object::SymbolRef::SF_Global)) - continue; - if (Symflags & object::SymbolRef::SF_Undefined && - !(Symflags & object::SymbolRef::SF_Indirect)) + if (!isArchiveSymbol(S)) continue; - unsigned NameOffset = NameOS.tell(); + uint64_t NameOffset = NameOS.tell(); if (auto EC = S.printName(NameOS)) return EC; NameOS << '\0'; MemberOffsetRefs.push_back(MemberNum); if (isBSDLike(Kind)) - print32(Out, Kind, NameOffset); - print32(Out, Kind, 0); // member offset + print(Out, Kind, NameOffset); + printNBits(Out, Kind, 0); // member offset } } @@ -344,13 +375,14 @@ StringRef StringTable = NameOS.str(); if (isBSDLike(Kind)) - print32(Out, Kind, StringTable.size()); // byte count of the string table + print(Out, Kind, + StringTable.size()); // byte count of the string table Out << StringTable; // If there are no symbols, emit an empty symbol table, to satisfy Solaris // tools, older versions of which expect a symbol table in a non-empty // archive, regardless of whether there are any symbols in it. if (StringTable.size() == 0) - print32(Out, Kind, 0); + print(Out, Kind, 0); // ld64 requires the next member header to start at an offset that is // 4 bytes aligned. @@ -359,7 +391,7 @@ Out.write(uint8_t(0)); // Patch up the size of the symbol table now that we know how big it is. - unsigned Pos = Out.tell(); + uint64_t Pos = Out.tell(); const unsigned MemberHeaderSize = 60; Out.seek(HeaderStartOffset + 48); // offset of the size field. printWithSpacePadding(Out, Pos - MemberHeaderSize - HeaderStartOffset, 10); @@ -368,12 +400,12 @@ Out.seek(BodyStartOffset); unsigned NumSyms = MemberOffsetRefs.size(); if (isBSDLike(Kind)) - print32(Out, Kind, NumSyms * 8); + print(Out, Kind, NumSyms * 8); else - print32(Out, Kind, NumSyms); + printNBits(Out, Kind, NumSyms); Out.seek(Pos); - return BodyStartOffset + 4; + return BodyStartOffset + (is64BitKind(Kind) ? 8 : 4); } std::error_code @@ -397,9 +429,52 @@ std::vector MemberOffsetRefs; - unsigned MemberReferenceOffset = 0; + uint64_t MemberReferenceOffset = 0; if (WriteSymtab) { - ErrorOr MemberReferenceOffsetOrErr = writeSymbolTable( + // check if we need to switch to 64-bit by computing size from here + uint64_t MaxOffset = MemberReferenceOffset; + uint64_t LastOffset = 0; + LLVMContext Context; + // Compute the size of each member plus the size to be added to the symbols + for (const auto &M : NewMembers) { + MemoryBufferRef MemberBuffer = M.Buf->getMemBufferRef(); + // The offset of this is the previous + LastOffset = MaxOffset; + // Add size of header + MaxOffset += 60; + // Add the size of the buffer + MaxOffset += M.Buf->getBufferSize(); + // Add the size of padding + if (Kind == object::Archive::K_DARWIN) + MaxOffset += OffsetToAlignment(M.Buf->getBufferSize(), 8); + // Add the size added at the end in order to get an even location + MaxOffset += MaxOffset & 1; + // Now we need to add space for each symbol + Expected> ObjOrErr = + object::SymbolicFile::createSymbolicFile( + MemberBuffer, llvm::file_magic::unknown, &Context); + if (!ObjOrErr) { + // FIXME: check only for "not an object file" errors. + consumeError(ObjOrErr.takeError()); + continue; + } + object::SymbolicFile &Obj = *ObjOrErr.get(); + for (const object::BasicSymbolRef &S : Obj.symbols()) { + if (!isArchiveSymbol(S)) + continue; + // Add space for the symbol offset + MaxOffset += 4; + // Add space for the string in the string table + SmallString<128> NameBuf; + raw_svector_ostream NameLengthBuf(NameBuf); + S.printName(NameLengthBuf); + MaxOffset += NameLengthBuf.tell(); + } + } + if (LastOffset >> 32 != 0) + Kind = object::Archive::K_GNU64; + // Store the location in case we have to do this all over again + ErrorOr MemberReferenceOffsetOrErr = writeSymbolTable( Out, Kind, NewMembers, MemberOffsetRefs, Deterministic); if (auto EC = MemberReferenceOffsetOrErr.getError()) return EC; @@ -411,12 +486,12 @@ writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin); std::vector::iterator StringMapIndexIter = StringMapIndexes.begin(); - std::vector MemberOffset; + std::vector MemberOffset; for (const NewArchiveMember &M : NewMembers) { MemoryBufferRef File = M.Buf->getMemBufferRef(); - unsigned Padding = 0; + uint64_t Padding = 0; - unsigned Pos = Out.tell(); + uint64_t Pos = Out.tell(); MemberOffset.push_back(Pos); // ld64 expects the members to be 8-byte aligned for 64-bit content and at @@ -444,7 +519,7 @@ for (unsigned MemberNum : MemberOffsetRefs) { if (isBSDLike(Kind)) Out.seek(Out.tell() + 4); // skip over the string offset - print32(Out, Kind, MemberOffset[MemberNum]); + printNBits(Out, Kind, MemberOffset[MemberNum]); } }