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) | |
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) | |
robertshield
2011/03/22 18:04:07
Are you going to fix these right away afterwards?
tommi (sloooow) - chröme
2011/03/22 18:37:49
I'm going to fix these afterwards, but you're righ
| |
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) | |
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) | |
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) | |
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) | |
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) | |
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) | |
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_, |
robertshield
2011/03/22 18:04:07
question probably for the next CL, but do you plan
tommi (sloooow) - chröme
2011/03/22 18:37:49
My plan is to implement it so that once a Write ha
| |
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 |