1 /* 2 * Copyright (c) 2023 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 #ifndef MAPLEBE_INCLUDE_CG_OBJ_EMIT_H 17 #define MAPLEBE_INCLUDE_CG_OBJ_EMIT_H 18 19 #include "emit.h" 20 #include "ifile.h" 21 #include "string_utils.h" 22 #ifdef JIT_ENABLE_CODE_SIGN 23 #include "jit_buffer_integrity.h" 24 #include "jit_signcode.h" 25 #endif 26 27 namespace maplebe { 28 #ifdef JIT_ENABLE_CODE_SIGN 29 using namespace OHOS::Security::CodeSign; 30 using namespace panda::ecmascript::kungfu; 31 #endif 32 enum FixupKind : uint32 { 33 kFKNone, 34 kExceptFixup, 35 kEhTypeDefFixup, 36 kEhTypeUndefFixup, 37 kFirstTargetFixupKind = 64, /* the kind in subclass start from 64 */ 38 }; 39 40 class Fixup { 41 public: Fixup(const std::string & label,uint32 relOffsetVal,uint32 offsetVal,FixupKind fixupKind)42 Fixup(const std::string &label, uint32 relOffsetVal, uint32 offsetVal, FixupKind fixupKind) 43 : labelName(label), relOffset(relOffsetVal), offset(offsetVal), kind(fixupKind) 44 { 45 } 46 47 ~Fixup() = default; 48 GetLabel()49 const std::string &GetLabel() const 50 { 51 return labelName; 52 } 53 GetRelOffset()54 uint32 GetRelOffset() const 55 { 56 return relOffset; 57 } 58 SetOffset(uint32 value)59 void SetOffset(uint32 value) 60 { 61 offset = value; 62 } 63 GetOffset()64 uint32 GetOffset() const 65 { 66 return offset; 67 } 68 GetFixupKind()69 FixupKind GetFixupKind() const 70 { 71 return kind; 72 } 73 74 private: 75 std::string labelName; /* target label name */ 76 uint32 relOffset; /* offset to target label */ 77 uint32 offset; /* record where to fix up */ 78 FixupKind kind; /* record how to fix up */ 79 }; 80 81 class LocalFixup { 82 public: LocalFixup(uint32 label,uint32 offsetVal,FixupKind fixupkind)83 LocalFixup(uint32 label, uint32 offsetVal, FixupKind fixupkind) 84 : labelIndex(label), offset(offsetVal), kind(fixupkind) 85 { 86 } 87 88 ~LocalFixup() = default; 89 GetLabelIndex()90 uint32 GetLabelIndex() const 91 { 92 return labelIndex; 93 } 94 GetOffset()95 uint32 GetOffset() const 96 { 97 return offset; 98 } 99 GetFixupKind()100 FixupKind GetFixupKind() const 101 { 102 return kind; 103 } 104 105 private: 106 uint32 labelIndex; /* target label index */ 107 uint32 offset; /* record where to fix up */ 108 FixupKind kind; /* record how to fix up */ 109 }; 110 111 enum SymbolKind : uint32 { 112 kStFunc, 113 kStNone, 114 }; 115 116 class ObjSymbol { 117 public: ObjSymbol(const std::string & name,SymbolKind kind,uint32 pos)118 ObjSymbol(const std::string &name, SymbolKind kind, uint32 pos) : symbolName(name), symbolKind(kind), offset(pos) {} 119 ~ObjSymbol() = default; 120 GetSymbolName()121 std::string GetSymbolName() const 122 { 123 return symbolName; 124 } 125 GetSymbolKind()126 SymbolKind GetSymbolKind() const 127 { 128 return symbolKind; 129 } 130 GetOffset()131 uint32 GetOffset() const 132 { 133 return offset; 134 } 135 136 private: 137 std::string symbolName; 138 SymbolKind symbolKind; 139 uint32 offset; 140 }; 141 142 class ObjFuncEmitInfo : public FuncEmitInfo { 143 public: ObjFuncEmitInfo(CGFunc & func,MemPool & inputMemPool)144 ObjFuncEmitInfo(CGFunc &func, MemPool &inputMemPool) 145 : FuncEmitInfo(func), 146 memPool(inputMemPool), 147 alloc(&memPool), 148 localFixups(alloc.Adapter()), 149 globalFixups(alloc.Adapter()), 150 relocations(alloc.Adapter()), 151 textData(alloc.Adapter()), 152 label2Order(alloc.Adapter()), 153 switchTableOffset(alloc.Adapter()), 154 offset2StackMapInfo(alloc.Adapter()), 155 funcName(&memPool) 156 { 157 } 158 159 virtual ~ObjFuncEmitInfo() = default; 160 161 struct StackMapInfo { 162 const std::vector<uint8> referenceMap; 163 const std::vector<uint8> deoptInfo; 164 }; 165 GetEndOffset()166 uint32 GetEndOffset() const 167 { 168 return endOffset; 169 } 170 SetEndOffset(uint32 offset)171 void SetEndOffset(uint32 offset) 172 { 173 endOffset = offset; 174 } 175 GetStartOffset()176 uint32 GetStartOffset() const 177 { 178 return startOffset; 179 } 180 SetStartOffset(uint32 offset)181 void SetStartOffset(uint32 offset) 182 { 183 startOffset = offset; 184 } 185 GetExceptStartOffset()186 uint32 GetExceptStartOffset() const 187 { 188 return exceptStartOffset; 189 } 190 SetExceptStartOffset(uint32 offset)191 void SetExceptStartOffset(uint32 offset) 192 { 193 exceptStartOffset = offset; 194 } 195 AppendLocalFixups(LocalFixup & fixup)196 ALWAYS_INLINE void AppendLocalFixups(LocalFixup &fixup) 197 { 198 localFixups.push_back(&fixup); 199 #ifdef JIT_ENABLE_CODE_SIGN 200 if (CGOptions::UseJitCodeSign()) { 201 WillFixUp(JitSignCode::GetInstance()->GetCodeSigner()); 202 } 203 #endif 204 } 205 AppendGlobalFixups(Fixup & fixup)206 ALWAYS_INLINE void AppendGlobalFixups(Fixup &fixup) 207 { 208 globalFixups.push_back(&fixup); 209 #ifdef JIT_ENABLE_CODE_SIGN 210 if (CGOptions::UseJitCodeSign()) { 211 WillFixUp(JitSignCode::GetInstance()->GetCodeSigner()); 212 } 213 #endif 214 } 215 AppendRelocations(Fixup & fixup)216 void AppendRelocations(Fixup &fixup) 217 { 218 relocations.push_back(&fixup); 219 } 220 GetGlobalFixups()221 const MapleVector<Fixup *> &GetGlobalFixups() const 222 { 223 return globalFixups; 224 } 225 AppendContents(uint64 binInsn,uint32 byteSize)226 virtual void AppendContents(uint64 binInsn, uint32 byteSize) 227 { 228 (void)binInsn; 229 (void)byteSize; 230 CHECK_FATAL(false, "this function should be implemented in subclass"); 231 } 232 HandleLocalBranchFixup(const std::vector<uint32> & label2Offset,const std::vector<uint32> & symbol2Offset)233 virtual void HandleLocalBranchFixup(const std::vector<uint32> &label2Offset, 234 const std::vector<uint32> &symbol2Offset) 235 { 236 (void)label2Offset; 237 CHECK_FATAL(false, "this fucntion should be implemented in subclass"); 238 } 239 GetFuncName()240 const MapleString &GetFuncName() const 241 { 242 return funcName; 243 } 244 SetFuncName(const std::string & name)245 void SetFuncName(const std::string &name) 246 { 247 funcName = name; 248 } 249 GetTextData()250 MapleVector<uint8> GetTextData() const 251 { 252 return textData; 253 } 254 GetTextDataSize()255 size_t GetTextDataSize() const 256 { 257 return textData.size(); 258 } 259 AppendTextData(const void * data,uint32 byteSize)260 ALWAYS_INLINE void AppendTextData(const void *data, uint32 byteSize) 261 { 262 auto pdata = reinterpret_cast<const uint8 *>(data); // data:0xa9be7c1d pdata:1d 7c be a9 263 (void)textData.insert(textData.end(), pdata, pdata + byteSize); 264 #ifdef JIT_ENABLE_CODE_SIGN 265 if (CGOptions::UseJitCodeSign()) { 266 JitSignCode *singleton = JitSignCode::GetInstance(); 267 RegisterTmpBuffer(singleton->GetCodeSigner(), textData.data()); 268 AppendData(singleton->GetCodeSigner(), pdata, byteSize); 269 singleton->signTableSize_ += 1; 270 } 271 #endif 272 } 273 AppendTextData(uint64 data,uint32 byteSize)274 ALWAYS_INLINE void AppendTextData(uint64 data, uint32 byteSize) 275 { 276 for (size_t i = 0; i < byteSize; i++) { 277 textData.push_back(static_cast<uint8>(data >> (i << k8BitShift))); 278 } 279 #ifdef JIT_ENABLE_CODE_SIGN 280 if (CGOptions::UseJitCodeSign()) { 281 JitSignCode *singleton = JitSignCode::GetInstance(); 282 RegisterTmpBuffer(singleton->GetCodeSigner(), textData.data()); 283 AppendData(singleton->GetCodeSigner(), &data, byteSize); 284 singleton->signTableSize_ += 1; 285 } 286 #endif 287 } 288 GetTextDataElem32(size_t index)289 uint32 GetTextDataElem32(size_t index) 290 { 291 uint32 value = 0; 292 errno_t res = memcpy_s(&value, sizeof(uint32), textData.data() + index, sizeof(uint32)); 293 CHECK_FATAL(res == EOK, "call memcpy_s failed"); 294 return value; 295 } 296 GetTextDataElem64(size_t index)297 uint64 GetTextDataElem64(size_t index) 298 { 299 uint64 value = 0; 300 errno_t res = memcpy_s(&value, sizeof(uint64), textData.data() + index, sizeof(uint64)); 301 CHECK_FATAL(res == EOK, "call memcpy_s failed"); 302 return value; 303 } 304 SwapTextData(const void * value,size_t index,size_t byteSize)305 ALWAYS_INLINE void SwapTextData(const void *value, size_t index, size_t byteSize) 306 { 307 errno_t res = memcpy_s(textData.data() + index, byteSize, value, byteSize); 308 CHECK_FATAL(res == EOK, "call memcpy_s failed"); 309 #ifdef JIT_ENABLE_CODE_SIGN 310 if (CGOptions::UseJitCodeSign()) { 311 JitSignCode *singleton = JitSignCode::GetInstance(); 312 RegisterTmpBuffer(singleton->GetCodeSigner(), textData.data()); 313 res = PatchData(singleton->GetCodeSigner(), index, textData.data() + index, byteSize); 314 } 315 #endif 316 } 317 FillTextDataPadding(uint32 padding)318 void FillTextDataPadding(uint32 padding) 319 { 320 for (uint32 i = 0; i < padding; ++i) { 321 textData.push_back(0); 322 } 323 } 324 FillTextDataNop(uint32 padding)325 void FillTextDataNop(uint32 padding) 326 { 327 DEBUG_ASSERT(padding % k4ByteSize == 0, "padding is not a multiple of 4!\n"); 328 uint32 nopNum = padding >> k2BitSize; 329 for (uint32 i = 0; i < nopNum; i++) { 330 AppendTextData(0xd503201f, k4ByteSize); 331 } 332 } 333 SetSwitchTableOffset(const std::string & name,uint32 offset)334 void SetSwitchTableOffset(const std::string &name, uint32 offset) 335 { 336 MapleString switchTableName(name, &memPool); 337 switchTableOffset[switchTableName] = offset; 338 } 339 GetSwitchTableOffset()340 const MapleMap<MapleString, uint32> &GetSwitchTableOffset() const 341 { 342 return switchTableOffset; 343 } 344 GetMethodHeader()345 const MethodHeader &GetMethodHeader() const 346 { 347 return methodHeader; 348 } 349 UpdateMethodCodeSize()350 void UpdateMethodCodeSize() 351 { 352 methodHeader.codeSize = static_cast<uint32>(GetTextDataSize()); 353 } 354 AppendLabel2Order(uint32 label)355 void AppendLabel2Order(uint32 label) 356 { 357 (void)label2Order.insert(std::make_pair(label, order)); 358 order++; 359 } 360 GetLabelOrder(uint32 label)361 uint32 GetLabelOrder(uint32 label) const 362 { 363 auto itr = label2Order.find(label); 364 CHECK_FATAL(itr != label2Order.end(), "not found label"); 365 return itr->second; 366 } 367 RecordOffset2StackMapInfo(size_t offset,const std::vector<uint8> & referenceMap,const std::vector<uint8> deoptInfo)368 void RecordOffset2StackMapInfo(size_t offset, const std::vector<uint8> &referenceMap, 369 const std::vector<uint8> deoptInfo) 370 { 371 offset2StackMapInfo.insert(std::pair<size_t, StackMapInfo>(offset, {referenceMap, deoptInfo})); 372 } 373 GetOffset2StackMapInfo()374 MapleUnorderedMap<size_t, StackMapInfo> &GetOffset2StackMapInfo() 375 { 376 return offset2StackMapInfo; 377 } 378 379 protected: 380 MemPool &memPool; 381 MapleAllocator alloc; 382 MapleVector<LocalFixup *> localFixups; 383 MapleVector<Fixup *> globalFixups; 384 MapleVector<Fixup *> relocations; 385 MapleVector<uint8> textData; 386 MapleMap<uint32, uint32> label2Order; /* this is used to sort callsite */ 387 MapleMap<MapleString, uint32> switchTableOffset; 388 MapleUnorderedMap<size_t, StackMapInfo> offset2StackMapInfo; 389 uint32 endOffset = 0; 390 uint32 startOffset = 0; 391 uint32 exceptStartOffset = 0; 392 MapleString funcName; 393 MethodHeader methodHeader; 394 uint32 order = 0; 395 }; 396 397 class ObjEmitter : public Emitter { 398 public: ObjEmitter(CG & cg,const std::string & objFileName)399 ObjEmitter(CG &cg, const std::string &objFileName) 400 : Emitter(cg, objFileName), alloc(memPool), sections(alloc.Adapter()), contents(alloc.Adapter()) 401 { 402 const auto &emitMemoryManager = maplebe::CGOptions::GetInstance().GetEmitMemoryManager(); 403 if (emitMemoryManager.codeSpace == nullptr) { 404 fileStream.open(objFileName, std::ios::trunc | std::ios::binary); 405 } 406 407 uint32 funcNum = 0; 408 for (auto func : cg.GetMIRModule()->GetFunctionList()) { 409 if (func->GetBody() != nullptr) { 410 funcNum++; 411 } 412 } 413 contents.resize(funcNum); 414 } 415 416 virtual ~ObjEmitter() = default; 417 418 void EmitFuncBinaryCode(ObjFuncEmitInfo &objFuncEmitInfo); 419 void EmitInstructions(ObjFuncEmitInfo &objFuncEmitInfo, std::vector<uint32> &label2Offset); 420 void EmitLocalFloatValue(ObjFuncEmitInfo &objFuncEmitInfo); 421 void EmitFullLSDA(ObjFuncEmitInfo &objFuncEmitInfo, const std::vector<uint32> &label2Offset); 422 void EmitSwitchTable(ObjFuncEmitInfo &objFuncEmitInfo, const std::vector<uint32> &symbol2Offset); 423 void WriteObjFile(); 424 HandleGlobalFixup()425 void HandleGlobalFixup() 426 { 427 for (auto *section : sections) { 428 section->HandleGlobalFixup(globalLabel2Offset); 429 } 430 } 431 432 void Run(FuncEmitInfo &funcEmitInfo); 433 void EmitFuncBuffer(CGFunc &cgFunc); 434 CreateFuncEmitInfo(CGFunc & cgFunc)435 FuncEmitInfo &CreateFuncEmitInfo(CGFunc &cgFunc) 436 { 437 CHECK_FATAL(false, "this function should be implemented in subclass"); 438 MemPool *memPool = cgFunc.GetCG()->GetMIRModule()->GetMemPool(); 439 return *memPool->New<ObjFuncEmitInfo>(cgFunc, *memPool); 440 } 441 442 void InitELFHeader(); 443 void AddFuncSymbol(const MapleString &name, Word size, Address value); 444 void ClearData(); 445 void HandleExceptFixup(); 446 UpdateSectionOffsetAddr(Section * section)447 void UpdateSectionOffsetAddr(Section *section) 448 { 449 if (section->GetType() != SHT_NOBITS) { 450 section->SetOffset(globalOffset); 451 } else { 452 section->SetOffset(0); 453 } 454 } 455 UpdateGlobalOffsetAddr(Section * section)456 void UpdateGlobalOffsetAddr(Section *section) 457 { 458 if ((section->GetFlags() & SHF_ALLOC) != 0) { 459 globalAddr += section->GetDataSize(); 460 } 461 if (section->GetType() != SHT_NOBITS) { 462 globalOffset += section->GetDataSize(); 463 } 464 } 465 RegisterSection(Section * section)466 void RegisterSection(Section *section) 467 { 468 sections.push_back(section); 469 DEBUG_ASSERT(sections.size() > 0, "sections not empty"); 470 section->SetIndex(sections.size() - 1); 471 } 472 RegisterGlobalLabel(const std::string labelName,ObjLabel label)473 void RegisterGlobalLabel(const std::string labelName, ObjLabel label) 474 { 475 (void)globalLabel2Offset.insert(std::make_pair(labelName, label)); 476 } 477 AddSectionName(const std::string & name)478 size_t AddSectionName(const std::string &name) 479 { 480 return name.empty() ? 0 : shStrSection->AddString(name); 481 } 482 Finish()483 void Finish() override 484 { 485 InitSections(); 486 AppendGlobalLabel(); 487 AppendSymsToSymTabSec(); 488 HandleTextSectionGlobalFixup(); 489 AppendTextSectionData(); 490 LayoutSections(); 491 WriteObjFile(); 492 ClearData(); 493 } 494 CloseOutput()495 void CloseOutput() override 496 { 497 if (fileStream.is_open()) { 498 fileStream << outStream.str(); 499 fileStream.close(); 500 } 501 } 502 503 virtual void EncodeInstruction(const Insn &insn, const std::vector<uint32> &label2Offset, 504 ObjFuncEmitInfo &objFuncEmitInfo) = 0; 505 virtual uint32 GetInsnSize(const Insn &insn) const = 0; 506 virtual void HandleTextSectionGlobalFixup() = 0; 507 virtual void AppendTextSectionData() = 0; 508 virtual void AppendGlobalLabel() = 0; 509 virtual void AppendSymsToSymTabSec() = 0; 510 virtual void InitSections() = 0; 511 virtual void LayoutSections() = 0; 512 virtual void UpdateMachineAndFlags(FileHeader &header) = 0; 513 GetContents()514 MapleVector<ObjFuncEmitInfo *> &GetContents() 515 { 516 return contents; 517 } 518 GetBeforeTextDataSize(ObjFuncEmitInfo & objFuncEmitInfo)519 size_t GetBeforeTextDataSize(ObjFuncEmitInfo &objFuncEmitInfo) const 520 { 521 size_t textDataSize = 0; 522 for (auto *content : contents) { 523 if (content == nullptr) { 524 continue; 525 } 526 textDataSize += content->GetTextDataSize(); 527 if (content->GetFuncName() == objFuncEmitInfo.GetFuncName()) { 528 break; 529 } 530 } 531 return textDataSize; 532 } 533 534 void EmitFunctionSymbolTable(ObjFuncEmitInfo &objFuncEmitInfo, std::vector<uint32> &symbol2Offset); 535 void EmitStr16Const(ObjFuncEmitInfo &objFuncEmitInfo, const MIRSymbol &str16Symbol); 536 void EmitStrConst(ObjFuncEmitInfo &objFuncEmitInfo, const MIRSymbol &strSymbol); 537 538 protected: 539 virtual void InsertNopInsn(ObjFuncEmitInfo &objFuncEmitInfo) const = 0; 540 virtual void EmitIntrinsicInsn(const Insn &insn, ObjFuncEmitInfo &objFuncEmitInfo) = 0; 541 virtual void EmitSpinIntrinsicInsn(const Insn &insn, ObjFuncEmitInfo &objFuncEmitInfo) = 0; 542 543 MapleString fileName; 544 MapleAllocator alloc; 545 MapleVector<Section *> sections; 546 Offset globalOffset = 0; /* global offset of the ifile */ 547 Address globalAddr = 0; /* global adress of the ifile */ 548 FileHeader header {}; 549 StringSection *shStrSection = nullptr; 550 StringSection *strTabSection = nullptr; 551 SymbolSection *symbolTabSection = nullptr; 552 DataSection *textSection = nullptr; 553 DataSection *dataSection = nullptr; 554 DataSection *rodataSection = nullptr; 555 RelaSection *relaSection = nullptr; 556 MapleVector<ObjFuncEmitInfo *> contents; /* each item is the code info of a cgfunc */ 557 Label2OffsetMap globalLabel2Offset; /* record global info */ 558 }; 559 } /* namespace maplebe */ 560 561 #endif /* MAPLEBE_INCLUDE_CG_OBJ_EMIT_H */ 562