• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 #include "trampoline_compiler.h"
18 
19 #include "jni_internal.h"
20 #include "utils/arm/assembler_arm.h"
21 #include "utils/arm64/assembler_arm64.h"
22 #include "utils/mips/assembler_mips.h"
23 #include "utils/x86/assembler_x86.h"
24 #include "utils/x86_64/assembler_x86_64.h"
25 
26 #define __ assembler->
27 
28 namespace art {
29 
30 namespace arm {
CreateTrampoline(EntryPointCallingConvention abi,ThreadOffset<4> offset)31 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
32                                                     ThreadOffset<4> offset) {
33   std::unique_ptr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kThumb2)));
34 
35   switch (abi) {
36     case kInterpreterAbi:  // Thread* is first argument (R0) in interpreter ABI.
37       __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
38       break;
39     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (R0).
40       __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset().Int32Value());
41       __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
42       break;
43     case kPortableAbi:  // R9 holds Thread*.
44     case kQuickAbi:  // Fall-through.
45       __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
46   }
47   __ bkpt(0);
48 
49   size_t cs = assembler->CodeSize();
50   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
51   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
52   assembler->FinalizeInstructions(code);
53 
54   return entry_stub.release();
55 }
56 }  // namespace arm
57 
58 namespace arm64 {
CreateTrampoline(EntryPointCallingConvention abi,ThreadOffset<8> offset)59 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
60                                                     ThreadOffset<8> offset) {
61   std::unique_ptr<Arm64Assembler> assembler(static_cast<Arm64Assembler*>(Assembler::Create(kArm64)));
62 
63   switch (abi) {
64     case kInterpreterAbi:  // Thread* is first argument (X0) in interpreter ABI.
65       __ JumpTo(Arm64ManagedRegister::FromCoreRegister(X0), Offset(offset.Int32Value()),
66           Arm64ManagedRegister::FromCoreRegister(IP1));
67 
68       break;
69     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (X0).
70       __ LoadRawPtr(Arm64ManagedRegister::FromCoreRegister(IP1),
71                       Arm64ManagedRegister::FromCoreRegister(X0),
72                       Offset(JNIEnvExt::SelfOffset().Int32Value()));
73 
74       __ JumpTo(Arm64ManagedRegister::FromCoreRegister(IP1), Offset(offset.Int32Value()),
75                 Arm64ManagedRegister::FromCoreRegister(IP0));
76 
77       break;
78     case kPortableAbi:  // X18 holds Thread*.
79     case kQuickAbi:  // Fall-through.
80       __ JumpTo(Arm64ManagedRegister::FromCoreRegister(TR), Offset(offset.Int32Value()),
81                 Arm64ManagedRegister::FromCoreRegister(IP0));
82 
83       break;
84   }
85 
86   size_t cs = assembler->CodeSize();
87   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
88   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
89   assembler->FinalizeInstructions(code);
90 
91   return entry_stub.release();
92 }
93 }  // namespace arm64
94 
95 namespace mips {
CreateTrampoline(EntryPointCallingConvention abi,ThreadOffset<4> offset)96 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
97                                                     ThreadOffset<4> offset) {
98   std::unique_ptr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
99 
100   switch (abi) {
101     case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
102       __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
103       break;
104     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
105       __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
106       __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
107       break;
108     case kPortableAbi:  // S1 holds Thread*.
109     case kQuickAbi:  // Fall-through.
110       __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
111   }
112   __ Jr(T9);
113   __ Nop();
114   __ Break();
115 
116   size_t cs = assembler->CodeSize();
117   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
118   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
119   assembler->FinalizeInstructions(code);
120 
121   return entry_stub.release();
122 }
123 }  // namespace mips
124 
125 namespace x86 {
CreateTrampoline(ThreadOffset<4> offset)126 static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
127   std::unique_ptr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
128 
129   // All x86 trampolines call via the Thread* held in fs.
130   __ fs()->jmp(Address::Absolute(offset));
131   __ int3();
132 
133   size_t cs = assembler->CodeSize();
134   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
135   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
136   assembler->FinalizeInstructions(code);
137 
138   return entry_stub.release();
139 }
140 }  // namespace x86
141 
142 namespace x86_64 {
CreateTrampoline(ThreadOffset<8> offset)143 static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<8> offset) {
144   std::unique_ptr<x86_64::X86_64Assembler>
145       assembler(static_cast<x86_64::X86_64Assembler*>(Assembler::Create(kX86_64)));
146 
147   // All x86 trampolines call via the Thread* held in gs.
148   __ gs()->jmp(x86_64::Address::Absolute(offset, true));
149   __ int3();
150 
151   size_t cs = assembler->CodeSize();
152   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
153   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
154   assembler->FinalizeInstructions(code);
155 
156   return entry_stub.release();
157 }
158 }  // namespace x86_64
159 
CreateTrampoline64(InstructionSet isa,EntryPointCallingConvention abi,ThreadOffset<8> offset)160 const std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, EntryPointCallingConvention abi,
161                                                ThreadOffset<8> offset) {
162   switch (isa) {
163     case kArm64:
164       return arm64::CreateTrampoline(abi, offset);
165     case kX86_64:
166       return x86_64::CreateTrampoline(offset);
167     default:
168       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
169       return nullptr;
170   }
171 }
172 
CreateTrampoline32(InstructionSet isa,EntryPointCallingConvention abi,ThreadOffset<4> offset)173 const std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, EntryPointCallingConvention abi,
174                                                ThreadOffset<4> offset) {
175   switch (isa) {
176     case kArm:
177     case kThumb2:
178       return arm::CreateTrampoline(abi, offset);
179     case kMips:
180       return mips::CreateTrampoline(abi, offset);
181     case kX86:
182       return x86::CreateTrampoline(offset);
183     default:
184       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
185       return nullptr;
186   }
187 }
188 
189 }  // namespace art
190