1 using System.IO;
2 using System.Collections;
3 
4 namespace PEAPI {
5 
6 	/**************************************************************************/
7 	/// <summary>
8 	/// Descriptor for an IL instruction
9 	/// </summary>
10 	internal abstract class CILInstruction {
11 		protected static readonly sbyte maxByteVal = 127;
12 		protected static readonly sbyte minByteVal = -128;
13 		protected static readonly byte leadByte = 0xFE;
14 		protected static readonly uint USHeapIndex = 0x70000000;
15 		protected static readonly int longInstrStart = (int)Op.arglist;
16 		public bool twoByteInstr = false;
17 		public uint size = 0;
18 		public uint offset;
19 
Check(MetaData md)20 		internal virtual bool Check(MetaData md)
21 		{
22 			return false;
23 		}
24 
Write(FileImage output)25 		internal virtual void Write(FileImage output) { }
26 
27 	}
28 
29 	internal class CILByte : CILInstruction {
30 		byte byteVal;
31 
CILByte(byte bVal)32 		internal CILByte(byte bVal)
33 		{
34 			byteVal = bVal;
35 			size = 1;
36 		}
37 
Write(FileImage output)38 		internal override void Write(FileImage output)
39 		{
40 			output.Write(byteVal);
41 		}
42 
43 	}
44 
45 	internal class Instr : CILInstruction {
46 		protected int instr;
47 
Instr(int inst)48 		internal Instr(int inst)
49 		{
50 			if (inst >= longInstrStart) {
51 				instr = inst - longInstrStart;
52 				twoByteInstr = true;
53 				size = 2;
54 			} else {
55 				instr = inst;
56 				size = 1;
57 			}
58 		}
59 
Write(FileImage output)60 		internal override void Write(FileImage output)
61 		{
62 			//Console.WriteLine("Writing instruction " + instr + " with size " + size);
63 			if (twoByteInstr) output.Write(leadByte);
64 			output.Write((byte)instr);
65 		}
66 
67 	}
68 
69 	internal class IntInstr : Instr {
70 		int val;
71 		bool byteNum;
72 
IntInstr(int inst, int num, bool byteSize)73 		internal IntInstr(int inst, int num, bool byteSize) : base(inst)
74 		{
75 			val = num;
76 			byteNum = byteSize;
77 			if (byteNum) size++;
78 			else size += 4;
79 		}
80 
Write(FileImage output)81 		internal sealed override void Write(FileImage output)
82 		{
83 			base.Write(output);
84 			if (byteNum)
85 				output.Write((sbyte)val);
86 			else
87 				output.Write(val);
88 		}
89 
90 	}
91 
92 	internal class UIntInstr : Instr {
93 		int val;
94 		bool byteNum;
95 
UIntInstr(int inst, int num, bool byteSize)96 		internal UIntInstr(int inst, int num, bool byteSize) : base(inst)
97 		{
98 			val = num;
99 			byteNum = byteSize;
100 			if (byteNum) size++;
101 			else size += 2;
102 		}
103 
Write(FileImage output)104 		internal sealed override void Write(FileImage output)
105 		{
106 			base.Write(output);
107 			if (byteNum)
108 				output.Write((byte)val);
109 			else
110 				output.Write((ushort)val);
111 		}
112 
113 	}
114 
115 	internal class LongInstr : Instr {
116 		long val;
117 
LongInstr(int inst, long l)118 		internal LongInstr(int inst, long l) : base(inst)
119 		{
120 			val = l;
121 			size += 8;
122 		}
123 
Write(FileImage output)124 		internal sealed override void Write(FileImage output)
125 		{
126 			base.Write(output);
127 			output.Write(val);
128 		}
129 
130 	}
131 
132 	internal class FloatInstr : Instr {
133 		float fVal;
134 
FloatInstr(int inst, float f)135 		internal FloatInstr(int inst, float f) : base(inst)
136 		{
137 			fVal = f;
138 			size += 4;
139 		}
140 
Write(FileImage output)141 		internal sealed override void Write(FileImage output)
142 		{
143 			base.Write(output);
144 			output.Write(fVal);
145 		}
146 
147 	}
148 
149 	internal class DoubleInstr : Instr {
150 		double val;
151 
DoubleInstr(int inst, double d)152 		internal DoubleInstr(int inst, double d) : base(inst)
153 		{
154 			val = d;
155 			size += 8;
156 		}
157 
Write(FileImage output)158 		internal sealed override void Write(FileImage output)
159 		{
160 			base.Write(output);
161 			output.Write(val);
162 		}
163 
164 	}
165 
166 	internal class StringInstr : Instr {
167 		string val;
168 		byte[] bval;
169 		uint strIndex;
170 
StringInstr(int inst, string str)171 		internal StringInstr(int inst, string str) : base(inst)
172 		{
173 			val = str;
174 			size += 4;
175 		}
176 
StringInstr(int inst, byte[] str)177 		internal StringInstr (int inst, byte[] str) : base (inst)
178 		{
179 			bval = str;
180 			size += 4;
181 		}
182 
Check(MetaData md)183 		internal sealed override bool Check(MetaData md)
184 		{
185 			if (val != null)
186 				strIndex = md.AddToUSHeap(val);
187 			else
188 				strIndex = md.AddToUSHeap (bval);
189 			return false;
190 		}
191 
Write(FileImage output)192 		internal sealed override void Write(FileImage output)
193 		{
194 			base.Write(output);
195 			output.Write(USHeapIndex  | strIndex);
196 		}
197 
198 	}
199 
200 	internal class LabelInstr : CILInstruction {
201 		CILLabel label;
202 
LabelInstr(CILLabel lab)203 		internal LabelInstr(CILLabel lab)
204 		{
205 			label = lab;
206 			label.AddLabelInstr(this);
207 		}
208 	}
209 
210 	internal class FieldInstr : Instr {
211 		Field field;
212 
FieldInstr(int inst, Field f)213 		internal FieldInstr(int inst, Field f) : base(inst)
214 		{
215 			field = f;
216 			size += 4;
217 		}
218 
Write(FileImage output)219 		internal sealed override void Write(FileImage output)
220 		{
221 			base.Write(output);
222 			output.Write(field.Token());
223 		}
224 
225 	}
226 
227 	internal class MethInstr : Instr {
228 		Method meth;
229 
MethInstr(int inst, Method m)230 		internal MethInstr(int inst, Method m) : base(inst)
231 		{
232 			meth = m;
233 			size += 4;
234 		}
235 
Write(FileImage output)236 		internal sealed override void Write(FileImage output)
237 		{
238 			base.Write(output);
239 			output.Write(meth.Token());
240 		}
241 
242 	}
243 
244 	internal class SigInstr : Instr {
245 		CalliSig signature;
246 
SigInstr(int inst, CalliSig sig)247 		internal SigInstr(int inst, CalliSig sig) : base(inst)
248 		{
249 			signature = sig;
250 			size += 4;
251 		}
252 
Check(MetaData md)253 		internal sealed override bool Check(MetaData md)
254 		{
255 			md.AddToTable(MDTable.StandAloneSig,signature);
256 			signature.BuildTables(md);
257 			return false;
258 		}
259 
Write(FileImage output)260 		internal sealed override void Write(FileImage output)
261 		{
262 			base.Write(output);
263 			output.Write(signature.Token());
264 		}
265 	}
266 
267 	internal class TypeInstr : Instr {
268 		MetaDataElement theType;
269 
TypeInstr(int inst, Type aType, MetaData md)270 		internal TypeInstr(int inst, Type aType, MetaData md) : base(inst)
271 		{
272 			theType = aType.GetTypeSpec(md);
273 			size += 4;
274 		}
275 
Write(FileImage output)276 		internal sealed override void Write(FileImage output)
277 		{
278 			base.Write(output);
279 			output.Write(theType.Token());
280 		}
281 
282 	}
283 
284 	internal class BranchInstr : Instr {
285 		CILLabel dest;
286 		private bool shortVer = true;
287 		private int target = 0;
288 
BranchInstr(int inst, CILLabel dst)289 		internal BranchInstr(int inst, CILLabel dst) : base(inst)
290 		{
291 			dest = dst;
292 			dest.AddBranch(this);
293 			size++;
294 
295 			if (inst >= (int) BranchOp.br && inst != (int) BranchOp.leave_s) {
296 				shortVer = false;
297 				size += 3;
298 			}
299 		}
300 
Check(MetaData md)301 		internal sealed override bool Check(MetaData md)
302 		{
303 			target = (int)dest.GetLabelOffset() - (int)(offset + size);
304 			return false;
305 		}
306 
Write(FileImage output)307 		internal sealed override void Write(FileImage output)
308 		{
309 			base.Write(output);
310 			if (shortVer)
311 				output.Write((sbyte)target);
312 			else
313 				output.Write(target);
314 		}
315 
316 	}
317 
318 	internal class SwitchInstr : Instr {
319 		CILLabel[] cases;
320 		uint numCases = 0;
321 
SwitchInstr(int inst, CILLabel[] dsts)322 		internal SwitchInstr(int inst, CILLabel[] dsts) : base(inst)
323 		{
324 			cases = dsts;
325 			if (cases != null) numCases = (uint)cases.Length;
326 			size += 4 + (numCases * 4);
327 			for (int i=0; i < numCases; i++) {
328 				cases[i].AddBranch(this);
329 			}
330 		}
331 
Write(FileImage output)332 		internal sealed override void Write(FileImage output)
333 		{
334 			base.Write(output);
335 			output.Write(numCases);
336 			for (int i=0; i < numCases; i++) {
337 				int target = (int)cases[i].GetLabelOffset() - (int)(offset + size);
338 				output.Write(target);
339 			}
340 		}
341 
342 	}
343 
344 	/**************************************************************************/
345 	/// <summary>
346 	/// The IL instructions for a method
347 	/// </summary>
348 	public class CILInstructions  {
349 		private static readonly uint ExHeaderSize = 4;
350 		private static readonly uint FatExClauseSize = 24;
351 		private static readonly uint SmlExClauseSize = 12;
352 		private static readonly sbyte maxByteVal = 127;
353 		private static readonly sbyte minByteVal = -128;
354 		private static readonly byte maxUByteVal = 255;
355 		private static readonly int smallSize = 64;
356 		private static readonly ushort TinyFormat = 0x2;
357 		private static readonly ushort FatFormat = 0x3003;
358 		private static readonly ushort MoreSects = 0x8;
359 		private static readonly ushort InitLocals = 0x10;
360 		private static readonly uint FatSize = 12;
361 		private static readonly byte FatExceptTable = 0x41;
362 		private static readonly byte SmlExceptTable = 0x01;
363 
364 		private MetaData metaData;
365 		private ArrayList exceptions, blockStack;
366 		//private bool codeChecked = false;
367 		private static readonly int INITSIZE = 5;
368 		private CILInstruction[] buffer = new CILInstruction[INITSIZE];
369 		private int tide = 0;
370 		private uint offset = 0;
371 		private ushort headerFlags = 0;
372 		private short maxStack;
373 		private uint paddingNeeded = 0;
374 		private byte exceptHeader = 0;
375 		uint localSigIx = 0;
376 		uint codeSize = 0, exceptSize = 0;
377 		bool tinyFormat, fatExceptionFormat = false;
378 
379 		public uint Offset {
380 			get { return offset; }
381 		}
382 
CILInstructions(MetaData md)383 		internal CILInstructions(MetaData md)
384 		{
385 			metaData = md;
386 		}
387 
AddToBuffer(CILInstruction inst)388 		private void AddToBuffer(CILInstruction inst)
389 		{
390 			if (tide >= buffer.Length) {
391 				CILInstruction[] tmp = buffer;
392 				buffer = new CILInstruction[tmp.Length * 2];
393 				for (int i=0; i < tide; i++) {
394 					buffer[i] = tmp[i];
395 				}
396 			}
397 			//Console.WriteLine("Adding instruction at offset " + offset + " with size " + inst.size);
398 			inst.offset = offset;
399 			offset += inst.size;
400 			buffer[tide++] = inst;
401 		}
402 
403 		/// <summary>
404 		/// Add a simple IL instruction
405 		/// </summary>
406 		/// <param name="inst">the IL instruction</param>
Inst(Op inst)407 		public void Inst(Op inst)
408 		{
409 			AddToBuffer(new Instr((int)inst));
410 		}
411 
412 		/// <summary>
413 		/// Add an IL instruction with an integer parameter
414 		/// </summary>
415 		/// <param name="inst">the IL instruction</param>
416 		/// <param name="val">the integer parameter value</param>
IntInst(IntOp inst, int val)417 		public void IntInst(IntOp inst, int val)
418 		{
419 			int instr = (int)inst;
420 			if ((inst == IntOp.ldc_i4_s) || (inst == IntOp.ldc_i4))
421 				AddToBuffer(new IntInstr(instr,val,(inst == IntOp.ldc_i4_s)));
422 			else
423 				AddToBuffer(new UIntInstr(instr,val,((inst < IntOp.ldc_i4_s) ||
424 								(inst == IntOp.unaligned))));
425 		}
426 
427 		/// <summary>
428 		/// Add the load long instruction
429 		/// </summary>
430 		/// <param name="cVal">the long value</param>
ldc_i8(long cVal)431 		public void ldc_i8(long cVal)
432 		{
433 			AddToBuffer(new LongInstr(0x21,cVal));
434 		}
435 
436 		/// <summary>
437 		/// Add the load float32 instruction
438 		/// </summary>
439 		/// <param name="cVal">the float value</param>
ldc_r4(float cVal)440 		public void ldc_r4(float cVal)
441 		{
442 			AddToBuffer(new FloatInstr(0x22,cVal));
443 		}
444 
445 		/// <summary>
446 		/// Add the load float64 instruction
447 		/// </summary>
448 		/// <param name="cVal">the float value</param>
ldc_r8(double cVal)449 		public void ldc_r8(double cVal)
450 		{
451 			AddToBuffer(new DoubleInstr(0x23,cVal));
452 		}
453 
454 		/// <summary>
455 		/// Add the load string instruction
456 		/// </summary>
457 		/// <param name="str">the string value</param>
ldstr(string str)458 		public void ldstr(string str)
459 		{
460 			AddToBuffer(new StringInstr(0x72,str));
461 		}
462 
463 		/// <summary>
464 		/// Add the load string instruction
465 		/// </summary>
ldstr(byte[] str)466 		public void ldstr (byte[] str)
467 		{
468 			AddToBuffer (new StringInstr (0x72, str));
469 		}
470 
471 		/// <summary>
472 		/// Add the calli instruction
473 		/// </summary>
474 		/// <param name="sig">the signature for the calli</param>
calli(CalliSig sig)475 		public void calli(CalliSig sig)
476 		{
477 			AddToBuffer(new SigInstr(0x29,sig));
478 		}
479 
480 		/// <summary>
481 		/// Add a label to the CIL instructions
482 		/// </summary>
483 		/// <param name="lab">the label to be added</param>
CodeLabel(CILLabel lab)484 		public void CodeLabel(CILLabel lab)
485 		{
486 			AddToBuffer(new LabelInstr(lab));
487 		}
488 
489 		/// <summary>
490 		/// Add an instruction with a field parameter
491 		/// </summary>
492 		/// <param name="inst">the CIL instruction</param>
493 		/// <param name="f">the field parameter</param>
FieldInst(FieldOp inst, Field f)494 		public void FieldInst(FieldOp inst, Field f)
495 		{
496 			AddToBuffer(new FieldInstr((int)inst,f));
497 		}
498 
499 		/// <summary>
500 		/// Add an instruction with a method parameter
501 		/// </summary>
502 		/// <param name="inst">the CIL instruction</param>
503 		/// <param name="m">the method parameter</param>
MethInst(MethodOp inst, Method m)504 		public void MethInst(MethodOp inst, Method m)
505 		{
506 			AddToBuffer(new MethInstr((int)inst,m));
507 		}
508 
509 		/// <summary>
510 		/// Add an instruction with a type parameter
511 		/// </summary>
512 		/// <param name="inst">the CIL instruction</param>
513 		/// <param name="t">the type argument for the CIL instruction</param>
TypeInst(TypeOp inst, Type aType)514 		public void TypeInst(TypeOp inst, Type aType)
515 		{
516 			AddToBuffer(new TypeInstr((int)inst,aType,metaData));
517 		}
518 
519 		/// <summary>
520 		/// Add a branch instruction
521 		/// </summary>
522 		/// <param name="inst">the branch instruction</param>
523 		/// <param name="lab">the label that is the target of the branch</param>
Branch(BranchOp inst, CILLabel lab)524 		public void Branch(BranchOp inst,  CILLabel lab)
525 		{
526 			AddToBuffer(new BranchInstr((int)inst,lab));
527 		}
528 
529 		/// <summary>
530 		/// Add a switch instruction
531 		/// </summary>
532 		/// <param name="labs">the target labels for the switch</param>
Switch(CILLabel[] labs)533 		public void Switch(CILLabel[] labs)
534 		{
535 			AddToBuffer(new SwitchInstr(0x45,labs));
536 		}
537 
538 		/// <summary>
539 		/// Add a byte to the CIL instructions (.emitbyte)
540 		/// </summary>
541 		/// <param name="bVal"></param>
emitbyte(byte bVal)542 		public void emitbyte(byte bVal)
543 		{
544 			AddToBuffer(new CILByte(bVal));
545 		}
546 
547 		/// <summary>
548 		/// Add an instruction which puts an integer on TOS.  This method
549 		/// selects the correct instruction based on the value of the integer.
550 		/// </summary>
551 		/// <param name="i">the integer value</param>
PushInt(int i)552 		public void PushInt(int i)
553 		{
554 			if (i == -1) {
555 				AddToBuffer(new Instr((int)Op.ldc_i4_m1));
556 			} else if ((i >= 0) && (i <= 8)) {
557 				Op op = (Op)(Op.ldc_i4_0 + i);
558 				AddToBuffer(new Instr((int)op));
559 			} else if ((i >= minByteVal) && (i <= maxByteVal)) {
560 				AddToBuffer(new IntInstr((int)IntOp.ldc_i4_s,i,true));
561 			} else {
562 				AddToBuffer(new IntInstr((int)IntOp.ldc_i4,i,false));
563 			}
564 		}
565 
566 		/// <summary>
567 		/// Add the instruction to load a long on TOS
568 		/// </summary>
569 		/// <param name="l">the long value</param>
PushLong(long l)570 		public void PushLong(long l)
571 		{
572 			AddToBuffer(new LongInstr(0x21,l));
573 		}
574 
575 		/// <summary>
576 		/// Add an instruction to push the boolean value true on TOS
577 		/// </summary>
PushTrue()578 		public void PushTrue()
579 		{
580 			AddToBuffer(new Instr((int)Op.ldc_i4_1));
581 		}
582 
583 		/// <summary>
584 		///  Add an instruction to push the boolean value false on TOS
585 		/// </summary>
PushFalse()586 		public void PushFalse()
587 		{
588 			AddToBuffer(new Instr((int)Op.ldc_i4_0));
589 		}
590 
591 		/// <summary>
592 		/// Add the instruction to load an argument on TOS.  This method
593 		/// selects the correct instruction based on the value of argNo
594 		/// </summary>
595 		/// <param name="argNo">the number of the argument</param>
LoadArg(int argNo)596 		public void LoadArg(int argNo)
597 		{
598 			if (argNo < 4) {
599 				int op = (int)Op.ldarg_0 + argNo;
600 				AddToBuffer(new Instr(op));
601 			} else if (argNo <= maxUByteVal) {
602 				AddToBuffer(new UIntInstr((int)IntOp.ldarg,argNo,true));
603 			} else {
604 				AddToBuffer(new UIntInstr(0x09,argNo,false));
605 			}
606 		}
607 
608 		/// <summary>
609 		/// Add the instruction to load the address of an argument on TOS.
610 		/// This method selects the correct instruction based on the value
611 		/// of argNo.
612 		/// </summary>
613 		/// <param name="argNo">the number of the argument</param>
LoadArgAdr(int argNo)614 		public void LoadArgAdr(int argNo)
615 		{
616 			if (argNo <= maxUByteVal) {
617 				AddToBuffer(new UIntInstr((int)IntOp.ldarga,argNo,true));
618 			} else {
619 				AddToBuffer(new UIntInstr(0x0A,argNo,false));
620 			}
621 		}
622 
623 		/// <summary>
624 		/// Add the instruction to load a local on TOS.  This method selects
625 		/// the correct instruction based on the value of locNo.
626 		/// </summary>
627 		/// <param name="locNo">the number of the local to load</param>
LoadLocal(int locNo)628 		public void LoadLocal(int locNo)
629 		{
630 			if (locNo < 4) {
631 				int op = (int)Op.ldloc_0 + locNo;
632 				AddToBuffer(new Instr(op));
633 			} else if (locNo <= maxUByteVal) {
634 				AddToBuffer(new UIntInstr((int)IntOp.ldloc,locNo,true));
635 			} else {
636 				AddToBuffer(new UIntInstr(0x0C,locNo,false));
637 			}
638 		}
639 
640 		/// <summary>
641 		/// Add the instruction to load the address of a local on TOS.
642 		/// This method selects the correct instruction based on the
643 		/// value of locNo.
644 		/// </summary>
645 		/// <param name="locNo">the number of the local</param>
LoadLocalAdr(int locNo)646 		public void LoadLocalAdr(int locNo)
647 		{
648 			if (locNo <= maxUByteVal) {
649 				AddToBuffer(new UIntInstr((int)IntOp.ldloca,locNo,true));
650 			} else {
651 				AddToBuffer(new UIntInstr(0x0D,locNo,false));
652 			}
653 		}
654 
655 		/// <summary>
656 		/// Add the instruction to store to an argument.  This method
657 		/// selects the correct instruction based on the value of argNo.
658 		/// </summary>
659 		/// <param name="argNo">the argument to be stored to</param>
StoreArg(int argNo)660 		public void StoreArg(int argNo)
661 		{
662 			if (argNo <= maxUByteVal) {
663 				AddToBuffer(new UIntInstr((int)IntOp.starg,argNo,true));
664 			} else {
665 				AddToBuffer(new UIntInstr(0x0B,argNo,false));
666 			}
667 		}
668 
669 		/// <summary>
670 		/// Add the instruction to store to a local.  This method selects
671 		/// the correct instruction based on the value of locNo.
672 		/// </summary>
673 		/// <param name="locNo">the local to be stored to</param>
StoreLocal(int locNo)674 		public void StoreLocal(int locNo)
675 		{
676 			if (locNo < 4) {
677 				int op = (int)Op.stloc_0 + locNo;
678 				AddToBuffer(new Instr(op));
679 			} else if (locNo <= maxUByteVal) {
680 				AddToBuffer(new UIntInstr((int)IntOp.stloc,locNo,true));
681 			} else {
682 				AddToBuffer(new UIntInstr(0x0E,locNo,false));
683 			}
684 		}
685 
686 		/// <summary>
687 		/// Create a new CIL label.  To place the label in the CIL instruction
688 		/// stream use CodeLabel.
689 		/// </summary>
690 		/// <returns>a new CIL label</returns>
NewLabel()691 		public CILLabel NewLabel()
692 		{
693 			return new CILLabel();
694 		}
695 
AddTryBlock(TryBlock tryBlock)696 		public void AddTryBlock(TryBlock tryBlock)
697 		{
698 			if (exceptions == null)
699 				exceptions = new ArrayList();
700 			else if (exceptions.Contains(tryBlock)) return;
701 			exceptions.Add(tryBlock);
702 			tryBlock.ResolveCatchBlocks (metaData);
703 		}
704 
705 		/// <summary>
706 		/// Create a new label at this position in the code buffer
707 		/// </summary>
708 		/// <returns>the label at the current position</returns>
NewCodedLabel()709 		public CILLabel NewCodedLabel()
710 		{
711 			CILLabel lab = new CILLabel();
712 			AddToBuffer(new LabelInstr(lab));
713 			return lab;
714 		}
715 
716 		/// <summary>
717 		/// Mark this position as the start of a new block
718 		/// (try, catch, filter, finally or fault)
719 		/// </summary>
StartBlock()720 		public void StartBlock()
721 		{
722 			if (blockStack == null) blockStack = new ArrayList();
723 			blockStack.Insert(0,NewCodedLabel());
724 		}
725 
726 		/// <summary>
727 		/// Mark this position as the end of the last started block and
728 		/// make it a try block.  This try block is added to the current
729 		/// instructions (ie do not need to call AddTryBlock)
730 		/// </summary>
731 		/// <returns>The try block just ended</returns>
EndTryBlock()732 		public TryBlock EndTryBlock()
733 		{
734 			TryBlock tBlock = new TryBlock((CILLabel)blockStack[0],NewCodedLabel());
735 			blockStack.RemoveAt(0);
736 			AddTryBlock(tBlock);
737 			return tBlock;
738 		}
739 
740 		/// <summary>
741 		/// Mark this position as the end of the last started block and
742 		/// make it a catch block.  This catch block is associated with the
743 		/// specified try block.
744 		/// </summary>
745 		/// <param name="exceptType">the exception type to be caught</param>
746 		/// <param name="tryBlock">the try block associated with this catch block</param>
EndCatchBlock(Class exceptType, TryBlock tryBlock)747 		public void EndCatchBlock(Class exceptType, TryBlock tryBlock)
748 		{
749 			Catch catchBlock = new Catch(exceptType,(CILLabel)blockStack[0],
750 					NewCodedLabel());
751 			tryBlock.AddHandler(catchBlock);
752 		}
753 
754 		/// <summary>
755 		/// Mark this position as the end of the last started block and
756 		/// make it a filter block.  This filter block is associated with the
757 		/// specified try block.
758 		/// </summary>
759 		/// <param name="filterLab">the label where the filter code is</param>
760 		/// <param name="tryBlock">the try block associated with this filter block</param>
EndFilterBlock(CILLabel filterLab, TryBlock tryBlock)761 		public void EndFilterBlock(CILLabel filterLab, TryBlock tryBlock)
762 		{
763 			Filter filBlock = new Filter(filterLab,(CILLabel)blockStack[0],NewCodedLabel());
764 			tryBlock.AddHandler(filBlock);
765 		}
766 
767 		/// <summary>
768 		/// Mark this position as the end of the last started block and
769 		/// make it a finally block.  This finally block is associated with the
770 		/// specified try block.
771 		/// </summary>
772 		/// <param name="tryBlock">the try block associated with this finally block</param>
EndFinallyBlock(TryBlock tryBlock)773 		public void EndFinallyBlock(TryBlock tryBlock)
774 		{
775 			Finally finBlock= new Finally((CILLabel)blockStack[0],NewCodedLabel());
776 			tryBlock.AddHandler(finBlock);
777 		}
778 
779 		/// <summary>
780 		/// Mark this position as the end of the last started block and
781 		/// make it a fault block.  This fault block is associated with the
782 		/// specified try block.
783 		/// </summary>
784 		/// <param name="tryBlock">the try block associated with this fault block</param>
EndFaultBlock(TryBlock tryBlock)785 		public void EndFaultBlock(TryBlock tryBlock)
786 		{
787 			Fault fBlock= new Fault((CILLabel)blockStack[0],NewCodedLabel());
788 			tryBlock.AddHandler(fBlock);
789 		}
790 
GetCodeSize()791 		internal uint GetCodeSize()
792 		{
793 			return codeSize + paddingNeeded + exceptSize;
794 		}
795 
CheckCode(uint locSigIx, bool initLocals, int maxStack)796 		internal void CheckCode(uint locSigIx, bool initLocals, int maxStack)
797 		{
798 			if (tide == 0) return;
799 			bool changed = true;
800 			while (changed) {
801 				changed = false;
802 				for (int i=0; i < tide; i++) {
803 					changed = buffer[i].Check(metaData) || changed;
804 				}
805 				if (changed) {
806 					for (int i=1; i < tide; i++) {
807 						buffer[i].offset = buffer[i-1].offset + buffer[i-1].size;
808 					}
809 					offset = buffer[tide-1].offset + buffer[tide-1].size;
810 				}
811 			}
812 			codeSize = offset;
813 			// Console.WriteLine("codeSize before header added = " + codeSize);
814 			if ((offset < smallSize) && (maxStack <= 8) && (locSigIx == 0) && (exceptions == null)) {
815 				// can use tiny header
816 				//Console.WriteLine("Tiny Header");
817 				tinyFormat = true;
818 				headerFlags = (ushort)(TinyFormat | ((ushort)codeSize << 2));
819 				codeSize++;
820 				if ((codeSize % 4) != 0) { paddingNeeded = 4 - (codeSize % 4); }
821 			} else {
822 				//Console.WriteLine("Fat Header");
823 				tinyFormat = false;
824 				localSigIx = locSigIx;
825 				this.maxStack = (short)maxStack;
826 				headerFlags = FatFormat;
827 				if (exceptions != null) {
828 					// Console.WriteLine("Got exceptions");
829 					headerFlags |= MoreSects;
830 					uint numExceptClauses = 0;
831 					for (int i=0; i < exceptions.Count; i++) {
832 						TryBlock tryBlock = (TryBlock)exceptions[i];
833 						tryBlock.SetSize();
834 						numExceptClauses += (uint)tryBlock.NumHandlers();
835 						if (tryBlock.isFat()) fatExceptionFormat = true;
836 					}
837 
838 					uint data_size = ExHeaderSize + numExceptClauses *
839 						(fatExceptionFormat ? FatExClauseSize : SmlExClauseSize);
840 
841 					if (data_size > 255)
842 						fatExceptionFormat = true;
843 
844 					// Console.WriteLine("numexceptclauses = " + numExceptClauses);
845 					if (fatExceptionFormat) {
846 						// Console.WriteLine("Fat exception format");
847 						exceptHeader = FatExceptTable;
848 						exceptSize = ExHeaderSize + numExceptClauses * FatExClauseSize;
849 					} else {
850 						// Console.WriteLine("Tiny exception format");
851 						exceptHeader = SmlExceptTable;
852 						exceptSize = ExHeaderSize + numExceptClauses * SmlExClauseSize;
853 					}
854 					// Console.WriteLine("exceptSize = " + exceptSize);
855 				}
856 				if (initLocals) headerFlags |= InitLocals;
857 				if ((offset % 4) != 0) { paddingNeeded = 4 - (offset % 4); }
858 				codeSize += FatSize;
859 			}
860 			// Console.WriteLine("codeSize = " + codeSize + "  headerFlags = " +
861 			//                   Hex.Short(headerFlags));
862 		}
863 
Write(FileImage output)864 		internal void Write(FileImage output)
865 		{
866 			// Console.WriteLine("Writing header flags = " + Hex.Short(headerFlags));
867 			if (tinyFormat) {
868 				// Console.WriteLine("Writing tiny code");
869 				output.Write((byte)headerFlags);
870 			} else {
871 				// Console.WriteLine("Writing fat code");
872 				output.Write(headerFlags);
873 				output.Write((ushort)maxStack);
874 				output.Write(offset);
875 				output.Write(localSigIx);
876 			}
877 			// Console.WriteLine(Hex.Int(tide) + " CIL instructions");
878 			// Console.WriteLine("starting instructions at " + output.Seek(0,SeekOrigin.Current));
879 			for (int i=0; i < tide; i++) {
880 				buffer[i].Write(output);
881 			}
882 			// Console.WriteLine("ending instructions at " + output.Seek(0,SeekOrigin.Current));
883 			for (int i=0; i < paddingNeeded; i++) { output.Write((byte)0); }
884 			if (exceptions != null) {
885 				// Console.WriteLine("Writing exceptions");
886 				// Console.WriteLine("header = " + Hex.Short(exceptHeader) + " exceptSize = " + Hex.Int(exceptSize));
887 				output.Write(exceptHeader);
888 				output.Write3Bytes((uint)exceptSize);
889 				for (int i=0; i < exceptions.Count; i++) {
890 					TryBlock tryBlock = (TryBlock)exceptions[i];
891 					tryBlock.Write(output,fatExceptionFormat);
892 				}
893 			}
894 		}
895 
896 	}
897 
898 	/**************************************************************************/
899 	public abstract class CodeBlock {
900 
901 		private static readonly int maxCodeSize = 255;
902 		protected CILLabel start, end;
903 		protected bool small = true;
904 
CodeBlock(CILLabel start, CILLabel end)905 		public CodeBlock(CILLabel start, CILLabel end)
906 		{
907 			this.start = start;
908 			this.end = end;
909 		}
910 
isFat()911 		internal virtual bool isFat()
912 		{
913 			// Console.WriteLine("block start = " + start.GetLabelOffset() +
914 			//                  "  block end = " + end.GetLabelOffset());
915 			return (end.GetLabelOffset() - start.GetLabelOffset()) > maxCodeSize;
916 		}
917 
Write(FileImage output, bool fatFormat)918 		internal virtual void Write(FileImage output, bool fatFormat)
919 		{
920 			if (fatFormat) output.Write(start.GetLabelOffset());
921 			else output.Write((short)start.GetLabelOffset());
922 			uint len = end.GetLabelOffset() - start.GetLabelOffset();
923 			if (fatFormat) output.Write(len);
924 			else output.Write((byte)len);
925 		}
926 
927 	}
928 
929 	/// <summary>
930 	/// The descriptor for a guarded block (.try)
931 	/// </summary>
932 	public class TryBlock : CodeBlock {
933 		protected bool fatFormat = false;
934 		protected int flags = 0;
935 		ArrayList handlers = new ArrayList();
936 
937 		/// <summary>
938 		/// Create a new try block
939 		/// </summary>
940 		/// <param name="start">start label for the try block</param>
941 		/// <param name="end">end label for the try block</param>
TryBlock(CILLabel start, CILLabel end)942 		public TryBlock(CILLabel start, CILLabel end) : base(start,end) { }
943 
944 		/// <summary>
945 		/// Add a handler to this try block
946 		/// </summary>
947 		/// <param name="handler">a handler to be added to the try block</param>
AddHandler(HandlerBlock handler)948 		public void AddHandler(HandlerBlock handler)
949 		{
950 			flags = handler.GetFlag();
951 			handlers.Add(handler);
952 		}
953 
SetSize()954 		internal void SetSize()
955 		{
956 			fatFormat = base.isFat();
957 			if (fatFormat) return;
958 			for (int i=0; i < handlers.Count; i++) {
959 				HandlerBlock handler = (HandlerBlock)handlers[i];
960 				if (handler.isFat()) {
961 					fatFormat = true;
962 					return;
963 				}
964 			}
965 		}
966 
NumHandlers()967 		internal int NumHandlers()
968 		{
969 			return handlers.Count;
970 		}
971 
isFat()972 		internal override bool isFat()
973 		{
974 			return fatFormat;
975 		}
976 
977 		//Hackish
ResolveCatchBlocks(MetaData md)978 		internal void ResolveCatchBlocks (MetaData md)
979 		{
980 			for (int i=0; i < handlers.Count; i++) {
981 				Catch c = handlers [i] as Catch;
982 				if (c != null)
983 					c.ResolveType (md);
984 			}
985 		}
986 
Write(FileImage output, bool fatFormat)987 		internal override void Write(FileImage output, bool fatFormat)
988 		{
989 			// Console.WriteLine("writing exception details");
990 			for (int i=0; i < handlers.Count; i++) {
991 				// Console.WriteLine("Except block " + i);
992 				HandlerBlock handler = (HandlerBlock)handlers[i];
993 				if (fatFormat) output.Write(flags);
994 				else output.Write((short)flags);
995 				// Console.WriteLine("flags = " + Hex.Short(flags));
996 				base.Write(output,fatFormat);
997 				handler.Write(output,fatFormat);
998 			}
999 		}
1000 	}
1001 
1002 	public abstract class HandlerBlock : CodeBlock  {
1003 
1004 		protected static readonly short ExceptionFlag = 0;
1005 		protected static readonly short FilterFlag = 0x01;
1006 		protected static readonly short FinallyFlag = 0x02;
1007 		protected static readonly short FaultFlag = 0x04;
1008 
HandlerBlock(CILLabel start, CILLabel end)1009 		public HandlerBlock(CILLabel start, CILLabel end) : base(start,end) { }
1010 
GetFlag()1011 		internal virtual short GetFlag() { return ExceptionFlag; }
1012 
Write(FileImage output, bool fatFormat)1013 		internal override void Write(FileImage output, bool fatFormat)
1014 		{
1015 			base.Write(output,fatFormat);
1016 		}
1017 
1018 	}
1019 
1020 	/// <summary>
1021 	/// The descriptor for a catch clause (.catch)
1022 	/// </summary>
1023 	public class Catch : HandlerBlock  {
1024 
1025 		MetaDataElement exceptType;
1026 
1027 		/// <summary>
1028 		/// Create a new catch clause
1029 		/// </summary>
1030 		/// <param name="except">the exception to be caught</param>
1031 		/// <param name="handlerStart">start of the handler code</param>
1032 		/// <param name="handlerEnd">end of the handler code</param>
Catch(Class except, CILLabel handlerStart, CILLabel handlerEnd)1033 		public Catch(Class except, CILLabel handlerStart, CILLabel handlerEnd)
1034 			: base(handlerStart, handlerEnd)
1035 		{
1036 			exceptType = except;
1037 		}
1038 
Catch(Type except, CILLabel handlerStart, CILLabel handlerEnd)1039 		public Catch(Type except, CILLabel handlerStart, CILLabel handlerEnd)
1040 			: base(handlerStart,handlerEnd)
1041 		{
1042 			exceptType = except;
1043 		}
1044 
ResolveType(MetaData md)1045 		internal void ResolveType (MetaData md)
1046 		{
1047 		       exceptType = ((Type) exceptType).GetTypeSpec (md);
1048 		}
1049 
Write(FileImage output, bool fatFormat)1050 		internal override void Write(FileImage output, bool fatFormat)
1051 		{
1052 			base.Write(output,fatFormat);
1053 			output.Write(exceptType.Token());
1054 		}
1055 	}
1056 
1057 	/// <summary>
1058 	/// The descriptor for a filter clause (.filter)
1059 	/// </summary>
1060 	public class Filter : HandlerBlock  {
1061 
1062 		CILLabel filterLabel;
1063 
1064 		/// <summary>
1065 		/// Create a new filter clause
1066 		/// </summary>
1067 		/// <param name="filterLabel">the label where the filter code starts</param>
1068 		/// <param name="handlerStart">the start of the handler code</param>
1069 		/// <param name="handlerEnd">the end of the handler code</param>
Filter(CILLabel filterLabel, CILLabel handlerStart, CILLabel handlerEnd)1070 		public Filter(CILLabel filterLabel, CILLabel handlerStart,
1071 				CILLabel handlerEnd) : base(handlerStart,handlerEnd)
1072 				{
1073 			this.filterLabel = filterLabel;
1074 		}
1075 
GetFlag()1076 		internal override short GetFlag()
1077 		{
1078 			return FilterFlag;
1079 		}
1080 
Write(FileImage output, bool fatFormat)1081 		internal override void Write(FileImage output, bool fatFormat)
1082 		{
1083 			base.Write(output,fatFormat);
1084 			output.Write(filterLabel.GetLabelOffset());
1085 		}
1086 
1087 	}
1088 
1089 	/// <summary>
1090 	/// Descriptor for a finally block (.finally)
1091 	/// </summary>
1092 	public class Finally : HandlerBlock  {
1093 
1094 		/// <summary>
1095 		/// Create a new finally clause
1096 		/// </summary>
1097 		/// <param name="finallyStart">start of finally code</param>
1098 		/// <param name="finallyEnd">end of finally code</param>
Finally(CILLabel finallyStart, CILLabel finallyEnd)1099 		public Finally(CILLabel finallyStart, CILLabel finallyEnd)
1100 			: base(finallyStart,finallyEnd) { }
1101 
GetFlag()1102 		internal override short GetFlag()
1103 		{
1104 			return FinallyFlag;
1105 		}
1106 
Write(FileImage output, bool fatFormat)1107 		internal override void Write(FileImage output, bool fatFormat)
1108 		{
1109 			base.Write(output,fatFormat);
1110 			output.Write((int)0);
1111 		}
1112 
1113 	}
1114 
1115 	/// <summary>
1116 	/// Descriptor for a fault block (.fault)
1117 	/// </summary>
1118 	public class Fault : HandlerBlock  {
1119 
1120 		/// <summary>
1121 		/// Create a new fault clause
1122 		/// </summary>
1123 		/// <param name="faultStart">start of the fault code</param>
1124 		/// <param name="faultEnd">end of the fault code</param>
Fault(CILLabel faultStart, CILLabel faultEnd)1125 		public Fault(CILLabel faultStart, CILLabel faultEnd)
1126 			: base(faultStart,faultEnd) { }
1127 
GetFlag()1128 		internal override short GetFlag()
1129 		{
1130 			return FaultFlag;
1131 		}
1132 
Write(FileImage output, bool fatFormat)1133 		internal override void Write(FileImage output, bool fatFormat)
1134 		{
1135 			base.Write(output,fatFormat);
1136 			output.Write((int)0);
1137 
1138 		}
1139 	}
1140 
1141 	/**************************************************************************/
1142 	/// <summary>
1143 	/// Descriptor for the locals for a method
1144 	/// </summary>
1145 	public class LocalSig : Signature {
1146 
1147 		private static readonly byte LocalSigByte = 0x7;
1148 		Local[] locals;
1149 
LocalSig(Local[] locals)1150 		public LocalSig(Local[] locals)
1151 		{
1152 			this.locals = locals;
1153 			tabIx = MDTable.StandAloneSig;
1154 		}
1155 
BuildTables(MetaData md)1156 		internal sealed override void BuildTables(MetaData md)
1157 		{
1158 			if (done) return;
1159 			MemoryStream sig = new MemoryStream();
1160 			sig.WriteByte(LocalSigByte);
1161 			MetaData.CompressNum((uint)locals.Length,sig);
1162 			for (int i=0; i < locals.Length; i++) {
1163 				((Local)locals[i]).TypeSig(sig);
1164 			}
1165 			sigIx = md.AddToBlobHeap(sig.ToArray());
1166 			done = true;
1167 		}
1168 
1169 	}
1170 
1171 	/**************************************************************************/
1172 	/// <summary>
1173 	/// Signature for calli instruction
1174 	/// </summary>
1175 	public class CalliSig : Signature {
1176 
1177 		private static readonly byte Sentinel = 0x41;
1178 		CallConv callConv;
1179 		Type returnType;
1180 		Type[] parameters, optParams;
1181 		uint numPars = 0, numOptPars = 0;
1182 
1183 		/// <summary>
1184 		/// Create a signature for a calli instruction
1185 		/// </summary>
1186 		/// <param name="cconv">calling conventions</param>
1187 		/// <param name="retType">return type</param>
1188 		/// <param name="pars">parameter types</param>
CalliSig(CallConv cconv, Type retType, Type[] pars)1189 		public CalliSig(CallConv cconv, Type retType, Type[] pars)
1190 		{
1191 			tabIx = MDTable.StandAloneSig;
1192 			callConv = cconv;
1193 			returnType = retType;
1194 			parameters = pars;
1195 			if (pars != null) numPars = (uint)pars.Length;
1196 		}
1197 
1198 		/// <summary>
1199 		/// Add the optional parameters to a vararg method
1200 		/// This method sets the vararg calling convention
1201 		/// </summary>
1202 		/// <param name="optPars">the optional pars for the vararg call</param>
AddVarArgs(Type[] optPars)1203 		public void AddVarArgs(Type[] optPars)
1204 		{
1205 			optParams = optPars;
1206 			if (optPars != null) numOptPars = (uint)optPars.Length;
1207 			callConv |= CallConv.Vararg;
1208 		}
1209 
1210 		/// <summary>
1211 		/// Add extra calling conventions to this callsite signature
1212 		/// </summary>
1213 		/// <param name="cconv"></param>
AddCallingConv(CallConv cconv)1214 		public void AddCallingConv(CallConv cconv)
1215 		{
1216 			callConv |= cconv;
1217 		}
1218 
BuildTables(MetaData md)1219 		internal sealed override void BuildTables(MetaData md)
1220 		{
1221 			if (done) return;
1222 			MemoryStream sig = new MemoryStream();
1223 			sig.WriteByte((byte)callConv);
1224 			MetaData.CompressNum(numPars+numOptPars,sig);
1225 			returnType.TypeSig(sig);
1226 			for (int i=0; i < numPars; i++) {
1227 				parameters[i].TypeSig(sig);
1228 			}
1229 			sigIx = md.AddToBlobHeap(sig.ToArray());
1230 			if (numOptPars > 0) {
1231 				sig.WriteByte(Sentinel);
1232 				for (int i=0; i < numOptPars; i++) {
1233 					optParams[i].TypeSig(sig);
1234 				}
1235 			}
1236 			done = true;
1237 		}
1238 
1239 	}
1240 
1241 	/**************************************************************************/
1242 	/// <summary>
1243 	/// Descriptor for a local of a method
1244 	/// </summary>
1245 	public class Local {
1246 
1247 		private static readonly byte Pinned = 0x45;
1248 		string name;
1249 		Type type;
1250 		bool pinned = false, byref = false;
1251 
1252 		/// <summary>
1253 		/// Create a new local variable
1254 		/// </summary>
1255 		/// <param name="lName">name of the local variable</param>
1256 		/// <param name="lType">type of the local variable</param>
Local(string lName, Type lType)1257 		public Local(string lName, Type lType)
1258 		{
1259 			name = lName;
1260 			type = lType;
1261 		}
1262 
1263 		/// <summary>
1264 		/// Create a new local variable that is byref and/or pinned
1265 		/// </summary>
1266 		/// <param name="lName">local name</param>
1267 		/// <param name="lType">local type</param>
1268 		/// <param name="byRef">is byref</param>
1269 		/// <param name="isPinned">has pinned attribute</param>
Local(string lName, Type lType, bool byRef, bool isPinned)1270 		public Local(string lName, Type lType, bool byRef, bool isPinned)
1271 		{
1272 			name = lName;
1273 			type = lType;
1274 			byref = byRef;
1275 			pinned = isPinned;
1276 		}
1277 
TypeSig(MemoryStream str)1278 		internal void TypeSig(MemoryStream str)
1279 		{
1280 			if (pinned) str.WriteByte(Pinned);
1281 			type.TypeSig(str);
1282 		}
1283 
1284 	}
1285 
1286 	/**************************************************************************/
1287 	/// <summary>
1288 	/// A label in the IL
1289 	/// </summary>
1290 	public class CILLabel {
1291 
1292 		CILInstruction branch;
1293 		CILInstruction[] multipleBranches;
1294 		int tide = 0;
1295 		CILInstruction labInstr;
1296 		uint offset = 0;
1297 		bool absolute;
1298 
1299 
CILLabel(uint offset, bool absolute)1300 		public CILLabel (uint offset, bool absolute)
1301 		{
1302 			this.offset = offset;
1303 			this.absolute = absolute;
1304 		}
1305 
CILLabel(uint offset)1306 		public CILLabel (uint offset) : this (offset, false)
1307 		{
1308 		}
1309 
1310 
CILLabel()1311 		internal CILLabel()
1312 		{
1313 		}
1314 
AddBranch(CILInstruction instr)1315 		internal void AddBranch(CILInstruction instr)
1316 		{
1317 			if (branch == null) {
1318 				branch = instr;
1319 				return;
1320 			}
1321 			if (multipleBranches == null) {
1322 				multipleBranches = new CILInstruction[2];
1323 			} else if (tide >= multipleBranches.Length) {
1324 				CILInstruction[] tmp = multipleBranches;
1325 				multipleBranches = new CILInstruction[tmp.Length*2];
1326 				for (int i=0; i < tide; i++) {
1327 					multipleBranches[i] = tmp[i];
1328 				}
1329 			}
1330 			multipleBranches[tide++] = instr;
1331 		}
1332 
AddLabelInstr(LabelInstr lInstr)1333 		internal void AddLabelInstr(LabelInstr lInstr)
1334 		{
1335 			labInstr = lInstr;
1336 		}
1337 
GetLabelOffset()1338 		internal uint GetLabelOffset()
1339 		{
1340 			if (absolute) return offset;
1341 			if (labInstr == null) return 0;
1342 			return labInstr.offset + offset;
1343 		}
1344 
1345 	}
1346 
1347 
1348 }
1349 
1350 
1351