1944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko/*
2944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Copyright (C) 2016 The Android Open Source Project
3944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko *
4944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Licensed under the Apache License, Version 2.0 (the "License");
5944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * you may not use this file except in compliance with the License.
6944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * You may obtain a copy of the License at
7944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko *
8944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko *      http://www.apache.org/licenses/LICENSE-2.0
9944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko *
10944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * Unless required by applicable law or agreed to in writing, software
11944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * distributed under the License is distributed on an "AS IS" BASIS,
12944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * See the License for the specific language governing permissions and
14944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko * limitations under the License.
15944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko */
16944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
17944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#ifndef ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
18944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#define ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
19944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
20944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "arch/instruction_set.h"
21944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "method_reference.h"
22944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "relative_patcher.h"
23944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#include "safe_map.h"
24944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
25944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markonamespace art {
26944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
27944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass CompiledMethod;
28944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass LinkerPatch;
29944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass InstructionSetFeatures;
30944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
31944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markonamespace linker {
32944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
33944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko// MultiOatRelativePatcher is a helper class for handling patching across
34944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko// any number of oat files. It provides storage for method code offsets
35944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko// and wraps RelativePatcher calls, adjusting relative offsets according
36944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko// to the value set by SetAdjustment().
37944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Markoclass MultiOatRelativePatcher FINAL {
38944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko public:
39944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  using const_iterator =
40944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      SafeMap<MethodReference, uint32_t, MethodReferenceComparator>::const_iterator;
41944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
42944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MultiOatRelativePatcher(InstructionSet instruction_set, const InstructionSetFeatures* features);
43944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
44944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Mark the start of a new oat file (for statistics retrieval) and set the
45944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // adjustment for a new oat file to apply to all relative offsets that are
46944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // passed to the MultiOatRelativePatcher.
47944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  //
48944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // The adjustment should be the global offset of the base from which relative
49944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // offsets are calculated, such as the start of .rodata for the current oat file.
50944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // It must must never point directly to a method's code to avoid relative offsets
51944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // with value 0 because this value is used as a missing offset indication in
52944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // GetOffset() and an error indication in WriteThunks(). Additionally, it must be
53944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // page-aligned, so that it does not skew alignment calculations, say arm64 ADRP.
54944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  void StartOatFile(uint32_t adjustment);
55944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
56944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Get relative offset. Returns 0 when the offset has not been set yet.
57944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t GetOffset(MethodReference method_ref) {
58944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    auto it = method_offset_map_.map.find(method_ref);
59944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    return (it != method_offset_map_.map.end()) ? it->second - adjustment_ : 0u;
60944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
61944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
62944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Set the offset.
63944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  void SetOffset(MethodReference method_ref, uint32_t offset) {
64944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    method_offset_map_.map.Put(method_ref, offset + adjustment_);
65944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
66944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
67944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Wrapper around RelativePatcher::ReserveSpace(), doing offset adjustment.
68944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t ReserveSpace(uint32_t offset,
69944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                        const CompiledMethod* compiled_method,
70944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                        MethodReference method_ref) {
71944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    offset += adjustment_;
72944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    offset = relative_patcher_->ReserveSpace(offset, compiled_method, method_ref);
73944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    offset -= adjustment_;
74944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    return offset;
75944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
76944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
77944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Wrapper around RelativePatcher::ReserveSpaceEnd(), doing offset adjustment.
78944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t ReserveSpaceEnd(uint32_t offset) {
79944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    offset += adjustment_;
80944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    offset = relative_patcher_->ReserveSpaceEnd(offset);
81944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    offset -= adjustment_;
82944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    return offset;
83944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
84944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
85944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Wrapper around RelativePatcher::WriteThunks(), doing offset adjustment.
86944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t WriteThunks(OutputStream* out, uint32_t offset) {
87944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    offset += adjustment_;
88944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    offset = relative_patcher_->WriteThunks(out, offset);
89944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    if (offset != 0u) {  // 0u indicates write error.
90944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko      offset -= adjustment_;
91944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    }
92944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    return offset;
93944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
94944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
95944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Wrapper around RelativePatcher::PatchCall(), doing offset adjustment.
96944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  void PatchCall(std::vector<uint8_t>* code,
97944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                 uint32_t literal_offset,
98944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                 uint32_t patch_offset,
99944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko                 uint32_t target_offset) {
100944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    patch_offset += adjustment_;
101944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    target_offset += adjustment_;
102944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    relative_patcher_->PatchCall(code, literal_offset, patch_offset, target_offset);
103944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
104944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
105944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Wrapper around RelativePatcher::PatchDexCacheReference(), doing offset adjustment.
106cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko  void PatchPcRelativeReference(std::vector<uint8_t>* code,
107cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                const LinkerPatch& patch,
108cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                uint32_t patch_offset,
109cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko                                uint32_t target_offset) {
110944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    patch_offset += adjustment_;
111944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    target_offset += adjustment_;
112cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko    relative_patcher_->PatchPcRelativeReference(code, patch, patch_offset, target_offset);
113944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  }
114944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
115944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Wrappers around RelativePatcher for statistics retrieval.
116944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t CodeAlignmentSize() const;
117944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t RelativeCallThunksSize() const;
118944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t MiscThunksSize() const;
119944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
120944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko private:
121944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Map method reference to assigned offset.
122944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  // Wrap the map in a class implementing linker::RelativePatcherTargetProvider.
123944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  class MethodOffsetMap : public linker::RelativePatcherTargetProvider {
124944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko   public:
125944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) OVERRIDE;
126944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko    SafeMap<MethodReference, uint32_t, MethodReferenceComparator> map;
127944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  };
128944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
129944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  MethodOffsetMap method_offset_map_;
130944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  std::unique_ptr<RelativePatcher> relative_patcher_;
131944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t adjustment_;
132944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  InstructionSet instruction_set_;
133944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
134944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t start_size_code_alignment_;
135944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t start_size_relative_call_thunks_;
136944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  uint32_t start_size_misc_thunks_;
137944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
138944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  friend class MultiOatRelativePatcherTest;
139944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
140944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko  DISALLOW_COPY_AND_ASSIGN(MultiOatRelativePatcher);
141944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko};
142944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
143944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}  // namespace linker
144944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko}  // namespace art
145944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko
146944da603cde59a4277f3bbc31d860a90842a1a2aVladimir Marko#endif  // ART_COMPILER_LINKER_MULTI_OAT_RELATIVE_PATCHER_H_
147