• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_ASSEMBLER_COMMON_H_
18 #define BERBERIS_ASSEMBLER_COMMON_H_
19 
20 #include <stdint.h>
21 
22 #include <string>
23 #include <utility>
24 
25 #include "berberis/assembler/machine_code.h"
26 #include "berberis/base/arena_alloc.h"
27 #include "berberis/base/arena_vector.h"
28 #include "berberis/base/logging.h"
29 #include "berberis/base/macros.h"  // DISALLOW_IMPLICIT_CONSTRUCTORS
30 
31 namespace berberis {
32 
33 class AssemblerBase {
34  public:
AssemblerBase(MachineCode * code)35   explicit AssemblerBase(MachineCode* code) : jumps_(code->arena()), code_(code) {}
36 
~AssemblerBase()37   ~AssemblerBase() {}
38 
39   class Label {
40    public:
Label()41     Label() : position_(kInvalid) {}
42 
43     // Label position is offset from the start of MachineCode
44     // where it is bound to.
position()45     uint32_t position() const { return position_; }
46 
Bind(uint32_t position)47     void Bind(uint32_t position) {
48       CHECK(!IsBound());
49       position_ = position;
50     }
51 
IsBound()52     bool IsBound() const { return position_ != kInvalid; }
53 
54    protected:
55     static const uint32_t kInvalid = 0xffffffff;
56     uint32_t position_;
57 
58    private:
59     DISALLOW_COPY_AND_ASSIGN(Label);
60   };
61 
pc()62   uint32_t pc() const { return code_->code_offset(); }
63 
64   // GNU-assembler inspired names: https://sourceware.org/binutils/docs-2.42/as.html#g_t8byte
65   template <typename... Args>
Byte(Args...args)66   void Byte(Args... args) {
67     static_assert((std::is_same_v<Args, uint8_t> && ...));
68     (Emit8(args), ...);
69   }
70 
71   template <typename... Args>
TwoByte(Args...args)72   void TwoByte(Args... args) {
73     static_assert((std::is_same_v<Args, uint16_t> && ...));
74     (Emit16(args), ...);
75   }
76 
77   template <typename... Args>
FourByte(Args...args)78   void FourByte(Args... args) {
79     static_assert((std::is_same_v<Args, uint32_t> && ...));
80     (Emit32(args), ...);
81   }
82 
83   template <typename... Args>
EigthByte(Args...args)84   void EigthByte(Args... args) {
85     static_assert((std::is_same_v<Args, uint64_t> && ...));
86     (Emit64(args), ...);
87   }
88 
89   // Macro operations.
Emit8(uint8_t v)90   void Emit8(uint8_t v) { code_->AddU8(v); }
91 
Emit16(int16_t v)92   void Emit16(int16_t v) { code_->Add<int16_t>(v); }
93 
Emit32(int32_t v)94   void Emit32(int32_t v) { code_->Add<int32_t>(v); }
95 
Emit64(int64_t v)96   void Emit64(int64_t v) { code_->Add<int64_t>(v); }
97 
98   template <typename T>
EmitSequence(const T * v,uint32_t count)99   void EmitSequence(const T* v, uint32_t count) {
100     code_->AddSequence(v, sizeof(T) * count);
101   }
102 
Bind(Label * label)103   void Bind(Label* label) { label->Bind(pc()); }
104 
MakeLabel()105   Label* MakeLabel() { return NewInArena<Label>(code_->arena()); }
106 
SetRecoveryPoint(Label * recovery_label)107   void SetRecoveryPoint(Label* recovery_label) {
108     jumps_.push_back(Jump{recovery_label, pc(), true});
109   }
110 
111  protected:
112   template <typename T>
AddrAs(uint32_t offset)113   T* AddrAs(uint32_t offset) {
114     return code_->AddrAs<T>(offset);
115   }
116 
AddRelocation(uint32_t dst,RelocationType type,uint32_t pc,intptr_t data)117   void AddRelocation(uint32_t dst, RelocationType type, uint32_t pc, intptr_t data) {
118     code_->AddRelocation(dst, type, pc, data);
119   }
120 
121   // These are 'static' relocations, resolved when code is finalized.
122   // We also have 'dynamic' relocations, resolved when code is installed.
123   struct Jump {
124     const Label* label;
125     // Position of field to store offset.  Note: unless it's recovery label precomputed
126     // "distance from the end of instruction" is stored there.
127     //
128     // This is needed because we keep pointer to the rip-offset field while value stored
129     // there is counted from the end of instruction (on x86) or, sometimes, from the end
130     // of next instruction (ARM).
131     uint32_t pc;
132     bool is_recovery;
133   };
134   using JumpList = ArenaVector<Jump>;
135   JumpList jumps_;
136 
137  private:
138   MachineCode* code_;
139 
140   DISALLOW_IMPLICIT_CONSTRUCTORS(AssemblerBase);
141 };
142 
143 }  // namespace berberis
144 
145 #endif  // BERBERIS_ASSEMBLER_COMMON_H_
146