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 #include "obj_emit.h"
17 #include "namemangler.h"
18 #include "cg.h"
19
20 namespace maplebe {
21 using namespace maple;
22 using namespace namemangler;
23
Run(FuncEmitInfo & funcEmitInfo)24 void ObjEmitter::Run(FuncEmitInfo &funcEmitInfo)
25 {
26 InsertNopInsn(static_cast<ObjFuncEmitInfo &>(funcEmitInfo));
27 EmitFuncBinaryCode(static_cast<ObjFuncEmitInfo &>(funcEmitInfo));
28 }
29
30 /* traverse insns, get the binary code and saved in buffer */
EmitFuncBinaryCode(ObjFuncEmitInfo & objFuncEmitInfo)31 void ObjEmitter::EmitFuncBinaryCode(ObjFuncEmitInfo &objFuncEmitInfo)
32 {
33 CGFunc &cgFunc = objFuncEmitInfo.GetCGFunc();
34 objFuncEmitInfo.SetFuncName(cgFunc.GetName());
35
36 int labelSize = static_cast<int>(cgFunc.GetLab2BBMap().size()) +
37 static_cast<int>(cgFunc.GetLabelAndValueMap().size()) + 1;
38 std::vector<uint32> label2Offset(labelSize, 0xFFFFFFFFULL);
39 EmitInstructions(objFuncEmitInfo, label2Offset);
40 objFuncEmitInfo.UpdateMethodCodeSize();
41
42 int symbolSize = static_cast<int>(cgFunc.GetLabelIdx() + 1);
43 std::vector<uint32> symbol2Offset(symbolSize, 0xFFFFFFFFULL);
44 EmitFunctionSymbolTable(objFuncEmitInfo, symbol2Offset);
45 EmitSwitchTable(objFuncEmitInfo, symbol2Offset);
46
47 /* local float variable */
48 for (const auto &mpPair : cgFunc.GetLabelAndValueMap()) {
49 CHECK_FATAL(mpPair.first < label2Offset.size(), "label2Offset");
50 label2Offset[mpPair.first] = objFuncEmitInfo.GetTextDataSize();
51 objFuncEmitInfo.AppendTextData(&(mpPair.second), k8ByteSize);
52 }
53
54 /* handle branch fixup here */
55 objFuncEmitInfo.HandleLocalBranchFixup(label2Offset, symbol2Offset);
56 }
57
EmitInstructions(ObjFuncEmitInfo & objFuncEmitInfo,std::vector<uint32> & label2Offset)58 void ObjEmitter::EmitInstructions(ObjFuncEmitInfo &objFuncEmitInfo, std::vector<uint32> &label2Offset)
59 {
60 CGFunc &cgFunc = objFuncEmitInfo.GetCGFunc();
61 FOR_ALL_BB(bb, &cgFunc) {
62 if (bb->GetLabIdx() != 0) {
63 CHECK_FATAL(bb->GetLabIdx() < label2Offset.size(), "label2Offset");
64 label2Offset[bb->GetLabIdx()] = objFuncEmitInfo.GetTextDataSize();
65 objFuncEmitInfo.AppendLabel2Order(bb->GetLabIdx());
66 }
67
68 FOR_BB_INSNS(insn, bb) {
69 if (!insn->IsMachineInstruction() || insn->IsAsmInsn() || insn->IsPseudo()) {
70 continue;
71 }
72
73 /* get binary code and save in buffer */
74 if (insn->GetDesc()->IsIntrinsic()) {
75 EmitIntrinsicInsn(*insn, objFuncEmitInfo);
76 } else if (insn->GetDesc()->IsSpecialIntrinsic()) {
77 EmitSpinIntrinsicInsn(*insn, objFuncEmitInfo);
78 } else {
79 EncodeInstruction(*insn, label2Offset, objFuncEmitInfo);
80 }
81 }
82 }
83 }
84
EmitSwitchTable(ObjFuncEmitInfo & objFuncEmitInfo,const std::vector<uint32> & symbol2Offset)85 void ObjEmitter::EmitSwitchTable(ObjFuncEmitInfo &objFuncEmitInfo, const std::vector<uint32> &symbol2Offset)
86 {
87 CGFunc &cgFunc = objFuncEmitInfo.GetCGFunc();
88 if (cgFunc.GetEmitStVec().size() == 0) {
89 return;
90 }
91 uint32 tmpOffset = GetBeforeTextDataSize(objFuncEmitInfo);
92 /* align is 8 push padding to objFuncEmitInfo.data */
93 uint32 startOffset = Alignment::Align<uint32>(tmpOffset, k8ByteSize);
94 uint32 padding = startOffset - tmpOffset;
95 objFuncEmitInfo.FillTextDataNop(padding);
96
97 uint32 curOffset = objFuncEmitInfo.GetTextDataSize();
98 for (std::pair<uint32, MIRSymbol *> st : cgFunc.GetEmitStVec()) {
99 objFuncEmitInfo.SetSwitchTableOffset(st.second->GetName(), curOffset);
100 MIRAggConst *arrayConst = safe_cast<MIRAggConst>(st.second->GetKonst());
101 DEBUG_ASSERT(arrayConst != nullptr, "null ptr check");
102 for (size_t i = 0; i < arrayConst->GetConstVec().size(); ++i) {
103 MIRLblConst *lblConst = safe_cast<MIRLblConst>(arrayConst->GetConstVecItem(i));
104 DEBUG_ASSERT(lblConst != nullptr, "null ptr check");
105 CHECK_FATAL(lblConst->GetValue() <= symbol2Offset.size(), "symbol2Offset");
106 uint64 offset = static_cast<uint64>(symbol2Offset[lblConst->GetValue()]) - static_cast<uint64>(curOffset);
107 objFuncEmitInfo.AppendTextData(offset, k8ByteSize);
108 }
109
110 curOffset += arrayConst->GetConstVec().size() * k8ByteSize;
111 }
112 }
113
WriteObjFile()114 void ObjEmitter::WriteObjFile()
115 {
116 const auto &emitMemorymanager = CGOptions::GetInstance().GetEmitMemoryManager();
117 if (emitMemorymanager.codeSpace != nullptr) {
118 DEBUG_ASSERT(textSection != nullptr, "textSection has not been initialized");
119 uint8 *codeSpace = emitMemorymanager.allocateDataSection(emitMemorymanager.codeSpace,
120 textSection->GetDataSize(), textSection->GetAlign(), textSection->GetName().c_str());
121 memcpy_s(codeSpace, textSection->GetDataSize(), textSection->GetData().data(), textSection->GetDataSize());
122 if (CGOptions::addFuncSymbol()) {
123 uint8 *symtabSpace = emitMemorymanager.allocateDataSection(emitMemorymanager.codeSpace,
124 symbolTabSection->GetDataSize(), symbolTabSection->GetAlign(), symbolTabSection->GetName().c_str());
125 memcpy_s(symtabSpace, symbolTabSection->GetDataSize(),
126 symbolTabSection->GetAddr(), symbolTabSection->GetDataSize());
127 uint8 *stringTabSpace = emitMemorymanager.allocateDataSection(emitMemorymanager.codeSpace,
128 strTabSection->GetDataSize(), strTabSection->GetAlign(), strTabSection->GetName().c_str());
129 memcpy_s(stringTabSpace, strTabSection->GetDataSize(),
130 strTabSection->GetData().data(), strTabSection->GetDataSize());
131 }
132
133 return;
134 }
135 /* write header */
136 Emit(&header, sizeof(header));
137
138 /* write sections */
139 for (auto *section : sections) {
140 if (section->GetType() == SHT_NOBITS) {
141 continue;
142 }
143
144 SetFileOffset(section->GetOffset());
145 section->WriteSection(outStream);
146 }
147
148 /* write section table */
149 SetFileOffset(header.e_shoff);
150 for (auto section : sections) {
151 Emit(§ion->GetSectionHeader(), sizeof(section->GetSectionHeader()));
152 }
153 }
154
AddSymbol(const std::string & name,Word size,const Section & section,Address value)155 void ObjEmitter::AddSymbol(const std::string &name, Word size, const Section §ion, Address value)
156 {
157 auto nameIndex = strTabSection->AddString(name);
158 symbolTabSection->AppendSymbol({static_cast<Word>(nameIndex),
159 static_cast<uint8_t>((STB_GLOBAL << 4) + (STT_SECTION & 0xf)), 0,
160 section.GetIndex(), value, size});
161 }
162
AddFuncSymbol(const MapleString & name,Word size,Address value)163 void ObjEmitter::AddFuncSymbol(const MapleString &name, Word size, Address value)
164 {
165 auto symbolStrIndex = strTabSection->AddString(name);
166 symbolTabSection->AppendSymbol({static_cast<Word>(symbolStrIndex),
167 static_cast<uint8>((STB_GLOBAL << k4BitSize) + (STT_FUNC & 0xf)), 0,
168 textSection->GetIndex(), value, size});
169 }
170
ClearData()171 void ObjEmitter::ClearData()
172 {
173 globalLabel2Offset.clear();
174 for (auto *section : sections) {
175 if (section != nullptr) {
176 section->ClearData();
177 }
178 }
179 }
180
InitELFHeader()181 void ObjEmitter::InitELFHeader()
182 {
183 header.e_ident[EI_MAG0] = ELFMAG0;
184 header.e_ident[EI_MAG1] = ELFMAG1;
185 header.e_ident[EI_MAG2] = ELFMAG2;
186 header.e_ident[EI_MAG3] = ELFMAG3;
187 header.e_ident[EI_CLASS] = ELFCLASS64;
188 header.e_ident[EI_DATA] = ELFDATA2LSB;
189 header.e_ident[EI_VERSION] = EV_CURRENT;
190 header.e_ident[EI_OSABI] = ELFOSABI_LINUX;
191 header.e_ident[EI_ABIVERSION] = 0;
192 std::fill_n(&header.e_ident[EI_PAD], EI_NIDENT - EI_PAD, 0);
193 header.e_type = ET_REL;
194 header.e_version = 1;
195 UpdateMachineAndFlags(header);
196 header.e_entry = 0;
197 header.e_ehsize = sizeof(FileHeader);
198 header.e_phentsize = sizeof(SegmentHeader);
199 header.e_shentsize = sizeof(SectionHeader);
200 header.e_shstrndx = shStrSection->GetIndex();
201 header.e_shoff = 0;
202 header.e_phoff = 0;
203 header.e_shnum = sections.size();
204 header.e_phnum = 0;
205 }
206
EmitMIRIntConst(EmitInfo & emitInfo)207 void ObjEmitter::EmitMIRIntConst(EmitInfo &emitInfo)
208 {
209 DEBUG_ASSERT(IsPrimitiveScalar(emitInfo.elemConst.GetType().GetPrimType()), "must be primitive type!");
210 MIRIntConst &intConst = static_cast<MIRIntConst &>(emitInfo.elemConst);
211 size_t size = GetPrimTypeSize(emitInfo.elemConst.GetType().GetPrimType());
212 const IntVal &value = intConst.GetValue();
213 int64 val = value.GetExtValue();
214 dataSection->AppendData(&val, size);
215 emitInfo.offset += size;
216 #ifdef OBJ_DEBUG
217 LogInfo::MapleLogger() << val << " size: " << size << "\n";
218 #endif
219 }
220
EmitMIRAddrofConstCommon(EmitInfo & emitInfo,uint64 specialOffset)221 void ObjEmitter::EmitMIRAddrofConstCommon(EmitInfo &emitInfo, uint64 specialOffset)
222 {
223 MIRAddrofConst &symAddr = static_cast<MIRAddrofConst &>(emitInfo.elemConst);
224 MIRSymbol *symAddrSym = GlobalTables::GetGsymTable().GetSymbolFromStidx(symAddr.GetSymbolIndex().Idx());
225 DEBUG_ASSERT(symAddrSym != nullptr, "null ptr check");
226 const std::string &symAddrName = symAddrSym->GetName();
227 LabelFixup labelFixup(symAddrName, emitInfo.offset, kLabelFixupDirect64);
228 if (specialOffset != 0) {
229 DataSection::AddLabelFixup(emitInfo.labelFixups, labelFixup);
230 }
231 uint64 value = specialOffset - emitInfo.offset;
232 size_t size = GetPrimTypeSize(emitInfo.elemConst.GetType().GetPrimType());
233 dataSection->AppendData(&value, size);
234 emitInfo.offset += size;
235
236 #ifdef OBJ_DEBUG
237 LogInfo::MapleLogger() << symAddrName << " size: " << size << "\n";
238 #endif
239 }
240
EmitMIRAddrofConst(EmitInfo & emitInfo)241 void ObjEmitter::EmitMIRAddrofConst(EmitInfo &emitInfo)
242 {
243 EmitMIRAddrofConstCommon(emitInfo, 0);
244 }
245
EmitMIRAddrofConstOffset(EmitInfo & emitInfo)246 void ObjEmitter::EmitMIRAddrofConstOffset(EmitInfo &emitInfo)
247 {
248 /* 2 is fixed offset in runtime */
249 EmitMIRAddrofConstCommon(emitInfo, 2);
250 }
251
EmitFunctionSymbolTable(ObjFuncEmitInfo & objFuncEmitInfo,std::vector<uint32> & symbol2Offset)252 void ObjEmitter::EmitFunctionSymbolTable(ObjFuncEmitInfo &objFuncEmitInfo, std::vector<uint32> &symbol2Offset)
253 {
254 CGFunc &cgFunc = objFuncEmitInfo.GetCGFunc();
255 MIRFunction *func = &cgFunc.GetFunction();
256
257 size_t size =
258 (func == nullptr) ? GlobalTables::GetGsymTable().GetTable().size() : func->GetSymTab()->GetTable().size();
259 for (size_t i = 0; i < size; ++i) {
260 const MIRSymbol *st = nullptr;
261 if (func == nullptr) {
262 auto &symTab = GlobalTables::GetGsymTable();
263 st = symTab.GetSymbol(i);
264 } else {
265 auto &symTab = *func->GetSymTab();
266 st = symTab.GetSymbolAt(i);
267 }
268 if (st == nullptr) {
269 continue;
270 }
271 MIRStorageClass storageClass = st->GetStorageClass();
272 MIRSymKind symKind = st->GetSKind();
273 if (storageClass == kScPstatic && symKind == kStConst) {
274 // align
275 size_t tmpOffset = GetBeforeTextDataSize(objFuncEmitInfo);
276 uint32 offset = Alignment::Align<uint32>(tmpOffset, k8ByteSize);
277 uint32 padding = offset - tmpOffset;
278 objFuncEmitInfo.FillTextDataNop(padding);
279 CHECK_FATAL(cgFunc.GetLocalSymLabelIndex(*st) <= symbol2Offset.size(), "symbol2Offset");
280 symbol2Offset[cgFunc.GetLocalSymLabelIndex(*st)] = static_cast<uint32>(objFuncEmitInfo.GetTextDataSize());
281 if (st->GetKonst()->GetKind() == kConstStr16Const) {
282 EmitStr16Const(objFuncEmitInfo, *st);
283 continue;
284 }
285
286 if (st->GetKonst()->GetKind() == kConstStrConst) {
287 EmitStrConst(objFuncEmitInfo, *st);
288 continue;
289 }
290
291 switch (st->GetKonst()->GetType().GetPrimType()) {
292 case PTY_u32: {
293 MIRIntConst *intConst = safe_cast<MIRIntConst>(st->GetKonst());
294 DEBUG_ASSERT(intConst != nullptr, "intConst should not be nullptr");
295 uint32 value = static_cast<uint32>(intConst->GetValue().GetExtValue());
296 objFuncEmitInfo.AppendTextData(&value, sizeof(value));
297 break;
298 }
299 case PTY_f32: {
300 MIRFloatConst *floatConst = safe_cast<MIRFloatConst>(st->GetKonst());
301 uint32 value = static_cast<uint32>(floatConst->GetIntValue());
302 objFuncEmitInfo.AppendTextData(&value, sizeof(value));
303 break;
304 }
305 case PTY_f64: {
306 MIRDoubleConst *doubleConst = safe_cast<MIRDoubleConst>(st->GetKonst());
307 uint32 value = doubleConst->GetIntLow32();
308 objFuncEmitInfo.AppendTextData(&value, sizeof(value));
309 value = doubleConst->GetIntHigh32();
310 objFuncEmitInfo.AppendTextData(&value, sizeof(value));
311 break;
312 }
313 default:
314 break;
315 }
316 }
317 }
318 }
319
EmitStr16Const(ObjFuncEmitInfo & objFuncEmitInfo,const MIRSymbol & str16Symbol)320 void ObjEmitter::EmitStr16Const(ObjFuncEmitInfo &objFuncEmitInfo, const MIRSymbol &str16Symbol)
321 {
322 MIRStr16Const *mirStr16Const = safe_cast<MIRStr16Const>(str16Symbol.GetKonst());
323 DEBUG_ASSERT(mirStr16Const != nullptr, "nullptr check");
324 const std::u16string &str16 = GlobalTables::GetU16StrTable().GetStringFromStrIdx(mirStr16Const->GetValue());
325
326 uint32 len = str16.length();
327 for (uint32 i = 0; i < len; ++i) {
328 char16_t c = str16[i];
329 objFuncEmitInfo.AppendTextData(&c, sizeof(c));
330 }
331 if ((str16.length() & 0x1) == 1) {
332 uint16 value = 0;
333 objFuncEmitInfo.AppendTextData(&value, sizeof(value));
334 }
335 }
336
EmitStrConst(ObjFuncEmitInfo & objFuncEmitInfo,const MIRSymbol & strSymbol)337 void ObjEmitter::EmitStrConst(ObjFuncEmitInfo &objFuncEmitInfo, const MIRSymbol &strSymbol)
338 {
339 MIRStrConst *mirStrConst = safe_cast<MIRStrConst>(strSymbol.GetKonst());
340 DEBUG_ASSERT(mirStrConst != nullptr, "null ptr check");
341 auto str = GlobalTables::GetUStrTable().GetStringFromStrIdx(mirStrConst->GetValue());
342 size_t size = str.length();
343 /* 1 is tail 0 of the str string */
344 objFuncEmitInfo.AppendTextData(str.c_str(), size + 1);
345 }
346 } /* namespace maplebe */
347