- [Static Interface Methods](#static-interface-methods)
- [Covariant Return Types](#covariant-return-types)
- [Unsigned data conversion with overflow detection](#unsigned-data-conversion-with-overflow-detection)
+- [Rules for IL rewriters](#rules-for-il-rewriters)
## Signatures
on the top of the stack is reinterpreted as an unsigned value before the conversion.
Note that integer values of less than 4 bytes are extended to int32 (not native int) on the
evaluation stack.
+
+## Rules for IL Rewriters
+
+There are apis such as `System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan<T>(...)` which require that the PE file have a particular structure. In particular, that api requires that the associated RVA of a FieldDef which is used to create a span must be naturally aligned over the data type that `CreateSpan` is instantiated over. There are 2 major concerns.
+
+1. That the RVA be aligned when the PE file is constructed. This may be achieved by whatever means is most convenient for the compiler.
+2. That in the presence of IL rewriters that the RVA remains aligned. This section descibes metadata which will be processed by IL rewriters in order to maintain the required alignment.
+
+In order to maintain alignment, if the field needs alignment to be preserved, the field must be of a type locally defined within the module which has a Pack (§II.10.7) value of the desired alignment. Unlike other uses of the .pack directive, in this circumstance the .pack specifies a minimum alignment.
{
// Use the typical field definition in case this is an instantiated generic type
field = field.GetTypicalFieldDefinition();
+ int fieldTypePack = (field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1;
return NodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field),
- ((EcmaField)field).GetFieldRvaData(), NodeFactory.Target.PointerSize);
+ ((EcmaField)field).GetFieldRvaData(), Math.Max(NodeFactory.Target.PointerSize, fieldTypePack));
}
}
}
ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
- builder.RequireInitialPointerAlignment();
+ byte[] rvaData = GetRvaData(factory.Target.PointerSize, out int requiredAlignment);
+ builder.RequireInitialAlignment(requiredAlignment);
builder.AddSymbol(this);
- builder.EmitBytes(GetRvaData(factory.Target.PointerSize));
+ builder.EmitBytes(rvaData);
return builder.ToObjectData();
}
- private unsafe byte[] GetRvaData(int targetPointerSize)
+ private unsafe byte[] GetRvaData(int targetPointerSize, out int requiredAlignment)
{
int size = 0;
+ requiredAlignment = targetPointerSize;
MetadataReader metadataReader = _module.MetadataReader;
BlobReader metadataBlob = new BlobReader(_module.PEReader.GetMetadata().Pointer, _module.PEReader.GetMetadata().Length);
Debug.Assert(field.HasRva);
int currentSize = field.FieldType.GetElementSize().AsInt;
+ requiredAlignment = Math.Max(requiredAlignment, (field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1);
if (currentSize > size)
{
// We need to handle overlapping fields by reusing blobs based on the rva, and just update
.class explicit ansi sealed nested private '__StaticArrayInitTypeSize=16'
extends [System.Runtime]System.ValueType
{
- .pack 1
+ .pack 4
.size 16
} // end of class '__StaticArrayInitTypeSize=16'