diff options
Diffstat (limited to 'zucchini_gen.cc')
-rw-r--r-- | zucchini_gen.cc | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/zucchini_gen.cc b/zucchini_gen.cc index af7c7dd..e88d37b 100644 --- a/zucchini_gen.cc +++ b/zucchini_gen.cc @@ -22,6 +22,7 @@ #include "components/zucchini/heuristic_ensemble_matcher.h" #include "components/zucchini/image_index.h" #include "components/zucchini/patch_writer.h" +#include "components/zucchini/reference_bytes_mixer.h" #include "components/zucchini/suffix_array.h" #include "components/zucchini/targets_affinity.h" @@ -120,6 +121,7 @@ bool GenerateRawDelta(ConstBufferView old_image, ConstBufferView new_image, const EquivalenceMap& equivalence_map, const ImageIndex& new_image_index, + ReferenceBytesMixer* reference_bytes_mixer, PatchElementWriter* patch_writer) { RawDeltaSink raw_delta_sink; @@ -130,14 +132,37 @@ bool GenerateRawDelta(ConstBufferView old_image, Equivalence equivalence = candidate.eq; // For each bytewise delta from |old_image| to |new_image|, compute "copy // offset" and pass it along with delta to the sink. - for (offset_t i = 0; i < equivalence.length; ++i) { - if (new_image_index.IsReference(equivalence.dst_offset + i)) - continue; // Skip references since they're handled elsewhere. - - int8_t diff = new_image[equivalence.dst_offset + i] - - old_image[equivalence.src_offset + i]; - if (diff) - raw_delta_sink.PutNext({base_copy_offset + i, diff}); + for (offset_t i = 0; i < equivalence.length;) { + if (new_image_index.IsReference(equivalence.dst_offset + i)) { + DCHECK(new_image_index.IsToken(equivalence.dst_offset + i)); + TypeTag type_tag = + new_image_index.LookupType(equivalence.dst_offset + i); + + // Reference delta has its own flow. On some architectures (e.g., x86) + // this does not involve raw delta, so we skip. On other architectures + // (e.g., ARM) references are mixed with other bits that may change, so + // we need to "mix" data and store some changed bits into raw delta. + int num_bytes = reference_bytes_mixer->NumBytes(type_tag.value()); + if (num_bytes) { + ConstBufferView mixed_ref_bytes = reference_bytes_mixer->Mix( + type_tag.value(), old_image.begin(), equivalence.src_offset + i, + new_image.begin(), equivalence.dst_offset + i); + for (int j = 0; j < num_bytes; ++j) { + int8_t diff = + mixed_ref_bytes[j] - old_image[equivalence.src_offset + i + j]; + if (diff) + raw_delta_sink.PutNext({base_copy_offset + i + j, diff}); + } + } + i += new_image_index.refs(type_tag).width(); + DCHECK_LE(i, equivalence.length); + } else { + int8_t diff = new_image[equivalence.dst_offset + i] - + old_image[equivalence.src_offset + i]; + if (diff) + raw_delta_sink.PutNext({base_copy_offset + i, diff}); + ++i; + } } base_copy_offset += equivalence.length; } @@ -225,10 +250,12 @@ bool GenerateRawElement(const std::vector<offset_t>& old_sa, kMinEquivalenceSimilarity); patch_writer->SetReferenceDeltaSink({}); + + ReferenceBytesMixer no_op_bytes_mixer; return GenerateEquivalencesAndExtraData(new_image, equivalences, patch_writer) && GenerateRawDelta(old_image, new_image, equivalences, new_image_index, - patch_writer); + &no_op_bytes_mixer, patch_writer); } bool GenerateExecutableElement(ExecutableType exe_type, @@ -282,11 +309,12 @@ bool GenerateExecutableElement(ExecutableType exe_type, } } patch_writer->SetReferenceDeltaSink(std::move(reference_delta_sink)); - + std::unique_ptr<ReferenceBytesMixer> reference_bytes_mixer = + ReferenceBytesMixer::Create(*old_disasm, *new_disasm); return GenerateEquivalencesAndExtraData(new_image, equivalences, patch_writer) && GenerateRawDelta(old_image, new_image, equivalences, new_image_index, - patch_writer); + reference_bytes_mixer.get(), patch_writer); } /******** Exported Functions ********/ |