1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/deoptimizer/relocator.h"
17 #include <climits>
18 #include <iomanip>
19 #include "ecmascript/compiler/assembler/aarch64/assembler_aarch64_constants.h"
20 #include "ecmascript/message_string.h"
21 #if !WIN_OR_MAC_OR_IOS_PLATFORM
22
23 namespace panda::ecmascript {
GetSymbol(const char * symbol) const24 std::optional<Elf64_Word> Relocator::GetSymbol(const char* symbol) const
25 {
26 ASSERT(symAndStrTabInfo_.symSize_ % sizeof(Elf64_Sym) == 0);
27 int n = symAndStrTabInfo_.symSize_ / sizeof(Elf64_Sym);
28 ASSERT(symAndStrTabInfo_.symAddr_ > 0 && symAndStrTabInfo_.symSize_ > 0);
29 Elf64_Sym *ptr = reinterpret_cast<Elf64_Sym *>(symAndStrTabInfo_.symAddr_);
30 for (int i = 0; i < n; i++) {
31 Elf64_Sym *cur = ptr + i;
32 const char *name = reinterpret_cast<char *>(symAndStrTabInfo_.strAddr_) + cur->st_name;
33 if (std::strcmp(symbol, name) == 0) {
34 return static_cast<Elf64_Word>(i);
35 }
36 }
37 return std::nullopt;
38 }
39
Relocate(Elf64_Rela * sec,uintptr_t symbolAddr,uintptr_t patchAddr)40 bool Relocator::Relocate(Elf64_Rela *sec, uintptr_t symbolAddr, uintptr_t patchAddr)
41 {
42 bool ret = false;
43 ASSERT(reinterpret_cast<intptr_t>(sec) > 0);
44 Elf64_Word type = GetType(sec);
45 Elf64_Sxword addend = sec->r_addend;
46
47 switch (type) {
48 case R_AARCH64_CALL26: {
49 /* S + A - P
50 S: (when used on its own) is the address of the symbol
51 A: is the addend for the relocation
52 P: is the address of the place beging relocated(derived from r_offset)
53 */
54 intptr_t imm = patchAddr + addend - symbolAddr;
55 ASSERT(-(1 << 27) <= imm && imm < (1 << 27)); // 27: "Check that -2^27 <= result < 2^27".
56 imm = (imm & 0x0FFFFFFC) >> 2; // 0x0FFFFFFC: get immediate file to bits [27:2]
57 *(reinterpret_cast<uint32_t *>(symbolAddr)) = imm | panda::ecmascript::aarch64::CallOpCode::BL;
58 break;
59 }
60 case R_X86_64_PLT32: {
61 /* S + A - P
62 S: (when used on its own) is the address of the symbol
63 A: is the addend for the relocation
64 P: is the address of the place beging relocated(derived from r_offset)
65 */
66 intptr_t v = patchAddr + addend - symbolAddr;
67 ASSERT((v >= INT_MIN) && (v <= INT_MAX));
68 *(reinterpret_cast<uint32_t *>(symbolAddr)) = v;
69 ret = true;
70 break;
71 }
72 default: {
73 LOG_COMPILER(FATAL) << " unsupported type:" << type;
74 return false;
75 }
76 }
77 return ret;
78 }
79
HasSymStrTable() const80 bool Relocator::HasSymStrTable() const
81 {
82 return (symAndStrTabInfo_.symAddr_ >= 0) && (symAndStrTabInfo_.symSize_ >= 0)
83 && (symAndStrTabInfo_.strAddr_ >= 0) && (symAndStrTabInfo_.strSize_ >= 0);
84 }
85
HasRelocateText() const86 bool Relocator::HasRelocateText() const
87 {
88 return (relocateTextInfo_.relaTextAddr_ > 0) && (relocateTextInfo_.relaTextSize_ > 0);
89 }
90
RelocateBySymbolId(Elf64_Word symbolId,uintptr_t patchAddr)91 bool Relocator::RelocateBySymbolId(Elf64_Word symbolId, uintptr_t patchAddr)
92 {
93 bool ret = false;
94 ASSERT(relocateTextInfo_.relaTextSize_ % sizeof(Elf64_Rela) == 0);
95 ASSERT(relocateTextInfo_.relaTextAddr_ > 0 && relocateTextInfo_.relaTextSize_ > 0);
96 size_t n = relocateTextInfo_.relaTextSize_ / sizeof(Elf64_Rela);
97 Elf64_Rela *ptr = reinterpret_cast<Elf64_Rela *>(relocateTextInfo_.relaTextAddr_);
98 for (size_t i = 0; i < n; i++) {
99 Elf64_Rela *cur = ptr + i;
100 Elf64_Word id = GetSymbol(cur);
101 intptr_t symbolAddr = relocateTextInfo_.textAddr_ + static_cast<uintptr_t>(cur->r_offset);
102 if (id == symbolId) {
103 ret = Relocate(cur, symbolAddr, patchAddr);
104 }
105 }
106 return ret;
107 }
108
RelocateBySymbol(const char * symbol,uintptr_t patchAddr)109 bool Relocator::RelocateBySymbol(const char* symbol, uintptr_t patchAddr)
110 {
111 if (!HasSymStrTable()) {
112 return false;
113 }
114 auto symId = GetSymbol(symbol);
115 if (!symId.has_value()) {
116 LOG_COMPILER(DEBUG) << " don't find symbol:" << symbol << " in symbol table.";
117 return false;
118 }
119 bool ret = RelocateBySymbolId(symId.value(), patchAddr);
120 return ret;
121 }
122
DumpRelocateText()123 void Relocator::DumpRelocateText()
124 {
125 if (!HasRelocateText()) {
126 LOG_COMPILER(ERROR) << " input valid relocateText addr & size:";
127 return;
128 }
129 ASSERT(relocateTextInfo_.relaTextSize_ % sizeof(Elf64_Rela) == 0);
130 ASSERT(relocateTextInfo_.relaTextAddr_ > 0 && relocateTextInfo_.relaTextSize_ > 0);
131 size_t n = relocateTextInfo_.relaTextSize_ / sizeof(Elf64_Rela);
132 Elf64_Rela *ptr = reinterpret_cast<Elf64_Rela *>(relocateTextInfo_.relaTextAddr_);
133 static constexpr int leftAdjustment = 12;
134 LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << "symbolId "
135 << std::left << std::setw(leftAdjustment) << "Info(0x): "
136 << std::left << std::setw(leftAdjustment) << "Type: "
137 << std::left << std::setw(leftAdjustment) << "r_offset(0x): "
138 << std::left << std::setw(leftAdjustment) << "addend: ";
139 for (size_t i = 0; i < n; i++) {
140 Elf64_Rela *cur = ptr + i;
141 Elf64_Word id = GetSymbol(cur);
142 Elf64_Word type = GetType(cur);
143 Elf64_Sxword addend = ptr->r_addend;
144 LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << id
145 << std::left << std::setw(leftAdjustment) << std::hex << cur->r_info
146 << std::left << std::setw(leftAdjustment) << std::dec << type
147 << std::left << std::setw(leftAdjustment) << std::hex << static_cast<intptr_t>(cur->r_offset)
148 << std::left << std::setw(leftAdjustment) << std::dec << static_cast<intptr_t>(addend);
149 }
150 if (!HasSymStrTable()) {
151 return;
152 }
153 ASSERT(symAndStrTabInfo_.symSize_ % sizeof(Elf64_Sym) == 0);
154 n = symAndStrTabInfo_.symSize_ / sizeof(Elf64_Sym);
155 ASSERT(symAndStrTabInfo_.symAddr_ > 0 && symAndStrTabInfo_.symSize_ > 0);
156 Elf64_Sym *symPtr = reinterpret_cast<Elf64_Sym *>(symAndStrTabInfo_.symAddr_);
157 LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << "symbolId "
158 << std::left << std::setw(leftAdjustment) << "binding: "
159 << std::left << std::setw(leftAdjustment) << "Type: "
160 << std::left << std::setw(leftAdjustment) << "st_name: "
161 << std::left << std::setw(leftAdjustment) << "name: ";
162 for (size_t i = 0; i < n; i++) {
163 Elf64_Sym *cur = symPtr + i;
164 const char *name = reinterpret_cast<char *>(symAndStrTabInfo_.strAddr_) + cur->st_name;
165 unsigned char binding = GetBinding(cur);
166 unsigned char type = GetType(cur);
167 LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << i
168 << std::left << std::setw(leftAdjustment) << std::dec << static_cast<int>(binding)
169 << std::left << std::setw(leftAdjustment) << std::dec << static_cast<int>(type)
170 << std::left << std::setw(leftAdjustment) << std::dec << cur->st_name
171 << std::left << std::setw(leftAdjustment) << name;
172 }
173 }
174 } // namespace panda::ecmascript
175 #endif