1 #include "stdafx.h"
2 #include "ElfRelocator.h"
3 #include "Core/Common.h"
4 #include "Core/Misc.h"
5 #include "Util/CRC.h"
6 #include "Util/Util.h"
7 #include "Commands/CAssemblerLabel.h"
8
9 struct ArFileHeader
10 {
11 char fileName[16];
12 char modifactionTime[12];
13 char ownerId[6];
14 char groupId[6];
15 char fileMode[8];
16 char fileSize[10];
17 char magic[2];
18 };
19
20 struct ArFileEntry
21 {
22 std::wstring name;
23 ByteArray data;
24 };
25
loadArArchive(const std::wstring & inputName)26 std::vector<ArFileEntry> loadArArchive(const std::wstring& inputName)
27 {
28 ByteArray input = ByteArray::fromFile(inputName);
29 std::vector<ArFileEntry> result;
30
31 if (input.size() < 8 || memcmp(input.data(),"!<arch>\n",8) != 0)
32 {
33 if (input.size() < 4 || memcmp(input.data(),"\x7F""ELF",4) != 0)
34 return result;
35
36 ArFileEntry entry;
37 entry.name = getFileNameFromPath(inputName);
38 entry.data = input;
39 result.push_back(entry);
40 return result;
41 }
42
43 size_t pos = 8;
44 while (pos < input.size())
45 {
46 ArFileHeader* header = (ArFileHeader*) input.data(pos);
47 pos += sizeof(ArFileHeader);
48
49 // get file size
50 int size = 0;
51 for (int i = 0; i < 10; i++)
52 {
53 if (header->fileSize[i] == ' ')
54 break;
55
56 size = size*10;
57 size += (header->fileSize[i]-'0');
58 }
59
60 // only ELF files are actually interesting
61 if (memcmp(input.data(pos),"\x7F""ELF",4) == 0)
62 {
63 // get file name
64 char fileName[17];
65 fileName[16] = 0;
66 for (int i = 0; i < 16; i++)
67 {
68 if (header->fileName[i] == ' ')
69 {
70 // remove trailing slashes of file names
71 if (i > 0 && fileName[i-1] == '/')
72 i--;
73 fileName[i] = 0;
74 break;;
75 }
76
77 fileName[i] = header->fileName[i];
78 }
79
80 ArFileEntry entry;
81 entry.name = convertUtf8ToWString(fileName);
82 entry.data = input.mid(pos,size);
83 result.push_back(entry);
84 }
85
86 pos += size;
87 if (pos % 2)
88 pos++;
89 }
90
91 return result;
92 }
93
init(const std::wstring & inputName)94 bool ElfRelocator::init(const std::wstring& inputName)
95 {
96 relocator = Arch->getElfRelocator();
97 if (relocator == nullptr)
98 {
99 Logger::printError(Logger::Error,L"Object importing not supported for this architecture");
100 return false;
101 }
102
103 auto inputFiles = loadArArchive(inputName);
104 if (inputFiles.size() == 0)
105 {
106 Logger::printError(Logger::Error,L"Could not load library");
107 return false;
108 }
109
110 for (ArFileEntry& entry: inputFiles)
111 {
112 ElfRelocatorFile file;
113
114 ElfFile* elf = new ElfFile();
115 if (elf->load(entry.data,false) == false)
116 {
117 Logger::printError(Logger::Error,L"Could not load object file %s",entry.name);
118 return false;
119 }
120
121 if (elf->getType() != ET_REL)
122 {
123 Logger::printError(Logger::Error,L"Unexpected ELF type %d in object file %s",elf->getType(),entry.name);
124 return false;
125 }
126
127 if (elf->getMachine() != relocator->expectedMachine())
128 {
129 Logger::printError(Logger::Error,L"Unexpected ELF machine %d in object file %s",elf->getMachine(),entry.name);
130 return false;
131 }
132
133 if (elf->getEndianness() != Arch->getEndianness())
134 {
135 Logger::printError(Logger::Error,L"Incorrect endianness in object file %s",entry.name);
136 return false;
137 }
138
139 if (elf->getSegmentCount() != 0)
140 {
141 Logger::printError(Logger::Error,L"Unexpected segment count %d in object file %s",elf->getSegmentCount(),entry.name);
142 return false;
143 }
144
145
146 // load all relevant sections of this file
147 for (size_t s = 0; s < elf->getSegmentlessSectionCount(); s++)
148 {
149 ElfSection* sec = elf->getSegmentlessSection(s);
150 if (!(sec->getFlags() & SHF_ALLOC))
151 continue;
152
153 if (sec->getType() == SHT_PROGBITS || sec->getType() == SHT_NOBITS || sec->getType() == SHT_INIT_ARRAY)
154 {
155 ElfRelocatorSection sectionEntry;
156 sectionEntry.section = sec;
157 sectionEntry.index = s;
158 sectionEntry.relSection = nullptr;
159 sectionEntry.label = nullptr;
160
161 // search relocation section
162 for (size_t k = 0; k < elf->getSegmentlessSectionCount(); k++)
163 {
164 ElfSection* relSection = elf->getSegmentlessSection(k);
165 if (relSection->getType() != SHT_REL)
166 continue;
167 if (relSection->getInfo() != s)
168 continue;
169
170 // got it
171 sectionEntry.relSection = relSection;
172 break;
173 }
174
175 // keep track of constructor sections
176 if (sec->getName() == ".ctors" || sec->getName() == ".init_array")
177 {
178 ElfRelocatorCtor ctor;
179 ctor.symbolName = Global.symbolTable.getUniqueLabelName();
180 ctor.size = sec->getSize();
181
182 sectionEntry.label = Global.symbolTable.getLabel(ctor.symbolName,-1,-1);
183 sectionEntry.label->setDefined(true);
184
185 ctors.push_back(ctor);
186 }
187
188 file.sections.push_back(sectionEntry);
189 }
190 }
191
192 // init exportable symbols
193 for (int i = 0; i < elf->getSymbolCount(); i++)
194 {
195 Elf32_Sym symbol;
196 elf->getSymbol(symbol, i);
197
198 if (ELF32_ST_BIND(symbol.st_info) == STB_GLOBAL && symbol.st_shndx != 0)
199 {
200 ElfRelocatorSymbol symEntry;
201 symEntry.type = ELF32_ST_TYPE(symbol.st_info);
202 symEntry.name = convertUtf8ToWString(elf->getStrTableString(symbol.st_name));
203 symEntry.relativeAddress = symbol.st_value;
204 symEntry.section = symbol.st_shndx;
205 symEntry.size = symbol.st_size;
206 symEntry.label = nullptr;
207
208 file.symbols.push_back(symEntry);
209 }
210 }
211
212 file.elf = elf;
213 file.name = entry.name;
214 files.push_back(file);
215 }
216
217 return true;
218 }
219
exportSymbols()220 bool ElfRelocator::exportSymbols()
221 {
222 bool error = false;
223
224 for (ElfRelocatorFile& file: files)
225 {
226 for (ElfRelocatorSymbol& sym: file.symbols)
227 {
228 if (sym.label != nullptr)
229 continue;
230
231 std::wstring lowered = sym.name;
232 std::transform(lowered.begin(), lowered.end(), lowered.begin(), ::towlower);
233
234 sym.label = Global.symbolTable.getLabel(lowered,-1,-1);
235 if (sym.label == nullptr)
236 {
237 Logger::printError(Logger::Error,L"Invalid label name \"%s\"",sym.name);
238 error = true;
239 continue;
240 }
241
242 if (sym.label->isDefined())
243 {
244 Logger::printError(Logger::Error,L"Label \"%s\" already defined",sym.name);
245 error = true;
246 continue;
247 }
248
249 RelocationData data;
250 data.symbolAddress = sym.relativeAddress;
251 relocator->setSymbolAddress(data,sym.relativeAddress,sym.type);
252
253 sym.relativeAddress = data.symbolAddress;
254 sym.label->setInfo(data.targetSymbolInfo);
255 sym.label->setIsData(sym.type == STT_OBJECT);
256 sym.label->setUpdateInfo(false);
257
258 sym.label->setValue(0);
259 sym.label->setDefined(true);
260 sym.label->setOriginalName(sym.name);
261 }
262 }
263
264 return !error;
265 }
266
generateCtor(const std::wstring & ctorName)267 std::unique_ptr<CAssemblerCommand> ElfRelocator::generateCtor(const std::wstring& ctorName)
268 {
269 std::unique_ptr<CAssemblerCommand> content = relocator->generateCtorStub(ctors);
270
271 auto func = ::make_unique<CDirectiveFunction>(ctorName,ctorName);
272 func->setContent(std::move(content));
273 return std::move(func);
274 }
275
loadRelocation(Elf32_Rel & rel,ByteArray & data,int offset,Endianness endianness)276 void ElfRelocator::loadRelocation(Elf32_Rel& rel, ByteArray& data, int offset, Endianness endianness)
277 {
278 rel.r_offset = data.getDoubleWord(offset + 0x00, endianness);
279 rel.r_info = data.getDoubleWord(offset + 0x04, endianness);
280 }
281
relocateFile(ElfRelocatorFile & file,int64_t & relocationAddress)282 bool ElfRelocator::relocateFile(ElfRelocatorFile& file, int64_t& relocationAddress)
283 {
284 ElfFile* elf = file.elf;
285 int64_t start = relocationAddress;
286
287 // calculate address for each section
288 std::map<int64_t,int64_t> relocationOffsets;
289 for (ElfRelocatorSection& entry: file.sections)
290 {
291 ElfSection* section = entry.section;
292 size_t index = entry.index;
293 int size = section->getSize();
294
295 while (relocationAddress % section->getAlignment())
296 relocationAddress++;
297
298 if (entry.label != nullptr)
299 entry.label->setValue(relocationAddress);
300
301 relocationOffsets[index] = relocationAddress;
302 relocationAddress += size;
303 }
304
305 size_t dataStart = outputData.size();
306 outputData.reserveBytes((size_t)(relocationAddress-start));
307
308 // load sections
309 bool error = false;
310 for (ElfRelocatorSection& entry: file.sections)
311 {
312 ElfSection* section = entry.section;
313 size_t index = entry.index;
314
315 if (section->getType() == SHT_NOBITS)
316 {
317 // reserveBytes initialized the data to 0 already
318 continue;
319 }
320
321 ByteArray sectionData = section->getData();
322
323 // relocate if necessary
324 ElfSection* relSection = entry.relSection;
325 if (relSection != nullptr)
326 {
327 for (unsigned int relOffset = 0; relOffset < relSection->getSize(); relOffset += sizeof(Elf32_Rel))
328 {
329 Elf32_Rel rel;
330 loadRelocation(rel, relSection->getData(), relOffset, elf->getEndianness());
331 int pos = rel.r_offset;
332
333 if (relocator->isDummyRelocationType(rel.getType()))
334 continue;
335
336 int symNum = rel.getSymbolNum();
337 if (symNum <= 0)
338 {
339 Logger::queueError(Logger::Warning,L"Invalid symbol num %06X",symNum);
340 error = true;
341 continue;
342 }
343
344 Elf32_Sym sym;
345 elf->getSymbol(sym, symNum);
346 int symSection = sym.st_shndx;
347
348 RelocationData relData;
349 relData.opcode = sectionData.getDoubleWord(pos, elf->getEndianness());
350 relData.opcodeOffset = pos+relocationOffsets[index];
351 relocator->setSymbolAddress(relData,sym.st_value,sym.st_info & 0xF);
352
353 // externs?
354 if (sym.st_shndx == 0)
355 {
356 if (sym.st_name == 0)
357 {
358 Logger::queueError(Logger::Error, L"Symbol without a name");
359 error = true;
360 continue;
361 }
362
363 std::wstring symName = toWLowercase(elf->getStrTableString(sym.st_name));
364
365 std::shared_ptr<Label> label = Global.symbolTable.getLabel(symName,-1,-1);
366 if (label == nullptr)
367 {
368 Logger::queueError(Logger::Error,L"Invalid external symbol %s",symName);
369 error = true;
370 continue;
371 }
372 if (label->isDefined() == false)
373 {
374 Logger::queueError(Logger::Error,L"Undefined external symbol %s in file %s",symName,file.name);
375 error = true;
376 continue;
377 }
378
379 relData.relocationBase = (unsigned int) label->getValue();
380 relData.targetSymbolType = label->isData() ? STT_OBJECT : STT_FUNC;
381 relData.targetSymbolInfo = label->getInfo();
382 } else {
383 relData.relocationBase = relocationOffsets[symSection]+relData.symbolAddress;
384 }
385
386 if (relocator->relocateOpcode(rel.getType(),relData) == false)
387 {
388 Logger::queueError(Logger::Error,relData.errorMessage);
389 error = true;
390 continue;
391 }
392
393 sectionData.replaceDoubleWord(pos,relData.opcode, elf->getEndianness());
394 }
395 }
396
397 size_t arrayStart = (size_t) (dataStart+relocationOffsets[index]-start);
398 memcpy(outputData.data(arrayStart),sectionData.data(),sectionData.size());
399 }
400
401 // now update symbols
402 for (ElfRelocatorSymbol& sym: file.symbols)
403 {
404 int64_t oldAddress = sym.relocatedAddress;
405
406 switch (sym.section)
407 {
408 case SHN_ABS: // address does not change
409 sym.relocatedAddress = sym.relativeAddress;
410 break;
411 case SHN_COMMON: // needs to be allocated. relativeAddress gives alignment constraint
412 {
413 int64_t start = relocationAddress;
414
415 while (relocationAddress % sym.relativeAddress)
416 relocationAddress++;
417
418 sym.relocatedAddress = relocationAddress;
419 relocationAddress += sym.size;
420 outputData.reserveBytes((size_t)(relocationAddress-start));
421 }
422 break;
423 default: // normal relocated symbol
424 sym.relocatedAddress = sym.relativeAddress+relocationOffsets[sym.section];
425 break;
426 }
427
428 if (sym.label != nullptr)
429 sym.label->setValue(sym.relocatedAddress);
430
431 if (oldAddress != sym.relocatedAddress)
432 dataChanged = true;
433 }
434
435 return !error;
436 }
437
relocate(int64_t & memoryAddress)438 bool ElfRelocator::relocate(int64_t& memoryAddress)
439 {
440 int oldCrc = getCrc32(outputData.data(),outputData.size());
441 outputData.clear();
442 dataChanged = false;
443
444 bool error = false;
445 int64_t start = memoryAddress;
446
447 for (ElfRelocatorFile& file: files)
448 {
449 if (relocateFile(file,memoryAddress) == false)
450 error = true;
451 }
452
453 int newCrc = getCrc32(outputData.data(),outputData.size());
454 if (oldCrc != newCrc)
455 dataChanged = true;
456
457 memoryAddress -= start;
458 return !error;
459 }
460
writeSymbols(SymbolData & symData) const461 void ElfRelocator::writeSymbols(SymbolData& symData) const
462 {
463 for (const ElfRelocatorFile& file: files)
464 {
465 for (const ElfRelocatorSymbol& sym: file.symbols)
466 {
467 symData.addLabel(sym.relocatedAddress,sym.name);
468
469 switch (sym.type)
470 {
471 case STT_OBJECT:
472 symData.addData(sym.relocatedAddress,sym.size,SymbolData::Data8);
473 break;
474 case STT_FUNC:
475 symData.startFunction(sym.relocatedAddress);
476 symData.endFunction(sym.relocatedAddress+sym.size);
477 break;
478 }
479 }
480 }
481 }
482