1b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko/*
2b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * Copyright (C) 2015 The Android Open Source Project
3b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko *
4b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * Licensed under the Apache License, Version 2.0 (the "License");
5b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * you may not use this file except in compliance with the License.
6b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * You may obtain a copy of the License at
7b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko *
8b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko *      http://www.apache.org/licenses/LICENSE-2.0
9b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko *
10b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * Unless required by applicable law or agreed to in writing, software
11b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * distributed under the License is distributed on an "AS IS" BASIS,
12b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * See the License for the specific language governing permissions and
14b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * limitations under the License.
15b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko */
16b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
17b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#ifndef ART_COMPILER_LINKER_RELATIVE_PATCHER_H_
18b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#define ART_COMPILER_LINKER_RELATIVE_PATCHER_H_
19b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
20b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#include <vector>
21b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
22b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#include "arch/instruction_set.h"
23b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#include "arch/instruction_set_features.h"
24b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#include "base/macros.h"
25b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#include "method_reference.h"
26b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#include "utils/array_ref.h"
27b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
28b163bb742a099c1808907b513ae39068b63b1692Vladimir Markonamespace art {
29b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
30b163bb742a099c1808907b513ae39068b63b1692Vladimir Markoclass CompiledMethod;
31b163bb742a099c1808907b513ae39068b63b1692Vladimir Markoclass LinkerPatch;
32b163bb742a099c1808907b513ae39068b63b1692Vladimir Markoclass OutputStream;
33b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
34b163bb742a099c1808907b513ae39068b63b1692Vladimir Markonamespace linker {
35b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
36b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko/**
37b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * @class RelativePatcherTargetProvider
38b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * @brief Interface for providing method offsets for relative call targets.
39b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko */
40b163bb742a099c1808907b513ae39068b63b1692Vladimir Markoclass RelativePatcherTargetProvider {
41b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko public:
42b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  /**
43b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   * Find the offset of the target method of a relative call if known.
44b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   *
45b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   * The process of assigning target method offsets includes calls to the relative patcher's
46b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   * ReserveSpace() which in turn can use FindMethodOffset() to determine if a method already
47b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   * has an offset assigned and, if so, what's that offset. If the offset has not yet been
48b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   * assigned or if it's too far for the particular architecture's relative call,
49b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   * ReserveSpace() may need to allocate space for a special dispatch thunk.
50b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   *
51b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   * @param ref the target method of the relative call.
52b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   * @return true in the first element of the pair if the method was found, false otherwise;
53b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   *         if found, the second element specifies the offset.
54b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko   */
55b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  virtual std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) = 0;
56b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
57b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko protected:
58b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  virtual ~RelativePatcherTargetProvider() { }
59b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko};
60b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
61b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko/**
62b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * @class RelativePatcher
63b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko * @brief Interface for architecture-specific link-time patching of PC-relative references.
64b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko */
65b163bb742a099c1808907b513ae39068b63b1692Vladimir Markoclass RelativePatcher {
66b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko public:
67b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  static std::unique_ptr<RelativePatcher> Create(
68b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko      InstructionSet instruction_set, const InstructionSetFeatures* features,
69b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko      RelativePatcherTargetProvider* provider);
70b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
71b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  virtual ~RelativePatcher() { }
72b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
73b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  uint32_t CodeAlignmentSize() const {
74b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko    return size_code_alignment_;
75b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  }
76b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
77b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  uint32_t RelativeCallThunksSize() const {
78b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko    return size_relative_call_thunks_;
79b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  }
80b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
81b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  uint32_t MiscThunksSize() const {
82b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko    return size_misc_thunks_;
83b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  }
84b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
8571b0ddf988208c9f77e7d2c1e75066cc3fe20c61Vladimir Marko  // Reserve space for thunks if needed before a method, return adjusted offset.
86944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  virtual uint32_t ReserveSpace(uint32_t offset,
87944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                                const CompiledMethod* compiled_method,
884d23c9d01b7a609813345eec95167a4dbc4fbae4Vladimir Marko                                MethodReference method_ref) = 0;
89b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
9071b0ddf988208c9f77e7d2c1e75066cc3fe20c61Vladimir Marko  // Reserve space for thunks if needed after the last method, return adjusted offset.
91944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // The caller may use this method to preemptively force thunk space reservation and
92944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // then resume reservation for more methods. This is useful when there is a gap in
93944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // the .text segment, for example when going to the next oat file for multi-image.
9471b0ddf988208c9f77e7d2c1e75066cc3fe20c61Vladimir Marko  virtual uint32_t ReserveSpaceEnd(uint32_t offset) = 0;
9571b0ddf988208c9f77e7d2c1e75066cc3fe20c61Vladimir Marko
96944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Write relative call thunks if needed, return adjusted offset. Returns 0 on write failure.
97b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  virtual uint32_t WriteThunks(OutputStream* out, uint32_t offset) = 0;
98b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
99b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  // Patch method code. The input displacement is relative to the patched location,
100b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  // the patcher may need to adjust it if the correct base is different.
101944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  virtual void PatchCall(std::vector<uint8_t>* code,
102944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                         uint32_t literal_offset,
103944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                         uint32_t patch_offset,
104944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                         uint32_t target_offset) = 0;
105b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
106b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  // Patch a reference to a dex cache location.
107cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko  virtual void PatchPcRelativeReference(std::vector<uint8_t>* code,
108cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                        const LinkerPatch& patch,
109cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                        uint32_t patch_offset,
110cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                        uint32_t target_offset) = 0;
111b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
112b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko protected:
113b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  RelativePatcher()
114b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko      : size_code_alignment_(0u),
115b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko        size_relative_call_thunks_(0u),
116b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko        size_misc_thunks_(0u) {
117b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  }
118b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
119b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta);
120b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  bool WriteRelCallThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
121b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  bool WriteMiscThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
122b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
123b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko private:
124b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  uint32_t size_code_alignment_;
125b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  uint32_t size_relative_call_thunks_;
126b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  uint32_t size_misc_thunks_;
127b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
128b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko  DISALLOW_COPY_AND_ASSIGN(RelativePatcher);
129b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko};
130b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
131b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko}  // namespace linker
132b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko}  // namespace art
133b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko
134b163bb742a099c1808907b513ae39068b63b1692Vladimir Marko#endif  // ART_COMPILER_LINKER_RELATIVE_PATCHER_H_
135