| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "courgette/encoded_program.h" | 5 #include "courgette/encoded_program.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 const int kStreamLimit = 9; | 33 const int kStreamLimit = 9; |
| 34 | 34 |
| 35 // Constructor is here rather than in the header. Although the constructor | 35 // Constructor is here rather than in the header. Although the constructor |
| 36 // appears to do nothing it is fact quite large because of the implict calls to | 36 // appears to do nothing it is fact quite large because of the implict calls to |
| 37 // field constructors. Ditto for the destructor. | 37 // field constructors. Ditto for the destructor. |
| 38 EncodedProgram::EncodedProgram() : image_base_(0) {} | 38 EncodedProgram::EncodedProgram() : image_base_(0) {} |
| 39 EncodedProgram::~EncodedProgram() {} | 39 EncodedProgram::~EncodedProgram() {} |
| 40 | 40 |
| 41 // Serializes a vector of integral values using Varint32 coding. | 41 // Serializes a vector of integral values using Varint32 coding. |
| 42 template<typename T, typename A> | 42 template<typename T, typename A> |
| 43 void WriteVector(const std::vector<T, A>& items, SinkStream* buffer) { | 43 CheckBool WriteVector(const std::vector<T, A>& items, SinkStream* buffer) { |
| 44 size_t count = items.size(); | 44 size_t count = items.size(); |
| 45 buffer->WriteSizeVarint32(count); | 45 bool ok = buffer->WriteSizeVarint32(count); |
| 46 for (size_t i = 0; i < count; ++i) { | 46 for (size_t i = 0; ok && i < count; ++i) { |
| 47 COMPILE_ASSERT(sizeof(T) <= sizeof(uint32), // NOLINT | 47 COMPILE_ASSERT(sizeof(T) <= sizeof(uint32), // NOLINT |
| 48 T_must_fit_in_uint32); | 48 T_must_fit_in_uint32); |
| 49 buffer->WriteSizeVarint32(items[i]); | 49 ok = buffer->WriteSizeVarint32(items[i]); |
| 50 } | 50 } |
| 51 return ok; |
| 51 } | 52 } |
| 52 | 53 |
| 53 template<typename T, typename A> | 54 template<typename T, typename A> |
| 54 bool ReadVector(std::vector<T, A>* items, SourceStream* buffer) { | 55 bool ReadVector(std::vector<T, A>* items, SourceStream* buffer) { |
| 55 uint32 count; | 56 uint32 count; |
| 56 if (!buffer->ReadVarint32(&count)) | 57 if (!buffer->ReadVarint32(&count)) |
| 57 return false; | 58 return false; |
| 58 | 59 |
| 59 items->clear(); | 60 items->clear(); |
| 60 items->reserve(count); | 61 items->reserve(count); |
| 61 for (size_t i = 0; i < count; ++i) { | 62 for (size_t i = 0; i < count; ++i) { |
| 62 uint32 item; | 63 uint32 item; |
| 63 if (!buffer->ReadVarint32(&item)) | 64 if (!buffer->ReadVarint32(&item)) |
| 64 return false; | 65 return false; |
| 66 // TODO(tommi): Handle errors. |
| 65 items->push_back(static_cast<T>(item)); | 67 items->push_back(static_cast<T>(item)); |
| 66 } | 68 } |
| 67 | 69 |
| 68 return true; | 70 return true; |
| 69 } | 71 } |
| 70 | 72 |
| 71 // Serializes a vector, using delta coding followed by Varint32 coding. | 73 // Serializes a vector, using delta coding followed by Varint32 coding. |
| 72 template<typename A> | 74 template<typename A> |
| 73 void WriteU32Delta(const std::vector<uint32, A>& set, SinkStream* buffer) { | 75 CheckBool WriteU32Delta(const std::vector<uint32, A>& set, SinkStream* buffer) { |
| 74 size_t count = set.size(); | 76 size_t count = set.size(); |
| 75 buffer->WriteSizeVarint32(count); | 77 bool ok = buffer->WriteSizeVarint32(count); |
| 76 uint32 prev = 0; | 78 uint32 prev = 0; |
| 77 for (size_t i = 0; i < count; ++i) { | 79 for (size_t i = 0; ok && i < count; ++i) { |
| 78 uint32 current = set[i]; | 80 uint32 current = set[i]; |
| 79 uint32 delta = current - prev; | 81 uint32 delta = current - prev; |
| 80 buffer->WriteVarint32(delta); | 82 ok = buffer->WriteVarint32(delta); |
| 81 prev = current; | 83 prev = current; |
| 82 } | 84 } |
| 85 return ok; |
| 83 } | 86 } |
| 84 | 87 |
| 85 template <typename A> | 88 template <typename A> |
| 86 static bool ReadU32Delta(std::vector<uint32, A>* set, SourceStream* buffer) { | 89 static CheckBool ReadU32Delta(std::vector<uint32, A>* set, |
| 90 SourceStream* buffer) { |
| 87 uint32 count; | 91 uint32 count; |
| 88 | 92 |
| 89 if (!buffer->ReadVarint32(&count)) | 93 if (!buffer->ReadVarint32(&count)) |
| 90 return false; | 94 return false; |
| 91 | 95 |
| 92 set->clear(); | 96 set->clear(); |
| 97 // TODO(tommi): Handle errors. |
| 93 set->reserve(count); | 98 set->reserve(count); |
| 94 uint32 prev = 0; | 99 uint32 prev = 0; |
| 95 | 100 |
| 96 for (size_t i = 0; i < count; ++i) { | 101 for (size_t i = 0; i < count; ++i) { |
| 97 uint32 delta; | 102 uint32 delta; |
| 98 if (!buffer->ReadVarint32(&delta)) | 103 if (!buffer->ReadVarint32(&delta)) |
| 99 return false; | 104 return false; |
| 100 uint32 current = prev + delta; | 105 uint32 current = prev + delta; |
| 106 // TODO(tommi): handle errors |
| 101 set->push_back(current); | 107 set->push_back(current); |
| 102 prev = current; | 108 prev = current; |
| 103 } | 109 } |
| 104 | 110 |
| 111 // TODO(tommi): Handle errors. |
| 105 return true; | 112 return true; |
| 106 } | 113 } |
| 107 | 114 |
| 108 // Write a vector as the byte representation of the contents. | 115 // Write a vector as the byte representation of the contents. |
| 109 // | 116 // |
| 110 // (This only really makes sense for a type T that has sizeof(T)==1, otherwise | 117 // (This only really makes sense for a type T that has sizeof(T)==1, otherwise |
| 111 // serilized representation is not endian-agnositic. But it is useful to keep | 118 // serialized representation is not endian-agnositic. But it is useful to keep |
| 112 // the possibility of a greater size for experiments comparing Varint32 encoding | 119 // the possibility of a greater size for experiments comparing Varint32 encoding |
| 113 // of a vector of larger integrals vs a plain form.) | 120 // of a vector of larger integrals vs a plain form.) |
| 114 // | 121 // |
| 115 template<typename T, typename A> | 122 template<typename T, typename A> |
| 116 void WriteVectorU8(const std::vector<T, A>& items, SinkStream* buffer) { | 123 CheckBool WriteVectorU8(const std::vector<T, A>& items, SinkStream* buffer) { |
| 117 size_t count = items.size(); | 124 size_t count = items.size(); |
| 118 buffer->WriteSizeVarint32(count); | 125 bool ok = buffer->WriteSizeVarint32(count); |
| 119 if (count != 0) { | 126 if (count != 0 && ok) { |
| 120 size_t byte_count = count * sizeof(T); | 127 size_t byte_count = count * sizeof(T); |
| 121 buffer->Write(static_cast<const void*>(&items[0]), byte_count); | 128 ok = buffer->Write(static_cast<const void*>(&items[0]), byte_count); |
| 122 } | 129 } |
| 130 return ok; |
| 123 } | 131 } |
| 124 | 132 |
| 125 template<typename T, typename A> | 133 template<typename T, typename A> |
| 126 bool ReadVectorU8(std::vector<T, A>* items, SourceStream* buffer) { | 134 bool ReadVectorU8(std::vector<T, A>* items, SourceStream* buffer) { |
| 127 uint32 count; | 135 uint32 count; |
| 128 if (!buffer->ReadVarint32(&count)) | 136 if (!buffer->ReadVarint32(&count)) |
| 129 return false; | 137 return false; |
| 130 | 138 |
| 131 items->clear(); | 139 items->clear(); |
| 140 // TODO(tommi): check error |
| 132 items->resize(count); | 141 items->resize(count); |
| 133 if (count != 0) { | 142 if (count != 0) { |
| 134 size_t byte_count = count * sizeof(T); | 143 size_t byte_count = count * sizeof(T); |
| 135 return buffer->Read(static_cast<void*>(&((*items)[0])), byte_count); | 144 return buffer->Read(static_cast<void*>(&((*items)[0])), byte_count); |
| 136 } | 145 } |
| 137 return true; | 146 return true; |
| 138 } | 147 } |
| 139 | 148 |
| 140 //////////////////////////////////////////////////////////////////////////////// | 149 //////////////////////////////////////////////////////////////////////////////// |
| 141 | 150 |
| 142 void EncodedProgram::DefineRel32Label(int index, RVA value) { | 151 CheckBool EncodedProgram::DefineRel32Label(int index, RVA value) { |
| 143 DefineLabelCommon(&rel32_rva_, index, value); | 152 return DefineLabelCommon(&rel32_rva_, index, value); |
| 144 } | 153 } |
| 145 | 154 |
| 146 void EncodedProgram::DefineAbs32Label(int index, RVA value) { | 155 CheckBool EncodedProgram::DefineAbs32Label(int index, RVA value) { |
| 147 DefineLabelCommon(&abs32_rva_, index, value); | 156 return DefineLabelCommon(&abs32_rva_, index, value); |
| 148 } | 157 } |
| 149 | 158 |
| 150 static const RVA kUnassignedRVA = static_cast<RVA>(-1); | 159 static const RVA kUnassignedRVA = static_cast<RVA>(-1); |
| 151 | 160 |
| 152 void EncodedProgram::DefineLabelCommon(RvaVector* rvas, | 161 CheckBool EncodedProgram::DefineLabelCommon(RvaVector* rvas, |
| 153 int index, | 162 int index, |
| 154 RVA rva) { | 163 RVA rva) { |
| 155 if (static_cast<int>(rvas->size()) <= index) { | 164 if (static_cast<int>(rvas->size()) <= index) { |
| 165 // TODO(tommi): handle error |
| 156 rvas->resize(index + 1, kUnassignedRVA); | 166 rvas->resize(index + 1, kUnassignedRVA); |
| 157 } | 167 } |
| 158 if ((*rvas)[index] != kUnassignedRVA) { | 168 if ((*rvas)[index] != kUnassignedRVA) { |
| 159 NOTREACHED() << "DefineLabel double assigned " << index; | 169 NOTREACHED() << "DefineLabel double assigned " << index; |
| 160 } | 170 } |
| 161 (*rvas)[index] = rva; | 171 (*rvas)[index] = rva; |
| 172 // TODO(tommi): Handle errors |
| 173 return true; |
| 162 } | 174 } |
| 163 | 175 |
| 164 void EncodedProgram::EndLabels() { | 176 void EncodedProgram::EndLabels() { |
| 165 FinishLabelsCommon(&abs32_rva_); | 177 FinishLabelsCommon(&abs32_rva_); |
| 166 FinishLabelsCommon(&rel32_rva_); | 178 FinishLabelsCommon(&rel32_rva_); |
| 167 } | 179 } |
| 168 | 180 |
| 169 void EncodedProgram::FinishLabelsCommon(RvaVector* rvas) { | 181 void EncodedProgram::FinishLabelsCommon(RvaVector* rvas) { |
| 170 // Replace all unassigned slots with the value at the previous index so they | 182 // Replace all unassigned slots with the value at the previous index so they |
| 171 // delta-encode to zero. (There might be better values than zero. The way to | 183 // delta-encode to zero. (There might be better values than zero. The way to |
| 172 // get that is have the higher level assembly program assign the unassigned | 184 // get that is have the higher level assembly program assign the unassigned |
| 173 // slots.) | 185 // slots.) |
| 174 RVA previous = 0; | 186 RVA previous = 0; |
| 175 size_t size = rvas->size(); | 187 size_t size = rvas->size(); |
| 176 for (size_t i = 0; i < size; ++i) { | 188 for (size_t i = 0; i < size; ++i) { |
| 177 if ((*rvas)[i] == kUnassignedRVA) | 189 if ((*rvas)[i] == kUnassignedRVA) |
| 178 (*rvas)[i] = previous; | 190 (*rvas)[i] = previous; |
| 179 else | 191 else |
| 180 previous = (*rvas)[i]; | 192 previous = (*rvas)[i]; |
| 181 } | 193 } |
| 182 } | 194 } |
| 183 | 195 |
| 184 void EncodedProgram::AddOrigin(RVA origin) { | 196 CheckBool EncodedProgram::AddOrigin(RVA origin) { |
| 197 //TODO(tommi): Handle errors |
| 185 ops_.push_back(ORIGIN); | 198 ops_.push_back(ORIGIN); |
| 186 origins_.push_back(origin); | 199 origins_.push_back(origin); |
| 200 return true; |
| 187 } | 201 } |
| 188 | 202 |
| 189 void EncodedProgram::AddCopy(uint32 count, const void* bytes) { | 203 CheckBool EncodedProgram::AddCopy(uint32 count, const void* bytes) { |
| 204 //TODO(tommi): Handle errors |
| 190 const uint8* source = static_cast<const uint8*>(bytes); | 205 const uint8* source = static_cast<const uint8*>(bytes); |
| 191 | 206 |
| 192 // Fold adjacent COPY instructions into one. This nearly halves the size of | 207 // Fold adjacent COPY instructions into one. This nearly halves the size of |
| 193 // an EncodedProgram with only COPY1 instructions since there are approx plain | 208 // an EncodedProgram with only COPY1 instructions since there are approx plain |
| 194 // 16 bytes per reloc. This has a working-set benefit during decompression. | 209 // 16 bytes per reloc. This has a working-set benefit during decompression. |
| 195 // For compression of files with large differences this makes a small (4%) | 210 // For compression of files with large differences this makes a small (4%) |
| 196 // improvement in size. For files with small differences this degrades the | 211 // improvement in size. For files with small differences this degrades the |
| 197 // compressed size by 1.3% | 212 // compressed size by 1.3% |
| 198 if (!ops_.empty()) { | 213 if (!ops_.empty()) { |
| 199 if (ops_.back() == COPY1) { | 214 if (ops_.back() == COPY1) { |
| 200 ops_.back() = COPY; | 215 ops_.back() = COPY; |
| 201 copy_counts_.push_back(1); | 216 copy_counts_.push_back(1); |
| 202 } | 217 } |
| 203 if (ops_.back() == COPY) { | 218 if (ops_.back() == COPY) { |
| 204 copy_counts_.back() += count; | 219 copy_counts_.back() += count; |
| 205 for (uint32 i = 0; i < count; ++i) { | 220 for (uint32 i = 0; i < count; ++i) { |
| 206 copy_bytes_.push_back(source[i]); | 221 copy_bytes_.push_back(source[i]); |
| 207 } | 222 } |
| 208 return; | 223 return true; |
| 209 } | 224 } |
| 210 } | 225 } |
| 211 | 226 |
| 212 if (count == 1) { | 227 if (count == 1) { |
| 213 ops_.push_back(COPY1); | 228 ops_.push_back(COPY1); |
| 214 copy_bytes_.push_back(source[0]); | 229 copy_bytes_.push_back(source[0]); |
| 215 } else { | 230 } else { |
| 216 ops_.push_back(COPY); | 231 ops_.push_back(COPY); |
| 217 copy_counts_.push_back(count); | 232 copy_counts_.push_back(count); |
| 218 for (uint32 i = 0; i < count; ++i) { | 233 for (uint32 i = 0; i < count; ++i) { |
| 219 copy_bytes_.push_back(source[i]); | 234 copy_bytes_.push_back(source[i]); |
| 220 } | 235 } |
| 221 } | 236 } |
| 237 |
| 238 return true; |
| 222 } | 239 } |
| 223 | 240 |
| 224 void EncodedProgram::AddAbs32(int label_index) { | 241 CheckBool EncodedProgram::AddAbs32(int label_index) { |
| 242 //TODO(tommi): Handle errors |
| 225 ops_.push_back(ABS32); | 243 ops_.push_back(ABS32); |
| 226 abs32_ix_.push_back(label_index); | 244 abs32_ix_.push_back(label_index); |
| 245 return true; |
| 227 } | 246 } |
| 228 | 247 |
| 229 void EncodedProgram::AddRel32(int label_index) { | 248 CheckBool EncodedProgram::AddRel32(int label_index) { |
| 249 //TODO(tommi): Handle errors |
| 230 ops_.push_back(REL32); | 250 ops_.push_back(REL32); |
| 231 rel32_ix_.push_back(label_index); | 251 rel32_ix_.push_back(label_index); |
| 252 return true; |
| 232 } | 253 } |
| 233 | 254 |
| 234 void EncodedProgram::AddMakeRelocs() { | 255 CheckBool EncodedProgram::AddMakeRelocs() { |
| 256 //TODO(tommi): Handle errors |
| 235 ops_.push_back(MAKE_BASE_RELOCATION_TABLE); | 257 ops_.push_back(MAKE_BASE_RELOCATION_TABLE); |
| 258 return true; |
| 236 } | 259 } |
| 237 | 260 |
| 238 void EncodedProgram::DebuggingSummary() { | 261 void EncodedProgram::DebuggingSummary() { |
| 239 VLOG(1) << "EncodedProgram Summary" | 262 VLOG(1) << "EncodedProgram Summary" |
| 240 << "\n image base " << image_base_ | 263 << "\n image base " << image_base_ |
| 241 << "\n abs32 rvas " << abs32_rva_.size() | 264 << "\n abs32 rvas " << abs32_rva_.size() |
| 242 << "\n rel32 rvas " << rel32_rva_.size() | 265 << "\n rel32 rvas " << rel32_rva_.size() |
| 243 << "\n ops " << ops_.size() | 266 << "\n ops " << ops_.size() |
| 244 << "\n origins " << origins_.size() | 267 << "\n origins " << origins_.size() |
| 245 << "\n copy_counts " << copy_counts_.size() | 268 << "\n copy_counts " << copy_counts_.size() |
| (...skipping 26 matching lines...) Expand all Loading... |
| 272 scoped_ptr<base::Environment> env(base::Environment::Create()); | 295 scoped_ptr<base::Environment> env(base::Environment::Create()); |
| 273 std::string s; | 296 std::string s; |
| 274 env->GetVar("A_FIELDS", &s); | 297 env->GetVar("A_FIELDS", &s); |
| 275 if (!s.empty()) { | 298 if (!s.empty()) { |
| 276 return static_cast<FieldSelect>(wcstoul(ASCIIToWide(s).c_str(), 0, 0)); | 299 return static_cast<FieldSelect>(wcstoul(ASCIIToWide(s).c_str(), 0, 0)); |
| 277 } | 300 } |
| 278 #endif | 301 #endif |
| 279 return static_cast<FieldSelect>(~0); | 302 return static_cast<FieldSelect>(~0); |
| 280 } | 303 } |
| 281 | 304 |
| 282 void EncodedProgram::WriteTo(SinkStreamSet* streams) { | 305 CheckBool EncodedProgram::WriteTo(SinkStreamSet* streams) { |
| 283 FieldSelect select = GetFieldSelect(); | 306 FieldSelect select = GetFieldSelect(); |
| 284 | 307 |
| 285 // The order of fields must be consistent in WriteTo and ReadFrom, regardless | 308 // The order of fields must be consistent in WriteTo and ReadFrom, regardless |
| 286 // of the streams used. The code can be configured with all kStreamXXX | 309 // of the streams used. The code can be configured with all kStreamXXX |
| 287 // constants the same. | 310 // constants the same. |
| 288 // | 311 // |
| 289 // If we change the code to pipeline reading with assembly (to avoid temporary | 312 // If we change the code to pipeline reading with assembly (to avoid temporary |
| 290 // storage vectors by consuming operands directly from the stream) then we | 313 // storage vectors by consuming operands directly from the stream) then we |
| 291 // need to read the base address and the random access address tables first, | 314 // need to read the base address and the random access address tables first, |
| 292 // the rest can be interleaved. | 315 // the rest can be interleaved. |
| 293 | 316 |
| 294 if (select & INCLUDE_MISC) { | 317 if (select & INCLUDE_MISC) { |
| 295 // TODO(sra): write 64 bits. | 318 // TODO(sra): write 64 bits. |
| 296 streams->stream(kStreamMisc)->WriteVarint32( | 319 if (!streams->stream(kStreamMisc)->WriteVarint32( |
| 297 static_cast<uint32>(image_base_)); | 320 static_cast<uint32>(image_base_))) { |
| 321 return false; |
| 322 } |
| 298 } | 323 } |
| 299 | 324 |
| 300 if (select & INCLUDE_ABS32_ADDRESSES) | 325 bool success = true; |
| 301 WriteU32Delta(abs32_rva_, streams->stream(kStreamAbs32Addresses)); | 326 |
| 302 if (select & INCLUDE_REL32_ADDRESSES) | 327 if (select & INCLUDE_ABS32_ADDRESSES) { |
| 303 WriteU32Delta(rel32_rva_, streams->stream(kStreamRel32Addresses)); | 328 success &= WriteU32Delta(abs32_rva_, |
| 329 streams->stream(kStreamAbs32Addresses)); |
| 330 } |
| 331 |
| 332 if (select & INCLUDE_REL32_ADDRESSES) { |
| 333 success &= WriteU32Delta(rel32_rva_, |
| 334 streams->stream(kStreamRel32Addresses)); |
| 335 } |
| 336 |
| 304 if (select & INCLUDE_MISC) | 337 if (select & INCLUDE_MISC) |
| 305 WriteVector(origins_, streams->stream(kStreamOriginAddresses)); | 338 success &= WriteVector(origins_, streams->stream(kStreamOriginAddresses)); |
| 339 |
| 306 if (select & INCLUDE_OPS) { | 340 if (select & INCLUDE_OPS) { |
| 307 streams->stream(kStreamOps)->Reserve(ops_.size() + 5); // 5 for length. | 341 // 5 for length. |
| 308 WriteVector(ops_, streams->stream(kStreamOps)); | 342 success &= streams->stream(kStreamOps)->Reserve(ops_.size() + 5); |
| 343 success &= WriteVector(ops_, streams->stream(kStreamOps)); |
| 309 } | 344 } |
| 345 |
| 310 if (select & INCLUDE_COPY_COUNTS) | 346 if (select & INCLUDE_COPY_COUNTS) |
| 311 WriteVector(copy_counts_, streams->stream(kStreamCopyCounts)); | 347 success &= WriteVector(copy_counts_, streams->stream(kStreamCopyCounts)); |
| 348 |
| 312 if (select & INCLUDE_BYTES) | 349 if (select & INCLUDE_BYTES) |
| 313 WriteVectorU8(copy_bytes_, streams->stream(kStreamBytes)); | 350 success &= WriteVectorU8(copy_bytes_, streams->stream(kStreamBytes)); |
| 351 |
| 314 if (select & INCLUDE_ABS32_INDEXES) | 352 if (select & INCLUDE_ABS32_INDEXES) |
| 315 WriteVector(abs32_ix_, streams->stream(kStreamAbs32Indexes)); | 353 success &= WriteVector(abs32_ix_, streams->stream(kStreamAbs32Indexes)); |
| 354 |
| 316 if (select & INCLUDE_REL32_INDEXES) | 355 if (select & INCLUDE_REL32_INDEXES) |
| 317 WriteVector(rel32_ix_, streams->stream(kStreamRel32Indexes)); | 356 success &= WriteVector(rel32_ix_, streams->stream(kStreamRel32Indexes)); |
| 357 |
| 358 return success; |
| 318 } | 359 } |
| 319 | 360 |
| 320 bool EncodedProgram::ReadFrom(SourceStreamSet* streams) { | 361 bool EncodedProgram::ReadFrom(SourceStreamSet* streams) { |
| 321 // TODO(sra): read 64 bits. | 362 // TODO(sra): read 64 bits. |
| 322 uint32 temp; | 363 uint32 temp; |
| 323 if (!streams->stream(kStreamMisc)->ReadVarint32(&temp)) | 364 if (!streams->stream(kStreamMisc)->ReadVarint32(&temp)) |
| 324 return false; | 365 return false; |
| 325 image_base_ = temp; | 366 image_base_ = temp; |
| 326 | 367 |
| 327 if (!ReadU32Delta(&abs32_rva_, streams->stream(kStreamAbs32Addresses))) | 368 if (!ReadU32Delta(&abs32_rva_, streams->stream(kStreamAbs32Addresses))) |
| (...skipping 25 matching lines...) Expand all Loading... |
| 353 // Safe, non-throwing version of std::vector::at(). Returns 'true' for success, | 394 // Safe, non-throwing version of std::vector::at(). Returns 'true' for success, |
| 354 // 'false' for out-of-bounds index error. | 395 // 'false' for out-of-bounds index error. |
| 355 template<typename T, typename A> | 396 template<typename T, typename A> |
| 356 bool VectorAt(const std::vector<T, A>& v, size_t index, T* output) { | 397 bool VectorAt(const std::vector<T, A>& v, size_t index, T* output) { |
| 357 if (index >= v.size()) | 398 if (index >= v.size()) |
| 358 return false; | 399 return false; |
| 359 *output = v[index]; | 400 *output = v[index]; |
| 360 return true; | 401 return true; |
| 361 } | 402 } |
| 362 | 403 |
| 363 bool EncodedProgram::AssembleTo(SinkStream* final_buffer) { | 404 CheckBool EncodedProgram::AssembleTo(SinkStream* final_buffer) { |
| 364 // For the most part, the assembly process walks the various tables. | 405 // For the most part, the assembly process walks the various tables. |
| 365 // ix_mumble is the index into the mumble table. | 406 // ix_mumble is the index into the mumble table. |
| 366 size_t ix_origins = 0; | 407 size_t ix_origins = 0; |
| 367 size_t ix_copy_counts = 0; | 408 size_t ix_copy_counts = 0; |
| 368 size_t ix_copy_bytes = 0; | 409 size_t ix_copy_bytes = 0; |
| 369 size_t ix_abs32_ix = 0; | 410 size_t ix_abs32_ix = 0; |
| 370 size_t ix_rel32_ix = 0; | 411 size_t ix_rel32_ix = 0; |
| 371 | 412 |
| 372 RVA current_rva = 0; | 413 RVA current_rva = 0; |
| 373 | 414 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 395 case COPY: { | 436 case COPY: { |
| 396 uint32 count; | 437 uint32 count; |
| 397 if (!VectorAt(copy_counts_, ix_copy_counts, &count)) | 438 if (!VectorAt(copy_counts_, ix_copy_counts, &count)) |
| 398 return false; | 439 return false; |
| 399 ++ix_copy_counts; | 440 ++ix_copy_counts; |
| 400 for (uint32 i = 0; i < count; ++i) { | 441 for (uint32 i = 0; i < count; ++i) { |
| 401 uint8 b; | 442 uint8 b; |
| 402 if (!VectorAt(copy_bytes_, ix_copy_bytes, &b)) | 443 if (!VectorAt(copy_bytes_, ix_copy_bytes, &b)) |
| 403 return false; | 444 return false; |
| 404 ++ix_copy_bytes; | 445 ++ix_copy_bytes; |
| 405 output->Write(&b, 1); | 446 if (!output->Write(&b, 1)) |
| 447 return false; |
| 406 } | 448 } |
| 407 current_rva += count; | 449 current_rva += count; |
| 408 break; | 450 break; |
| 409 } | 451 } |
| 410 | 452 |
| 411 case COPY1: { | 453 case COPY1: { |
| 412 uint8 b; | 454 uint8 b; |
| 413 if (!VectorAt(copy_bytes_, ix_copy_bytes, &b)) | 455 if (!VectorAt(copy_bytes_, ix_copy_bytes, &b)) |
| 414 return false; | 456 return false; |
| 415 ++ix_copy_bytes; | 457 ++ix_copy_bytes; |
| 416 output->Write(&b, 1); | 458 if (!output->Write(&b, 1)) |
| 459 return false; |
| 417 current_rva += 1; | 460 current_rva += 1; |
| 418 break; | 461 break; |
| 419 } | 462 } |
| 420 | 463 |
| 421 case REL32: { | 464 case REL32: { |
| 422 uint32 index; | 465 uint32 index; |
| 423 if (!VectorAt(rel32_ix_, ix_rel32_ix, &index)) | 466 if (!VectorAt(rel32_ix_, ix_rel32_ix, &index)) |
| 424 return false; | 467 return false; |
| 425 ++ix_rel32_ix; | 468 ++ix_rel32_ix; |
| 426 RVA rva; | 469 RVA rva; |
| 427 if (!VectorAt(rel32_rva_, index, &rva)) | 470 if (!VectorAt(rel32_rva_, index, &rva)) |
| 428 return false; | 471 return false; |
| 429 uint32 offset = (rva - (current_rva + 4)); | 472 uint32 offset = (rva - (current_rva + 4)); |
| 430 output->Write(&offset, 4); | 473 if (!output->Write(&offset, 4)) |
| 474 return false; |
| 431 current_rva += 4; | 475 current_rva += 4; |
| 432 break; | 476 break; |
| 433 } | 477 } |
| 434 | 478 |
| 435 case ABS32: { | 479 case ABS32: { |
| 436 uint32 index; | 480 uint32 index; |
| 437 if (!VectorAt(abs32_ix_, ix_abs32_ix, &index)) | 481 if (!VectorAt(abs32_ix_, ix_abs32_ix, &index)) |
| 438 return false; | 482 return false; |
| 439 ++ix_abs32_ix; | 483 ++ix_abs32_ix; |
| 440 RVA rva; | 484 RVA rva; |
| 441 if (!VectorAt(abs32_rva_, index, &rva)) | 485 if (!VectorAt(abs32_rva_, index, &rva)) |
| 442 return false; | 486 return false; |
| 443 uint32 abs32 = static_cast<uint32>(rva + image_base_); | 487 uint32 abs32 = static_cast<uint32>(rva + image_base_); |
| 444 abs32_relocs_.push_back(current_rva); | 488 abs32_relocs_.push_back(current_rva); |
| 445 output->Write(&abs32, 4); | 489 if (!output->Write(&abs32, 4)) |
| 490 return false; |
| 446 current_rva += 4; | 491 current_rva += 4; |
| 447 break; | 492 break; |
| 448 } | 493 } |
| 449 | 494 |
| 450 case MAKE_BASE_RELOCATION_TABLE: { | 495 case MAKE_BASE_RELOCATION_TABLE: { |
| 451 // We can see the base relocation anywhere, but we only have the | 496 // We can see the base relocation anywhere, but we only have the |
| 452 // information to generate it at the very end. So we divert the bytes | 497 // information to generate it at the very end. So we divert the bytes |
| 453 // we are generating to a temporary stream. | 498 // we are generating to a temporary stream. |
| 454 if (pending_base_relocation_table) // Can't have two base relocation | 499 if (pending_base_relocation_table) // Can't have two base relocation |
| 455 // tables. | 500 // tables. |
| 456 return false; | 501 return false; |
| 457 | 502 |
| 458 pending_base_relocation_table = true; | 503 pending_base_relocation_table = true; |
| 459 output = &bytes_following_base_relocation_table; | 504 output = &bytes_following_base_relocation_table; |
| 460 break; | 505 break; |
| 461 // There is a potential problem *if* the instruction stream contains | 506 // There is a potential problem *if* the instruction stream contains |
| 462 // some REL32 relocations following the base relocation and in the same | 507 // some REL32 relocations following the base relocation and in the same |
| 463 // section. We don't know the size of the table, so 'current_rva' will | 508 // section. We don't know the size of the table, so 'current_rva' will |
| 464 // be wrong, causing REL32 offsets to be miscalculated. This never | 509 // be wrong, causing REL32 offsets to be miscalculated. This never |
| 465 // happens; the base relocation table is usually in a section of its | 510 // happens; the base relocation table is usually in a section of its |
| 466 // own, a data-only section, and following everything else in the | 511 // own, a data-only section, and following everything else in the |
| 467 // executable except some padding zero bytes. We could fix this by | 512 // executable except some padding zero bytes. We could fix this by |
| 468 // emitting an ORIGIN after the MAKE_BASE_RELOCATION_TABLE. | 513 // emitting an ORIGIN after the MAKE_BASE_RELOCATION_TABLE. |
| 469 } | 514 } |
| 470 } | 515 } |
| 471 } | 516 } |
| 472 | 517 |
| 473 if (pending_base_relocation_table) { | 518 if (pending_base_relocation_table) { |
| 474 GenerateBaseRelocations(final_buffer); | 519 if (!GenerateBaseRelocations(final_buffer) || |
| 475 final_buffer->Append(&bytes_following_base_relocation_table); | 520 !final_buffer->Append(&bytes_following_base_relocation_table)) |
| 521 return false; |
| 476 } | 522 } |
| 477 | 523 |
| 478 // Final verification check: did we consume all lists? | 524 // Final verification check: did we consume all lists? |
| 479 if (ix_copy_counts != copy_counts_.size()) | 525 if (ix_copy_counts != copy_counts_.size()) |
| 480 return false; | 526 return false; |
| 481 if (ix_copy_bytes != copy_bytes_.size()) | 527 if (ix_copy_bytes != copy_bytes_.size()) |
| 482 return false; | 528 return false; |
| 483 if (ix_abs32_ix != abs32_ix_.size()) | 529 if (ix_abs32_ix != abs32_ix_.size()) |
| 484 return false; | 530 return false; |
| 485 if (ix_rel32_ix != rel32_ix_.size()) | 531 if (ix_rel32_ix != rel32_ix_.size()) |
| 486 return false; | 532 return false; |
| 487 | 533 |
| 488 return true; | 534 return true; |
| 489 } | 535 } |
| 490 | 536 |
| 491 | |
| 492 // RelocBlock has the layout of a block of relocations in the base relocation | 537 // RelocBlock has the layout of a block of relocations in the base relocation |
| 493 // table file format. | 538 // table file format. |
| 494 // | 539 // |
| 495 struct RelocBlockPOD { | 540 struct RelocBlockPOD { |
| 496 uint32 page_rva; | 541 uint32 page_rva; |
| 497 uint32 block_size; | 542 uint32 block_size; |
| 498 uint16 relocs[4096]; // Allow up to one relocation per byte of a 4k page. | 543 uint16 relocs[4096]; // Allow up to one relocation per byte of a 4k page. |
| 499 }; | 544 }; |
| 500 | 545 |
| 501 COMPILE_ASSERT(offsetof(RelocBlockPOD, relocs) == 8, reloc_block_header_size); | 546 COMPILE_ASSERT(offsetof(RelocBlockPOD, relocs) == 8, reloc_block_header_size); |
| 502 | 547 |
| 503 class RelocBlock { | 548 class RelocBlock { |
| 504 public: | 549 public: |
| 505 RelocBlock() { | 550 RelocBlock() { |
| 506 pod.page_rva = ~0; | 551 pod.page_rva = ~0; |
| 507 pod.block_size = 8; | 552 pod.block_size = 8; |
| 508 } | 553 } |
| 509 | 554 |
| 510 void Add(uint16 item) { | 555 void Add(uint16 item) { |
| 511 pod.relocs[(pod.block_size-8)/2] = item; | 556 pod.relocs[(pod.block_size-8)/2] = item; |
| 512 pod.block_size += 2; | 557 pod.block_size += 2; |
| 513 } | 558 } |
| 514 | 559 |
| 515 void Flush(SinkStream* buffer) { | 560 CheckBool Flush(SinkStream* buffer) { |
| 561 bool ok = true; |
| 516 if (pod.block_size != 8) { | 562 if (pod.block_size != 8) { |
| 517 if (pod.block_size % 4 != 0) { // Pad to make size multiple of 4 bytes. | 563 if (pod.block_size % 4 != 0) { // Pad to make size multiple of 4 bytes. |
| 518 Add(0); | 564 Add(0); |
| 519 } | 565 } |
| 520 buffer->Write(&pod, pod.block_size); | 566 ok = buffer->Write(&pod, pod.block_size); |
| 521 pod.block_size = 8; | 567 pod.block_size = 8; |
| 522 } | 568 } |
| 569 return ok; |
| 523 } | 570 } |
| 524 RelocBlockPOD pod; | 571 RelocBlockPOD pod; |
| 525 }; | 572 }; |
| 526 | 573 |
| 527 void EncodedProgram::GenerateBaseRelocations(SinkStream* buffer) { | 574 CheckBool EncodedProgram::GenerateBaseRelocations(SinkStream* buffer) { |
| 528 std::sort(abs32_relocs_.begin(), abs32_relocs_.end()); | 575 std::sort(abs32_relocs_.begin(), abs32_relocs_.end()); |
| 529 | 576 |
| 530 RelocBlock block; | 577 RelocBlock block; |
| 531 | 578 |
| 532 for (size_t i = 0; i < abs32_relocs_.size(); ++i) { | 579 bool ok = true; |
| 580 for (size_t i = 0; ok && i < abs32_relocs_.size(); ++i) { |
| 533 uint32 rva = abs32_relocs_[i]; | 581 uint32 rva = abs32_relocs_[i]; |
| 534 uint32 page_rva = rva & ~0xFFF; | 582 uint32 page_rva = rva & ~0xFFF; |
| 535 if (page_rva != block.pod.page_rva) { | 583 if (page_rva != block.pod.page_rva) { |
| 536 block.Flush(buffer); | 584 ok &= block.Flush(buffer); |
| 537 block.pod.page_rva = page_rva; | 585 block.pod.page_rva = page_rva; |
| 538 } | 586 } |
| 539 block.Add(0x3000 | (rva & 0xFFF)); | 587 if (ok) |
| 588 block.Add(0x3000 | (rva & 0xFFF)); |
| 540 } | 589 } |
| 541 block.Flush(buffer); | 590 ok &= block.Flush(buffer); |
| 591 return ok; |
| 542 } | 592 } |
| 543 | 593 |
| 544 //////////////////////////////////////////////////////////////////////////////// | 594 //////////////////////////////////////////////////////////////////////////////// |
| 545 | 595 |
| 546 Status WriteEncodedProgram(EncodedProgram* encoded, SinkStreamSet* sink) { | 596 Status WriteEncodedProgram(EncodedProgram* encoded, SinkStreamSet* sink) { |
| 547 encoded->WriteTo(sink); | 597 if (!encoded->WriteTo(sink)) |
| 598 return C_STREAM_ERROR; |
| 548 return C_OK; | 599 return C_OK; |
| 549 } | 600 } |
| 550 | 601 |
| 551 Status ReadEncodedProgram(SourceStreamSet* streams, EncodedProgram** output) { | 602 Status ReadEncodedProgram(SourceStreamSet* streams, EncodedProgram** output) { |
| 552 EncodedProgram* encoded = new EncodedProgram(); | 603 EncodedProgram* encoded = new EncodedProgram(); |
| 553 if (encoded->ReadFrom(streams)) { | 604 if (encoded->ReadFrom(streams)) { |
| 554 *output = encoded; | 605 *output = encoded; |
| 555 return C_OK; | 606 return C_OK; |
| 556 } | 607 } |
| 557 delete encoded; | 608 delete encoded; |
| 558 return C_DESERIALIZATION_FAILED; | 609 return C_DESERIALIZATION_FAILED; |
| 559 } | 610 } |
| 560 | 611 |
| 561 Status Assemble(EncodedProgram* encoded, SinkStream* buffer) { | 612 Status Assemble(EncodedProgram* encoded, SinkStream* buffer) { |
| 562 bool assembled = encoded->AssembleTo(buffer); | 613 bool assembled = encoded->AssembleTo(buffer); |
| 563 if (assembled) | 614 if (assembled) |
| 564 return C_OK; | 615 return C_OK; |
| 565 return C_ASSEMBLY_FAILED; | 616 return C_ASSEMBLY_FAILED; |
| 566 } | 617 } |
| 567 | 618 |
| 568 void DeleteEncodedProgram(EncodedProgram* encoded) { | 619 void DeleteEncodedProgram(EncodedProgram* encoded) { |
| 569 delete encoded; | 620 delete encoded; |
| 570 } | 621 } |
| 571 | 622 |
| 572 } // end namespace | 623 } // end namespace |
| OLD | NEW |