| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <stddef.h> |
| 6 |
| 5 #include "courgette/assembly_program.h" | 7 #include "courgette/assembly_program.h" |
| 6 | 8 |
| 7 #include "base/callback.h" | |
| 8 #include "base/logging.h" | 9 #include "base/logging.h" |
| 9 #include "courgette/courgette.h" | |
| 10 #include "courgette/disassembler.h" | |
| 11 #include "courgette/encoded_program.h" | 10 #include "courgette/encoded_program.h" |
| 11 #include "courgette/instruction_utils.h" |
| 12 | 12 |
| 13 namespace courgette { | 13 namespace courgette { |
| 14 | 14 |
| 15 namespace { | 15 namespace { |
| 16 | 16 |
| 17 // Sets the current address for the emitting instructions. | 17 // An instruction receptor that adds each received abs32/rel32 Label* to the |
| 18 class OriginInstruction : public Instruction { | 18 // matching VECTOR member variable. Template VECTOR allows code reuse for |
| 19 // counting (CountingVector) and storage (std::vector). |
| 20 template <template <typename T, typename... Args> class CONTAINER> |
| 21 class LabelReceptor : public InstructionReceptor { |
| 19 public: | 22 public: |
| 20 explicit OriginInstruction(RVA rva) : Instruction(ORIGIN, 0), rva_(rva) {} | 23 using VECTOR = CONTAINER<Label*>; |
| 21 RVA origin_rva() const { return rva_; } | |
| 22 private: | |
| 23 RVA rva_; | |
| 24 }; | |
| 25 | 24 |
| 26 // Emits an entire PE base relocation table. | 25 LabelReceptor() = default; |
| 27 class PeRelocsInstruction : public Instruction { | 26 ~LabelReceptor() override = default; |
| 28 public: | |
| 29 PeRelocsInstruction() : Instruction(MAKEPERELOCS) {} | |
| 30 }; | |
| 31 | 27 |
| 32 // Emits an ELF relocation table. | 28 VECTOR* mutable_abs32_vector() { return &abs32_vector_; } |
| 33 class ElfRelocsInstruction : public Instruction { | 29 VECTOR* mutable_rel32_vector() { return &rel32_vector_; } |
| 34 public: | |
| 35 ElfRelocsInstruction() : Instruction(MAKEELFRELOCS) {} | |
| 36 }; | |
| 37 | |
| 38 // Emits an ELF ARM relocation table. | |
| 39 class ElfARMRelocsInstruction : public Instruction { | |
| 40 public: | |
| 41 ElfARMRelocsInstruction() : Instruction(MAKEELFARMRELOCS) {} | |
| 42 }; | |
| 43 | |
| 44 // Emits a single byte. | |
| 45 class ByteInstruction : public Instruction { | |
| 46 public: | |
| 47 explicit ByteInstruction(uint8_t value) : Instruction(DEFBYTE, value) {} | |
| 48 uint8_t byte_value() const { return info_; } | |
| 49 }; | |
| 50 | |
| 51 // Emits a single byte. | |
| 52 class BytesInstruction : public Instruction { | |
| 53 public: | |
| 54 BytesInstruction(const uint8_t* values, size_t len) | |
| 55 : Instruction(DEFBYTES, 0), values_(values), len_(len) {} | |
| 56 const uint8_t* byte_values() const { return values_; } | |
| 57 size_t len() const { return len_; } | |
| 58 | |
| 59 private: | |
| 60 const uint8_t* values_; | |
| 61 size_t len_; | |
| 62 }; | |
| 63 | |
| 64 // A ABS32 to REL32 instruction emits a reference to a label's address. | |
| 65 class InstructionWithLabel : public Instruction { | |
| 66 public: | |
| 67 InstructionWithLabel(OP op, Label* label) | |
| 68 : Instruction(op, 0), label_(label) { | |
| 69 if (label == NULL) NOTREACHED(); | |
| 70 } | |
| 71 Label* label() const { return label_; } | |
| 72 protected: | |
| 73 Label* label_; | |
| 74 }; | |
| 75 | |
| 76 // An ARM REL32 instruction emits a reference to a label's address and | |
| 77 // a specially-compressed ARM op. | |
| 78 class InstructionWithLabelARM : public InstructionWithLabel { | |
| 79 public: | |
| 80 InstructionWithLabelARM(OP op, | |
| 81 uint16_t compressed_op, | |
| 82 Label* label, | |
| 83 const uint8_t* arm_op, | |
| 84 uint16_t op_size) | |
| 85 : InstructionWithLabel(op, label), | |
| 86 compressed_op_(compressed_op), | |
| 87 arm_op_(arm_op), | |
| 88 op_size_(op_size) { | |
| 89 if (label == NULL) NOTREACHED(); | |
| 90 } | |
| 91 uint16_t compressed_op() const { return compressed_op_; } | |
| 92 const uint8_t* arm_op() const { return arm_op_; } | |
| 93 uint16_t op_size() const { return op_size_; } | |
| 94 | |
| 95 private: | |
| 96 uint16_t compressed_op_; | |
| 97 const uint8_t* arm_op_; | |
| 98 uint16_t op_size_; | |
| 99 }; | |
| 100 | |
| 101 /******** InstructionCountReceptor ********/ | |
| 102 | |
| 103 // An InstructionReceptor that counts space occupied by emitted instructions. | |
| 104 class InstructionCountReceptor : public InstructionReceptor { | |
| 105 public: | |
| 106 InstructionCountReceptor() = default; | |
| 107 | |
| 108 size_t abs_count() const { return abs_count_; } | |
| 109 size_t rel_count() const { return rel_count_; } | |
| 110 | 30 |
| 111 // InstructionReceptor: | 31 // InstructionReceptor: |
| 112 CheckBool EmitPeRelocs() override { return true; } | 32 CheckBool EmitPeRelocs() override { return true; } |
| 113 CheckBool EmitElfRelocation() override { return true; } | 33 CheckBool EmitElfRelocation() override { return true; } |
| 114 CheckBool EmitElfARMRelocation() override { return true; } | 34 CheckBool EmitElfARMRelocation() override { return true; } |
| 115 CheckBool EmitOrigin(RVA rva) override { return true; } | 35 CheckBool EmitOrigin(RVA rva) override { return true; } |
| 116 CheckBool EmitSingleByte(uint8_t byte) override { return true; } | 36 CheckBool EmitSingleByte(uint8_t byte) override { return true; } |
| 117 CheckBool EmitMultipleBytes(const uint8_t* bytes, size_t len) override { | 37 CheckBool EmitMultipleBytes(const uint8_t* bytes, size_t len) override { |
| 118 return true; | 38 return true; |
| 119 } | 39 } |
| 120 CheckBool EmitRel32(Label* label) override { | 40 CheckBool EmitRel32(Label* label) override { |
| 121 ++rel_count_; | 41 rel32_vector_.push_back(label); |
| 122 return true; | 42 return true; |
| 123 } | 43 } |
| 124 CheckBool EmitRel32ARM(uint16_t op, | 44 CheckBool EmitRel32ARM(uint16_t op, |
| 125 Label* label, | 45 Label* label, |
| 126 const uint8_t* arm_op, | 46 const uint8_t* arm_op, |
| 127 uint16_t op_size) override { | 47 uint16_t op_size) override { |
| 128 ++rel_count_; | 48 rel32_vector_.push_back(label); |
| 129 return true; | 49 return true; |
| 130 } | 50 } |
| 131 CheckBool EmitAbs32(Label* label) override { | 51 CheckBool EmitAbs32(Label* label) override { |
| 132 ++abs_count_; | 52 abs32_vector_.push_back(label); |
| 133 return true; | 53 return true; |
| 134 } | 54 } |
| 135 CheckBool EmitAbs64(Label* label) override { | 55 CheckBool EmitAbs64(Label* label) override { |
| 136 ++abs_count_; | 56 abs32_vector_.push_back(label); |
| 137 return true; | 57 return true; |
| 138 } | 58 } |
| 139 | 59 |
| 140 private: | 60 private: |
| 141 size_t abs_count_ = 0; | 61 VECTOR abs32_vector_; |
| 142 size_t rel_count_ = 0; | 62 VECTOR rel32_vector_; |
| 143 | 63 |
| 144 DISALLOW_COPY_AND_ASSIGN(InstructionCountReceptor); | 64 DISALLOW_COPY_AND_ASSIGN(LabelReceptor); |
| 145 }; | |
| 146 | |
| 147 /******** InstructionStoreReceptor ********/ | |
| 148 | |
| 149 // An InstructionReceptor that stores emitted instructions. | |
| 150 class InstructionStoreReceptor : public InstructionReceptor { | |
| 151 public: | |
| 152 InstructionStoreReceptor(AssemblyProgram* program, bool annotate_labels) | |
| 153 : program_(program), annotate_labels_(annotate_labels) { | |
| 154 CHECK(program_); | |
| 155 } | |
| 156 | |
| 157 // TODO(huangs): 2017/04: Add Reserve(). | |
| 158 | |
| 159 // InstructionReceptor: | |
| 160 // TODO(huangs): 2017/04: Move implementations here. | |
| 161 CheckBool EmitPeRelocs() override { return program_->EmitPeRelocs(); } | |
| 162 CheckBool EmitElfRelocation() override { | |
| 163 return program_->EmitElfRelocation(); | |
| 164 } | |
| 165 CheckBool EmitElfARMRelocation() override { | |
| 166 return program_->EmitElfARMRelocation(); | |
| 167 } | |
| 168 CheckBool EmitOrigin(RVA rva) override { return program_->EmitOrigin(rva); } | |
| 169 CheckBool EmitSingleByte(uint8_t byte) override { | |
| 170 return program_->EmitSingleByte(byte); | |
| 171 } | |
| 172 CheckBool EmitMultipleBytes(const uint8_t* bytes, size_t len) override { | |
| 173 return program_->EmitMultipleBytes(bytes, len); | |
| 174 } | |
| 175 CheckBool EmitRel32(Label* label) override { | |
| 176 if (annotate_labels_) | |
| 177 program_->mutable_rel32_label_annotations()->push_back(label); | |
| 178 return program_->EmitRel32(label); | |
| 179 } | |
| 180 CheckBool EmitRel32ARM(uint16_t op, | |
| 181 Label* label, | |
| 182 const uint8_t* arm_op, | |
| 183 uint16_t op_size) override { | |
| 184 if (annotate_labels_) | |
| 185 program_->mutable_rel32_label_annotations()->push_back(label); | |
| 186 return program_->EmitRel32ARM(op, label, arm_op, op_size); | |
| 187 } | |
| 188 CheckBool EmitAbs32(Label* label) override { | |
| 189 if (annotate_labels_) | |
| 190 program_->mutable_abs32_label_annotations()->push_back(label); | |
| 191 return program_->EmitAbs32(label); | |
| 192 } | |
| 193 CheckBool EmitAbs64(Label* label) override { | |
| 194 if (annotate_labels_) | |
| 195 program_->mutable_abs32_label_annotations()->push_back(label); | |
| 196 return program_->EmitAbs64(label); | |
| 197 } | |
| 198 | |
| 199 private: | |
| 200 AssemblyProgram* program_; | |
| 201 const bool annotate_labels_; | |
| 202 | |
| 203 DISALLOW_COPY_AND_ASSIGN(InstructionStoreReceptor); | |
| 204 }; | 65 }; |
| 205 | 66 |
| 206 } // namespace | 67 } // namespace |
| 207 | 68 |
| 208 /******** AssemblyProgram ********/ | |
| 209 | |
| 210 AssemblyProgram::AssemblyProgram(ExecutableType kind, uint64_t image_base) | 69 AssemblyProgram::AssemblyProgram(ExecutableType kind, uint64_t image_base) |
| 211 : kind_(kind), image_base_(image_base) {} | 70 : kind_(kind), image_base_(image_base) {} |
| 212 | 71 |
| 213 AssemblyProgram::~AssemblyProgram() { | 72 AssemblyProgram::~AssemblyProgram() = default; |
| 214 for (size_t i = 0; i < instructions_.size(); ++i) { | |
| 215 Instruction* instruction = instructions_[i]; | |
| 216 if (instruction->op() != DEFBYTE) // Owned by byte_instruction_cache_. | |
| 217 UncheckedDelete(instruction); | |
| 218 } | |
| 219 if (byte_instruction_cache_.get()) { | |
| 220 for (size_t i = 0; i < 256; ++i) | |
| 221 UncheckedDelete(byte_instruction_cache_[i]); | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 CheckBool AssemblyProgram::EmitPeRelocs() { | |
| 226 return Emit(ScopedInstruction(UncheckedNew<PeRelocsInstruction>())); | |
| 227 } | |
| 228 | |
| 229 CheckBool AssemblyProgram::EmitElfRelocation() { | |
| 230 return Emit(ScopedInstruction(UncheckedNew<ElfRelocsInstruction>())); | |
| 231 } | |
| 232 | |
| 233 CheckBool AssemblyProgram::EmitElfARMRelocation() { | |
| 234 return Emit(ScopedInstruction(UncheckedNew<ElfARMRelocsInstruction>())); | |
| 235 } | |
| 236 | |
| 237 CheckBool AssemblyProgram::EmitOrigin(RVA rva) { | |
| 238 return Emit(ScopedInstruction(UncheckedNew<OriginInstruction>(rva))); | |
| 239 } | |
| 240 | |
| 241 CheckBool AssemblyProgram::EmitSingleByte(uint8_t byte) { | |
| 242 return EmitShared(GetByteInstruction(byte)); | |
| 243 } | |
| 244 | |
| 245 CheckBool AssemblyProgram::EmitMultipleBytes(const uint8_t* bytes, size_t len) { | |
| 246 return Emit(ScopedInstruction(UncheckedNew<BytesInstruction>(bytes, len))); | |
| 247 } | |
| 248 | |
| 249 CheckBool AssemblyProgram::EmitRel32(Label* label) { | |
| 250 return Emit( | |
| 251 ScopedInstruction(UncheckedNew<InstructionWithLabel>(REL32, label))); | |
| 252 } | |
| 253 | |
| 254 CheckBool AssemblyProgram::EmitRel32ARM(uint16_t op, | |
| 255 Label* label, | |
| 256 const uint8_t* arm_op, | |
| 257 uint16_t op_size) { | |
| 258 return Emit(ScopedInstruction(UncheckedNew<InstructionWithLabelARM>( | |
| 259 REL32ARM, op, label, arm_op, op_size))); | |
| 260 } | |
| 261 | |
| 262 CheckBool AssemblyProgram::EmitAbs32(Label* label) { | |
| 263 return Emit( | |
| 264 ScopedInstruction(UncheckedNew<InstructionWithLabel>(ABS32, label))); | |
| 265 } | |
| 266 | |
| 267 CheckBool AssemblyProgram::EmitAbs64(Label* label) { | |
| 268 return Emit( | |
| 269 ScopedInstruction(UncheckedNew<InstructionWithLabel>(ABS64, label))); | |
| 270 } | |
| 271 | 73 |
| 272 void AssemblyProgram::PrecomputeLabels(RvaVisitor* abs32_visitor, | 74 void AssemblyProgram::PrecomputeLabels(RvaVisitor* abs32_visitor, |
| 273 RvaVisitor* rel32_visitor) { | 75 RvaVisitor* rel32_visitor) { |
| 274 abs32_label_manager_.Read(abs32_visitor); | 76 abs32_label_manager_.Read(abs32_visitor); |
| 275 rel32_label_manager_.Read(rel32_visitor); | 77 rel32_label_manager_.Read(rel32_visitor); |
| 276 TrimLabels(); | 78 TrimLabels(); |
| 277 } | 79 } |
| 278 | 80 |
| 279 // Chosen empirically to give the best reduction in payload size for | 81 // Chosen empirically to give the best reduction in payload size for |
| 280 // an update from daisy_3701.98.0 to daisy_4206.0.0. | 82 // an update from daisy_3701.98.0 to daisy_4206.0.0. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 308 } | 110 } |
| 309 | 111 |
| 310 Label* AssemblyProgram::FindAbs32Label(RVA rva) { | 112 Label* AssemblyProgram::FindAbs32Label(RVA rva) { |
| 311 return abs32_label_manager_.Find(rva); | 113 return abs32_label_manager_.Find(rva); |
| 312 } | 114 } |
| 313 | 115 |
| 314 Label* AssemblyProgram::FindRel32Label(RVA rva) { | 116 Label* AssemblyProgram::FindRel32Label(RVA rva) { |
| 315 return rel32_label_manager_.Find(rva); | 117 return rel32_label_manager_.Find(rva); |
| 316 } | 118 } |
| 317 | 119 |
| 318 CheckBool AssemblyProgram::GenerateInstructions(const InstructionGenerator& gen, | 120 CheckBool AssemblyProgram::AnnotateLabels(const InstructionGenerator& gen) { |
| 319 bool annotate_labels) { | 121 // Pass 1: Compute required space. |
| 320 // Pass 1: Count storage space required and reserve in advance. | 122 LabelReceptor<CountingVector> count_receptor; |
| 321 InstructionCountReceptor count_receptor; | |
| 322 if (!gen.Run(&count_receptor)) | 123 if (!gen.Run(&count_receptor)) |
| 323 return false; | 124 return false; |
| 324 | 125 |
| 325 if (annotate_labels) { | 126 // Pass 2: Reserve and store annotations. |
| 326 DCHECK(abs32_label_annotations_.empty()); | 127 LabelReceptor<std::vector> annotate_receptor; |
| 327 abs32_label_annotations_.reserve(count_receptor.abs_count()); | 128 annotate_receptor.mutable_abs32_vector()->reserve( |
| 328 DCHECK(rel32_label_annotations_.empty()); | 129 count_receptor.mutable_abs32_vector()->size()); |
| 329 rel32_label_annotations_.reserve(count_receptor.rel_count()); | 130 annotate_receptor.mutable_rel32_vector()->reserve( |
| 330 } | 131 count_receptor.mutable_rel32_vector()->size()); |
| 132 if (!gen.Run(&annotate_receptor)) |
| 133 return false; |
| 331 | 134 |
| 332 // Pass 2: Emit all instructions to reserved buffer (uses Phase 1 count). | 135 // Move results to |abs32_label_annotations_| and |re32_label_annotations_|. |
| 333 // Populates |abs32_label_annotations_| and |re32_label_annotations_| if | 136 abs32_label_annotations_.swap(*annotate_receptor.mutable_abs32_vector()); |
| 334 // |annotate_labels| is true. | 137 rel32_label_annotations_.swap(*annotate_receptor.mutable_rel32_vector()); |
| 335 InstructionStoreReceptor store_receptor(this, annotate_labels); | |
| 336 return gen.Run(&store_receptor); | |
| 337 } | |
| 338 | |
| 339 CheckBool AssemblyProgram::Emit(ScopedInstruction instruction) { | |
| 340 if (!instruction || !instructions_.push_back(instruction.get())) | |
| 341 return false; | |
| 342 // Ownership successfully passed to instructions_. | |
| 343 ignore_result(instruction.release()); | |
| 344 return true; | 138 return true; |
| 345 } | 139 } |
| 346 | 140 |
| 347 CheckBool AssemblyProgram::EmitShared(Instruction* instruction) { | 141 bool AssemblyProgram::PrepareEncodedProgram(EncodedProgram* encoded) const { |
| 348 DCHECK(!instruction || instruction->op() == DEFBYTE); | |
| 349 return instruction && instructions_.push_back(instruction); | |
| 350 } | |
| 351 | |
| 352 std::unique_ptr<EncodedProgram> AssemblyProgram::Encode() const { | |
| 353 std::unique_ptr<EncodedProgram> encoded(new EncodedProgram()); | |
| 354 | |
| 355 encoded->set_image_base(image_base_); | 142 encoded->set_image_base(image_base_); |
| 356 | 143 return encoded->ImportLabels(abs32_label_manager_, rel32_label_manager_); |
| 357 if (!encoded->ImportLabels(abs32_label_manager_, rel32_label_manager_)) | |
| 358 return nullptr; | |
| 359 | |
| 360 for (size_t i = 0; i < instructions_.size(); ++i) { | |
| 361 Instruction* instruction = instructions_[i]; | |
| 362 | |
| 363 switch (instruction->op()) { | |
| 364 case ORIGIN: { | |
| 365 OriginInstruction* org = static_cast<OriginInstruction*>(instruction); | |
| 366 if (!encoded->AddOrigin(org->origin_rva())) | |
| 367 return nullptr; | |
| 368 break; | |
| 369 } | |
| 370 case DEFBYTE: { | |
| 371 uint8_t b = static_cast<ByteInstruction*>(instruction)->byte_value(); | |
| 372 if (!encoded->AddCopy(1, &b)) | |
| 373 return nullptr; | |
| 374 break; | |
| 375 } | |
| 376 case DEFBYTES: { | |
| 377 const uint8_t* byte_values = | |
| 378 static_cast<BytesInstruction*>(instruction)->byte_values(); | |
| 379 size_t len = static_cast<BytesInstruction*>(instruction)->len(); | |
| 380 | |
| 381 if (!encoded->AddCopy(len, byte_values)) | |
| 382 return nullptr; | |
| 383 break; | |
| 384 } | |
| 385 case REL32: { | |
| 386 Label* label = static_cast<InstructionWithLabel*>(instruction)->label(); | |
| 387 if (!encoded->AddRel32(label->index_)) | |
| 388 return nullptr; | |
| 389 break; | |
| 390 } | |
| 391 case REL32ARM: { | |
| 392 Label* label = | |
| 393 static_cast<InstructionWithLabelARM*>(instruction)->label(); | |
| 394 uint16_t compressed_op = | |
| 395 static_cast<InstructionWithLabelARM*>(instruction)->compressed_op(); | |
| 396 if (!encoded->AddRel32ARM(compressed_op, label->index_)) | |
| 397 return nullptr; | |
| 398 break; | |
| 399 } | |
| 400 case ABS32: { | |
| 401 Label* label = static_cast<InstructionWithLabel*>(instruction)->label(); | |
| 402 if (!encoded->AddAbs32(label->index_)) | |
| 403 return nullptr; | |
| 404 break; | |
| 405 } | |
| 406 case ABS64: { | |
| 407 Label* label = static_cast<InstructionWithLabel*>(instruction)->label(); | |
| 408 if (!encoded->AddAbs64(label->index_)) | |
| 409 return nullptr; | |
| 410 break; | |
| 411 } | |
| 412 case MAKEPERELOCS: { | |
| 413 if (!encoded->AddPeMakeRelocs(kind_)) | |
| 414 return nullptr; | |
| 415 break; | |
| 416 } | |
| 417 case MAKEELFRELOCS: { | |
| 418 if (!encoded->AddElfMakeRelocs()) | |
| 419 return nullptr; | |
| 420 break; | |
| 421 } | |
| 422 case MAKEELFARMRELOCS: { | |
| 423 if (!encoded->AddElfARMMakeRelocs()) | |
| 424 return nullptr; | |
| 425 break; | |
| 426 } | |
| 427 default: { | |
| 428 NOTREACHED() << "Unknown Insn OP kind"; | |
| 429 } | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 return encoded; | |
| 434 } | |
| 435 | |
| 436 Instruction* AssemblyProgram::GetByteInstruction(uint8_t byte) { | |
| 437 if (!byte_instruction_cache_) { | |
| 438 Instruction** ram = nullptr; | |
| 439 if (!base::UncheckedMalloc(sizeof(Instruction*) * 256, | |
| 440 reinterpret_cast<void**>(&ram))) { | |
| 441 return nullptr; | |
| 442 } | |
| 443 byte_instruction_cache_.reset(ram); | |
| 444 | |
| 445 for (int i = 0; i < 256; ++i) { | |
| 446 byte_instruction_cache_[i] = | |
| 447 UncheckedNew<ByteInstruction>(static_cast<uint8_t>(i)); | |
| 448 if (!byte_instruction_cache_[i]) { | |
| 449 for (int j = 0; j < i; ++j) | |
| 450 UncheckedDelete(byte_instruction_cache_[j]); | |
| 451 byte_instruction_cache_.reset(); | |
| 452 return nullptr; | |
| 453 } | |
| 454 } | |
| 455 } | |
| 456 | |
| 457 return byte_instruction_cache_[byte]; | |
| 458 } | |
| 459 | |
| 460 //////////////////////////////////////////////////////////////////////////////// | |
| 461 | |
| 462 Status Encode(const AssemblyProgram& program, | |
| 463 std::unique_ptr<EncodedProgram>* output) { | |
| 464 // Explicitly release any memory associated with the output before encoding. | |
| 465 output->reset(); | |
| 466 | |
| 467 *output = program.Encode(); | |
| 468 return (*output) ? C_OK : C_GENERAL_ERROR; | |
| 469 } | 144 } |
| 470 | 145 |
| 471 } // namespace courgette | 146 } // namespace courgette |
| OLD | NEW |