1 #include "stdafx.h"
2 #include "PsxRelocator.h"
3 #include "Core/Misc.h"
4 #include "Core/Common.h"
5 #include <map>
6 #include "Util/CRC.h"
7 #include "Core/FileManager.h"
8 #include "Util/Util.h"
9 
10 struct PsxLibEntry
11 {
12 	std::wstring name;
13 	ByteArray data;
14 };
15 
16 const unsigned char psxObjectFileMagicNum[6] = { 'L', 'N', 'K', '\x02', '\x2E', '\x07' };
17 
loadPsxLibrary(const std::wstring & inputName)18 std::vector<PsxLibEntry> loadPsxLibrary(const std::wstring& inputName)
19 {
20 	ByteArray input = ByteArray::fromFile(inputName);
21 	std::vector<PsxLibEntry> result;
22 
23 	if (input.size() == 0)
24 		return result;
25 
26 	if (memcmp(input.data(),psxObjectFileMagicNum,sizeof(psxObjectFileMagicNum)) == 0)
27 	{
28 		PsxLibEntry entry;
29 		entry.name = getFileNameFromPath(inputName);
30 		entry.data = input;
31 		result.push_back(entry);
32 		return result;
33 	}
34 
35 	if (memcmp(input.data(),"LIB\x01",4) != 0)
36 		return result;
37 
38 	size_t pos = 4;
39 	while (pos < input.size())
40 	{
41 		PsxLibEntry entry;
42 
43 		for (int i = 0; i < 16 && input[pos+i] != ' '; i++)
44 		{
45 			entry.name += input[pos+i];
46 		}
47 
48 		int size = input.getDoubleWord(pos+16);
49 		int skip = 20;
50 
51 		while (input[pos+skip] != 0)
52 		{
53 			skip += 1+input[pos+skip];
54 		}
55 
56 		skip++;
57 
58 		entry.data = input.mid(pos+skip,size-skip);
59 		pos += size;
60 
61 		result.push_back(entry);
62 	}
63 
64 	return result;
65 }
66 
loadString(ByteArray & data,size_t pos,std::wstring & dest)67 size_t PsxRelocator::loadString(ByteArray& data, size_t pos, std::wstring& dest)
68 {
69 	dest = L"";
70 	int len = data[pos++];
71 
72 	for (int i = 0; i < len; i++)
73 	{
74 		dest += data[pos++];
75 	}
76 
77 	return len+1;
78 }
79 
parseObject(ByteArray data,PsxRelocatorFile & dest)80 bool PsxRelocator::parseObject(ByteArray data, PsxRelocatorFile& dest)
81 {
82 	if (memcmp(data.data(),psxObjectFileMagicNum,sizeof(psxObjectFileMagicNum)) != 0)
83 		return false;
84 
85 	size_t pos = 6;
86 
87 	std::vector<PsxSegment>& segments = dest.segments;
88 	std::vector<PsxSymbol>& syms = dest.symbols;
89 
90 	int activeSegment = -1;
91 	int lastSegmentPartStart = -1;
92 	while (pos < data.size())
93 	{
94 		switch (data[pos])
95 		{
96 		case 0x10:	// segment definition
97 			{
98 				PsxSegment seg;
99 				seg.id = data.getDoubleWord(pos+1);
100 				segments.push_back(seg);
101 				pos += 5;
102 
103 				if (data[pos] != 8)
104 					return false;
105 
106 				std::wstring& name = segments[segments.size()-1].name;
107 				pos += 1 + loadString(data,pos+1,name);
108 			}
109 			break;
110 		case 0x14:	// group?
111 			pos += data[pos+4]+5;
112 			break;
113 		case 0x1C:	// source file name
114 			pos += data[pos+3]+4;
115 			break;
116 
117 		case 0x06:	// set segment id
118 			{
119 				int id = data.getWord(pos+1);
120 				pos += 3;
121 
122 				int num = -1;
123 				for (size_t i = 0; i < segments.size(); i++)
124 					{
125 					if (segments[i].id == id)
126 					{
127 						num = (int) i;
128 						break;
129 					}
130 				}
131 
132 				activeSegment = num;
133 			}
134 			break;
135 		case 0x02:	// append to data segment
136 			{
137 				int size = data.getWord(pos+1);
138 				pos += 3;
139 
140 				ByteArray d = data.mid(pos,size);
141 				pos += size;
142 
143 				lastSegmentPartStart = (int) segments[activeSegment].data.size();
144 				segments[activeSegment].data.append(d);
145 			}
146 			break;
147 		case 0x08:	// append zeroes data segment
148 			{
149 				int size = data.getWord(pos+1);
150 				pos += 3;
151 
152 				ByteArray d;
153 				d.reserveBytes(size);
154 				segments[activeSegment].data.append(d);
155 			}
156 			break;
157 		case 0x0A:	// relocation data
158 			{
159 				int type = data[pos+1];
160 				pos += 2;
161 
162 				PsxRelocation rel;
163 				rel.relativeOffset = 0;
164 				rel.filePos = (int) pos-2;
165 
166 				switch (type)
167 				{
168 				case 0x10:	// 32 bit word
169 					rel.type = PsxRelocationType::WordLiteral;
170 					rel.segmentOffset = data.getWord(pos);
171 					pos += 2;
172 					break;
173 				case 0x4A:	// jal
174 					rel.type = PsxRelocationType::FunctionCall;
175 					rel.segmentOffset = data.getWord(pos);
176 					pos += 2;
177 					break;
178 				case 0x52:	// upper immerdiate
179 					rel.type = PsxRelocationType::UpperImmediate;
180 					rel.segmentOffset = data.getWord(pos);
181 					pos += 2;
182 					break;
183 				case 0x54:	// lower immediate (add)
184 					rel.type = PsxRelocationType::LowerImmediate;
185 					rel.segmentOffset = data.getWord(pos);
186 					pos += 2;
187 					break;
188 				default:
189 					return false;
190 				}
191 
192 				rel.segmentOffset += lastSegmentPartStart;
193 checkothertype:
194 				int otherType = data[pos++];
195 				switch (otherType)
196 				{
197 				case 0x02:	// reference to symbol with id num
198 					rel.refType = PsxRelocationRefType::SymblId;
199 					rel.referenceId = data.getWord(pos);
200 					pos += 2;
201 					break;
202 				case 0x2C:	// ref to other segment?
203 					rel.refType = PsxRelocationRefType::SegmentOffset;
204 
205 					switch (data[pos++])
206 					{
207 					case 0x00:
208 						rel.relativeOffset = data.getDoubleWord(pos);
209 						pos += 4;
210 						goto checkothertype;
211 					case 0x04:
212 						rel.referenceId = data.getWord(pos);	// segment id
213 						pos += 2;
214 
215 						if (data[pos++] != 0x00)
216 						{
217 							return false;
218 						}
219 
220 						rel.referencePos = data.getDoubleWord(pos);
221 						pos += 4;
222 						break;
223 					default:
224 						return false;
225 					}
226 					break;
227 				case 0x2E:	// negative ref?
228 					rel.refType = PsxRelocationRefType::SegmentOffset;
229 
230 					switch (data[pos++])
231 					{
232 					case 0x00:
233 						rel.relativeOffset = -data.getDoubleWord(pos);
234 						pos += 4;
235 						goto checkothertype;
236 					default:
237 						return false;
238 					}
239 					break;
240 				default:
241 					return false;
242 				}
243 
244 				segments[activeSegment].relocations.push_back(rel);
245 			}
246 			break;
247 		case 0x12:	// internal symbol
248 			{
249 				PsxSymbol sym;
250 				sym.type = PsxSymbolType::Internal;
251 				sym.segment = data.getWord(pos+1);
252 				sym.offset = data.getDoubleWord(pos+3);
253 				pos += 7 + loadString(data,pos+7,sym.name);
254 				syms.push_back(sym);
255 			}
256 			break;
257 		case 0x0E:	// external symbol
258 			{
259 				PsxSymbol sym;
260 				sym.type = PsxSymbolType::External;
261 				sym.id = data.getWord(pos+1);
262 				pos += 3 + loadString(data,pos+3,sym.name);
263 				syms.push_back(sym);
264 			}
265 			break;
266 		case 0x30:	// bss symbol?
267 			{
268 				PsxSymbol sym;
269 				sym.type = PsxSymbolType::BSS;
270 				sym.id = data.getWord(pos+1);
271 				sym.segment = data.getWord(pos+3);
272 				sym.size = data.getDoubleWord(pos+5);
273 				pos += 9 + loadString(data,pos+9,sym.name);
274 				syms.push_back(sym);
275 			}
276 			break;
277 		case 0x0C:	// internal with id
278 			{
279 				PsxSymbol sym;
280 				sym.type = PsxSymbolType::InternalID;
281 				sym.id = data.getWord(pos+1);
282 				sym.segment = data.getWord(pos+3);
283 				sym.offset = data.getDoubleWord(pos+5);
284 				pos += 9 + loadString(data,pos+9,sym.name);
285 				syms.push_back(sym);
286 			}
287 			break;
288 		case 0x4A:	// function
289 			{
290 				PsxSymbol sym;
291 				sym.type = PsxSymbolType::Function;
292 				sym.segment = data.getWord(pos+1);
293 				sym.offset = data.getDoubleWord(pos+3);
294 				pos += 0x1D + loadString(data,pos+0x1D,sym.name);
295 				syms.push_back(sym);
296 			}
297 			break;
298 		case 0x4C:	// function size
299 			pos += 11;
300 			break;
301 		case 0x3C:	// ??
302 			pos += 3;
303 			break;
304 		case 0x00:	// ??
305 			pos++;
306 			break;
307 		case 0x32:	// ??
308 			pos += 3;
309 			break;
310 		case 0x3A:	// ??
311 			pos += 9;
312 			break;
313 		default:
314 			return false;
315 		}
316 	}
317 
318 	return true;
319 }
320 
init(const std::wstring & inputName)321 bool PsxRelocator::init(const std::wstring& inputName)
322 {
323 	auto inputFiles = loadPsxLibrary(inputName);
324 	if (inputFiles.size() == 0)
325 	{
326 		Logger::printError(Logger::Error,L"Could not load library");
327 		return false;
328 	}
329 
330 	reloc = new MipsElfRelocator();
331 
332 	for (PsxLibEntry& entry: inputFiles)
333 	{
334 		PsxRelocatorFile file;
335 		file.name = entry.name;
336 
337 		if (parseObject(entry.data,file) == false)
338 		{
339 			Logger::printError(Logger::Error,L"Could not load object file %s",entry.name);
340 			return false;
341 		}
342 
343 		// init symbols
344 		for (PsxSymbol& sym: file.symbols)
345 		{
346 			std::wstring lowered = sym.name;
347 			std::transform(lowered.begin(), lowered.end(), lowered.begin(), ::towlower);
348 
349 			sym.label = Global.symbolTable.getLabel(lowered,-1,-1);
350 			if (sym.label == nullptr)
351 			{
352 				Logger::printError(Logger::Error,L"Invalid label name \"%s\"",sym.name);
353 				continue;
354 			}
355 
356 			if (sym.label->isDefined() && sym.type != PsxSymbolType::External)
357 			{
358 				Logger::printError(Logger::Error,L"Label \"%s\" already defined",sym.name);
359 				continue;
360 			}
361 
362 			sym.label->setOriginalName(sym.name);
363 		}
364 
365 		files.push_back(file);
366 	}
367 
368 	return true;
369 }
370 
relocateFile(PsxRelocatorFile & file,int & relocationAddress)371 bool PsxRelocator::relocateFile(PsxRelocatorFile& file, int& relocationAddress)
372 {
373 	std::map<int,int> relocationOffsets;
374 	std::map<int,int> symbolOffsets;
375 	int start = relocationAddress;
376 
377 	// assign addresses to segments
378 	for (PsxSegment& seg: file.segments)
379 	{
380 		int index = seg.id;
381 		size_t size = seg.data.size();
382 
383 		relocationOffsets[index] = relocationAddress;
384 		relocationAddress += (int) size;
385 
386 		while (relocationAddress % 4)
387 			relocationAddress++;
388 	}
389 
390 	// parse/add/relocate symbols
391 	bool error = false;
392 	for (PsxSymbol& sym: file.symbols)
393 	{
394 		int pos;
395 		switch (sym.type)
396 		{
397 		case PsxSymbolType::Internal:
398 		case PsxSymbolType::Function:
399 			sym.label->setValue(relocationOffsets[sym.segment]+sym.offset);
400 			sym.label->setDefined(true);
401 			break;
402 		case PsxSymbolType::InternalID:
403 			pos = relocationOffsets[sym.segment]+sym.offset;
404 			sym.label->setValue(pos);
405 			sym.label->setDefined(true);
406 			symbolOffsets[sym.id] = pos;
407 			break;
408 		case PsxSymbolType::BSS:
409 			sym.label->setValue(relocationAddress);
410 			sym.label->setDefined(true);
411 			symbolOffsets[sym.id] = relocationAddress;
412 			relocationAddress += sym.size;
413 
414 			while (relocationAddress % 4)
415 				relocationAddress++;
416 			break;
417 		case PsxSymbolType::External:
418 			if (sym.label->isDefined() == false)
419 			{
420 				Logger::queueError(Logger::Error,L"Undefined external symbol %s in file %s",sym.name,file.name);
421 				error = true;
422 				continue;
423 			}
424 
425 			symbolOffsets[sym.id] = (int) sym.label->getValue();
426 			break;
427 		}
428 	}
429 
430 	if (error)
431 		return false;
432 
433 	size_t dataStart = outputData.size();
434 	outputData.reserveBytes(relocationAddress-start);
435 
436 	// load code and data
437 	for (PsxSegment& seg: file.segments)
438 	{
439 		// relocate
440 		ByteArray sectionData = seg.data;
441 		for (PsxRelocation& rel: seg.relocations)
442 		{
443 			RelocationData relData;
444 			int pos = rel.segmentOffset;
445 			relData.opcode = sectionData.getDoubleWord(pos);
446 
447 			switch (rel.refType)
448 			{
449 			case PsxRelocationRefType::SymblId:
450 				relData.relocationBase = symbolOffsets[rel.referenceId]+rel.relativeOffset;
451 				break;
452 			case PsxRelocationRefType::SegmentOffset:
453 				relData.relocationBase = relocationOffsets[rel.referenceId] + rel.referencePos+rel.relativeOffset;
454 				break;
455 			}
456 
457 			switch (rel.type)
458 			{
459 			case PsxRelocationType::WordLiteral:
460 				reloc->relocateOpcode(R_MIPS_32,relData);
461 				break;
462 			case PsxRelocationType::UpperImmediate:
463 				reloc->relocateOpcode(R_MIPS_HI16,relData);
464 				break;
465 			case PsxRelocationType::LowerImmediate:
466 				reloc->relocateOpcode(R_MIPS_LO16,relData);
467 				break;
468 			case PsxRelocationType::FunctionCall:
469 				reloc->relocateOpcode(R_MIPS_26,relData);
470 				break;
471 			}
472 
473 			sectionData.replaceDoubleWord(pos,relData.opcode);
474 		}
475 
476 		size_t arrayStart = dataStart+relocationOffsets[seg.id]-start;
477 		memcpy(outputData.data(arrayStart),sectionData.data(),sectionData.size());
478 	}
479 
480 	return true;
481 }
482 
relocate(int & memoryAddress)483 bool PsxRelocator::relocate(int& memoryAddress)
484 {
485 	int oldCrc = getCrc32(outputData.data(),outputData.size());
486 	outputData.clear();
487 	dataChanged = false;
488 
489 	bool error = false;
490 	int start = memoryAddress;
491 
492 	for (PsxRelocatorFile& file: files)
493 	{
494 		if (relocateFile(file,memoryAddress) == false)
495 			error = true;
496 	}
497 
498 	int newCrc = getCrc32(outputData.data(),outputData.size());
499 	if (oldCrc != newCrc)
500 		dataChanged = true;
501 
502 	memoryAddress -= start;
503 	return !error;
504 }
505 
506 
writeSymbols(SymbolData & symData) const507 void PsxRelocator::writeSymbols(SymbolData& symData) const
508 {
509 	for (const PsxRelocatorFile& file: files)
510 	{
511 		for (const PsxSymbol& sym: file.symbols)
512 		{
513 			if (sym.type != PsxSymbolType::External)
514 				symData.addLabel(sym.label->getValue(),sym.name.c_str());
515 		}
516 	}
517 }
518 
519 //
520 // DirectivePsxObjImport
521 //
522 
DirectivePsxObjImport(const std::wstring & fileName)523 DirectivePsxObjImport::DirectivePsxObjImport(const std::wstring& fileName)
524 {
525 	if (rel.init(fileName))
526 	{
527 	}
528 }
529 
Validate()530 bool DirectivePsxObjImport::Validate()
531 {
532 	int memory = (int) g_fileManager->getVirtualAddress();
533 	rel.relocate(memory);
534 	g_fileManager->advanceMemory(memory);
535 	return rel.hasDataChanged();
536 }
537 
Encode() const538 void DirectivePsxObjImport::Encode() const
539 {
540 	const ByteArray& data = rel.getData();
541 	g_fileManager->write(data.data(),data.size());
542 }
543 
writeSymData(SymbolData & symData) const544 void DirectivePsxObjImport::writeSymData(SymbolData& symData) const
545 {
546 	rel.writeSymbols(symData);
547 }
548