blob: b58e3dffbd665e2363e67d06a85264483ec22e9f [file] [log] [blame]
Vladimir Markob163bb72015-03-31 21:49:49 +01001/*
2 * Copyright (C) 2015 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 ART_COMPILER_LINKER_RELATIVE_PATCHER_H_
18#define ART_COMPILER_LINKER_RELATIVE_PATCHER_H_
19
20#include <vector>
21
22#include "arch/instruction_set.h"
23#include "arch/instruction_set_features.h"
David Brazdild9c90372016-09-14 16:53:55 +010024#include "base/array_ref.h"
Vladimir Markob163bb72015-03-31 21:49:49 +010025#include "base/macros.h"
David Sehr312f3b22018-03-19 08:39:26 -070026#include "dex/method_reference.h"
Vladimir Markob163bb72015-03-31 21:49:49 +010027
28namespace art {
29
30class CompiledMethod;
Vladimir Markob163bb72015-03-31 21:49:49 +010031
Vladimir Marko1b404a82017-09-01 13:35:26 +010032namespace debug {
33struct MethodDebugInfo;
34} // namespace debug
35
Vladimir Markob163bb72015-03-31 21:49:49 +010036namespace linker {
37
Vladimir Markod8dbc8d2017-09-20 13:37:47 +010038class LinkerPatch;
Vladimir Marko74527972016-11-29 15:57:32 +000039class OutputStream;
40
Vladimir Markob163bb72015-03-31 21:49:49 +010041/**
42 * @class RelativePatcherTargetProvider
43 * @brief Interface for providing method offsets for relative call targets.
44 */
45class RelativePatcherTargetProvider {
46 public:
47 /**
48 * Find the offset of the target method of a relative call if known.
49 *
50 * The process of assigning target method offsets includes calls to the relative patcher's
51 * ReserveSpace() which in turn can use FindMethodOffset() to determine if a method already
52 * has an offset assigned and, if so, what's that offset. If the offset has not yet been
53 * assigned or if it's too far for the particular architecture's relative call,
54 * ReserveSpace() may need to allocate space for a special dispatch thunk.
55 *
56 * @param ref the target method of the relative call.
57 * @return true in the first element of the pair if the method was found, false otherwise;
58 * if found, the second element specifies the offset.
59 */
60 virtual std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) = 0;
61
62 protected:
63 virtual ~RelativePatcherTargetProvider() { }
64};
65
66/**
67 * @class RelativePatcher
68 * @brief Interface for architecture-specific link-time patching of PC-relative references.
69 */
70class RelativePatcher {
71 public:
72 static std::unique_ptr<RelativePatcher> Create(
Vladimir Marko5806a9e2018-04-04 17:23:28 +000073 InstructionSet instruction_set, const InstructionSetFeatures* features,
74 RelativePatcherTargetProvider* provider);
Vladimir Markob163bb72015-03-31 21:49:49 +010075
76 virtual ~RelativePatcher() { }
77
78 uint32_t CodeAlignmentSize() const {
79 return size_code_alignment_;
80 }
81
82 uint32_t RelativeCallThunksSize() const {
83 return size_relative_call_thunks_;
84 }
85
86 uint32_t MiscThunksSize() const {
87 return size_misc_thunks_;
88 }
89
Vladimir Marko71b0ddf2015-04-02 19:45:06 +010090 // Reserve space for thunks if needed before a method, return adjusted offset.
Vladimir Marko944da602016-02-19 12:27:55 +000091 virtual uint32_t ReserveSpace(uint32_t offset,
92 const CompiledMethod* compiled_method,
Vladimir Marko4d23c9d2015-04-01 23:03:09 +010093 MethodReference method_ref) = 0;
Vladimir Markob163bb72015-03-31 21:49:49 +010094
Vladimir Marko71b0ddf2015-04-02 19:45:06 +010095 // Reserve space for thunks if needed after the last method, return adjusted offset.
Vladimir Marko944da602016-02-19 12:27:55 +000096 // The caller may use this method to preemptively force thunk space reservation and
97 // then resume reservation for more methods. This is useful when there is a gap in
98 // the .text segment, for example when going to the next oat file for multi-image.
Vladimir Marko71b0ddf2015-04-02 19:45:06 +010099 virtual uint32_t ReserveSpaceEnd(uint32_t offset) = 0;
100
Vladimir Marko944da602016-02-19 12:27:55 +0000101 // Write relative call thunks if needed, return adjusted offset. Returns 0 on write failure.
Vladimir Markob163bb72015-03-31 21:49:49 +0100102 virtual uint32_t WriteThunks(OutputStream* out, uint32_t offset) = 0;
103
104 // Patch method code. The input displacement is relative to the patched location,
105 // the patcher may need to adjust it if the correct base is different.
Vladimir Marko944da602016-02-19 12:27:55 +0000106 virtual void PatchCall(std::vector<uint8_t>* code,
107 uint32_t literal_offset,
108 uint32_t patch_offset,
109 uint32_t target_offset) = 0;
Vladimir Markob163bb72015-03-31 21:49:49 +0100110
111 // Patch a reference to a dex cache location.
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000112 virtual void PatchPcRelativeReference(std::vector<uint8_t>* code,
113 const LinkerPatch& patch,
114 uint32_t patch_offset,
115 uint32_t target_offset) = 0;
Vladimir Markob163bb72015-03-31 21:49:49 +0100116
Vladimir Markof4f2daa2017-03-20 18:26:59 +0000117 // Patch a branch to a Baker read barrier thunk.
118 virtual void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
119 const LinkerPatch& patch,
120 uint32_t patch_offset) = 0;
121
Vladimir Marko1b404a82017-09-01 13:35:26 +0100122 virtual std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(
123 uint32_t executable_offset) = 0;
124
Vladimir Markob163bb72015-03-31 21:49:49 +0100125 protected:
126 RelativePatcher()
127 : size_code_alignment_(0u),
128 size_relative_call_thunks_(0u),
129 size_misc_thunks_(0u) {
130 }
131
132 bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta);
Vladimir Markof4f2daa2017-03-20 18:26:59 +0000133 bool WriteThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
Vladimir Markob163bb72015-03-31 21:49:49 +0100134 bool WriteMiscThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
135
136 private:
137 uint32_t size_code_alignment_;
138 uint32_t size_relative_call_thunks_;
139 uint32_t size_misc_thunks_;
140
141 DISALLOW_COPY_AND_ASSIGN(RelativePatcher);
142};
143
144} // namespace linker
145} // namespace art
146
147#endif // ART_COMPILER_LINKER_RELATIVE_PATCHER_H_