Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2015-02-17 16:48:31 +0300
committerMarek Safar <marek.safar@gmail.com>2015-02-18 14:49:17 +0300
commitcd4bed9dd6540c380177c5b9c72f4d020f1b138f (patch)
treef7cf4cc627a964282591ab470fe8c75233a3725b /reflect
parent9830ce248ed867f7037c72152265966e31d43235 (diff)
Added UniverseOptions.DeterministicOutput to enable deterministic output (i.e. setting the PE file header time stamp to zero and computing the module version id based on the contents, instead of using a random guid).
Diffstat (limited to 'reflect')
-rw-r--r--reflect/Emit/ModuleBuilder.cs45
-rw-r--r--reflect/Impl/MdbWriter.cs5
-rw-r--r--reflect/Impl/PdbWriter.cs5
-rw-r--r--reflect/Impl/SymbolSupport.cs2
-rw-r--r--reflect/Universe.cs13
-rw-r--r--reflect/Writer/ModuleWriter.cs36
-rw-r--r--reflect/Writer/TextSection.cs4
7 files changed, 99 insertions, 11 deletions
diff --git a/reflect/Emit/ModuleBuilder.cs b/reflect/Emit/ModuleBuilder.cs
index 646c3553..b415262d 100644
--- a/reflect/Emit/ModuleBuilder.cs
+++ b/reflect/Emit/ModuleBuilder.cs
@@ -41,8 +41,8 @@ namespace IKVM.Reflection.Emit
public sealed class ModuleBuilder : Module, ITypeOwner
{
private static readonly bool usePublicKeyAssemblyReference = false;
- private Guid mvid = Guid.NewGuid();
- private DateTime timestamp = DateTime.UtcNow;
+ private Guid mvid;
+ private uint timestamp;
private long imageBaseAddress = 0x00400000;
private long stackReserve = -1;
private int fileAlignment = 0x200;
@@ -251,6 +251,15 @@ namespace IKVM.Reflection.Emit
if (emitSymbolInfo)
{
symbolWriter = SymbolSupport.CreateSymbolWriterFor(this);
+ if (universe.Deterministic && !symbolWriter.IsDeterministic)
+ {
+ throw new NotSupportedException();
+ }
+ }
+ if (!universe.Deterministic)
+ {
+ __PEHeaderTimeDateStamp = DateTime.UtcNow;
+ mvid = Guid.NewGuid();
}
// <Module> must be the first record in the TypeDef table
moduleType = new TypeBuilder(this, null, "<Module>");
@@ -1122,7 +1131,7 @@ namespace IKVM.Reflection.Emit
}
}
- internal void WriteMetadata(MetadataWriter mw)
+ internal void WriteMetadata(MetadataWriter mw, out int guidHeapOffset)
{
mw.Write(0x424A5342); // Signature ("BSJB")
mw.Write((ushort)1); // MajorVersion
@@ -1175,6 +1184,7 @@ namespace IKVM.Reflection.Emit
Tables.Write(mw);
Strings.Write(mw);
UserStrings.Write(mw);
+ guidHeapOffset = mw.Position;
Guids.Write(mw);
if (!Blobs.IsEmpty)
{
@@ -1396,26 +1406,49 @@ namespace IKVM.Reflection.Emit
get { return fileName; }
}
+ internal Guid GetModuleVersionIdOrEmpty()
+ {
+ return mvid;
+ }
+
public override Guid ModuleVersionId
{
- get { return mvid; }
+ get
+ {
+ if (mvid == Guid.Empty && universe.Deterministic)
+ {
+ // if a deterministic GUID is used, it can't be queried before the assembly has been written
+ throw new InvalidOperationException();
+ }
+ return mvid;
+ }
}
public void __SetModuleVersionId(Guid guid)
{
+ if (guid == Guid.Empty && universe.Deterministic)
+ {
+ // if you want to use Guid.Empty, don't set UniverseOptions.DeterministicOutput
+ throw new ArgumentOutOfRangeException();
+ }
mvid = guid;
}
+ internal uint GetTimeDateStamp()
+ {
+ return timestamp;
+ }
+
public DateTime __PEHeaderTimeDateStamp
{
- get { return timestamp; }
+ get { return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp); }
set
{
if (value < new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) || value > new DateTime(2106, 2, 7, 6, 28, 15, DateTimeKind.Utc))
{
throw new ArgumentOutOfRangeException();
}
- timestamp = value;
+ timestamp = (uint)(value - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
}
}
diff --git a/reflect/Impl/MdbWriter.cs b/reflect/Impl/MdbWriter.cs
index 226137b9..4d1e2cd7 100644
--- a/reflect/Impl/MdbWriter.cs
+++ b/reflect/Impl/MdbWriter.cs
@@ -228,6 +228,11 @@ namespace IKVM.Reflection.Impl
{
throw new InvalidOperationException();
}
+
+ public bool IsDeterministic
+ {
+ get { return true; }
+ }
}
}
#endif // MONO
diff --git a/reflect/Impl/PdbWriter.cs b/reflect/Impl/PdbWriter.cs
index b8976bbf..4d8fc1d8 100644
--- a/reflect/Impl/PdbWriter.cs
+++ b/reflect/Impl/PdbWriter.cs
@@ -1184,5 +1184,10 @@ namespace IKVM.Reflection.Impl
{
throw new NotImplementedException();
}
+
+ public bool IsDeterministic
+ {
+ get { return false; }
+ }
}
}
diff --git a/reflect/Impl/SymbolSupport.cs b/reflect/Impl/SymbolSupport.cs
index c573b2b5..7b4e8906 100644
--- a/reflect/Impl/SymbolSupport.cs
+++ b/reflect/Impl/SymbolSupport.cs
@@ -55,6 +55,7 @@ namespace IKVM.Reflection.Impl
void RemapToken(int oldToken, int newToken);
void DefineLocalVariable2(string name, FieldAttributes attributes, int signature, int addrKind, int addr1, int addr2, int addr3, int startOffset, int endOffset);
void OpenMethod(SymbolToken symbolToken, MethodBase mb);
+ bool IsDeterministic { get; }
}
#else
interface ISymbolWriterImpl : ISymbolWriter
@@ -63,6 +64,7 @@ namespace IKVM.Reflection.Impl
void RemapToken(int oldToken, int newToken);
void DefineLocalVariable2(string name, FieldAttributes attributes, int signature, SymAddressKind addrKind, int addr1, int addr2, int addr3, int startOffset, int endOffset);
void OpenMethod(SymbolToken symbolToken, MethodBase mb);
+ bool IsDeterministic { get; }
}
#endif
diff --git a/reflect/Universe.cs b/reflect/Universe.cs
index 30ed1204..82fad202 100644
--- a/reflect/Universe.cs
+++ b/reflect/Universe.cs
@@ -115,6 +115,12 @@ namespace IKVM.Reflection
* - Module.__ReadDataFromRVA()
* - MethodBase.GetMethodBody()
* - FieldInfo.__GetDataFromRVA()
+ *
+ * DeterministicOutput
+ * The generated output file will depend only on the input. In other words,
+ * the PE file header time stamp will be set to zero and the module version
+ * id will be based on a SHA1 of the contents, instead of a random guid.
+ * This option can not be used in combination with PDB file generation.
*/
[Flags]
@@ -129,6 +135,8 @@ namespace IKVM.Reflection
ResolveMissingMembers = 32,
DisableWindowsRuntimeProjection = 64,
DecodeVersionInfoAttributeBlobs = 128,
+ DeterministicOutput = 256,
+
SupressReferenceTypeIdentityConversion = 1 << 20
}
@@ -1250,5 +1258,10 @@ namespace IKVM.Reflection
{
get { return (options & UniverseOptions.SupressReferenceTypeIdentityConversion) != 0; }
}
+
+ internal bool Deterministic
+ {
+ get { return (options & UniverseOptions.DeterministicOutput) != 0; }
+ }
}
}
diff --git a/reflect/Writer/ModuleWriter.cs b/reflect/Writer/ModuleWriter.cs
index ba3bf85a..7ef9c6d6 100644
--- a/reflect/Writer/ModuleWriter.cs
+++ b/reflect/Writer/ModuleWriter.cs
@@ -81,7 +81,8 @@ namespace IKVM.Reflection.Writer
moduleBuilder.ApplyUnmanagedExports(imageFileMachine);
moduleBuilder.FixupMethodBodyTokens();
- moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleBuilder.Guids.Add(moduleBuilder.ModuleVersionId), 0, 0);
+ int moduleVersionIdIndex = moduleBuilder.Guids.Add(moduleBuilder.GetModuleVersionIdOrEmpty());
+ moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleVersionIdIndex, 0, 0);
if (moduleBuilder.UserStrings.IsEmpty)
{
@@ -213,7 +214,7 @@ namespace IKVM.Reflection.Writer
}
// Set the PE File timestamp
- writer.Headers.FileHeader.TimeDateStamp = (uint)(moduleBuilder.__PEHeaderTimeDateStamp - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
+ writer.Headers.FileHeader.TimeDateStamp = moduleBuilder.GetTimeDateStamp();
// we need to start by computing the number of sections, because code.PointerToRawData depends on that
writer.Headers.FileHeader.NumberOfSections = 2;
@@ -312,7 +313,8 @@ namespace IKVM.Reflection.Writer
}
stream.Seek(text.PointerToRawData, SeekOrigin.Begin);
- code.Write(mw, sdata.VirtualAddress);
+ int guidHeapOffset;
+ code.Write(mw, sdata.VirtualAddress, out guidHeapOffset);
if (sdata.SizeOfRawData != 0)
{
@@ -335,6 +337,15 @@ namespace IKVM.Reflection.Writer
// file alignment
stream.SetLength(reloc.PointerToRawData + reloc.SizeOfRawData);
+ // if we don't have a guid, generate one based on the contents of the assembly
+ if (moduleBuilder.universe.Deterministic && moduleBuilder.GetModuleVersionIdOrEmpty() == Guid.Empty)
+ {
+ Guid guid = GenerateModuleVersionId(stream);
+ stream.Position = guidHeapOffset + (moduleVersionIdIndex - 1) * 16;
+ stream.Write(guid.ToByteArray(), 0, 16);
+ moduleBuilder.__SetModuleVersionId(guid);
+ }
+
// do the strong naming
if (keyPair != null)
{
@@ -429,5 +440,24 @@ namespace IKVM.Reflection.Writer
length -= read;
}
}
+
+ private static Guid GenerateModuleVersionId(Stream stream)
+ {
+ SHA1Managed hash = new SHA1Managed();
+ using (CryptoStream cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write))
+ {
+ stream.Seek(0, SeekOrigin.Begin);
+ byte[] buf = new byte[8192];
+ HashChunk(stream, cs, buf, (int)stream.Length);
+ }
+ byte[] bytes = new byte[16];
+ Buffer.BlockCopy(hash.Hash, 0, bytes, 0, bytes.Length);
+ // set GUID type to "version 4" (random)
+ bytes[7] &= 0x0F;
+ bytes[7] |= 0x40;
+ bytes[8] &= 0x3F;
+ bytes[8] |= 0x80;
+ return new Guid(bytes);
+ }
}
}
diff --git a/reflect/Writer/TextSection.cs b/reflect/Writer/TextSection.cs
index 4657d30e..fceedcf6 100644
--- a/reflect/Writer/TextSection.cs
+++ b/reflect/Writer/TextSection.cs
@@ -275,7 +275,7 @@ namespace IKVM.Reflection.Writer
}
}
- internal void Write(MetadataWriter mw, uint sdataRVA)
+ internal void Write(MetadataWriter mw, uint sdataRVA, out int guidHeapOffset)
{
// Now that we're ready to start writing, we need to do some fix ups
moduleBuilder.TypeRef.Fixup(moduleBuilder);
@@ -356,7 +356,7 @@ namespace IKVM.Reflection.Writer
// Metadata
AssertRVA(mw, MetadataRVA);
- moduleBuilder.WriteMetadata(mw);
+ moduleBuilder.WriteMetadata(mw, out guidHeapOffset);
// alignment padding
for (int i = (int)(VTableFixupsRVA - (MetadataRVA + MetadataLength)); i > 0; i--)