1 #include <assert.h>
2 #include <stdexcept>
3 #include "X86Assembler.h"
4 
CX86Assembler()5 CX86Assembler::CX86Assembler()
6 : m_outputStream(nullptr)
7 , m_currentLabel(nullptr)
8 , m_nextLabelId(1)
9 {
10 
11 }
12 
~CX86Assembler()13 CX86Assembler::~CX86Assembler()
14 {
15 
16 }
17 
Begin()18 void CX86Assembler::Begin()
19 {
20 	m_nextLabelId = 1;
21 	m_currentLabel = nullptr;
22 	m_tmpStream.ResetBuffer();
23 	m_labels.clear();
24 	m_labelOrder.clear();
25 }
26 
End()27 void CX86Assembler::End()
28 {
29 	//Mark last label
30 	if(m_currentLabel != nullptr)
31 	{
32 		uint32 currentPos = static_cast<uint32>(m_tmpStream.Tell());
33 		m_currentLabel->size = currentPos - m_currentLabel->start;
34 	}
35 
36 	//Initialize
37 	for(auto& labelPair : m_labels)
38 	{
39 		auto& label = labelPair.second;
40 		label.projectedStart = label.start;
41 	}
42 
43 	while(1)
44 	{
45 		bool changed = false;
46 
47 		for(LabelArray::const_iterator labelIterator(m_labelOrder.begin());
48 			labelIterator != m_labelOrder.end(); labelIterator++)
49 		{
50 			LABELINFO& label = m_labels[*labelIterator];
51 
52 			for(LabelRefArray::iterator labelRefIterator(label.labelRefs.begin());
53 				labelRefIterator != label.labelRefs.end(); labelRefIterator++)
54 			{
55 				LABELREF& labelRef(*labelRefIterator);
56 				switch(labelRef.length)
57 				{
58 					case JMP_NOTSET:
59 						{
60 							//Assume a short jump first.
61 							unsigned int jumpSize = GetJumpSize(labelRef.type, JMP_NEAR);
62 							labelRef.length = JMP_NEAR;
63 							IncrementJumpOffsetsLocal(label, labelRefIterator + 1, jumpSize);
64 							IncrementJumpOffsets(labelIterator + 1, jumpSize);
65 							changed = true;
66 						}
67 						break;
68 					case JMP_NEAR:
69 						{
70 							//We need to verify if the jump is still good for us, since sizes might have changed
71 							LABELINFO& referencedLabel(m_labels[labelRef.label]);
72 							unsigned int smallJumpSize = GetJumpSize(labelRef.type, JMP_NEAR);
73 							uint32 offset = referencedLabel.projectedStart - (labelRef.offset + smallJumpSize);
74 							uint32 offsetSize = GetMinimumConstantSize(offset);
75 							if(offsetSize != 1)
76 							{
77 								//Doesn't fit, recompute offsets
78 								labelRef.length = JMP_FAR;
79 								unsigned int longJumpSize = GetJumpSize(labelRef.type, JMP_FAR);
80 								unsigned int incrementAmount = longJumpSize - smallJumpSize;
81 								IncrementJumpOffsetsLocal(label, labelRefIterator + 1, incrementAmount);
82 								IncrementJumpOffsets(labelIterator + 1, incrementAmount);
83 								changed = true;
84 							}
85 						}
86 						break;
87 				}
88 			}
89 		}
90 
91 		if(!changed) break;
92 	}
93 
94 	assert(m_outputStream != nullptr);
95 	m_tmpStream.Seek(0, Framework::STREAM_SEEK_SET);
96 
97 	for(const auto& labelId : m_labelOrder)
98 	{
99 		const auto& label = m_labels[labelId];
100 
101 		unsigned int currentPos = label.start;
102 		unsigned int currentProjectedPos = label.projectedStart;
103 		unsigned int endPos = label.start + label.size;
104 
105 		for(const auto& labelRef : label.labelRefs)
106 		{
107 			const auto& referencedLabel(m_labels[labelRef.label]);
108 
109 			unsigned int readSize = labelRef.offset - currentProjectedPos;
110 			if(readSize != 0)
111 			{
112 				m_copyBuffer.resize(readSize);
113 				m_tmpStream.Read(&m_copyBuffer[0], readSize);
114 				m_outputStream->Write(&m_copyBuffer[0], readSize);
115 			}
116 
117 			//Write our jump here.
118 			unsigned int jumpSize = GetJumpSize(labelRef.type, labelRef.length);
119 			uint32 distance = referencedLabel.projectedStart - (labelRef.offset + jumpSize);
120 			WriteJump(m_outputStream, labelRef.type, labelRef.length, distance);
121 
122 			currentProjectedPos += readSize + jumpSize;
123 			currentPos += readSize;
124 		}
125 
126 		unsigned int lastCopySize = endPos - currentPos;
127 		if(lastCopySize != 0)
128 		{
129 			m_copyBuffer.resize(lastCopySize);
130 			m_tmpStream.Read(&m_copyBuffer[0], lastCopySize);
131 			m_outputStream->Write(&m_copyBuffer[0], lastCopySize);
132 		}
133 	}
134 }
135 
IncrementJumpOffsets(LabelArray::const_iterator startLabel,unsigned int amount)136 void CX86Assembler::IncrementJumpOffsets(LabelArray::const_iterator startLabel, unsigned int amount)
137 {
138 	for(LabelArray::const_iterator labelIterator(startLabel);
139 		labelIterator != m_labelOrder.end(); labelIterator++)
140 	{
141 		LABELINFO& label = m_labels[*labelIterator];
142 		label.projectedStart += amount;
143 		IncrementJumpOffsetsLocal(label, label.labelRefs.begin(), amount);
144 	}
145 }
146 
IncrementJumpOffsetsLocal(LABELINFO & label,LabelRefArray::iterator startJump,unsigned int amount)147 void CX86Assembler::IncrementJumpOffsetsLocal(LABELINFO& label, LabelRefArray::iterator startJump, unsigned int amount)
148 {
149 	for(LabelRefArray::iterator labelRefIterator(startJump);
150 		labelRefIterator != label.labelRefs.end(); labelRefIterator++)
151 	{
152 		LABELREF& labelRef(*labelRefIterator);
153 		labelRef.offset += amount;
154 	}
155 }
156 
SetStream(Framework::CStream * stream)157 void CX86Assembler::SetStream(Framework::CStream* stream)
158 {
159 	m_outputStream = stream;
160 }
161 
MakeRegisterAddress(REGISTER nRegister)162 CX86Assembler::CAddress CX86Assembler::MakeRegisterAddress(REGISTER nRegister)
163 {
164 	CAddress Address;
165 
166 	if(nRegister > 7)
167 	{
168 		Address.nIsExtendedModRM = true;
169 		nRegister = static_cast<REGISTER>(nRegister & 7);
170 	}
171 
172 	Address.ModRm.nMod = 3;
173 	Address.ModRm.nRM = nRegister;
174 
175 	return Address;
176 }
177 
MakeXmmRegisterAddress(XMMREGISTER registerId)178 CX86Assembler::CAddress CX86Assembler::MakeXmmRegisterAddress(XMMREGISTER registerId)
179 {
180 	return MakeRegisterAddress(static_cast<REGISTER>(registerId));
181 }
182 
MakeByteRegisterAddress(REGISTER registerId)183 CX86Assembler::CAddress CX86Assembler::MakeByteRegisterAddress(REGISTER registerId)
184 {
185 	if(registerId > 3)
186 	{
187 		throw std::runtime_error("Unsupported byte register index.");
188 	}
189 
190 	return MakeRegisterAddress(registerId);
191 }
192 
MakeIndRegAddress(REGISTER registerId)193 CX86Assembler::CAddress CX86Assembler::MakeIndRegAddress(REGISTER registerId)
194 {
195 	CAddress address;
196 
197 	//Cannot be done with rBP
198 	assert(registerId != rBP);
199 	assert(registerId < 8);
200 
201 	if(registerId == rSP)
202 	{
203 		registerId = static_cast<REGISTER>(4);
204 		address.sib.scale = 0;
205 		address.sib.index = 4;
206 		address.sib.base = 4;
207 	}
208 
209 	address.ModRm.nMod = 0;
210 	address.ModRm.nRM = registerId;
211 	return address;
212 }
213 
MakeIndRegOffAddress(REGISTER nRegister,uint32 nOffset)214 CX86Assembler::CAddress CX86Assembler::MakeIndRegOffAddress(REGISTER nRegister, uint32 nOffset)
215 {
216 	if((nOffset == 0) && (nRegister != CX86Assembler::rBP))
217 	{
218 		return MakeIndRegAddress(nRegister);
219 	}
220 
221 	CAddress Address;
222 
223 	if(nRegister == rSP)
224 	{
225 		nRegister = static_cast<REGISTER>(4);
226 		Address.sib.scale = 0;
227 		Address.sib.index = 4;
228 		Address.sib.base = 4;
229 	}
230 
231 	if(nRegister > 7)
232 	{
233 		Address.nIsExtendedModRM = true;
234 		nRegister = static_cast<REGISTER>(nRegister & 7);
235 	}
236 
237 	if(GetMinimumConstantSize(nOffset) == 1)
238 	{
239 		Address.ModRm.nMod = 1;
240 		Address.nOffset = static_cast<uint8>(nOffset);
241 	}
242 	else
243 	{
244 		Address.ModRm.nMod = 2;
245 		Address.nOffset = nOffset;
246 	}
247 
248 	Address.ModRm.nRM = nRegister;
249 
250 	return Address;
251 }
252 
MakeBaseIndexScaleAddress(REGISTER base,REGISTER index,uint8 scale)253 CX86Assembler::CAddress CX86Assembler::MakeBaseIndexScaleAddress(REGISTER base, REGISTER index, uint8 scale)
254 {
255 	CAddress address;
256 	address.ModRm.nRM = 4;
257 	if(base == rBP || base == r13)
258 	{
259 		throw std::runtime_error("Invalid base.");
260 	}
261 	if(index == rSP)
262 	{
263 		throw std::runtime_error("Invalid index.");
264 	}
265 	if(base > 7)
266 	{
267 		address.nIsExtendedModRM = true;
268 		base = static_cast<REGISTER>(base & 7);
269 	}
270 	if(index > 7)
271 	{
272 		address.nIsExtendedSib = true;
273 		index = static_cast<REGISTER>(index & 7);
274 	}
275 	address.sib.base = base;
276 	address.sib.index = index;
277 	switch(scale)
278 	{
279 	case 1:
280 		address.sib.scale = 0;
281 		break;
282 	case 2:
283 		address.sib.scale = 1;
284 		break;
285 	case 4:
286 		address.sib.scale = 2;
287 		break;
288 	case 8:
289 		address.sib.scale = 3;
290 		break;
291 	default:
292 		throw std::runtime_error("Invalid scale.");
293 		break;
294 	}
295 
296 	return address;
297 }
298 
CreateLabel()299 CX86Assembler::LABEL CX86Assembler::CreateLabel()
300 {
301 	LABEL newLabelId = m_nextLabelId++;
302 	m_labels[newLabelId] = LABELINFO();
303 	return newLabelId;
304 }
305 
MarkLabel(LABEL label,int32 offset)306 void CX86Assembler::MarkLabel(LABEL label, int32 offset)
307 {
308 	uint32 currentPos = static_cast<uint32>(m_tmpStream.Tell()) + offset;
309 
310 	if(m_currentLabel != NULL)
311 	{
312 		m_currentLabel->size = currentPos - m_currentLabel->start;
313 	}
314 
315 	auto labelIterator(m_labels.find(label));
316 	assert(labelIterator != m_labels.end());
317 	LABELINFO& labelInfo(labelIterator->second);
318 	labelInfo.start = currentPos;
319 	m_currentLabel = &labelInfo;
320 	m_labelOrder.push_back(label);
321 }
322 
GetLabelOffset(LABEL label) const323 uint32 CX86Assembler::GetLabelOffset(LABEL label) const
324 {
325 	auto labelIterator(m_labels.find(label));
326 	assert(labelIterator != m_labels.end());
327 	const auto& labelInfo(labelIterator->second);
328 	return labelInfo.projectedStart;
329 }
330 
AdcEd(REGISTER registerId,const CAddress & address)331 void CX86Assembler::AdcEd(REGISTER registerId, const CAddress& address)
332 {
333 	WriteEvGvOp(0x13, false, address, registerId);
334 }
335 
AdcId(const CAddress & address,uint32 constant)336 void CX86Assembler::AdcId(const CAddress& address, uint32 constant)
337 {
338 	WriteEvId(0x02, address, constant);
339 }
340 
AddEd(REGISTER registerId,const CAddress & address)341 void CX86Assembler::AddEd(REGISTER registerId, const CAddress& address)
342 {
343 	WriteEvGvOp(0x03, false, address, registerId);
344 }
345 
AddEq(REGISTER registerId,const CAddress & address)346 void CX86Assembler::AddEq(REGISTER registerId, const CAddress& address)
347 {
348 	WriteEvGvOp(0x03, true, address, registerId);
349 }
350 
AddId(const CAddress & Address,uint32 nConstant)351 void CX86Assembler::AddId(const CAddress& Address, uint32 nConstant)
352 {
353 	WriteEvId(0x00, Address, nConstant);
354 }
355 
AddIq(const CAddress & address,uint64 constant)356 void CX86Assembler::AddIq(const CAddress& address, uint64 constant)
357 {
358 	WriteEvIq(0x00, address, constant);
359 }
360 
AndEd(REGISTER registerId,const CAddress & address)361 void CX86Assembler::AndEd(REGISTER registerId, const CAddress& address)
362 {
363 	WriteEvGvOp(0x23, false, address, registerId);
364 }
365 
AndEq(REGISTER registerId,const CAddress & address)366 void CX86Assembler::AndEq(REGISTER registerId, const CAddress& address)
367 {
368 	WriteEvGvOp(0x23, true, address, registerId);
369 }
370 
AndIb(const CAddress & address,uint8 constant)371 void CX86Assembler::AndIb(const CAddress& address, uint8 constant)
372 {
373 	WriteEvIb(0x04, address, constant);
374 }
375 
AndId(const CAddress & address,uint32 constant)376 void CX86Assembler::AndId(const CAddress& address, uint32 constant)
377 {
378 	WriteEvId(0x04, address, constant);
379 }
380 
AndIq(const CAddress & address,uint64 constant)381 void CX86Assembler::AndIq(const CAddress& address, uint64 constant)
382 {
383 	assert(0);
384 }
385 
BsrEd(REGISTER registerId,const CAddress & address)386 void CX86Assembler::BsrEd(REGISTER registerId, const CAddress& address)
387 {
388 	WriteEvGvOp0F(0xBD, false, address, registerId);
389 }
390 
CallEd(const CAddress & address)391 void CX86Assembler::CallEd(const CAddress& address)
392 {
393 	WriteEvOp(0xFF, 0x02, false, address);
394 }
395 
CmovsEd(REGISTER registerId,const CAddress & address)396 void CX86Assembler::CmovsEd(REGISTER registerId, const CAddress& address)
397 {
398 	WriteEvGvOp0F(0x48, false, address, registerId);
399 }
400 
CmovnsEd(REGISTER registerId,const CAddress & address)401 void CX86Assembler::CmovnsEd(REGISTER registerId, const CAddress& address)
402 {
403 	WriteEvGvOp0F(0x49, false, address, registerId);
404 }
405 
CmpEd(REGISTER registerId,const CAddress & address)406 void CX86Assembler::CmpEd(REGISTER registerId, const CAddress& address)
407 {
408 	WriteEvGvOp(0x3B, false, address, registerId);
409 }
410 
CmpEq(REGISTER nRegister,const CAddress & Address)411 void CX86Assembler::CmpEq(REGISTER nRegister, const CAddress& Address)
412 {
413 	WriteEvGvOp(0x3B, true, Address, nRegister);
414 }
415 
CmpIb(const CAddress & address,uint8 constant)416 void CX86Assembler::CmpIb(const CAddress& address, uint8 constant)
417 {
418 	WriteEvIb(0x07, address, constant);
419 }
420 
CmpId(const CAddress & address,uint32 constant)421 void CX86Assembler::CmpId(const CAddress& address, uint32 constant)
422 {
423 	WriteEvId(0x07, address, constant);
424 }
425 
CmpIq(const CAddress & Address,uint64 nConstant)426 void CX86Assembler::CmpIq(const CAddress& Address, uint64 nConstant)
427 {
428 	WriteEvIq(0x07, Address, nConstant);
429 }
430 
Cdq()431 void CX86Assembler::Cdq()
432 {
433 	WriteByte(0x99);
434 }
435 
DivEd(const CAddress & address)436 void CX86Assembler::DivEd(const CAddress& address)
437 {
438 	WriteEvOp(0xF7, 0x06, false, address);
439 }
440 
IdivEd(const CAddress & address)441 void CX86Assembler::IdivEd(const CAddress& address)
442 {
443 	WriteEvOp(0xF7, 0x07, false, address);
444 }
445 
ImulEw(const CAddress & address)446 void CX86Assembler::ImulEw(const CAddress& address)
447 {
448 	WriteByte(0x66);
449 	WriteEvOp(0xF7, 0x05, false, address);
450 }
451 
ImulEd(const CAddress & address)452 void CX86Assembler::ImulEd(const CAddress& address)
453 {
454 	WriteEvOp(0xF7, 0x05, false, address);
455 }
456 
JbJx(LABEL label)457 void CX86Assembler::JbJx(LABEL label)
458 {
459 	CreateLabelReference(label, JMP_B);
460 }
461 
JnbJx(LABEL label)462 void CX86Assembler::JnbJx(LABEL label)
463 {
464 	CreateLabelReference(label, JMP_NB);
465 }
466 
JlJx(LABEL label)467 void CX86Assembler::JlJx(LABEL label)
468 {
469 	CreateLabelReference(label, JMP_L);
470 }
471 
JleJx(LABEL label)472 void CX86Assembler::JleJx(LABEL label)
473 {
474 	CreateLabelReference(label, JMP_LE);
475 }
476 
JnlJx(LABEL label)477 void CX86Assembler::JnlJx(LABEL label)
478 {
479 	CreateLabelReference(label, JMP_NL);
480 }
481 
JnleJx(LABEL label)482 void CX86Assembler::JnleJx(LABEL label)
483 {
484 	CreateLabelReference(label, JMP_NLE);
485 }
486 
JmpJx(LABEL label)487 void CX86Assembler::JmpJx(LABEL label)
488 {
489 	CreateLabelReference(label, JMP_ALWAYS);
490 }
491 
JzJx(LABEL label)492 void CX86Assembler::JzJx(LABEL label)
493 {
494 	CreateLabelReference(label, JMP_Z);
495 }
496 
JnzJx(LABEL label)497 void CX86Assembler::JnzJx(LABEL label)
498 {
499 	CreateLabelReference(label, JMP_NZ);
500 }
501 
JnoJx(LABEL label)502 void CX86Assembler::JnoJx(LABEL label)
503 {
504 	CreateLabelReference(label, JMP_NO);
505 }
506 
JnsJx(LABEL label)507 void CX86Assembler::JnsJx(LABEL label)
508 {
509 	CreateLabelReference(label, JMP_NS);
510 }
511 
LeaGd(REGISTER registerId,const CAddress & address)512 void CX86Assembler::LeaGd(REGISTER registerId, const CAddress& address)
513 {
514 	WriteEvGvOp(0x8D, false, address, registerId);
515 }
516 
LeaGq(REGISTER registerId,const CAddress & address)517 void CX86Assembler::LeaGq(REGISTER registerId, const CAddress& address)
518 {
519 	WriteEvGvOp(0x8D, true, address, registerId);
520 }
521 
MovEw(REGISTER registerId,const CAddress & address)522 void CX86Assembler::MovEw(REGISTER registerId, const CAddress& address)
523 {
524 	WriteByte(0x66);
525 	WriteEvGvOp(0x8B, false, address, registerId);
526 }
527 
MovEd(REGISTER nRegister,const CAddress & Address)528 void CX86Assembler::MovEd(REGISTER nRegister, const CAddress& Address)
529 {
530 	WriteEvGvOp(0x8B, false, Address, nRegister);
531 }
532 
MovEq(REGISTER nRegister,const CAddress & Address)533 void CX86Assembler::MovEq(REGISTER nRegister, const CAddress& Address)
534 {
535 	WriteEvGvOp(0x8B, true, Address, nRegister);
536 }
537 
MovGd(const CAddress & Address,REGISTER nRegister)538 void CX86Assembler::MovGd(const CAddress& Address, REGISTER nRegister)
539 {
540 	WriteEvGvOp(0x89, false, Address, nRegister);
541 }
542 
MovGq(const CAddress & Address,REGISTER nRegister)543 void CX86Assembler::MovGq(const CAddress& Address, REGISTER nRegister)
544 {
545 	WriteEvGvOp(0x89, true, Address, nRegister);
546 }
547 
MovId(REGISTER nRegister,uint32 nConstant)548 void CX86Assembler::MovId(REGISTER nRegister, uint32 nConstant)
549 {
550 	CAddress Address(MakeRegisterAddress(nRegister));
551 	WriteRexByte(false, Address);
552 	WriteByte(0xB8 | Address.ModRm.nRM);
553 	WriteDWord(nConstant);
554 }
555 
MovIq(REGISTER registerId,uint64 constant)556 void CX86Assembler::MovIq(REGISTER registerId, uint64 constant)
557 {
558 	CAddress address(MakeRegisterAddress(registerId));
559 	WriteRexByte(true, address);
560 	WriteByte(0xB8 | address.ModRm.nRM);
561 	WriteDWord(static_cast<uint32>(constant & 0xFFFFFFFF));
562 	WriteDWord(static_cast<uint32>(constant >> 32));
563 }
564 
MovId(const CX86Assembler::CAddress & address,uint32 constant)565 void CX86Assembler::MovId(const CX86Assembler::CAddress& address, uint32 constant)
566 {
567 	WriteRexByte(false, address);
568 	CAddress newAddress(address);
569 	newAddress.ModRm.nFnReg = 0x00;
570 
571 	WriteByte(0xC7);
572 	newAddress.Write(&m_tmpStream);
573 	WriteDWord(constant);
574 }
575 
MovsxEb(REGISTER registerId,const CAddress & address)576 void CX86Assembler::MovsxEb(REGISTER registerId, const CAddress& address)
577 {
578 	WriteEvGvOp0F(0xBE, false, address, registerId);
579 }
580 
MovsxEw(REGISTER registerId,const CAddress & address)581 void CX86Assembler::MovsxEw(REGISTER registerId, const CAddress& address)
582 {
583 	WriteEvGvOp0F(0xBF, false, address, registerId);
584 }
585 
MovzxEb(REGISTER registerId,const CAddress & address)586 void CX86Assembler::MovzxEb(REGISTER registerId, const CAddress& address)
587 {
588 	WriteEvGvOp0F(0xB6, false, address, registerId);
589 }
590 
MulEd(const CAddress & address)591 void CX86Assembler::MulEd(const CAddress& address)
592 {
593 	WriteEvOp(0xF7, 0x04, false, address);
594 }
595 
NegEd(const CAddress & address)596 void CX86Assembler::NegEd(const CAddress& address)
597 {
598 	WriteEvOp(0xF7, 0x03, false, address);
599 }
600 
Nop()601 void CX86Assembler::Nop()
602 {
603 	WriteByte(0x90);
604 }
605 
NotEd(const CAddress & address)606 void CX86Assembler::NotEd(const CAddress& address)
607 {
608 	WriteEvOp(0xF7, 0x02, false, address);
609 }
610 
OrEd(REGISTER registerId,const CAddress & address)611 void CX86Assembler::OrEd(REGISTER registerId, const CAddress& address)
612 {
613 	WriteEvGvOp(0x0B, false, address, registerId);
614 }
615 
OrId(const CAddress & address,uint32 constant)616 void CX86Assembler::OrId(const CAddress& address, uint32 constant)
617 {
618 	WriteEvId(0x01, address, constant);
619 }
620 
Pop(REGISTER registerId)621 void CX86Assembler::Pop(REGISTER registerId)
622 {
623 	CAddress Address(MakeRegisterAddress(registerId));
624 	WriteRexByte(false, Address);
625 	WriteByte(0x58 | Address.ModRm.nRM);
626 }
627 
Push(REGISTER registerId)628 void CX86Assembler::Push(REGISTER registerId)
629 {
630 	CAddress Address(MakeRegisterAddress(registerId));
631 	WriteRexByte(false, Address);
632 	WriteByte(0x50 | Address.ModRm.nRM);
633 }
634 
PushEd(const CAddress & address)635 void CX86Assembler::PushEd(const CAddress& address)
636 {
637 	WriteEvOp(0xFF, 0x06, false, address);
638 }
639 
PushId(uint32 value)640 void CX86Assembler::PushId(uint32 value)
641 {
642 	WriteByte(0x68);
643 	WriteDWord(value);
644 }
645 
RclEd(const CAddress & address,uint8 amount)646 void CX86Assembler::RclEd(const CAddress& address, uint8 amount)
647 {
648 	WriteEvOp(0xC1, 0x02, false, address);
649 	WriteByte(amount);
650 }
651 
RepMovsb()652 void CX86Assembler::RepMovsb()
653 {
654 	WriteByte(0xF3);
655 	WriteByte(0xA4);
656 }
657 
Ret()658 void CX86Assembler::Ret()
659 {
660 	WriteByte(0xC3);
661 }
662 
SarEd(const CAddress & address)663 void CX86Assembler::SarEd(const CAddress& address)
664 {
665 	WriteEvOp(0xD3, 0x07, false, address);
666 }
667 
SarEd(const CAddress & address,uint8 amount)668 void CX86Assembler::SarEd(const CAddress& address, uint8 amount)
669 {
670 	WriteEvOp(0xC1, 0x07, false, address);
671 	WriteByte(amount);
672 }
673 
SarEq(const CAddress & address)674 void CX86Assembler::SarEq(const CAddress& address)
675 {
676 	WriteEvOp(0xD3, 0x07, true, address);
677 }
678 
SarEq(const CAddress & address,uint8 amount)679 void CX86Assembler::SarEq(const CAddress& address, uint8 amount)
680 {
681 	WriteEvOp(0xC1, 0x07, true, address);
682 	WriteByte(amount);
683 }
684 
SbbEd(REGISTER registerId,const CAddress & address)685 void CX86Assembler::SbbEd(REGISTER registerId, const CAddress& address)
686 {
687 	WriteEvGvOp(0x1B, false, address, registerId);
688 }
689 
SbbId(const CAddress & Address,uint32 nConstant)690 void CX86Assembler::SbbId(const CAddress& Address, uint32 nConstant)
691 {
692 	WriteEvId(0x03, Address, nConstant);
693 }
694 
SetaEb(const CAddress & address)695 void CX86Assembler::SetaEb(const CAddress& address)
696 {
697 	WriteByte(0x0F);
698 	WriteEvOp(0x97, 0x00, false, address);
699 }
700 
SetaeEb(const CAddress & address)701 void CX86Assembler::SetaeEb(const CAddress& address)
702 {
703 	throw std::exception();
704 }
705 
SetbEb(const CAddress & address)706 void CX86Assembler::SetbEb(const CAddress& address)
707 {
708 	WriteByte(0x0F);
709 	WriteEvOp(0x92, 0x00, false, address);
710 }
711 
SetbeEb(const CAddress & address)712 void CX86Assembler::SetbeEb(const CAddress& address)
713 {
714 	WriteByte(0x0F);
715 	WriteEvOp(0x96, 0x00, false, address);
716 }
717 
SeteEb(const CAddress & address)718 void CX86Assembler::SeteEb(const CAddress& address)
719 {
720 	WriteByte(0x0F);
721 	WriteEvOp(0x94, 0x00, false, address);
722 }
723 
SetneEb(const CAddress & address)724 void CX86Assembler::SetneEb(const CAddress& address)
725 {
726 	WriteByte(0x0F);
727 	WriteEvOp(0x95, 0x00, false, address);
728 }
729 
SetlEb(const CAddress & address)730 void CX86Assembler::SetlEb(const CAddress& address)
731 {
732 	WriteByte(0x0F);
733 	WriteEvOp(0x9C, 0x00, false, address);
734 }
735 
SetleEb(const CAddress & address)736 void CX86Assembler::SetleEb(const CAddress& address)
737 {
738 	WriteByte(0x0F);
739 	WriteEvOp(0x9E, 0x00, false, address);
740 }
741 
SetgEb(const CAddress & address)742 void CX86Assembler::SetgEb(const CAddress& address)
743 {
744 	WriteByte(0x0F);
745 	WriteEvOp(0x9F, 0x00, false, address);
746 }
747 
ShlEd(const CAddress & address)748 void CX86Assembler::ShlEd(const CAddress& address)
749 {
750 	WriteEvOp(0xD3, 0x04, false, address);
751 }
752 
ShlEd(const CAddress & address,uint8 amount)753 void CX86Assembler::ShlEd(const CAddress& address, uint8 amount)
754 {
755 	WriteEvOp(0xC1, 0x04, false, address);
756 	WriteByte(amount);
757 }
758 
ShlEq(const CAddress & address)759 void CX86Assembler::ShlEq(const CAddress& address)
760 {
761 	WriteEvOp(0xD3, 0x04, true, address);
762 }
763 
ShlEq(const CAddress & address,uint8 amount)764 void CX86Assembler::ShlEq(const CAddress& address, uint8 amount)
765 {
766 	WriteEvOp(0xC1, 0x04, true, address);
767 	WriteByte(amount);
768 }
769 
ShrEd(const CAddress & address)770 void CX86Assembler::ShrEd(const CAddress& address)
771 {
772 	WriteEvOp(0xD3, 0x05, false, address);
773 }
774 
ShrEd(const CAddress & address,uint8 amount)775 void CX86Assembler::ShrEd(const CAddress& address, uint8 amount)
776 {
777 	WriteEvOp(0xC1, 0x05, false, address);
778 	WriteByte(amount);
779 }
780 
ShrEq(const CAddress & address)781 void CX86Assembler::ShrEq(const CAddress& address)
782 {
783 	WriteEvOp(0xD3, 0x05, true, address);
784 }
785 
ShrEq(const CAddress & address,uint8 amount)786 void CX86Assembler::ShrEq(const CAddress& address, uint8 amount)
787 {
788 	WriteEvOp(0xC1, 0x05, true, address);
789 	WriteByte(amount);
790 }
791 
ShldEd(const CAddress & address,REGISTER registerId)792 void CX86Assembler::ShldEd(const CAddress& address, REGISTER registerId)
793 {
794 	WriteByte(0x0F);
795 	WriteEvGvOp(0xA5, false, address, registerId);
796 }
797 
ShldEd(const CAddress & address,REGISTER registerId,uint8 amount)798 void CX86Assembler::ShldEd(const CAddress& address, REGISTER registerId, uint8 amount)
799 {
800 	WriteByte(0x0F);
801 	WriteEvGvOp(0xA4, false, address, registerId);
802 	WriteByte(amount);
803 }
804 
ShrdEd(const CAddress & address,REGISTER registerId)805 void CX86Assembler::ShrdEd(const CAddress& address, REGISTER registerId)
806 {
807 	WriteByte(0x0F);
808 	WriteEvGvOp(0xAD, false, address, registerId);
809 }
810 
ShrdEd(const CAddress & address,REGISTER registerId,uint8 amount)811 void CX86Assembler::ShrdEd(const CAddress& address, REGISTER registerId, uint8 amount)
812 {
813 	WriteByte(0x0F);
814 	WriteEvGvOp(0xAC, false, address, registerId);
815 	WriteByte(amount);
816 }
817 
SubEd(REGISTER nRegister,const CAddress & Address)818 void CX86Assembler::SubEd(REGISTER nRegister, const CAddress& Address)
819 {
820 	WriteEvGvOp(0x2B, false, Address, nRegister);
821 }
822 
SubEq(REGISTER nRegister,const CAddress & Address)823 void CX86Assembler::SubEq(REGISTER nRegister, const CAddress& Address)
824 {
825 	WriteEvGvOp(0x2B, true, Address, nRegister);
826 }
827 
SubId(const CAddress & Address,uint32 nConstant)828 void CX86Assembler::SubId(const CAddress& Address, uint32 nConstant)
829 {
830 	WriteEvId(0x05, Address, nConstant);
831 }
832 
SubIq(const CAddress & address,uint64 constant)833 void CX86Assembler::SubIq(const CAddress& address, uint64 constant)
834 {
835 	WriteEvIq(0x05, address, constant);
836 }
837 
TestEb(REGISTER registerId,const CAddress & address)838 void CX86Assembler::TestEb(REGISTER registerId, const CAddress& address)
839 {
840 	if(registerId > 3)
841 	{
842 		throw std::runtime_error("Unsupported byte register index.");
843 	}
844 	WriteEvGvOp(0x84, false, address, registerId);
845 }
846 
TestEd(REGISTER registerId,const CAddress & address)847 void CX86Assembler::TestEd(REGISTER registerId, const CAddress& address)
848 {
849 	WriteEvGvOp(0x85, false, address, registerId);
850 }
851 
XorEd(REGISTER registerId,const CAddress & address)852 void CX86Assembler::XorEd(REGISTER registerId, const CAddress& address)
853 {
854 	WriteEvGvOp(0x33, false, address, registerId);
855 }
856 
XorId(const CAddress & address,uint32 constant)857 void CX86Assembler::XorId(const CAddress& address, uint32 constant)
858 {
859 	WriteEvId(0x06, address, constant);
860 }
861 
XorGd(const CAddress & Address,REGISTER nRegister)862 void CX86Assembler::XorGd(const CAddress& Address, REGISTER nRegister)
863 {
864 	WriteEvGvOp(0x31, false, Address, nRegister);
865 }
866 
XorGq(const CAddress & Address,REGISTER nRegister)867 void CX86Assembler::XorGq(const CAddress& Address, REGISTER nRegister)
868 {
869 	WriteEvGvOp(0x31, true, Address, nRegister);
870 }
871 
WriteRexByte(bool nIs64,const CAddress & Address)872 void CX86Assembler::WriteRexByte(bool nIs64, const CAddress& Address)
873 {
874 	REGISTER nTemp = rAX;
875 	WriteRexByte(nIs64, Address, nTemp);
876 }
877 
WriteRexByte(bool nIs64,const CAddress & Address,REGISTER & nRegister)878 void CX86Assembler::WriteRexByte(bool nIs64, const CAddress& Address, REGISTER& nRegister)
879 {
880 	if((nIs64) || (Address.nIsExtendedModRM) || (nRegister > 7))
881 	{
882 		uint8 nByte = 0x40;
883 		nByte |= nIs64 ? 0x8 : 0x0;
884 		nByte |= (nRegister > 7) ? 0x04 : 0x0;
885 		nByte |= Address.nIsExtendedModRM ? 0x1 : 0x0;
886 
887 		nRegister = static_cast<REGISTER>(nRegister & 7);
888 
889 		WriteByte(nByte);
890 	}
891 }
892 
WriteEvOp(uint8 opcode,uint8 subOpcode,bool is64,const CAddress & address)893 void CX86Assembler::WriteEvOp(uint8 opcode, uint8 subOpcode, bool is64, const CAddress& address)
894 {
895 	WriteRexByte(is64, address);
896 	CAddress newAddress(address);
897 	newAddress.ModRm.nFnReg = subOpcode;
898 	WriteByte(opcode);
899 	newAddress.Write(&m_tmpStream);
900 }
901 
WriteEvGvOp(uint8 nOp,bool nIs64,const CAddress & Address,REGISTER nRegister)902 void CX86Assembler::WriteEvGvOp(uint8 nOp, bool nIs64, const CAddress& Address, REGISTER nRegister)
903 {
904 	WriteRexByte(nIs64, Address, nRegister);
905 	CAddress NewAddress(Address);
906 	NewAddress.ModRm.nFnReg = nRegister;
907 	WriteByte(nOp);
908 	NewAddress.Write(&m_tmpStream);
909 }
910 
WriteEvGvOp0F(uint8 nOp,bool nIs64,const CAddress & Address,REGISTER nRegister)911 void CX86Assembler::WriteEvGvOp0F(uint8 nOp, bool nIs64, const CAddress& Address, REGISTER nRegister)
912 {
913 	WriteRexByte(nIs64, Address, nRegister);
914 	WriteByte(0x0F);
915 	CAddress NewAddress(Address);
916 	NewAddress.ModRm.nFnReg = nRegister;
917 	WriteByte(nOp);
918 	NewAddress.Write(&m_tmpStream);
919 }
920 
WriteEvIb(uint8 op,const CAddress & address,uint8 constant)921 void CX86Assembler::WriteEvIb(uint8 op, const CAddress& address, uint8 constant)
922 {
923 	WriteRexByte(false, address);
924 	CAddress newAddress(address);
925 	newAddress.ModRm.nFnReg = op;
926 	WriteByte(0x80);
927 	newAddress.Write(&m_tmpStream);
928 	WriteByte(constant);
929 }
930 
WriteEvId(uint8 nOp,const CAddress & Address,uint32 nConstant)931 void CX86Assembler::WriteEvId(uint8 nOp, const CAddress& Address, uint32 nConstant)
932 {
933 	//0x81 -> Id
934 	//0x83 -> Ib
935 
936 	WriteRexByte(false, Address);
937 	CAddress NewAddress(Address);
938 	NewAddress.ModRm.nFnReg = nOp;
939 
940 	if(GetMinimumConstantSize(nConstant) == 1)
941 	{
942 		WriteByte(0x83);
943 		NewAddress.Write(&m_tmpStream);
944 		WriteByte(static_cast<uint8>(nConstant));
945 	}
946 	else
947 	{
948 		WriteByte(0x81);
949 		NewAddress.Write(&m_tmpStream);
950 		WriteDWord(nConstant);
951 	}
952 }
953 
WriteEvIq(uint8 nOp,const CAddress & Address,uint64 nConstant)954 void CX86Assembler::WriteEvIq(uint8 nOp, const CAddress& Address, uint64 nConstant)
955 {
956 	unsigned int nConstantSize(GetMinimumConstantSize64(nConstant));
957 	//assert(nConstantSize <= 4); //GetMinimumConstantSize64 seems to sign extend 32 bit values
958 
959 	WriteRexByte(true, Address);
960 	CAddress NewAddress(Address);
961 	NewAddress.ModRm.nFnReg = nOp;
962 
963 	if(nConstantSize == 1)
964 	{
965 		WriteByte(0x83);
966 		NewAddress.Write(&m_tmpStream);
967 		WriteByte(static_cast<uint8>(nConstant));
968 	}
969 	else
970 	{
971 		WriteByte(0x81);
972 		NewAddress.Write(&m_tmpStream);
973 		WriteDWord(static_cast<uint32>(nConstant));
974 	}
975 }
976 
CreateLabelReference(LABEL label,JMP_TYPE type)977 void CX86Assembler::CreateLabelReference(LABEL label, JMP_TYPE type)
978 {
979 	assert(m_currentLabel != NULL);
980 
981 	LABELREF reference;
982 	reference.label			= label;
983 	reference.offset		= static_cast<uint32>(m_tmpStream.Tell());
984 	reference.type			= type;
985 
986 	m_currentLabel->labelRefs.push_back(reference);
987 }
988 
GetMinimumConstantSize(uint32 nConstant)989 unsigned int CX86Assembler::GetMinimumConstantSize(uint32 nConstant)
990 {
991 	if((static_cast<int32>(nConstant) >= -128) && (static_cast<int32>(nConstant) <= 127))
992 	{
993 		return 1;
994 	}
995 	return 4;
996 }
997 
GetMinimumConstantSize64(uint64 nConstant)998 unsigned int CX86Assembler::GetMinimumConstantSize64(uint64 nConstant)
999 {
1000 	if((static_cast<int64>(nConstant) >= -128) && (static_cast<int64>(nConstant) <= 127))
1001 	{
1002 		return 1;
1003 	}
1004 	if((static_cast<int64>(nConstant) >= -2147483647) && (static_cast<int64>(nConstant) <= 2147483647))
1005 	{
1006 		return 4;
1007 	}
1008 	return 8;
1009 }
1010 
GetJumpSize(JMP_TYPE type,JMP_LENGTH length)1011 unsigned int CX86Assembler::GetJumpSize(JMP_TYPE type, JMP_LENGTH length)
1012 {
1013 	if(length == JMP_NEAR)
1014 	{
1015 		return 2;
1016 	}
1017 	else
1018 	{
1019 		if(type == JMP_ALWAYS)
1020 		{
1021 			return 5;
1022 		}
1023 		else
1024 		{
1025 			return 6;
1026 		}
1027 	}
1028 }
1029 
WriteJump(Framework::CStream * stream,JMP_TYPE type,JMP_LENGTH length,uint32 offset)1030 void CX86Assembler::WriteJump(Framework::CStream* stream, JMP_TYPE type, JMP_LENGTH length, uint32 offset)
1031 {
1032 	if(length == JMP_FAR)
1033 	{
1034 		switch(type)
1035 		{
1036 		case JMP_ALWAYS:
1037 			stream->Write8(0xE9);
1038 			break;
1039 		default:
1040 			stream->Write8(0x0F);
1041 			stream->Write8(0x80 | static_cast<uint8>(type));
1042 			break;
1043 		}
1044 		stream->Write32(offset);
1045 	}
1046 	else
1047 	{
1048 		switch(type)
1049 		{
1050 		case JMP_ALWAYS:
1051 			stream->Write8(0xEB);
1052 			break;
1053 		default:
1054 			stream->Write8(0x70 | static_cast<uint8>(type));
1055 			break;
1056 		}
1057 		stream->Write8(static_cast<uint8>(offset));
1058 	}
1059 }
1060 
WriteByte(uint8 nByte)1061 void CX86Assembler::WriteByte(uint8 nByte)
1062 {
1063 	m_tmpStream.Write8(nByte);
1064 }
1065 
WriteDWord(uint32 nDWord)1066 void CX86Assembler::WriteDWord(uint32 nDWord)
1067 {
1068 	//Endianess should be good, unless we target a different processor...
1069 	m_tmpStream.Write32(nDWord);
1070 }
1071 
1072 /////////////////////////////////////////////////
1073 /////////////////////////////////////////////////
1074 
CAddress()1075 CX86Assembler::CAddress::CAddress()
1076 {
1077 	nOffset = 0;
1078 	ModRm.nByte = 0;
1079 	sib.byteValue = 0;
1080 	nIsExtendedModRM = false;
1081 	nIsExtendedSib = false;
1082 }
1083 
Write(Framework::CStream * stream)1084 void CX86Assembler::CAddress::Write(Framework::CStream* stream)
1085 {
1086 	stream->Write8(ModRm.nByte);
1087 
1088 	if(HasSib())
1089 	{
1090 		stream->Write8(sib.byteValue);
1091 	}
1092 
1093 	if(ModRm.nMod == 1)
1094 	{
1095 		stream->Write8(static_cast<uint8>(nOffset));
1096 	}
1097 	else if(ModRm.nMod == 2)
1098 	{
1099 		stream->Write32(nOffset);
1100 	}
1101 }
1102 
HasSib() const1103 bool CX86Assembler::CAddress::HasSib() const
1104 {
1105 	if(ModRm.nMod == 3) return false;
1106 	return ModRm.nRM == 4;
1107 }
1108