encoded_program.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "courgette/encoded_program.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "courgette/courgette.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "courgette/streams.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "courgette/types_elf.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace courgette {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Stream indexes.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamMisc    = 0;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamOps     = 1;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamBytes   = 2;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamAbs32Indexes = 3;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamRel32Indexes = 4;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamAbs32Addresses = 5;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamRel32Addresses = 6;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamCopyCounts = 7;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamOriginAddresses = kStreamMisc;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStreamLimit = 9;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Constructor is here rather than in the header.  Although the constructor
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// appears to do nothing it is fact quite large because of the implicit calls to
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// field constructors.  Ditto for the destructor.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EncodedProgram::EncodedProgram() : image_base_(0) {}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EncodedProgram::~EncodedProgram() {}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Serializes a vector of integral values using Varint32 coding.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename V>
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool WriteVector(const V& items, SinkStream* buffer) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t count = items.size();
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = buffer->WriteSizeVarint32(count);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; ok && i < count;  ++i) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    COMPILE_ASSERT(sizeof(items[0]) <= sizeof(uint32),  // NOLINT
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   T_must_fit_in_uint32);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = buffer->WriteSizeVarint32(items[i]);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename V>
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReadVector(V* items, SourceStream* buffer) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 count;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer->ReadVarint32(&count))
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  items->clear();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = items->reserve(count);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0;  ok && i < count;  ++i) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 item;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = buffer->ReadVarint32(&item);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ok)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok = items->push_back(static_cast<typename V::value_type>(item));
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Serializes a vector, using delta coding followed by Varint32 coding.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename V>
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool WriteU32Delta(const V& set, SinkStream* buffer) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t count = set.size();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = buffer->WriteSizeVarint32(count);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 prev = 0;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0;  ok && i < count;  ++i) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 current = set[i];
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 delta = current - prev;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = buffer->WriteVarint32(delta);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prev = current;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <typename V>
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static CheckBool ReadU32Delta(V* set, SourceStream* buffer) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 count;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer->ReadVarint32(&count))
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set->clear();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = set->reserve(count);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 prev = 0;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; ok && i < count;  ++i) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 delta;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = buffer->ReadVarint32(&delta);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ok) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32 current = prev + delta;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok = set->push_back(current);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      prev = current;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Write a vector as the byte representation of the contents.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (This only really makes sense for a type T that has sizeof(T)==1, otherwise
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// serialized representation is not endian-agnostic.  But it is useful to keep
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the possibility of a greater size for experiments comparing Varint32 encoding
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of a vector of larger integrals vs a plain form.)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename V>
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool WriteVectorU8(const V& items, SinkStream* buffer) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t count = items.size();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = buffer->WriteSizeVarint32(count);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (count != 0 && ok) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t byte_count = count * sizeof(typename V::value_type);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = buffer->Write(static_cast<const void*>(&items[0]), byte_count);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename V>
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReadVectorU8(V* items, SourceStream* buffer) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 count;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer->ReadVarint32(&count))
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  items->clear();
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = items->resize(count, 0);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ok && count != 0) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t byte_count = count * sizeof(typename V::value_type);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return buffer->Read(static_cast<void*>(&((*items)[0])), byte_count);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::DefineRel32Label(int index, RVA value) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DefineLabelCommon(&rel32_rva_, index, value);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::DefineAbs32Label(int index, RVA value) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DefineLabelCommon(&abs32_rva_, index, value);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const RVA kUnassignedRVA = static_cast<RVA>(-1);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::DefineLabelCommon(RvaVector* rvas,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            int index,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            RVA rva) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = true;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<int>(rvas->size()) <= index)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = rvas->resize(index + 1, kUnassignedRVA);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ok) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ((*rvas)[index], kUnassignedRVA)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        << "DefineLabel double assigned " << index;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*rvas)[index] = rva;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EncodedProgram::EndLabels() {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FinishLabelsCommon(&abs32_rva_);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FinishLabelsCommon(&rel32_rva_);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EncodedProgram::FinishLabelsCommon(RvaVector* rvas) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace all unassigned slots with the value at the previous index so they
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // delta-encode to zero.  (There might be better values than zero.  The way to
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // get that is have the higher level assembly program assign the unassigned
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // slots.)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RVA previous = 0;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size = rvas->size();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0;  i < size;  ++i) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*rvas)[i] == kUnassignedRVA)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*rvas)[i] = previous;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous = (*rvas)[i];
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::AddOrigin(RVA origin) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ops_.push_back(ORIGIN) && origins_.push_back(origin);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::AddCopy(uint32 count, const void* bytes) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint8* source = static_cast<const uint8*>(bytes);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = true;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fold adjacent COPY instructions into one.  This nearly halves the size of
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an EncodedProgram with only COPY1 instructions since there are approx plain
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 16 bytes per reloc.  This has a working-set benefit during decompression.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For compression of files with large differences this makes a small (4%)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // improvement in size.  For files with small differences this degrades the
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compressed size by 1.3%
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ops_.empty()) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ops_.back() == COPY1) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ops_.back() = COPY;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok = copy_counts_.push_back(1);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ok && ops_.back() == COPY) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      copy_counts_.back() += count;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (uint32 i = 0; ok && i < count; ++i) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ok = copy_bytes_.push_back(source[i]);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ok;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ok) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (count == 1) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok = ops_.push_back(COPY1) && copy_bytes_.push_back(source[0]);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok = ops_.push_back(COPY) && copy_counts_.push_back(count);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (uint32 i = 0; ok && i < count; ++i) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ok = copy_bytes_.push_back(source[i]);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::AddAbs32(int label_index) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ops_.push_back(ABS32) && abs32_ix_.push_back(label_index);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::AddRel32(int label_index) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ops_.push_back(REL32) && rel32_ix_.push_back(label_index);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::AddPeMakeRelocs() {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ops_.push_back(MAKE_PE_RELOCATION_TABLE);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::AddElfMakeRelocs() {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ops_.push_back(MAKE_ELF_RELOCATION_TABLE);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EncodedProgram::DebuggingSummary() {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "EncodedProgram Summary"
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  image base  " << image_base_
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  abs32 rvas  " << abs32_rva_.size()
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  rel32 rvas  " << rel32_rva_.size()
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  ops         " << ops_.size()
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  origins     " << origins_.size()
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  copy_counts " << copy_counts_.size()
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  copy_bytes  " << copy_bytes_.size()
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  abs32_ix    " << abs32_ix_.size()
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << "\n  rel32_ix    " << rel32_ix_.size();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For algorithm refinement purposes it is useful to write subsets of the file
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// format.  This gives us the ability to estimate the entropy of the
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// differential compression of the individual streams, which can provide
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// invaluable insights.  The default, of course, is to include all the streams.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum FieldSelect {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INCLUDE_ABS32_ADDRESSES = 0x0001,
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INCLUDE_REL32_ADDRESSES = 0x0002,
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INCLUDE_ABS32_INDEXES   = 0x0010,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INCLUDE_REL32_INDEXES   = 0x0020,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INCLUDE_OPS             = 0x0100,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INCLUDE_BYTES           = 0x0200,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INCLUDE_COPY_COUNTS     = 0x0400,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INCLUDE_MISC            = 0x1000
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static FieldSelect GetFieldSelect() {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 1
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sra): Use better configuration.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Environment> env(base::Environment::Create());
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string s;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  env->GetVar("A_FIELDS", &s);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!s.empty()) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return static_cast<FieldSelect>(wcstoul(ASCIIToWide(s).c_str(), 0, 0));
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return  static_cast<FieldSelect>(~0);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::WriteTo(SinkStreamSet* streams) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FieldSelect select = GetFieldSelect();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The order of fields must be consistent in WriteTo and ReadFrom, regardless
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the streams used.  The code can be configured with all kStreamXXX
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // constants the same.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we change the code to pipeline reading with assembly (to avoid temporary
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // storage vectors by consuming operands directly from the stream) then we
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // need to read the base address and the random access address tables first,
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the rest can be interleaved.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_MISC) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(sra): write 64 bits.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!streams->stream(kStreamMisc)->WriteVarint32(
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            static_cast<uint32>(image_base_))) {
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = true;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_ABS32_ADDRESSES) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= WriteU32Delta(abs32_rva_,
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             streams->stream(kStreamAbs32Addresses));
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_REL32_ADDRESSES) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= WriteU32Delta(rel32_rva_,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             streams->stream(kStreamRel32Addresses));
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_MISC)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= WriteVector(origins_, streams->stream(kStreamOriginAddresses));
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_OPS) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // 5 for length.
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= streams->stream(kStreamOps)->Reserve(ops_.size() + 5);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= WriteVector(ops_, streams->stream(kStreamOps));
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_COPY_COUNTS)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= WriteVector(copy_counts_, streams->stream(kStreamCopyCounts));
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_BYTES)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= WriteVectorU8(copy_bytes_, streams->stream(kStreamBytes));
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_ABS32_INDEXES)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= WriteVector(abs32_ix_, streams->stream(kStreamAbs32Indexes));
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (select & INCLUDE_REL32_INDEXES)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success &= WriteVector(rel32_ix_, streams->stream(kStreamRel32Indexes));
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EncodedProgram::ReadFrom(SourceStreamSet* streams) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sra): read 64 bits.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 temp;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!streams->stream(kStreamMisc)->ReadVarint32(&temp))
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_base_ = temp;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadU32Delta(&abs32_rva_, streams->stream(kStreamAbs32Addresses)))
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadU32Delta(&rel32_rva_, streams->stream(kStreamRel32Addresses)))
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadVector(&origins_, streams->stream(kStreamOriginAddresses)))
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadVector(&ops_, streams->stream(kStreamOps)))
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadVector(&copy_counts_, streams->stream(kStreamCopyCounts)))
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadVectorU8(&copy_bytes_, streams->stream(kStreamBytes)))
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadVector(&abs32_ix_, streams->stream(kStreamAbs32Indexes)))
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadVector(&rel32_ix_, streams->stream(kStreamRel32Indexes)))
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that streams have been completely consumed.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0;  i < kStreamLimit;  ++i) {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (streams->stream(i)->Remaining() > 0)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Safe, non-throwing version of std::vector::at().  Returns 'true' for success,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'false' for out-of-bounds index error.
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename V, typename T>
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool VectorAt(const V& v, size_t index, T* output) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index >= v.size())
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *output = v[index];
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) {
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For the most part, the assembly process walks the various tables.
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ix_mumble is the index into the mumble table.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t ix_origins = 0;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t ix_copy_counts = 0;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t ix_copy_bytes = 0;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t ix_abs32_ix = 0;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t ix_rel32_ix = 0;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RVA current_rva = 0;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool pending_pe_relocation_table = false;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool pending_elf_relocation_table = false;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SinkStream bytes_following_relocation_table;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SinkStream* output = final_buffer;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t ix_ops = 0;  ix_ops < ops_.size();  ++ix_ops) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OP op = ops_[ix_ops];
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (op) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ORIGIN: {
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RVA section_rva;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VectorAt(origins_, ix_origins, &section_rva))
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++ix_origins;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_rva = section_rva;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case COPY: {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint32 count;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VectorAt(copy_counts_, ix_copy_counts, &count))
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++ix_copy_counts;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (uint32 i = 0;  i < count;  ++i) {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          uint8 b;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!VectorAt(copy_bytes_, ix_copy_bytes, &b))
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ++ix_copy_bytes;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!output->Write(&b, 1))
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_rva += count;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case COPY1: {
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint8 b;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VectorAt(copy_bytes_, ix_copy_bytes, &b))
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++ix_copy_bytes;
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!output->Write(&b, 1))
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_rva += 1;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case REL32: {
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint32 index;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VectorAt(rel32_ix_, ix_rel32_ix, &index))
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++ix_rel32_ix;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RVA rva;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VectorAt(rel32_rva_, index, &rva))
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint32 offset = (rva - (current_rva + 4));
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!output->Write(&offset, 4))
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_rva += 4;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ABS32: {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint32 index;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VectorAt(abs32_ix_, ix_abs32_ix, &index))
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++ix_abs32_ix;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RVA rva;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!VectorAt(abs32_rva_, index, &rva))
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        uint32 abs32 = static_cast<uint32>(rva + image_base_);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!abs32_relocs_.push_back(current_rva) || !output->Write(&abs32, 4))
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_rva += 4;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case MAKE_PE_RELOCATION_TABLE: {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We can see the base relocation anywhere, but we only have the
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // information to generate it at the very end.  So we divert the bytes
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // we are generating to a temporary stream.
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pending_pe_relocation_table)  // Can't have two base relocation
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            // tables.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_pe_relocation_table = true;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output = &bytes_following_relocation_table;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // There is a potential problem *if* the instruction stream contains
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // some REL32 relocations following the base relocation and in the same
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // section.  We don't know the size of the table, so 'current_rva' will
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // be wrong, causing REL32 offsets to be miscalculated.  This never
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // happens; the base relocation table is usually in a section of its
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // own, a data-only section, and following everything else in the
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // executable except some padding zero bytes.  We could fix this by
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // emitting an ORIGIN after the MAKE_BASE_RELOCATION_TABLE.
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case MAKE_ELF_RELOCATION_TABLE: {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We can see the base relocation anywhere, but we only have the
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // information to generate it at the very end.  So we divert the bytes
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // we are generating to a temporary stream.
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pending_elf_relocation_table)  // Can't have two relocation
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           // tables.
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_elf_relocation_table = true;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output = &bytes_following_relocation_table;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_pe_relocation_table) {
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GeneratePeRelocations(final_buffer) ||
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !final_buffer->Append(&bytes_following_relocation_table))
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_elf_relocation_table) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GenerateElfRelocations(final_buffer) ||
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !final_buffer->Append(&bytes_following_relocation_table))
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Final verification check: did we consume all lists?
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ix_copy_counts != copy_counts_.size())
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ix_copy_bytes != copy_bytes_.size())
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ix_abs32_ix != abs32_ix_.size())
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ix_rel32_ix != rel32_ix_.size())
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RelocBlock has the layout of a block of relocations in the base relocation
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// table file format.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct RelocBlockPOD {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 page_rva;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 block_size;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 relocs[4096];  // Allow up to one relocation per byte of a 4k page.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(offsetof(RelocBlockPOD, relocs) == 8, reloc_block_header_size);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RelocBlock {
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RelocBlock() {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pod.page_rva = ~0;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pod.block_size = 8;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Add(uint16 item) {
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pod.relocs[(pod.block_size-8)/2] = item;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pod.block_size += 2;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckBool Flush(SinkStream* buffer) WARN_UNUSED_RESULT {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ok = true;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pod.block_size != 8) {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (pod.block_size % 4 != 0) {  // Pad to make size multiple of 4 bytes.
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Add(0);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok = buffer->Write(&pod, pod.block_size);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pod.block_size = 8;
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ok;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RelocBlockPOD pod;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::GeneratePeRelocations(SinkStream* buffer) {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(abs32_relocs_.begin(), abs32_relocs_.end());
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RelocBlock block;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = true;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0;  ok && i < abs32_relocs_.size();  ++i) {
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 rva = abs32_relocs_[i];
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32 page_rva = rva & ~0xFFF;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (page_rva != block.pod.page_rva) {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok &= block.Flush(buffer);
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      block.pod.page_rva = page_rva;
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ok)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      block.Add(0x3000 | (rva & 0xFFF));
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok &= block.Flush(buffer);
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CheckBool EncodedProgram::GenerateElfRelocations(SinkStream* buffer) {
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(abs32_relocs_.begin(), abs32_relocs_.end());
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Elf32_Rel relocation_block;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only handle this specific type of relocation, so far.
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  relocation_block.r_info = R_386_RELATIVE;
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = true;
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0;  ok && i < abs32_relocs_.size();  ++i) {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    relocation_block.r_offset = abs32_relocs_[i];
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = buffer->Write(&relocation_block, sizeof(Elf32_Rel));
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ok;
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status WriteEncodedProgram(EncodedProgram* encoded, SinkStreamSet* sink) {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!encoded->WriteTo(sink))
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return C_STREAM_ERROR;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return C_OK;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status ReadEncodedProgram(SourceStreamSet* streams, EncodedProgram** output) {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EncodedProgram* encoded = new EncodedProgram();
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (encoded->ReadFrom(streams)) {
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *output = encoded;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return C_OK;
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete encoded;
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return C_DESERIALIZATION_FAILED;
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Status Assemble(EncodedProgram* encoded, SinkStream* buffer) {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool assembled = encoded->AssembleTo(buffer);
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (assembled)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return C_OK;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return C_ASSEMBLY_FAILED;
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeleteEncodedProgram(EncodedProgram* encoded) {
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete encoded;
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // end namespace
651