aboutsummaryrefslogtreecommitdiff
path: root/lib/Bitcode
diff options
context:
space:
mode:
authorKarl Schimpf <kschimpf@google.com>2013-06-06 10:03:24 -0700
committerKarl Schimpf <kschimpf@google.com>2013-06-06 10:03:24 -0700
commit37bdd9174a1cba17b369c8c1f561e70c458e0c13 (patch)
tree1f6a984ebb94ccd819c6e38646d91bb5c7eb6977 /lib/Bitcode
parentc0d9b337419b72e69cbd9c64f84ae39560ab344f (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.txt1
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp259
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp111
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h26
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp132
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());
}