1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Diagnostics;
7 
8 namespace ILCompiler.DependencyAnalysis.X86
9 {
10     public struct X86Emitter
11     {
X86EmitterILCompiler.DependencyAnalysis.X86.X86Emitter12         public X86Emitter(NodeFactory factory, bool relocsOnly)
13         {
14             Builder = new ObjectDataBuilder(factory, relocsOnly);
15             TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem);
16         }
17 
18         public ObjectDataBuilder Builder;
19         public TargetRegisterMap TargetRegister;
20 
EmitADDILCompiler.DependencyAnalysis.X86.X86Emitter21         public void EmitADD(ref AddrMode addrMode, sbyte immediate)
22         {
23             if (addrMode.Size == AddrModeSize.Int16)
24                 Builder.EmitByte(0x66);
25             EmitIndirInstruction((byte)((addrMode.Size != AddrModeSize.Int8) ? 0x83 : 0x80), (byte)0, ref addrMode);
26             Builder.EmitByte((byte)immediate);
27         }
28 
EmitJMPILCompiler.DependencyAnalysis.X86.X86Emitter29         public void EmitJMP(ISymbolNode symbol)
30         {
31             if (symbol.RepresentsIndirectionCell)
32             {
33                 Builder.EmitByte(0xff);
34                 Builder.EmitByte(0x25);
35                 Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);
36             }
37             else
38             {
39                 Builder.EmitByte(0xE9);
40                 Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);
41             }
42         }
43 
EmitINT3ILCompiler.DependencyAnalysis.X86.X86Emitter44         public void EmitINT3()
45         {
46             Builder.EmitByte(0xCC);
47         }
48 
InSignedByteRangeILCompiler.DependencyAnalysis.X86.X86Emitter49         private bool InSignedByteRange(int i)
50         {
51             return i == (int)(sbyte)i;
52         }
53 
EmitImmediateILCompiler.DependencyAnalysis.X86.X86Emitter54         private void EmitImmediate(int immediate, int size)
55         {
56             switch (size)
57             {
58                 case 0:
59                     break;
60                 case 1:
61                     Builder.EmitByte((byte)immediate);
62                     break;
63                 case 2:
64                     Builder.EmitShort((short)immediate);
65                     break;
66                 case 4:
67                     Builder.EmitInt(immediate);
68                     break;
69                 default:
70                     throw new NotImplementedException();
71             }
72         }
73 
EmitModRMILCompiler.DependencyAnalysis.X86.X86Emitter74         private void EmitModRM(byte subOpcode, ref AddrMode addrMode)
75         {
76             byte modRM = (byte)((subOpcode & 0x07) << 3);
77             if (addrMode.BaseReg > Register.None)
78             {
79                 Debug.Assert(addrMode.BaseReg >= Register.RegDirect);
80 
81                 Register reg = (Register)(addrMode.BaseReg - Register.RegDirect);
82                 Builder.EmitByte((byte)(0xC0 | modRM | ((int)reg & 0x07)));
83             }
84             else
85             {
86                 byte lowOrderBitsOfBaseReg = (byte)((int)addrMode.BaseReg & 0x07);
87                 modRM |= lowOrderBitsOfBaseReg;
88                 int offsetSize = 0;
89 
90                 if (addrMode.Offset == 0 && (lowOrderBitsOfBaseReg != (byte)Register.EBP))
91                 {
92                     offsetSize = 0;
93                 }
94                 else if (InSignedByteRange(addrMode.Offset))
95                 {
96                     offsetSize = 1;
97                     modRM |= 0x40;
98                 }
99                 else
100                 {
101                     offsetSize = 4;
102                     modRM |= 0x80;
103                 }
104 
105                 bool emitSibByte = false;
106                 Register sibByteBaseRegister = addrMode.BaseReg;
107 
108                 if (addrMode.BaseReg == Register.None)
109                 {
110                     emitSibByte = (addrMode.IndexReg != Register.NoIndex);
111                     modRM &= 0x38;    // set Mod bits to 00 and clear out base reg
112                     offsetSize = 4;   // this forces 32-bit displacement
113 
114                     if (emitSibByte)
115                     {
116                         // EBP in SIB byte means no base
117                         // ModRM base register forced to ESP in SIB code below
118                         sibByteBaseRegister = Register.EBP;
119                     }
120                     else
121                     {
122                         // EBP in ModRM means no base
123                         modRM |= (byte)(Register.EBP);
124                     }
125                 }
126                 else if (lowOrderBitsOfBaseReg == (byte)Register.ESP || addrMode.IndexReg.HasValue)
127                 {
128                     emitSibByte = true;
129                 }
130 
131                 if (!emitSibByte)
132                 {
133                     Builder.EmitByte(modRM);
134                 }
135                 else
136                 {
137                     modRM = (byte)((modRM & 0xF8) | (int)Register.ESP);
138                     Builder.EmitByte(modRM);
139                     int indexRegAsInt = (int)(addrMode.IndexReg.HasValue ? addrMode.IndexReg.Value : Register.ESP);
140                     Builder.EmitByte((byte)((addrMode.Scale << 6) + ((indexRegAsInt & 0x07) << 3) + ((int)sibByteBaseRegister & 0x07)));
141                 }
142                 EmitImmediate(addrMode.Offset, offsetSize);
143             }
144         }
145 
EmitExtendedOpcodeILCompiler.DependencyAnalysis.X86.X86Emitter146         private void EmitExtendedOpcode(int opcode)
147         {
148             if ((opcode >> 16) != 0)
149             {
150                 if ((opcode >> 24) != 0)
151                 {
152                     Builder.EmitByte((byte)(opcode >> 24));
153                 }
154                 Builder.EmitByte((byte)(opcode >> 16));
155             }
156             Builder.EmitByte((byte)(opcode >> 8));
157         }
158 
EmitIndirInstructionILCompiler.DependencyAnalysis.X86.X86Emitter159         private void EmitIndirInstruction(int opcode, byte subOpcode, ref AddrMode addrMode)
160         {
161             if ((opcode >> 8) != 0)
162             {
163                 EmitExtendedOpcode(opcode);
164             }
165             Builder.EmitByte((byte)opcode);
166             EmitModRM(subOpcode, ref addrMode);
167         }
168     }
169 }
170