xref: /aosp_15_r20/external/zucchini/reference_bytes_mixer.h (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1*a03ca8b9SKrzysztof Kosiński // Copyright 2018 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński 
5*a03ca8b9SKrzysztof Kosiński #ifndef COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_
6*a03ca8b9SKrzysztof Kosiński #define COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_
7*a03ca8b9SKrzysztof Kosiński 
8*a03ca8b9SKrzysztof Kosiński #include <stdint.h>
9*a03ca8b9SKrzysztof Kosiński 
10*a03ca8b9SKrzysztof Kosiński #include <memory>
11*a03ca8b9SKrzysztof Kosiński 
12*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_view.h"
13*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/image_utils.h"
14*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/rel32_utils.h"
15*a03ca8b9SKrzysztof Kosiński 
16*a03ca8b9SKrzysztof Kosiński namespace zucchini {
17*a03ca8b9SKrzysztof Kosiński 
18*a03ca8b9SKrzysztof Kosiński class Disassembler;
19*a03ca8b9SKrzysztof Kosiński 
20*a03ca8b9SKrzysztof Kosiński // References encoding may be quite complex in some architectures (e.g., ARM),
21*a03ca8b9SKrzysztof Kosiński // requiring bit-level manipulation. In general, bits in a reference body fall
22*a03ca8b9SKrzysztof Kosiński // under 2 categories:
23*a03ca8b9SKrzysztof Kosiński // - Operation bits: Instruction op code, conditionals, or structural data.
24*a03ca8b9SKrzysztof Kosiński // - Payload bits: Actual target data of the reference. These may be absolute,
25*a03ca8b9SKrzysztof Kosiński //   or be displacements relative to instruction pointer / program counter.
26*a03ca8b9SKrzysztof Kosiński // During patch application,
27*a03ca8b9SKrzysztof Kosiński //   Old reference bytes = {old operation, old payload},
28*a03ca8b9SKrzysztof Kosiński // is transformed to
29*a03ca8b9SKrzysztof Kosiński //   New reference bytes = {new operation, new payload}.
30*a03ca8b9SKrzysztof Kosiński // New image bytes are written by three sources:
31*a03ca8b9SKrzysztof Kosiński //   (1) Direct copy from old image to new image for matched blocks.
32*a03ca8b9SKrzysztof Kosiński //   (2) Bytewise diff correction.
33*a03ca8b9SKrzysztof Kosiński //   (3) Dedicated reference target correction.
34*a03ca8b9SKrzysztof Kosiński //
35*a03ca8b9SKrzysztof Kosiński // For references whose operation and payload bits are stored in easily
36*a03ca8b9SKrzysztof Kosiński // separable bytes (e.g., rel32 reference in X86), (2) can exclude payload bits.
37*a03ca8b9SKrzysztof Kosiński // So during patch application, (1) naively copies everything, (2) fixes
38*a03ca8b9SKrzysztof Kosiński // operation bytes only, and (3) fixes payload bytes only.
39*a03ca8b9SKrzysztof Kosiński //
40*a03ca8b9SKrzysztof Kosiński // For architectures with references whose operation and payload bits may mix
41*a03ca8b9SKrzysztof Kosiński // within shared bytes (e.g., ARM rel32), a dilemma arises:
42*a03ca8b9SKrzysztof Kosiński // - (2) cannot ignores shared bytes, since otherwise new operation bits not
43*a03ca8b9SKrzysztof Kosiński //   properly transfer.
44*a03ca8b9SKrzysztof Kosiński // - Having (2) always overwrite these bytes would reduce the benefits of
45*a03ca8b9SKrzysztof Kosiński //   reference correction, since references are likely to change.
46*a03ca8b9SKrzysztof Kosiński //
47*a03ca8b9SKrzysztof Kosiński // Our solution applies a hybrid approach: For each matching old / new reference
48*a03ca8b9SKrzysztof Kosiński // pair, define:
49*a03ca8b9SKrzysztof Kosiński //   Mixed reference bytes = {new operation, old payload},
50*a03ca8b9SKrzysztof Kosiński //
51*a03ca8b9SKrzysztof Kosiński // During patch generation, we compute bytewise correction from old reference
52*a03ca8b9SKrzysztof Kosiński // bytes to the mixed reference bytes. So during patch application, (2) only
53*a03ca8b9SKrzysztof Kosiński // corrects operation bit changes (and skips if they don't change), and (3)
54*a03ca8b9SKrzysztof Kosiński // overwrites old payload bits to new payload bits.
55*a03ca8b9SKrzysztof Kosiński 
56*a03ca8b9SKrzysztof Kosiński // A base class for (stateful) mixed reference byte generation. This base class
57*a03ca8b9SKrzysztof Kosiński // serves as a stub. Architectures whose references store operation bits and
58*a03ca8b9SKrzysztof Kosiński // payload bits can share common bytes (e.g., ARM rel32) should override this.
59*a03ca8b9SKrzysztof Kosiński class ReferenceBytesMixer {
60*a03ca8b9SKrzysztof Kosiński  public:
61*a03ca8b9SKrzysztof Kosiński   ReferenceBytesMixer();
62*a03ca8b9SKrzysztof Kosiński   ReferenceBytesMixer(const ReferenceBytesMixer&) = delete;
63*a03ca8b9SKrzysztof Kosiński   const ReferenceBytesMixer& operator=(const ReferenceBytesMixer&) = delete;
64*a03ca8b9SKrzysztof Kosiński   virtual ~ReferenceBytesMixer();
65*a03ca8b9SKrzysztof Kosiński 
66*a03ca8b9SKrzysztof Kosiński   // Returns a new ReferenceBytesMixer instance that's owned by the caller.
67*a03ca8b9SKrzysztof Kosiński   static std::unique_ptr<ReferenceBytesMixer> Create(
68*a03ca8b9SKrzysztof Kosiński       const Disassembler& src_dis,
69*a03ca8b9SKrzysztof Kosiński       const Disassembler& dst_dis);
70*a03ca8b9SKrzysztof Kosiński 
71*a03ca8b9SKrzysztof Kosiński   // Returns the number of bytes that need to be mixed for references with given
72*a03ca8b9SKrzysztof Kosiński   // |type|. Returns 0 if no mixing is required.
73*a03ca8b9SKrzysztof Kosiński   virtual int NumBytes(uint8_t type) const;
74*a03ca8b9SKrzysztof Kosiński 
75*a03ca8b9SKrzysztof Kosiński   // Computes mixed reference bytes by combining (a) "payload bits" from an
76*a03ca8b9SKrzysztof Kosiński   // "old" reference of |type| at |old_view[old_offset]| with (b) "operation
77*a03ca8b9SKrzysztof Kosiński   // bits" from a "new" reference of |type| at |new_view[new_offset]|. Returns
78*a03ca8b9SKrzysztof Kosiński   // the result as ConstBufferView, which is valid only until the next call to
79*a03ca8b9SKrzysztof Kosiński   // Mix().
80*a03ca8b9SKrzysztof Kosiński   virtual ConstBufferView Mix(uint8_t type,
81*a03ca8b9SKrzysztof Kosiński                               ConstBufferView old_view,
82*a03ca8b9SKrzysztof Kosiński                               offset_t old_offset,
83*a03ca8b9SKrzysztof Kosiński                               ConstBufferView new_view,
84*a03ca8b9SKrzysztof Kosiński                               offset_t new_offset);
85*a03ca8b9SKrzysztof Kosiński };
86*a03ca8b9SKrzysztof Kosiński 
87*a03ca8b9SKrzysztof Kosiński // In AArch32 and AArch64, instructions mix operation bits and payload bits in
88*a03ca8b9SKrzysztof Kosiński // complex ways. This is the main use case of ReferenceBytesMixer.
89*a03ca8b9SKrzysztof Kosiński class ReferenceBytesMixerElfArm : public ReferenceBytesMixer {
90*a03ca8b9SKrzysztof Kosiński  public:
91*a03ca8b9SKrzysztof Kosiński   // |exe_type| must be EXE_TYPE_ELF_ARM or EXE_TYPE_ELF_AARCH64.
92*a03ca8b9SKrzysztof Kosiński   explicit ReferenceBytesMixerElfArm(ExecutableType exe_type);
93*a03ca8b9SKrzysztof Kosiński   ReferenceBytesMixerElfArm(const ReferenceBytesMixerElfArm&) = delete;
94*a03ca8b9SKrzysztof Kosiński   const ReferenceBytesMixerElfArm& operator=(const ReferenceBytesMixerElfArm&) =
95*a03ca8b9SKrzysztof Kosiński       delete;
96*a03ca8b9SKrzysztof Kosiński   ~ReferenceBytesMixerElfArm() override;
97*a03ca8b9SKrzysztof Kosiński 
98*a03ca8b9SKrzysztof Kosiński   // ReferenceBytesMixer:
99*a03ca8b9SKrzysztof Kosiński   int NumBytes(uint8_t type) const override;
100*a03ca8b9SKrzysztof Kosiński   ConstBufferView Mix(uint8_t type,
101*a03ca8b9SKrzysztof Kosiński                       ConstBufferView old_view,
102*a03ca8b9SKrzysztof Kosiński                       offset_t old_offset,
103*a03ca8b9SKrzysztof Kosiński                       ConstBufferView new_view,
104*a03ca8b9SKrzysztof Kosiński                       offset_t new_offset) override;
105*a03ca8b9SKrzysztof Kosiński 
106*a03ca8b9SKrzysztof Kosiński  private:
107*a03ca8b9SKrzysztof Kosiński   ArmCopyDispFun GetCopier(uint8_t type) const;
108*a03ca8b9SKrzysztof Kosiński 
109*a03ca8b9SKrzysztof Kosiński   // For simplicity, 32-bit vs. 64-bit distinction is represented by state
110*a03ca8b9SKrzysztof Kosiński   // |exe_type_|, instead of creating derived classes.
111*a03ca8b9SKrzysztof Kosiński   const ExecutableType exe_type_;
112*a03ca8b9SKrzysztof Kosiński 
113*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> out_buffer_;
114*a03ca8b9SKrzysztof Kosiński };
115*a03ca8b9SKrzysztof Kosiński 
116*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
117*a03ca8b9SKrzysztof Kosiński 
118*a03ca8b9SKrzysztof Kosiński #endif  // COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_
119