• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, const std::vector<uint32> &label2Offset,
541                                    ObjFuncEmitInfo &objFuncEmitInfo) = 0;
542     virtual void EmitSpinIntrinsicInsn(const Insn &insn, ObjFuncEmitInfo &objFuncEmitInfo) = 0;
543 
544     MapleString fileName;
545     MapleAllocator alloc;
546     MapleVector<Section *> sections;
547     Offset globalOffset = 0; /* global offset of the ifile */
548     Address globalAddr = 0;  /* global adress of the ifile */
549     FileHeader header {};
550     StringSection *shStrSection = nullptr;
551     StringSection *strTabSection = nullptr;
552     SymbolSection *symbolTabSection = nullptr;
553     DataSection *textSection = nullptr;
554     DataSection *dataSection = nullptr;
555     DataSection *rodataSection = nullptr;
556     RelaSection *relaSection = nullptr;
557     MapleVector<ObjFuncEmitInfo *> contents; /* each item is the code info of a cgfunc */
558     Label2OffsetMap globalLabel2Offset;      /* record global info */
559 };
560 } /* namespace maplebe */
561 
562 #endif /* MAPLEBE_INCLUDE_CG_OBJ_EMIT_H */
563