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 if (BlInRange(imm)) {
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 ret = true;
59 }
60 break;
61 }
62 case R_X86_64_PLT32: {
63 /* S + A - P
64 S: (when used on its own) is the address of the symbol
65 A: is the addend for the relocation
66 P: is the address of the place beging relocated(derived from r_offset)
67 */
68 intptr_t v = patchAddr + addend - symbolAddr;
69 ASSERT((v >= INT_MIN) && (v <= INT_MAX));
70 *(reinterpret_cast<uint32_t *>(symbolAddr)) = v;
71 ret = true;
72 break;
73 }
74 default: {
75 LOG_COMPILER(FATAL) << " unsupported type:" << type;
76 return false;
77 }
78 }
79 return ret;
80 }
81
HasSymStrTable() const82 bool Relocator::HasSymStrTable() const
83 {
84 return (symAndStrTabInfo_.symAddr_ >= 0) && (symAndStrTabInfo_.symSize_ >= 0)
85 && (symAndStrTabInfo_.strAddr_ >= 0) && (symAndStrTabInfo_.strSize_ >= 0);
86 }
87
HasRelocateText() const88 bool Relocator::HasRelocateText() const
89 {
90 return (relocateTextInfo_.relaTextAddr_ > 0) && (relocateTextInfo_.relaTextSize_ > 0);
91 }
92
RelocateBySymbolId(Elf64_Word symbolId,uintptr_t patchAddr)93 bool Relocator::RelocateBySymbolId(Elf64_Word symbolId, uintptr_t patchAddr)
94 {
95 bool ret = false;
96 ASSERT(relocateTextInfo_.relaTextSize_ % sizeof(Elf64_Rela) == 0);
97 ASSERT(relocateTextInfo_.relaTextAddr_ > 0 && relocateTextInfo_.relaTextSize_ > 0);
98 size_t n = relocateTextInfo_.relaTextSize_ / sizeof(Elf64_Rela);
99 Elf64_Rela *ptr = reinterpret_cast<Elf64_Rela *>(relocateTextInfo_.relaTextAddr_);
100 for (size_t i = 0; i < n; i++) {
101 Elf64_Rela *cur = ptr + i;
102 Elf64_Word id = GetSymbol(cur);
103 intptr_t symbolAddr = relocateTextInfo_.textAddr_ + static_cast<uintptr_t>(cur->r_offset);
104 if (id == symbolId) {
105 ret = Relocate(cur, symbolAddr, patchAddr);
106 }
107 }
108 return ret;
109 }
110
RelocateBySymbol(const char * symbol,uintptr_t patchAddr)111 bool Relocator::RelocateBySymbol(const char* symbol, uintptr_t patchAddr)
112 {
113 if (!HasSymStrTable()) {
114 return false;
115 }
116 auto symId = GetSymbol(symbol);
117 if (!symId.has_value()) {
118 LOG_COMPILER(DEBUG) << " don't find symbol:" << symbol << " in symbol table.";
119 return false;
120 }
121 bool ret = RelocateBySymbolId(symId.value(), patchAddr);
122 return ret;
123 }
124
DumpRelocateText()125 void Relocator::DumpRelocateText()
126 {
127 if (!HasRelocateText()) {
128 LOG_COMPILER(ERROR) << " input valid relocateText addr & size:";
129 return;
130 }
131 ASSERT(relocateTextInfo_.relaTextSize_ % sizeof(Elf64_Rela) == 0);
132 ASSERT(relocateTextInfo_.relaTextAddr_ > 0 && relocateTextInfo_.relaTextSize_ > 0);
133 size_t n = relocateTextInfo_.relaTextSize_ / sizeof(Elf64_Rela);
134 Elf64_Rela *ptr = reinterpret_cast<Elf64_Rela *>(relocateTextInfo_.relaTextAddr_);
135 static constexpr int leftAdjustment = 12;
136 LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << "symbolId "
137 << std::left << std::setw(leftAdjustment) << "Info(0x): "
138 << std::left << std::setw(leftAdjustment) << "Type: "
139 << std::left << std::setw(leftAdjustment) << "r_offset(0x): "
140 << std::left << std::setw(leftAdjustment) << "addend: ";
141 for (size_t i = 0; i < n; i++) {
142 Elf64_Rela *cur = ptr + i;
143 Elf64_Word id = GetSymbol(cur);
144 Elf64_Word type = GetType(cur);
145 Elf64_Sxword addend = ptr->r_addend;
146 LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << id
147 << std::left << std::setw(leftAdjustment) << std::hex << cur->r_info
148 << std::left << std::setw(leftAdjustment) << std::dec << type
149 << std::left << std::setw(leftAdjustment) << std::hex << static_cast<intptr_t>(cur->r_offset)
150 << std::left << std::setw(leftAdjustment) << std::dec << static_cast<intptr_t>(addend);
151 }
152 if (!HasSymStrTable()) {
153 return;
154 }
155 ASSERT(symAndStrTabInfo_.symSize_ % sizeof(Elf64_Sym) == 0);
156 n = symAndStrTabInfo_.symSize_ / sizeof(Elf64_Sym);
157 ASSERT(symAndStrTabInfo_.symAddr_ > 0 && symAndStrTabInfo_.symSize_ > 0);
158 Elf64_Sym *symPtr = reinterpret_cast<Elf64_Sym *>(symAndStrTabInfo_.symAddr_);
159 LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << "symbolId "
160 << std::left << std::setw(leftAdjustment) << "binding: "
161 << std::left << std::setw(leftAdjustment) << "Type: "
162 << std::left << std::setw(leftAdjustment) << "st_name: "
163 << std::left << std::setw(leftAdjustment) << "name: ";
164 for (size_t i = 0; i < n; i++) {
165 Elf64_Sym *cur = symPtr + i;
166 const char *name = reinterpret_cast<char *>(symAndStrTabInfo_.strAddr_) + cur->st_name;
167 unsigned char binding = GetBinding(cur);
168 unsigned char type = GetType(cur);
169 LOG_COMPILER(DEBUG) << std::left << std::setw(leftAdjustment) << i
170 << std::left << std::setw(leftAdjustment) << std::dec << static_cast<int>(binding)
171 << std::left << std::setw(leftAdjustment) << std::dec << static_cast<int>(type)
172 << std::left << std::setw(leftAdjustment) << std::dec << cur->st_name
173 << std::left << std::setw(leftAdjustment) << name;
174 }
175 }
176
BlInRange(intptr_t imm)177 bool Relocator::BlInRange(intptr_t imm)
178 {
179 return -(1 << 27) <= imm && imm < (1 << 27);
180 }
181 } // namespace panda::ecmascript
182 #endif
183