5 // Jb Evain (jbevain@novell.com)
7 // (C) 2008 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System
.Collections
;
33 using Mono
.Cecil
.Binary
;
35 using Mono
.Cecil
.Metadata
;
37 namespace Mono
.CilStripper
{
39 class AssemblyStripper
{
41 AssemblyDefinition assembly
;
47 ReflectionWriter reflection_writer
;
48 MetadataWriter metadata_writer
;
50 TablesHeap original_tables
;
51 TablesHeap stripped_tables
;
53 AssemblyStripper (AssemblyDefinition assembly
, BinaryWriter writer
)
55 this.assembly
= assembly
;
72 assembly
.MainModule
.FullLoad ();
75 void ClearMethodBodies ()
77 foreach (TypeDefinition type
in assembly
.MainModule
.Types
) {
78 ClearMethodBodies (type
.Constructors
);
79 ClearMethodBodies (type
.Methods
);
83 static void ClearMethodBodies (ICollection methods
)
85 foreach (MethodDefinition method
in methods
) {
89 MethodBody body
= new MethodBody (method
);
90 body
.CilWorker
.Emit (OpCodes
.Ret
);
96 void CopyOriginalImage ()
98 original
= assembly
.MainModule
.Image
;
99 stripped
= Image
.CreateImage();
101 stripped
.Accept (new CopyImageVisitor (original
));
103 assembly
.MainModule
.Image
= stripped
;
105 original_tables
= original
.MetadataRoot
.Streams
.TablesHeap
;
106 stripped_tables
= stripped
.MetadataRoot
.Streams
.TablesHeap
;
108 TableCollection tables
= original_tables
.Tables
;
109 foreach (IMetadataTable table
in tables
)
110 stripped_tables
.Tables
.Add(table
);
112 stripped_tables
.Valid
= original_tables
.Valid
;
113 stripped_tables
.Sorted
= original_tables
.Sorted
;
115 reflection_writer
= new ReflectionWriter (assembly
.MainModule
);
116 reflection_writer
.StructureWriter
= new StructureWriter (assembly
, writer
);
117 reflection_writer
.CodeWriter
.Stripped
= true;
119 metadata_writer
= reflection_writer
.MetadataWriter
;
121 PatchHeap (metadata_writer
.StringWriter
, original
.MetadataRoot
.Streams
.StringsHeap
);
122 PatchHeap (metadata_writer
.GuidWriter
, original
.MetadataRoot
.Streams
.GuidHeap
);
123 PatchHeap (metadata_writer
.UserStringWriter
, original
.MetadataRoot
.Streams
.UserStringsHeap
);
124 PatchHeap (metadata_writer
.BlobWriter
, original
.MetadataRoot
.Streams
.BlobHeap
);
126 if (assembly
.EntryPoint
!= null)
127 metadata_writer
.EntryPointToken
= assembly
.EntryPoint
.MetadataToken
.ToUInt ();
130 static void PatchHeap (MemoryBinaryWriter heap_writer
, MetadataHeap heap
)
135 heap_writer
.BaseStream
.Position
= 0;
136 heap_writer
.Write (heap
.Data
);
141 MethodTable methodTable
= (MethodTable
) stripped_tables
[MethodTable
.RId
];
142 if (methodTable
== null)
145 RVA method_rva
= RVA
.Zero
;
147 for (int i
= 0; i
< methodTable
.Rows
.Count
; i
++) {
148 MethodRow methodRow
= methodTable
[i
];
150 MetadataToken methodToken
= MetadataToken
.FromMetadataRow (TokenType
.Method
, i
);
152 MethodDefinition method
= (MethodDefinition
) assembly
.MainModule
.LookupByToken (methodToken
);
154 if (method
.HasBody
) {
155 method_rva
= method_rva
!= RVA
.Zero
157 : reflection_writer
.CodeWriter
.WriteMethodBody (method
);
159 methodRow
.RVA
= method_rva
;
161 methodRow
.RVA
= RVA
.Zero
;
167 FieldRVATable fieldRvaTable
= (FieldRVATable
) stripped_tables
[FieldRVATable
.RId
];
168 if (fieldRvaTable
== null)
171 for (int i
= 0; i
< fieldRvaTable
.Rows
.Count
; i
++) {
172 FieldRVARow fieldRvaRow
= fieldRvaTable
[i
];
174 MetadataToken fieldToken
= new MetadataToken (TokenType
.Field
, fieldRvaRow
.Field
);
176 FieldDefinition field
= (FieldDefinition
) assembly
.MainModule
.LookupByToken (fieldToken
);
178 fieldRvaRow
.RVA
= metadata_writer
.GetDataCursor ();
179 metadata_writer
.AddData (field
.InitialValue
.Length
+ 3 & (~
3));
180 metadata_writer
.AddFieldInitData (field
.InitialValue
);
184 void PatchResources ()
186 ManifestResourceTable resourceTable
= (ManifestResourceTable
) stripped_tables
[ManifestResourceTable
.RId
];
187 if (resourceTable
== null)
190 for (int i
= 0; i
< resourceTable
.Rows
.Count
; i
++) {
191 ManifestResourceRow resourceRow
= resourceTable
[i
];
193 if (resourceRow
.Implementation
.RID
!= 0)
196 foreach (Resource resource
in assembly
.MainModule
.Resources
) {
197 EmbeddedResource er
= resource
as EmbeddedResource
;
201 if (resource
.Name
!= original
.MetadataRoot
.Streams
.StringsHeap
[resourceRow
.Name
])
204 resourceRow
.Offset
= metadata_writer
.AddResource (er
.Data
);
211 stripped
.MetadataRoot
.Accept (metadata_writer
);
214 public static void StripAssembly (AssemblyDefinition assembly
, string file
)
216 using (FileStream fs
= new FileStream (file
, FileMode
.Create
, FileAccess
.Write
, FileShare
.None
)) {
217 new AssemblyStripper (assembly
, new BinaryWriter (fs
)).Strip ();