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