diff options
author | Karl Schimpf <kschimpf@google.com> | 2013-06-06 10:03:24 -0700 |
---|---|---|
committer | Karl Schimpf <kschimpf@google.com> | 2013-06-06 10:03:24 -0700 |
commit | 37bdd9174a1cba17b369c8c1f561e70c458e0c13 (patch) | |
tree | 1f6a984ebb94ccd819c6e38646d91bb5c7eb6977 /lib/Bitcode | |
parent | c0d9b337419b72e69cbd9c64f84ae39560ab344f (diff) |
Make PNaCl bitcode files have a different format from LLVM bitcode files.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3405
R=dschuff@chromium.org
Review URL: https://codereview.chromium.org/15907008
Diffstat (limited to 'lib/Bitcode')
-rw-r--r-- | lib/Bitcode/NaCl/Reader/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp | 259 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp | 111 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h | 26 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp | 132 |
5 files changed, 355 insertions, 174 deletions
diff --git a/lib/Bitcode/NaCl/Reader/CMakeLists.txt b/lib/Bitcode/NaCl/Reader/CMakeLists.txt index 1013174307..9e4de723c1 100644 --- a/lib/Bitcode/NaCl/Reader/CMakeLists.txt +++ b/lib/Bitcode/NaCl/Reader/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMNaClBitReader + NaClBitcodeHeader.cpp NaClBitcodeReader.cpp NaClBitstreamReader.cpp ) diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp new file mode 100644 index 0000000000..5193417619 --- /dev/null +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp @@ -0,0 +1,259 @@ +//===- NaClBitcodeHeader.cpp ----------------------------------------------===// +// PNaCl bitcode header reader. +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" +#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/StreamableMemoryObject.h" + +#include <limits> +#include <cstring> +#include <iomanip> + +using namespace llvm; + +NaClBitcodeHeaderField::NaClBitcodeHeaderField() + : ID(kInvalid), FType(kBufferType), Len(0), Data(0) {} + +NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, uint32_t MyValue) + : ID(MyID), FType(kUInt32Type), Len(4), Data(new uint8_t[4]) { + Data[0] = static_cast<uint8_t>(MyValue & 0xFF); + Data[1] = static_cast<uint8_t>((MyValue >> 8) & 0xFF); + Data[2] = static_cast<uint8_t>((MyValue >> 16) & 0xFF); + Data[3] = static_cast<uint8_t>((MyValue >> 24) & 0xFF); +} + +uint32_t NaClBitcodeHeaderField::GetUInt32Value() const { + assert(FType == kUInt32Type && "Header field must be uint32"); + return static_cast<uint32_t>(Data[0]) | + (static_cast<uint32_t>(Data[1]) << 8) | + (static_cast<uint32_t>(Data[2]) << 16) | + (static_cast<uint32_t>(Data[2]) << 24); +} + +NaClBitcodeHeaderField::NaClBitcodeHeaderField(Tag MyID, size_t MyLen, + uint8_t *MyData) + : ID(MyID), FType(kBufferType), Len(MyLen), Data(new uint8_t[MyLen]) { + for (size_t i = 0; i < MyLen; ++i) { + Data[i] = MyData[i]; + } +} + +bool NaClBitcodeHeaderField::Write(uint8_t *Buf, size_t BufLen) const { + size_t FieldsLen = kTagLenSize + Len; + size_t PadLen = (WordSize - (FieldsLen & (WordSize-1))) & (WordSize-1); + // Ensure buffer is large enough and that length can be represented + // in 32 bits + if (BufLen < FieldsLen + PadLen || + Len > std::numeric_limits<FixedSubfield>::max()) + return false; + + WriteFixedSubfield(EncodeTypedID(), Buf); + WriteFixedSubfield(static_cast<FixedSubfield>(Len), + Buf + sizeof(FixedSubfield)); + memcpy(Buf + kTagLenSize, Data, Len); + // Pad out to word alignment + if (PadLen) { + memset(Buf + FieldsLen, 0, PadLen); + } + return true; +} + +bool NaClBitcodeHeaderField::Read(const uint8_t *Buf, size_t BufLen) { + if (BufLen < kTagLenSize) + return false; + FixedSubfield IdField; + ReadFixedSubfield(&IdField, Buf); + FixedSubfield LengthField; + ReadFixedSubfield(&LengthField, Buf + sizeof(FixedSubfield)); + size_t Length = static_cast<size_t>(LengthField); + if (BufLen < kTagLenSize + Length) + return false; + if (Len != Length) { + // Need to reallocate data buffer. + if (Data) + delete[] Data; + Data = new uint8_t[Length]; + } + Len = Length; + DecodeTypedID(IdField, ID, FType); + memcpy(Data, Buf + kTagLenSize, Len); + return true; +} + +std::string NaClBitcodeHeaderField::Contents() const { + std::string buffer; + raw_string_ostream ss(buffer); + switch (ID) { + case kPNaClVersion: + ss << "PNaCl Version"; + break; + case kInvalid: + ss << "Invalid"; + break; + default: + report_fatal_error("PNaCl bitcode file contains unknown field tag"); + } + ss << ": "; + switch (FType) { + case kUInt32Type: + ss << GetUInt32Value(); + break; + case kBufferType: + ss << "["; + for (size_t i = 0; i < Len; ++i) { + if (i) + ss << " "; + ss << format("%02x", Data[i]); + } + ss << "]"; + break; + default: + report_fatal_error("PNaCL bitcode file contains unknown field type"); + } + return ss.str(); +} + +NaClBitcodeHeader::NaClBitcodeHeader() + : HeaderSize(0), UnsupportedMessage(), IsSupportedFlag(false), + IsReadableFlag(false), PNaClVersion(0) {} + +NaClBitcodeHeader::~NaClBitcodeHeader() { + for (std::vector<NaClBitcodeHeaderField *>::const_iterator + Iter = Fields.begin(), + IterEnd = Fields.end(); + Iter != IterEnd; ++Iter) { + delete *Iter; + } +} + +bool NaClBitcodeHeader::ReadPrefix(const unsigned char *BufPtr, + const unsigned char *BufEnd, + unsigned &NumFields, unsigned &NumBytes) { + // Must contain PEXE. + if (!isNaClBitcode(BufPtr, BufEnd)) + return true; + BufPtr += WordSize; + + // Read #Fields and number of bytes needed for the header. + if (BufPtr + WordSize > BufEnd) + return true; + NumFields = static_cast<unsigned>(BufPtr[0]) | + (static_cast<unsigned>(BufPtr[1]) << 8); + NumBytes = static_cast<unsigned>(BufPtr[2]) | + (static_cast<unsigned>(BufPtr[3]) << 8); + BufPtr += WordSize; + return false; +} + +bool NaClBitcodeHeader::ReadFields(const unsigned char *BufPtr, + const unsigned char *BufEnd, + unsigned NumFields, unsigned NumBytes) { + HeaderSize = NumBytes + (2 * WordSize); + + // Read in each field. + for (size_t i = 0; i < NumFields; ++i) { + NaClBitcodeHeaderField *Field = new NaClBitcodeHeaderField(); + Fields.push_back(Field); + if (!Field->Read(BufPtr, BufEnd - BufPtr)) + return true; + size_t FieldSize = Field->GetTotalSize(); + BufPtr += FieldSize; + } + return false; +} + +bool NaClBitcodeHeader::Read(const unsigned char *&BufPtr, + const unsigned char *&BufEnd) { + unsigned NumFields; + unsigned NumBytes; + if (ReadPrefix(BufPtr, BufEnd, NumFields, NumBytes)) + return true; + BufPtr += 2 * WordSize; + + if (ReadFields(BufPtr, BufEnd, NumFields, NumBytes)) + return true; + BufPtr += NumBytes; + InstallFields(); + return false; +} + +bool NaClBitcodeHeader::Read(StreamingMemoryObject *Bytes) { + unsigned NumFields; + unsigned NumBytes; + { + unsigned char Buffer[2 * WordSize]; + if (Bytes->readBytes(0, sizeof(Buffer), Buffer, NULL) || + ReadPrefix(Buffer, Buffer + sizeof(Buffer), NumFields, NumBytes)) + return true; + } + uint8_t *Header = new uint8_t[NumBytes]; + bool results = + Bytes->readBytes(2 * WordSize, NumBytes, Header, NULL) || + ReadFields(Header, Header + sizeof(Header), NumFields, NumBytes); + delete[] Header; + InstallFields(); + return results; +} + +NaClBitcodeHeaderField * +NaClBitcodeHeader::GetTaggedField(NaClBitcodeHeaderField::Tag ID) const { + for (std::vector<NaClBitcodeHeaderField *>::const_iterator + Iter = Fields.begin(), + IterEnd = Fields.end(); + Iter != IterEnd; ++Iter) { + if ((*Iter)->GetID() == ID) { + return *Iter; + } + } + return 0; +} + +NaClBitcodeHeaderField *NaClBitcodeHeader::GetField(size_t index) const { + if (index >= Fields.size()) + return 0; + return Fields[index]; +} + +NaClBitcodeHeaderField *GetPNaClVersionPtr(NaClBitcodeHeader *Header) { + if (NaClBitcodeHeaderField *Version = + Header->GetTaggedField(NaClBitcodeHeaderField::kPNaClVersion)) { + if (Version->GetType() == NaClBitcodeHeaderField::kUInt32Type) { + return Version; + } + } + return 0; +} + +void NaClBitcodeHeader::InstallFields() { + // Assume supported until contradicted. + bool UpdatedUnsupportedMessage = false; + IsSupportedFlag = true; + IsReadableFlag = true; + UnsupportedMessage = "Supported"; + PNaClVersion = 0; + if (NaClBitcodeHeaderField *Version = GetPNaClVersionPtr(this)) { + PNaClVersion = Version->GetUInt32Value(); + } + if (PNaClVersion != 1) { + IsSupportedFlag = false; + IsReadableFlag = false; + UnsupportedMessage = "Unsupported Version"; + UpdatedUnsupportedMessage = true; + } + if (Fields.size() != 1) { + IsSupportedFlag = false; + IsReadableFlag = false; + if (!UpdatedUnsupportedMessage) + UnsupportedMessage = "Unknown header field(s) found"; + } +} diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp index df93c1b4de..4add89f6ab 100644 --- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp @@ -1813,15 +1813,6 @@ bool NaClBitcodeReader::ParseBitcodeInto(Module *M) { if (InitStream()) return true; - // Sniff for the signature. - if (Stream.Read(8) != 'B' || - Stream.Read(8) != 'C' || - Stream.Read(4) != 0x0 || - Stream.Read(4) != 0xC || - Stream.Read(4) != 0xE || - Stream.Read(4) != 0xD) - return Error("Invalid bitcode signature"); - // We expect a number of well-defined blocks, though we don't necessarily // need to understand them all. while (1) { @@ -1913,48 +1904,6 @@ bool NaClBitcodeReader::ParseModuleTriple(std::string &Triple) { } } -bool NaClBitcodeReader::ParseTriple(std::string &Triple) { - if (InitStream()) return true; - - // Sniff for the signature. - if (Stream.Read(8) != 'B' || - Stream.Read(8) != 'C' || - Stream.Read(4) != 0x0 || - Stream.Read(4) != 0xC || - Stream.Read(4) != 0xE || - Stream.Read(4) != 0xD) - return Error("Invalid bitcode signature"); - - // We expect a number of well-defined blocks, though we don't necessarily - // need to understand them all. - while (1) { - NaClBitstreamEntry Entry = Stream.advance(); - - switch (Entry.Kind) { - case NaClBitstreamEntry::Error: - Error("malformed module file"); - return true; - case NaClBitstreamEntry::EndBlock: - return false; - - case NaClBitstreamEntry::SubBlock: - if (Entry.ID == naclbitc::MODULE_BLOCK_ID) - return ParseModuleTriple(Triple); - - // Ignore other sub-blocks. - if (Stream.SkipBlock()) { - Error("malformed block record in AST file"); - return true; - } - continue; - - case NaClBitstreamEntry::Record: - Stream.skipRecord(Entry.ID); - continue; - } - } -} - /// ParseMetadataAttachment - Parse metadata attachments. bool NaClBitcodeReader::ParseMetadataAttachment() { DEBUG(dbgs() << "-> ParseMetadataAttachment\n"); @@ -3030,48 +2979,26 @@ bool NaClBitcodeReader::InitStreamFromBuffer() { const unsigned char *BufPtr = (const unsigned char*)Buffer->getBufferStart(); const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize(); - if (Buffer->getBufferSize() & 3) { - if (!isNaClRawBitcode(BufPtr, BufEnd) && - !isNaClBitcodeWrapper(BufPtr, BufEnd)) - return Error("Invalid bitcode signature"); - else - return Error("Bitcode stream should be a multiple of 4 bytes in length"); - } + if (Buffer->getBufferSize() & 3) + return Error("Bitcode stream should be a multiple of 4 bytes in length"); - // If we have a wrapper header, parse it and ignore the non-bc file contents. - // The magic number is 0x0B17C0DE stored in little endian. - if (isNaClBitcodeWrapper(BufPtr, BufEnd)) - if (SkipNaClBitcodeWrapperHeader(BufPtr, BufEnd, true)) - return Error("Invalid bitcode wrapper header"); + if (Header.Read(BufPtr, BufEnd)) + return Error("Invalid PNaCl bitcode header"); StreamFile.reset(new NaClBitstreamReader(BufPtr, BufEnd)); Stream.init(*StreamFile); - return false; + return AcceptHeader(); } bool NaClBitcodeReader::InitLazyStream() { - // Check and strip off the bitcode wrapper; NaClBitstreamReader expects - // never to see it. StreamingMemoryObject *Bytes = new StreamingMemoryObject(LazyStreamer); - StreamFile.reset(new NaClBitstreamReader(Bytes)); - Stream.init(*StreamFile); - - unsigned char buf[16]; - if (Bytes->readBytes(0, 16, buf, NULL) == -1) - return Error("Bitcode stream must be at least 16 bytes in length"); + if (Header.Read(Bytes)) + return Error("Invalid PNaCl bitcode header"); - if (!isNaClBitcode(buf, buf + 16)) - return Error("Invalid bitcode signature"); - - if (isNaClBitcodeWrapper(buf, buf + 4)) { - const unsigned char *bitcodeStart = buf; - const unsigned char *bitcodeEnd = buf + 16; - SkipNaClBitcodeWrapperHeader(bitcodeStart, bitcodeEnd, false); - Bytes->dropLeadingBytes(bitcodeStart - buf); - Bytes->setKnownObjectSize(bitcodeEnd - bitcodeStart); - } - return false; + StreamFile.reset(new NaClBitstreamReader(Bytes, Header.getHeaderSize())); + Stream.init(*StreamFile); + return AcceptHeader(); } //===----------------------------------------------------------------------===// @@ -3082,9 +3009,11 @@ bool NaClBitcodeReader::InitLazyStream() { /// Module *llvm::getNaClLazyBitcodeModule(MemoryBuffer *Buffer, LLVMContext& Context, - std::string *ErrMsg) { + std::string *ErrMsg, + bool AcceptSupportedOnly) { Module *M = new Module(Buffer->getBufferIdentifier(), Context); - NaClBitcodeReader *R = new NaClBitcodeReader(Buffer, Context); + NaClBitcodeReader *R = + new NaClBitcodeReader(Buffer, Context, AcceptSupportedOnly); M->setMaterializer(R); if (R->ParseBitcodeInto(M)) { if (ErrMsg) @@ -3107,9 +3036,11 @@ Module *llvm::getNaClLazyBitcodeModule(MemoryBuffer *Buffer, Module *llvm::getNaClStreamedBitcodeModule(const std::string &name, DataStreamer *streamer, LLVMContext &Context, - std::string *ErrMsg) { + std::string *ErrMsg, + bool AcceptSupportedOnly) { Module *M = new Module(name, Context); - NaClBitcodeReader *R = new NaClBitcodeReader(streamer, Context); + NaClBitcodeReader *R = + new NaClBitcodeReader(streamer, Context, AcceptSupportedOnly); M->setMaterializer(R); if (R->ParseBitcodeInto(M)) { if (ErrMsg) @@ -3129,8 +3060,10 @@ Module *llvm::getNaClStreamedBitcodeModule(const std::string &name, /// NaClParseBitcodeFile - Read the specified bitcode file, returning the module. /// If an error occurs, return null and fill in *ErrMsg if non-null. Module *llvm::NaClParseBitcodeFile(MemoryBuffer *Buffer, LLVMContext& Context, - std::string *ErrMsg){ - Module *M = getNaClLazyBitcodeModule(Buffer, Context, ErrMsg); + std::string *ErrMsg, + bool AcceptSupportedOnly){ + Module *M = getNaClLazyBitcodeModule(Buffer, Context, ErrMsg, + AcceptSupportedOnly); if (!M) return 0; // Don't let the NaClBitcodeReader dtor delete 'Buffer', regardless of whether diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h index f3d36862c3..935e77011e 100644 --- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h @@ -16,6 +16,7 @@ #define NACL_BITCODE_READER_H #include "llvm/ADT/DenseMap.h" +#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" #include "llvm/Bitcode/NaCl/NaClBitstreamReader.h" #include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h" #include "llvm/GVMaterializer.h" @@ -123,6 +124,7 @@ public: }; class NaClBitcodeReader : public GVMaterializer { + NaClBitcodeHeader Header; // Header fields of the PNaCl bitcode file. LLVMContext &Context; Module *TheModule; MemoryBuffer *Buffer; @@ -192,18 +194,25 @@ class NaClBitcodeReader : public GVMaterializer { /// not need this flag. bool UseRelativeIDs; + /// \brief True if we should only accept supported bitcode format. + bool AcceptSupportedBitcodeOnly; + public: - explicit NaClBitcodeReader(MemoryBuffer *buffer, LLVMContext &C) + explicit NaClBitcodeReader(MemoryBuffer *buffer, LLVMContext &C, + bool AcceptSupportedOnly = true) : Context(C), TheModule(0), Buffer(buffer), BufferOwned(false), LazyStreamer(0), NextUnreadBit(0), SeenValueSymbolTable(false), ErrorString(0), ValueList(C), MDValueList(C), - SeenFirstFunctionBody(false), UseRelativeIDs(false) { + SeenFirstFunctionBody(false), UseRelativeIDs(false), + AcceptSupportedBitcodeOnly(AcceptSupportedOnly) { } - explicit NaClBitcodeReader(DataStreamer *streamer, LLVMContext &C) + explicit NaClBitcodeReader(DataStreamer *streamer, LLVMContext &C, + bool AcceptSupportedOnly = true) : Context(C), TheModule(0), Buffer(0), BufferOwned(false), LazyStreamer(streamer), NextUnreadBit(0), SeenValueSymbolTable(false), ErrorString(0), ValueList(C), MDValueList(C), - SeenFirstFunctionBody(false), UseRelativeIDs(false) { + SeenFirstFunctionBody(false), UseRelativeIDs(false), + AcceptSupportedBitcodeOnly(AcceptSupportedOnly) { } ~NaClBitcodeReader() { FreeState(); @@ -233,11 +242,12 @@ public: /// @returns true if an error occurred. bool ParseBitcodeInto(Module *M); - /// @brief Cheap mechanism to just extract module triple - /// @returns true if an error occurred. - bool ParseTriple(std::string &Triple); - private: + // Returns false if Header is acceptable. + bool AcceptHeader() const { + return !(Header.IsSupported() || + (!AcceptSupportedBitcodeOnly && Header.IsReadable())); + } Type *getTypeByID(unsigned ID); Value *getFnValueByID(unsigned ID, Type *Ty) { if (Ty && Ty->isMetadataTy()) diff --git a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp index d77a79a2c9..522ef1bbba 100644 --- a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp +++ b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "NaClBitcodeWriter" +#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" #include "NaClValueEnumerator.h" #include "llvm/ADT/Triple.h" @@ -1903,24 +1904,6 @@ static void WriteModule(const Module *M, NaClBitstreamWriter &Stream) { DEBUG(dbgs() << "<- WriteModule\n"); } -/// EmitDarwinBCHeader - If generating a bc file on darwin, we have to emit a -/// header and trailer to make it compatible with the system archiver. To do -/// this we emit the following header, and then emit a trailer that pads the -/// file out to be a multiple of 16 bytes. -/// -/// struct bc_header { -/// uint32_t Magic; // 0x0B17C0DE -/// uint32_t Version; // Version, currently always 0. -/// uint32_t BitcodeOffset; // Offset to traditional bitcode file. -/// uint32_t BitcodeSize; // Size of traditional bitcode file. -/// uint32_t CPUType; // CPU specifier. -/// ... potentially more later ... -/// }; -enum { - DarwinBCSizeFieldOffset = 3*4, // Offset to bitcode_size. - DarwinBCHeaderSize = 5*4 -}; - static void WriteInt32ToBuffer(uint32_t Value, SmallVectorImpl<char> &Buffer, uint32_t &Position) { Buffer[Position + 0] = (unsigned char) (Value >> 0); @@ -1930,52 +1913,49 @@ static void WriteInt32ToBuffer(uint32_t Value, SmallVectorImpl<char> &Buffer, Position += 4; } -static void EmitDarwinBCHeaderAndTrailer(SmallVectorImpl<char> &Buffer, - const Triple &TT) { - unsigned CPUType = ~0U; - - // Match x86_64-*, i[3-9]86-*, powerpc-*, powerpc64-*, arm-*, thumb-*, - // armv[0-9]-*, thumbv[0-9]-*, armv5te-*, or armv6t2-*. The CPUType is a magic - // number from /usr/include/mach/machine.h. It is ok to reproduce the - // specific constants here because they are implicitly part of the Darwin ABI. - enum { - DARWIN_CPU_ARCH_ABI64 = 0x01000000, - DARWIN_CPU_TYPE_X86 = 7, - DARWIN_CPU_TYPE_ARM = 12, - DARWIN_CPU_TYPE_POWERPC = 18 - }; - - Triple::ArchType Arch = TT.getArch(); - if (Arch == Triple::x86_64) - CPUType = DARWIN_CPU_TYPE_X86 | DARWIN_CPU_ARCH_ABI64; - else if (Arch == Triple::x86) - CPUType = DARWIN_CPU_TYPE_X86; - else if (Arch == Triple::ppc) - CPUType = DARWIN_CPU_TYPE_POWERPC; - else if (Arch == Triple::ppc64) - CPUType = DARWIN_CPU_TYPE_POWERPC | DARWIN_CPU_ARCH_ABI64; - else if (Arch == Triple::arm || Arch == Triple::thumb) - CPUType = DARWIN_CPU_TYPE_ARM; - - // Traditional Bitcode starts after header. - assert(Buffer.size() >= DarwinBCHeaderSize && - "Expected header size to be reserved"); - unsigned BCOffset = DarwinBCHeaderSize; - unsigned BCSize = Buffer.size()-DarwinBCHeaderSize; - - // Write the magic and version. - unsigned Position = 0; - WriteInt32ToBuffer(0x0B17C0DE , Buffer, Position); - WriteInt32ToBuffer(0 , Buffer, Position); // Version. - WriteInt32ToBuffer(BCOffset , Buffer, Position); - WriteInt32ToBuffer(BCSize , Buffer, Position); - WriteInt32ToBuffer(CPUType , Buffer, Position); - - // If the file is not a multiple of 16 bytes, insert dummy padding. - while (Buffer.size() & 15) - Buffer.push_back(0); +// Max size for variable fields. Currently only used for writing them +// out to files (the parsing works for arbitrary sizes). +static const size_t kMaxVariableFieldSize = 256; + +// Write out the given fields to the bitstream. +static void WriteHeaderFields( + const std::vector<NaClBitcodeHeaderField*> &Fields, + NaClBitstreamWriter& Stream) { + // Emit placeholder for number of bytes used to hold header fields. + // This value is necessary so that the streamable reader can preallocate + // a buffer to read the fields. + Stream.Emit(0, naclbitc::BlockSizeWidth); + unsigned BytesForHeader = 0; + + unsigned NumberFields = Fields.size(); + if (NumberFields > 0xFFFF) + report_fatal_error("Too many header fields"); + + uint8_t Buffer[kMaxVariableFieldSize]; + for (std::vector<NaClBitcodeHeaderField*>::const_iterator + Iter = Fields.begin(), IterEnd = Fields.end(); + Iter != IterEnd; ++Iter) { + if (!(*Iter)->Write(Buffer, kMaxVariableFieldSize)) + report_fatal_error("Header field too big to generate"); + size_t limit = (*Iter)->GetTotalSize(); + for (size_t i = 0; i < limit; i++) { + Stream.Emit(Buffer[i], 8); + } + BytesForHeader += limit; + } + + if (BytesForHeader > 0xFFFF) + report_fatal_error("Header fields to big to save"); + + // Encode #fields in top two bytes, and #bytes to hold fields in + // bottom two bytes. Then backpatch into second word. + unsigned Value = NumberFields | (BytesForHeader << 16); + Stream.BackpatchWord(NaClBitcodeHeader::WordSize, Value); } +// Define the version of PNaCl bitcode we are generating. +static const uint16_t kPNaClVersion = 1; + /// WriteBitcodeToFile - Write the specified module to the specified output /// stream. void llvm::NaClWriteBitcodeToFile(const Module *M, raw_ostream &Out) { @@ -1985,31 +1965,29 @@ void llvm::NaClWriteBitcodeToFile(const Module *M, raw_ostream &Out) { // Convert Deplib info to metadata M->convertLibraryListToMetadata(); // @LOCALMOD - // If this is darwin or another generic macho target, reserve space for the - // header. - Triple TT(M->getTargetTriple()); - if (TT.isOSDarwin()) - Buffer.insert(Buffer.begin(), DarwinBCHeaderSize, 0); - // Emit the module into the buffer. { NaClBitstreamWriter Stream(Buffer); // Emit the file header. - Stream.Emit((unsigned)'B', 8); - Stream.Emit((unsigned)'C', 8); - Stream.Emit(0x0, 4); - Stream.Emit(0xC, 4); - Stream.Emit(0xE, 4); - Stream.Emit(0xD, 4); + Stream.Emit((unsigned)'P', 8); + Stream.Emit((unsigned)'E', 8); + Stream.Emit((unsigned)'X', 8); + Stream.Emit((unsigned)'E', 8); + + // Collect header fields to add. + { + std::vector<NaClBitcodeHeaderField*> HeaderFields; + HeaderFields.push_back( + new NaClBitcodeHeaderField(NaClBitcodeHeaderField::kPNaClVersion, + kPNaClVersion)); + WriteHeaderFields(HeaderFields, Stream); + } // Emit the module. WriteModule(M, Stream); } - if (TT.isOSDarwin()) - EmitDarwinBCHeaderAndTrailer(Buffer, TT); - // Write the generated bitstream to "Out". Out.write((char*)&Buffer.front(), Buffer.size()); } |