1 #include "CoffObjectFile.h"
2 #include <string.h>
3 #include <assert.h>
4 #include <time.h>
5 #include <algorithm>
6 
7 using namespace Jitter;
8 
CCoffObjectFile(CPU_ARCH cpuArch)9 CCoffObjectFile::CCoffObjectFile(CPU_ARCH cpuArch)
10 : CObjectFile(cpuArch)
11 {
12 
13 }
14 
~CCoffObjectFile()15 CCoffObjectFile::~CCoffObjectFile()
16 {
17 
18 }
19 
Write(Framework::CStream & stream)20 void CCoffObjectFile::Write(Framework::CStream& stream)
21 {
22 	struct OffsetKeeper
23 	{
24 		OffsetKeeper()
25 		{
26 			currentOffset = 0;
27 		}
28 
29 		uint32 Advance(uint32 size)
30 		{
31 			currentOffset += size;
32 			return currentOffset;
33 		}
34 
35 		uint32 currentOffset;
36 	};
37 
38 	auto internalSymbolInfos = InternalSymbolInfoArray(m_internalSymbols.size());
39 	auto externalSymbolInfos = ExternalSymbolInfoArray(m_externalSymbols.size());
40 
41 	StringTable stringTable;
42 	FillStringTable(stringTable, m_internalSymbols, internalSymbolInfos);
43 	FillStringTable(stringTable, m_externalSymbols, externalSymbolInfos);
44 
45 	auto textSection = BuildSection(m_internalSymbols, internalSymbolInfos, INTERNAL_SYMBOL_LOCATION_TEXT);
46 	auto dataSection = BuildSection(m_internalSymbols, internalSymbolInfos, INTERNAL_SYMBOL_LOCATION_DATA);
47 
48 	auto symbols = BuildSymbols(m_internalSymbols, internalSymbolInfos,
49 		m_externalSymbols, externalSymbolInfos, textSection.data.size(), dataSection.data.size());
50 
51 	unsigned int sectionHeaderCount = 2;
52 
53 	OffsetKeeper offsetKeeper;
54 	uint32 textSectionDataOffset = offsetKeeper.Advance(sizeof(Coff::HEADER) + (sectionHeaderCount * sizeof(Coff::SECTION_HEADER)));
55 	uint32 textSectionRelocOffset = offsetKeeper.Advance(textSection.data.size());
56 	uint32 dataSectionDataOffset = offsetKeeper.Advance((textSection.symbolReferences.size() * sizeof(Coff::RELOCATION)));
57 	uint32 dataSectionRelocOffset = offsetKeeper.Advance(dataSection.data.size());
58 	uint32 symbolTableOffset = offsetKeeper.Advance(dataSection.symbolReferences.size() * sizeof(Coff::RELOCATION));
59 
60 	SectionHeaderArray sectionHeaders;
61 
62 	{
63 		Coff::SECTION_HEADER sectionHeader = {};
64 		strncpy(sectionHeader.name, ".text", 8);
65 		sectionHeader.virtualSize			= 0;
66 		sectionHeader.virtualAddress		= 0;
67 		sectionHeader.sizeOfRawData			= textSection.data.size();
68 		sectionHeader.pointerToRawData		= textSectionDataOffset;
69 		sectionHeader.pointerToRelocations	= (textSection.symbolReferences.size() == 0) ? 0 : textSectionRelocOffset;
70 		sectionHeader.pointerToLineNumbers	= 0;
71 		sectionHeader.numberOfRelocations	= textSection.symbolReferences.size();
72 		sectionHeader.numberOfLineNumbers	= 0;
73 		sectionHeader.characteristics		= 0x60500020;
74 		sectionHeaders.push_back(sectionHeader);
75 	}
76 
77 	{
78 		Coff::SECTION_HEADER sectionHeader = {};
79 		strncpy(sectionHeader.name, ".data", 8);
80 		sectionHeader.virtualSize			= 0;
81 		sectionHeader.virtualAddress		= 0;
82 		sectionHeader.sizeOfRawData			= dataSection.data.size();
83 		sectionHeader.pointerToRawData		= dataSectionDataOffset;
84 		sectionHeader.pointerToRelocations	= (dataSection.symbolReferences.size() == 0) ? 0 : dataSectionRelocOffset;
85 		sectionHeader.pointerToLineNumbers	= 0;
86 		sectionHeader.numberOfRelocations	= dataSection.symbolReferences.size();
87 		sectionHeader.numberOfLineNumbers	= 0;
88 		sectionHeader.characteristics		= 0xC0500040;
89 		sectionHeaders.push_back(sectionHeader);
90 	}
91 
92 	auto textSectionRelocations = BuildRelocations(textSection, internalSymbolInfos, externalSymbolInfos);
93 	auto dataSectionRelocations = BuildRelocations(dataSection, internalSymbolInfos, externalSymbolInfos);
94 
95 	Coff::HEADER header = {};
96 	header.machine				= Coff::MACHINE_TYPE_I386;
97 	header.numberOfSections		= sectionHeaderCount;
98 	header.timeDateStamp		= static_cast<uint32>(time(nullptr));
99 	header.pointerToSymbolTable	= symbolTableOffset;
100 	header.numberOfSymbols		= symbols.size();
101 	header.sizeOfOptionalHeader	= 0;
102 	header.characteristics		= 0;
103 
104 	stream.Write(&header, sizeof(Coff::HEADER));
105 	stream.Write(sectionHeaders.data(), sectionHeaders.size() * sizeof(Coff::SECTION_HEADER));
106 	stream.Write(textSection.data.data(), textSection.data.size());
107 	stream.Write(textSectionRelocations.data(), textSectionRelocations.size() * sizeof(Coff::RELOCATION));
108 	stream.Write(dataSection.data.data(), dataSection.data.size());
109 	stream.Write(dataSectionRelocations.data(), dataSectionRelocations.size() * sizeof(Coff::RELOCATION));
110 	stream.Write(symbols.data(), symbols.size() * sizeof(Coff::SYMBOL));
111 	stream.Write32(stringTable.size() + 4);
112 	stream.Write(stringTable.data(), stringTable.size());
113 }
114 
FillStringTable(StringTable & stringTable,const InternalSymbolArray & internalSymbols,InternalSymbolInfoArray & internalSymbolInfos)115 void CCoffObjectFile::FillStringTable(StringTable& stringTable, const InternalSymbolArray& internalSymbols, InternalSymbolInfoArray& internalSymbolInfos)
116 {
117 	uint32 stringTableSizeIncrement = 0;
118 	for(const auto& internalSymbol : internalSymbols)
119 	{
120 		stringTableSizeIncrement += internalSymbol.name.length() + 1;
121 	}
122 	stringTable.reserve(stringTable.size() + stringTableSizeIncrement);
123 	for(uint32 i = 0; i < internalSymbols.size(); i++)
124 	{
125 		const auto& internalSymbol = internalSymbols[i];
126 		auto& internalSymbolInfo = internalSymbolInfos[i];
127 		internalSymbolInfo.nameOffset = stringTable.size();
128 		stringTable.insert(std::end(stringTable), std::begin(internalSymbol.name), std::end(internalSymbol.name));
129 		stringTable.push_back(0);
130 	}
131 }
132 
FillStringTable(StringTable & stringTable,const ExternalSymbolArray & externalSymbols,ExternalSymbolInfoArray & externalSymbolInfos)133 void CCoffObjectFile::FillStringTable(StringTable& stringTable, const ExternalSymbolArray& externalSymbols, ExternalSymbolInfoArray& externalSymbolInfos)
134 {
135 	uint32 stringTableSizeIncrement = 0;
136 	for(const auto& externalSymbol : externalSymbols)
137 	{
138 		stringTableSizeIncrement += externalSymbol.name.length() + 1;
139 	}
140 	stringTable.reserve(stringTable.size() + stringTableSizeIncrement);
141 	for(uint32 i = 0; i < externalSymbols.size(); i++)
142 	{
143 		const auto& externalSymbol = externalSymbols[i];
144 		auto& externalSymbolInfo = externalSymbolInfos[i];
145 		externalSymbolInfo.nameOffset = stringTable.size();
146 		stringTable.insert(std::end(stringTable), std::begin(externalSymbol.name), std::end(externalSymbol.name));
147 		stringTable.push_back(0);
148 	}
149 }
150 
BuildSection(const InternalSymbolArray & internalSymbols,InternalSymbolInfoArray & internalSymbolInfos,INTERNAL_SYMBOL_LOCATION location)151 CCoffObjectFile::SECTION CCoffObjectFile::BuildSection(const InternalSymbolArray& internalSymbols, InternalSymbolInfoArray& internalSymbolInfos, INTERNAL_SYMBOL_LOCATION location)
152 {
153 	SECTION section;
154 	auto& sectionData(section.data);
155 	uint32 sectionSize = 0;
156 	for(const auto& internalSymbol : internalSymbols)
157 	{
158 		sectionSize += internalSymbol.data.size();
159 	}
160 	sectionData.reserve(sectionSize);
161 	for(uint32 i = 0; i < internalSymbols.size(); i++)
162 	{
163 		const auto& internalSymbol = internalSymbols[i];
164 		if(internalSymbol.location != location) continue;
165 
166 		auto& internalSymbolInfo = internalSymbolInfos[i];
167 		internalSymbolInfo.dataOffset = sectionData.size();
168 		for(const auto& symbolReference : internalSymbol.symbolReferences)
169 		{
170 			SYMBOL_REFERENCE newReference;
171 			newReference.offset			= symbolReference.offset + internalSymbolInfo.dataOffset;
172 			newReference.symbolIndex	= symbolReference.symbolIndex;
173 			newReference.type			= symbolReference.type;
174 			section.symbolReferences.push_back(newReference);
175 		}
176 		sectionData.insert(std::end(sectionData), std::begin(internalSymbol.data), std::end(internalSymbol.data));
177 	}
178 	return section;
179 }
180 
BuildSymbols(const InternalSymbolArray & internalSymbols,InternalSymbolInfoArray & internalSymbolInfos,const ExternalSymbolArray & externalSymbols,ExternalSymbolInfoArray & externalSymbolInfos,uint32 textSectionSize,uint32 dataSectionSize)181 CCoffObjectFile::SymbolArray CCoffObjectFile::BuildSymbols(const InternalSymbolArray& internalSymbols, InternalSymbolInfoArray& internalSymbolInfos,
182 														   const ExternalSymbolArray& externalSymbols, ExternalSymbolInfoArray& externalSymbolInfos,
183 														   uint32 textSectionSize, uint32 dataSectionSize)
184 {
185 	SymbolArray symbols;
186 	symbols.reserve(5 + internalSymbols.size() + externalSymbols.size());
187 
188 	//SafeSEH stuff
189 	{
190 		Coff::SYMBOL symbol = {};
191 		strncpy(symbol.name.shortName, "@feat.00", 8);
192 		symbol.value				= 0x01;
193 		symbol.sectionNumber		= 0xFFFF;
194 		symbol.type					= 0;
195 		symbol.storageClass			= 0x03;		//CLASS_STATIC
196 		symbol.numberOfAuxSymbols	= 0;
197 		symbols.push_back(symbol);
198 	}
199 
200 	//Text Section
201 	{
202 		Coff::SYMBOL symbol = {};
203 		strncpy(symbol.name.shortName, ".text", 8);
204 		symbol.value				= 0;
205 		symbol.sectionNumber		= 1;
206 		symbol.type					= 0;
207 		symbol.storageClass			= 0x03;		//CLASS_STATIC
208 		symbol.numberOfAuxSymbols	= 1;
209 		symbols.push_back(symbol);
210 	}
211 
212 	{
213 		Coff::SYMBOL symbol = {};
214 		symbol.name.offset			= 0;
215 		symbol.name.zeroes			= textSectionSize;
216 		symbols.push_back(symbol);
217 	}
218 
219 	//Data Section
220 	{
221 		Coff::SYMBOL symbol = {};
222 		strncpy(symbol.name.shortName, ".data", 8);
223 		symbol.value				= 0;
224 		symbol.sectionNumber		= 2;
225 		symbol.type					= 0;
226 		symbol.storageClass			= 0x03;		//CLASS_STATIC
227 		symbol.numberOfAuxSymbols	= 1;
228 		symbols.push_back(symbol);
229 	}
230 
231 	{
232 		Coff::SYMBOL symbol = {};
233 		symbol.name.offset			= 0;
234 		symbol.name.zeroes			= dataSectionSize;
235 		symbols.push_back(symbol);
236 	}
237 
238 	//Internal symbols
239 	for(uint32 i = 0; i < internalSymbols.size(); i++)
240 	{
241 		const auto& internalSymbol = internalSymbols[i];
242 		auto& internalSymbolInfo = internalSymbolInfos[i];
243 		internalSymbolInfo.symbolIndex = symbols.size();
244 
245 		Coff::SYMBOL symbol = {};
246 		symbol.name.offset			= 4 + internalSymbolInfo.nameOffset;
247 		symbol.value				= internalSymbolInfo.dataOffset;
248 		symbol.sectionNumber		= (internalSymbol.location == CObjectFile::INTERNAL_SYMBOL_LOCATION_TEXT) ? 1 : 2;		//.text or .data section
249 		symbol.type					= (internalSymbol.location == CObjectFile::INTERNAL_SYMBOL_LOCATION_TEXT) ? 0x20 : 0;	//DT_FUNCTION or nothing
250 		symbol.storageClass			= 0x02;		//CLASS_EXTERNAL
251 		symbol.numberOfAuxSymbols	= 0;
252 		symbols.push_back(symbol);
253 	}
254 
255 	//External symbols
256 	for(uint32 i = 0; i < externalSymbols.size(); i++)
257 	{
258 		const auto& externalSymbol = externalSymbols[i];
259 		auto& externalSymbolInfo = externalSymbolInfos[i];
260 		externalSymbolInfo.symbolIndex = symbols.size();
261 
262 		Coff::SYMBOL symbol = {};
263 		symbol.name.offset			= 4 + externalSymbolInfo.nameOffset;
264 		symbol.value				= 0;
265 		symbol.sectionNumber		= 0;
266 		symbol.type					= 0;
267 		symbol.storageClass			= 0x02;		//CLASS_EXTERNAL
268 		symbol.numberOfAuxSymbols	= 0;
269 		symbols.push_back(symbol);
270 	}
271 
272 	return symbols;
273 }
274 
BuildRelocations(SECTION & section,const InternalSymbolInfoArray & internalSymbolInfos,const ExternalSymbolInfoArray & externalSymbolInfos)275 CCoffObjectFile::RelocationArray CCoffObjectFile::BuildRelocations(SECTION& section, const InternalSymbolInfoArray& internalSymbolInfos, const ExternalSymbolInfoArray& externalSymbolInfos)
276 {
277 	RelocationArray relocations;
278 	relocations.resize(section.symbolReferences.size());
279 
280 	for(uint32 i = 0; i < section.symbolReferences.size(); i++)
281 	{
282 		const auto& symbolReference = section.symbolReferences[i];
283 		uint32 symbolIndex = (symbolReference.type == SYMBOL_TYPE_INTERNAL) ?
284 			internalSymbolInfos[symbolReference.symbolIndex].symbolIndex :
285 			externalSymbolInfos[symbolReference.symbolIndex].symbolIndex;
286 
287 		auto& relocation = relocations[i];
288 		relocation.type				= 0x06;			//I386_DIR32
289 		relocation.symbolIndex		= symbolIndex;
290 		relocation.rva				= symbolReference.offset;
291 
292 		*reinterpret_cast<uint32*>(section.data.data() + symbolReference.offset) = 0;
293 	}
294 
295 	return relocations;
296 }
297