예제 #1
0
void ElfFile::loadProgramHeader(Elf32_Phdr& header, ByteArray& data, int pos)
{
	bool bigEndian = isBigEndian();
	header.p_type   = data.getDoubleWord(pos + 0x00, bigEndian);
	header.p_offset = data.getDoubleWord(pos + 0x04, bigEndian);
	header.p_vaddr  = data.getDoubleWord(pos + 0x08, bigEndian);
	header.p_paddr  = data.getDoubleWord(pos + 0x0C, bigEndian);
	header.p_filesz = data.getDoubleWord(pos + 0x10, bigEndian);
	header.p_memsz  = data.getDoubleWord(pos + 0x14, bigEndian);
	header.p_flags  = data.getDoubleWord(pos + 0x18, bigEndian);
	header.p_align  = data.getDoubleWord(pos + 0x1C, bigEndian);
}
예제 #2
0
void ElfFile::loadSectionHeader(Elf32_Shdr& header, ByteArray& data, int pos)
{
	bool bigEndian = isBigEndian();
	header.sh_name      = data.getDoubleWord(pos + 0x00, bigEndian);
	header.sh_type      = data.getDoubleWord(pos + 0x04, bigEndian);
	header.sh_flags     = data.getDoubleWord(pos + 0x08, bigEndian);
	header.sh_addr      = data.getDoubleWord(pos + 0x0C, bigEndian);
	header.sh_offset    = data.getDoubleWord(pos + 0x10, bigEndian);
	header.sh_size      = data.getDoubleWord(pos + 0x14, bigEndian);
	header.sh_link      = data.getDoubleWord(pos + 0x18, bigEndian);
	header.sh_info      = data.getDoubleWord(pos + 0x1C, bigEndian);
	header.sh_addralign = data.getDoubleWord(pos + 0x20, bigEndian);
	header.sh_entsize   = data.getDoubleWord(pos + 0x24, bigEndian);
}
예제 #3
0
std::vector<PsxLibEntry> loadPsxLibrary(const std::wstring& inputName)
{
	ByteArray input = ByteArray::fromFile(inputName);
	std::vector<PsxLibEntry> result;

	if (input.size() == 0)
		return result;

	if (memcmp(input.data(),psxObjectFileMagicNum,sizeof(psxObjectFileMagicNum)) == 0)
	{
		PsxLibEntry entry;
		entry.name = getFileNameFromPath(inputName);
		entry.data = input;
		result.push_back(entry);
		return result;
	}
	
	if (memcmp(input.data(),"LIB\x01",4) != 0)
		return result;

	int pos = 4;
	while (pos < input.size())
	{
		PsxLibEntry entry;
		
		for (int i = 0; i < 16 && input[pos+i] != ' '; i++)
		{
			entry.name += input[pos+i];
		}

		int size = input.getDoubleWord(pos+16);
		int skip = 20;

		while (input[pos+skip] != 0)
		{
			skip += input[pos+skip++];
		}

		skip++;

		entry.data = input.mid(pos+skip,size-skip);
		pos += size;

		result.push_back(entry);
	}

	return result;
}
예제 #4
0
bool ElfRelocator::relocateFile(ElfRelocatorFile& file, u64& relocationAddress)
{
	ElfFile* elf = file.elf;
	u64 start = relocationAddress;

	// calculate address for each section
	std::map<u64,u64> relocationOffsets;
	for (ElfRelocatorSection& entry: file.sections)
	{
		ElfSection* section = entry.section;
		size_t index = entry.index;
		int size = section->getSize();

		while (relocationAddress % section->getAlignment())
			relocationAddress++;

		if (entry.label != NULL)
			entry.label->setValue(relocationAddress);

		relocationOffsets[index] = relocationAddress;
		relocationAddress += size;
	}

	size_t dataStart = outputData.size();
	outputData.reserveBytes((size_t)(relocationAddress-start));

	// load sections
	bool error = false;
	for (ElfRelocatorSection& entry: file.sections)
	{
		ElfSection* section = entry.section;
		size_t index = entry.index;

		if (section->getType() == SHT_NOBITS)
		{
			// reserveBytes initialized the data to 0 already
			continue;
		}
		
		ByteArray sectionData = section->getData();

		// relocate if necessary
		ElfSection* relSection = entry.relSection;
		if (relSection != NULL)
		{
			for (unsigned int relOffset = 0; relOffset < relSection->getSize(); relOffset += sizeof(Elf32_Rel))
			{
				Elf32_Rel rel;
				loadRelocation(rel, relSection->getData(), relOffset, elf->isBigEndian());
				int pos = rel.r_offset;

				int symNum = rel.getSymbolNum();
				if (symNum <= 0)
				{
					Logger::queueError(Logger::Warning,L"Invalid symbol num %06X",symNum);
					error = true;
					continue;
				}

				Elf32_Sym sym;
				auto found = elf->getSymbol(sym, symNum);
				int symSection = sym.st_shndx;
				
				RelocationData relData;
				relData.opcode = sectionData.getDoubleWord(pos, elf->isBigEndian());
				relData.opcodeOffset = pos+relocationOffsets[index];
				relocator->setSymbolAddress(relData,sym.st_value,sym.st_info & 0xF);

				// externs?
				if (relData.targetSymbolType == STT_NOTYPE && sym.st_shndx == 0)
				{
					std::wstring symName = toWLowercase(elf->getStrTableString(sym.st_name));

					Label* label = Global.symbolTable.getLabel(symName,-1,-1);
					if (label == NULL)
					{
						Logger::queueError(Logger::Error,L"Invalid external symbol %s",symName);	
						error = true;
						continue;
					}
					if (label->isDefined() == false)
					{
						Logger::queueError(Logger::Error,L"Undefined external symbol %s in file %s",symName,file.name);
						error = true;
						continue;
					}
					
					relData.relocationBase = (unsigned int) label->getValue();
					relData.targetSymbolType = label->isData() ? STT_OBJECT : STT_FUNC;
					relData.targetSymbolInfo = label->getInfo();
				} else {
					relData.relocationBase = relocationOffsets[symSection]+relData.symbolAddress;
				}

				if (relocator->relocateOpcode(rel.getType(),relData) == false)
				{
					Logger::queueError(Logger::Error,relData.errorMessage);
					error = true;
					continue;
				}

				sectionData.replaceDoubleWord(pos,relData.opcode, elf->isBigEndian());
			}
		}

		size_t arrayStart = (size_t) (dataStart+relocationOffsets[index]-start);
		memcpy(outputData.data(arrayStart),sectionData.data(),sectionData.size());
	}
	
	// now update symbols
	for (ElfRelocatorSymbol& sym: file.symbols)
	{
		u64 oldAddress = sym.relocatedAddress;

		switch (sym.section)
		{
		case SHN_ABS:		// address does not change
			sym.relocatedAddress = sym.relativeAddress;
			break;
		case SHN_COMMON:	// needs to be allocated. relativeAddress gives alignment constraint
			{
				u64 start = relocationAddress;

				while (relocationAddress % sym.relativeAddress)
					relocationAddress++;

				sym.relocatedAddress = relocationAddress;
				relocationAddress += sym.size;
				outputData.reserveBytes((size_t)(relocationAddress-start));
			}
			break;
		default:			// normal relocated symbol
			sym.relocatedAddress = sym.relativeAddress+relocationOffsets[sym.section];
			break;
		}

		if (sym.label != NULL)
			sym.label->setValue(sym.relocatedAddress);

		if (oldAddress != sym.relocatedAddress)
			dataChanged = true;
	}

	return !error;
}
예제 #5
0
void ElfRelocator::loadRelocation(Elf32_Rel& rel, ByteArray& data, int offset, bool bigEndian)
{
	rel.r_offset = data.getDoubleWord(offset + 0x00, bigEndian);
	rel.r_info   = data.getDoubleWord(offset + 0x04, bigEndian);
}
예제 #6
0
bool PsxRelocator::parseObject(ByteArray data, PsxRelocatorFile& dest)
{
	if (memcmp(data.data(),psxObjectFileMagicNum,sizeof(psxObjectFileMagicNum)) != 0)
		return false;

	int pos = 6;

	std::vector<PsxSegment>& segments = dest.segments;
	std::vector<PsxSymbol>& syms = dest.symbols;

	int activeSegment = -1;
	int lastSegmentPartStart = -1;
	while (pos < data.size())
	{
		switch (data[pos])
		{
		case 0x10:	// segment definition
			{
				PsxSegment seg;
				seg.id = data.getDoubleWord(pos+1);
				segments.push_back(seg);
				pos += 5;

				if (data[pos] != 8)
					return false;

				int nameLen = data[pos+1];
				std::wstring& name = segments[segments.size()-1].name;
				pos += 1 + loadString(data,pos+1,name);
			}
			break;
		case 0x14:	// group?
			pos += data[pos+4]+5;
			break;
		case 0x1C:	// source file name
			pos += data[pos+3]+4;
			break;

		case 0x06:	// set segment id
			{
				int id = data.getWord(pos+1);
				pos += 3;
				
				int num = -1;
				for (size_t i = 0; i < segments.size(); i++)
					{
					if (segments[i].id == id)
					{
						num = i;
						break;
					}
				}

				activeSegment = num;
			}
			break;
		case 0x02:	// append to data segment
			{
				int size = data.getWord(pos+1);
				pos += 3;

				ByteArray d = data.mid(pos,size);
				pos += size;

				lastSegmentPartStart = segments[activeSegment].data.size();
				segments[activeSegment].data.append(d);
			}
			break;
		case 0x08:	// append zeroes data segment
			{
				int size = data.getWord(pos+1);
				pos += 3;

				ByteArray d;
				d.reserveBytes(size);
				segments[activeSegment].data.append(d);
			}
			break;
		case 0x0A:	// relocation data
			{
				int type = data[pos+1];
				pos += 2;

				PsxRelocation rel;
				rel.relativeOffset = 0;
				rel.filePos = pos-2;

				switch (type)
				{
				case 0x10:	// 32 bit word
					rel.type = PsxRelocationType::WordLiteral;
					rel.segmentOffset = data.getWord(pos);
					pos += 2;
					break;
				case 0x4A:	// jal
					rel.type = PsxRelocationType::FunctionCall;
					rel.segmentOffset = data.getWord(pos);
					pos += 2;
					break;
				case 0x52:	// upper immerdiate
					rel.type = PsxRelocationType::UpperImmediate;
					rel.segmentOffset = data.getWord(pos);
					pos += 2;
					break;
				case 0x54:	// lower immediate (add)
					rel.type = PsxRelocationType::LowerImmediate;
					rel.segmentOffset = data.getWord(pos);
					pos += 2;
					break;
				default:
					return false;
				}

				rel.segmentOffset += lastSegmentPartStart;
checkothertype:
				int otherType = data[pos++];
				switch (otherType)
				{
				case 0x02:	// reference to symbol with id num
					rel.refType = PsxRelocationRefType::SymblId;
					rel.referenceId = data.getWord(pos);
					pos += 2;
					break;
				case 0x2C:	// ref to other segment?
					rel.refType = PsxRelocationRefType::SegmentOffset;

					switch (data[pos++])
					{
					case 0x00:
						rel.relativeOffset = data.getDoubleWord(pos);
						pos += 4;
						goto checkothertype;
					case 0x04:					
						rel.referenceId = data.getWord(pos);	// segment id
						pos += 2;
					
						if (data[pos++] != 0x00)
						{
							return false;
						}

						rel.referencePos = data.getDoubleWord(pos);
						pos += 4;
						break;
					default:
						return false;
					}
					break;
				case 0x2E:	// negative ref?
					rel.refType = PsxRelocationRefType::SegmentOffset;

					switch (data[pos++])
					{
					case 0x00:
						rel.relativeOffset = -data.getDoubleWord(pos);
						pos += 4;
						goto checkothertype;
					default:
						return false;
					}
					break;
				default:
					return false;
				}

				segments[activeSegment].relocations.push_back(rel);
			}
			break;
		case 0x12:	// internal symbol
			{
				PsxSymbol sym;
				sym.type = PsxSymbolType::Internal;
				sym.segment = data.getWord(pos+1);
				sym.offset = data.getDoubleWord(pos+3);
				pos += 7 + loadString(data,pos+7,sym.name);
				syms.push_back(sym);
			}
			break;
		case 0x0E:	// external symbol
			{
				PsxSymbol sym;
				sym.type = PsxSymbolType::External;
				sym.id = data.getWord(pos+1);
				pos += 3 + loadString(data,pos+3,sym.name);
				syms.push_back(sym);
			}
			break;
		case 0x30:	// bss symbol?
			{
				PsxSymbol sym;
				sym.type = PsxSymbolType::BSS;
				sym.id = data.getWord(pos+1);
				sym.segment = data.getWord(pos+3);
				sym.size = data.getDoubleWord(pos+5);
				pos += 9 + loadString(data,pos+9,sym.name);
				syms.push_back(sym);
			}
			break;
		case 0x0C:	// internal with id
			{
				PsxSymbol sym;
				sym.type = PsxSymbolType::InternalID;
				sym.id = data.getWord(pos+1);
				sym.segment = data.getWord(pos+3);
				sym.offset = data.getDoubleWord(pos+5);
				pos += 9 + loadString(data,pos+9,sym.name);
				syms.push_back(sym);
			}
			break;
		case 0x4A:	// function
			{
				PsxSymbol sym;
				sym.type = PsxSymbolType::Function;
				sym.segment = data.getWord(pos+1);
				sym.offset = data.getDoubleWord(pos+3);
				pos += 0x1D + loadString(data,pos+0x1D,sym.name);
				syms.push_back(sym);
			}
			break;
		case 0x4C:	// function size
			pos += 11;
			break;
		case 0x3C:	// ??
			pos += 3;
			break;
		case 0x00:	// ??
			pos++;
			break;
		case 0x32:	// ??
			pos += 3;
			break;
		case 0x3A:	// ??
			pos += 9;
			break;
		default:
			return false;
		}
	}

	return true;
}
예제 #7
0
bool PsxRelocator::relocateFile(PsxRelocatorFile& file, int& relocationAddress)
{
	std::map<int,int> relocationOffsets;
	std::map<int,int> symbolOffsets;
	int start = relocationAddress;

	// assign addresses to segments
	for (PsxSegment& seg: file.segments)
	{
		int index = seg.id;
		int size = seg.data.size();
		
		relocationOffsets[index] = relocationAddress;
		relocationAddress += size;

		while (relocationAddress % 4)
			relocationAddress++;
	}
	
	// parse/add/relocate symbols
	bool error = false;
	for (PsxSymbol& sym: file.symbols)
	{
		int pos;
		switch (sym.type)
		{
		case PsxSymbolType::Internal:
		case PsxSymbolType::Function:
			sym.label->setValue(relocationOffsets[sym.segment]+sym.offset);
			sym.label->setDefined(true);
			break;
		case PsxSymbolType::InternalID:
			pos = relocationOffsets[sym.segment]+sym.offset;
			sym.label->setValue(pos);
			sym.label->setDefined(true);
			symbolOffsets[sym.id] = pos;
			break;
		case PsxSymbolType::BSS:
			sym.label->setValue(relocationAddress);
			sym.label->setDefined(true);
			symbolOffsets[sym.id] = relocationAddress;
			relocationAddress += sym.size;
			
			while (relocationAddress % 4)
				relocationAddress++;
			break;
		case PsxSymbolType::External:
			if (sym.label->isDefined() == false)
			{
				Logger::queueError(Logger::Error,L"Undefined external symbol %s in file %s",sym.name,file.name);
				error = true;
				continue;
			}
			
			symbolOffsets[sym.id] = sym.label->getValue();
			break;
		}
	}

	if (error)
		return false;

	int dataStart = outputData.size();
	outputData.reserveBytes(relocationAddress-start);

	// load code and data
	for (PsxSegment& seg: file.segments)
	{
		// relocate
		ByteArray sectionData = seg.data;
		for (PsxRelocation& rel: seg.relocations)
		{
			RelocationData relData;
			int pos = rel.segmentOffset;
			relData.opcode = sectionData.getDoubleWord(pos);

			switch (rel.refType)
			{
			case PsxRelocationRefType::SymblId:
				relData.relocationBase = symbolOffsets[rel.referenceId]+rel.relativeOffset;
				break;
			case PsxRelocationRefType::SegmentOffset:
				relData.relocationBase = relocationOffsets[rel.referenceId] + rel.referencePos+rel.relativeOffset;
				break;
			}
			
			switch (rel.type)
			{
			case PsxRelocationType::WordLiteral:
				reloc->relocateOpcode(R_MIPS_32,relData);
				break;
			case PsxRelocationType::UpperImmediate:
				reloc->relocateOpcode(R_MIPS_HI16,relData);
				break;
			case PsxRelocationType::LowerImmediate:
				reloc->relocateOpcode(R_MIPS_LO16,relData);
				break;
			case PsxRelocationType::FunctionCall:
				reloc->relocateOpcode(R_MIPS_26,relData);
				break;
			}

			sectionData.replaceDoubleWord(pos,relData.opcode);
		}

		int arrayStart = dataStart+relocationOffsets[seg.id]-start;
		memcpy(outputData.data(arrayStart),sectionData.data(),sectionData.size());
	}

	return true;
}