Code.cs 33 KB

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