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