Skip to content

Commit a56b5bd

Browse files
FieldRVA alignment (#817)
* FieldRVA alignment In support of dotnet/runtime#60948 the linker (an assembly rewriter) will need to be able to preserve the alignment of RVA based fields which are to be used to create the data for `CreateSpan<T>` records This is implemented by adding a concept that RVA fields detect their required alignment by examining the PackingSize of the type of the field (if the field type is defined locally in the module) * Update Mono.Cecil.Metadata/Buffers.cs Co-authored-by: Aaron Robinson <arobins@microsoft.com> * Enhace logic used to ensure type providing PackingSize is local to the module. Co-authored-by: Aaron Robinson <arobins@microsoft.com>
1 parent 75372c7 commit a56b5bd

File tree

5 files changed

+147
-3
lines changed

5 files changed

+147
-3
lines changed

Mono.Cecil.Metadata/Buffers.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,17 +256,33 @@ public uint AddResource (byte [] resource)
256256

257257
sealed class DataBuffer : ByteBuffer {
258258

259+
int buffer_align = 4;
260+
259261
public DataBuffer ()
260262
: base (0)
261263
{
262264
}
263265

264-
public RVA AddData (byte [] data)
266+
void Align (int align)
267+
{
268+
align--;
269+
// Compute the number of bytes to align the current position.
270+
// Values of 0 will be written.
271+
WriteBytes (((position + align) & ~align) - position);
272+
}
273+
274+
public RVA AddData (byte [] data, int align)
265275
{
276+
if (buffer_align < align)
277+
buffer_align = align;
278+
279+
Align (align);
266280
var rva = (RVA) position;
267281
WriteBytes (data);
268282
return rva;
269283
}
284+
285+
public int BufferAlign => buffer_align;
270286
}
271287

272288
abstract class HeapBuffer : ByteBuffer {

Mono.Cecil.PE/ImageWriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ void BuildTextMap ()
694694

695695
map.AddMap (TextSegment.Code, metadata.code.length, !pe64 ? 4 : 16);
696696
map.AddMap (TextSegment.Resources, metadata.resources.length, 8);
697-
map.AddMap (TextSegment.Data, metadata.data.length, 4);
697+
map.AddMap (TextSegment.Data, metadata.data.length, metadata.data.BufferAlign);
698698
if (metadata.data.length > 0)
699699
metadata.table_heap.FixupData (map.GetRVA (TextSegment.Data));
700700
map.AddMap (TextSegment.StrongNameSignature, GetStrongNameLength (), 4);

Mono.Cecil/AssemblyWriter.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1613,8 +1613,21 @@ void AddField (FieldDefinition field)
16131613
void AddFieldRVA (FieldDefinition field)
16141614
{
16151615
var table = GetTable<FieldRVATable> (Table.FieldRVA);
1616+
1617+
// To allow for safe implementation of metadata rewriters for code which uses CreateSpan<T>
1618+
// if the Field RVA refers to a locally defined type with a pack > 1, align the InitialValue
1619+
// to pack boundary. This logic is restricted to only being affected by metadata local to the module
1620+
// as PackingSize is only used when examining a type local to the module being written.
1621+
1622+
int align = 1;
1623+
if (field.FieldType.IsDefinition && !field.FieldType.IsGenericInstance) {
1624+
var type = field.FieldType.Resolve ();
1625+
1626+
if ((type.Module == module) && (type.PackingSize > 1))
1627+
align = type.PackingSize;
1628+
}
16161629
table.AddRow (new FieldRVARow (
1617-
data.AddData (field.InitialValue),
1630+
data.AddData (field.InitialValue, align),
16181631
field.token.RID));
16191632
}
16201633

Test/Mono.Cecil.Tests/FieldTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.IO;
23

34
using Mono.Cecil.PE;
45

@@ -133,6 +134,49 @@ public void FieldRVA ()
133134
});
134135
}
135136

137+
int AlignmentOfInteger(int input)
138+
{
139+
if (input == 0)
140+
return 0x40000000;
141+
if (input < 0)
142+
Assert.Fail ();
143+
int alignment = 1;
144+
while ((input & alignment) == 0)
145+
alignment *= 2;
146+
147+
return alignment;
148+
}
149+
150+
[Test]
151+
public void FieldRVAAlignment ()
152+
{
153+
TestIL ("FieldRVAAlignment.il", ilmodule => {
154+
155+
var path = Path.GetTempFileName ();
156+
157+
ilmodule.Write (path);
158+
159+
using (var module = ModuleDefinition.ReadModule (path, new ReaderParameters { ReadWrite = true })) {
160+
var priv_impl = GetPrivateImplementationType (module);
161+
Assert.IsNotNull (priv_impl);
162+
163+
Assert.AreEqual (6, priv_impl.Fields.Count);
164+
165+
foreach (var field in priv_impl.Fields)
166+
{
167+
Assert.IsNotNull (field);
168+
169+
Assert.AreNotEqual (0, field.RVA);
170+
Assert.IsNotNull (field.InitialValue);
171+
172+
int rvaAlignment = AlignmentOfInteger (field.RVA);
173+
int desiredAlignment = Math.Min(8, AlignmentOfInteger (field.InitialValue.Length));
174+
Assert.GreaterOrEqual (rvaAlignment, desiredAlignment);
175+
}
176+
}
177+
});
178+
}
179+
136180
[Test]
137181
public void GenericFieldDefinition ()
138182
{
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
.assembly extern mscorlib
2+
{
3+
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
4+
.ver 4:0:0:0
5+
}
6+
.assembly FieldRVAAlignment {}
7+
8+
.module FieldRVAAlignment.dll
9+
10+
.class private auto ansi '<PrivateImplementationDetails>{9B33BB20-87EF-4094-9948-34882DB2F001}'
11+
extends [mscorlib]System.Object
12+
{
13+
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
14+
.class explicit ansi sealed nested private '__StaticArrayInitTypeSize=3'
15+
extends [mscorlib]System.ValueType
16+
{
17+
.pack 1
18+
.size 3
19+
} // end of class '__StaticArrayInitTypeSize=3'
20+
21+
.class explicit ansi sealed nested private '__StaticArrayInitTypeSize=16'
22+
extends [mscorlib]System.ValueType
23+
{
24+
.pack 8
25+
.size 16
26+
} // end of class '__StaticArrayInitTypeSize=16'
27+
28+
.class explicit ansi sealed nested private '__StaticArrayInitTypeSize=20'
29+
extends [mscorlib]System.ValueType
30+
{
31+
.pack 4
32+
.size 20
33+
} // end of class '__StaticArrayInitTypeSize=20'
34+
35+
.class explicit ansi sealed nested private '__StaticArrayInitTypeSize=5'
36+
extends [mscorlib]System.ValueType
37+
{
38+
.pack 1
39+
.size 5
40+
} // end of class '__StaticArrayInitTypeSize=5'
41+
42+
.class explicit ansi sealed nested private '__StaticArrayInitTypeSize=6'
43+
extends [mscorlib]System.ValueType
44+
{
45+
.pack 2
46+
.size 6
47+
} // end of class '__StaticArrayInitTypeSize=6'
48+
49+
.field static assembly valuetype '<PrivateImplementationDetails>{9B33BB20-87EF-4094-9948-34882DB2F001}'/'__StaticArrayInitTypeSize=3' '$$method0x6000001-1' at I_000020F0
50+
.field static assembly valuetype '<PrivateImplementationDetails>{9B33BB20-87EF-4094-9948-34882DB2F001}'/'__StaticArrayInitTypeSize=20' '$$method0x6000001-2' at I_000020F8
51+
.field static assembly valuetype '<PrivateImplementationDetails>{9B33BB20-87EF-4094-9948-34882DB2F001}'/'__StaticArrayInitTypeSize=5' '$$method0x6000001-3' at I_00002108
52+
.field static assembly valuetype '<PrivateImplementationDetails>{9B33BB20-87EF-4094-9948-34882DB2F001}'/'__StaticArrayInitTypeSize=20' '$$method0x6000001-4' at I_00002110
53+
.field static assembly valuetype '<PrivateImplementationDetails>{9B33BB20-87EF-4094-9948-34882DB2F001}'/'__StaticArrayInitTypeSize=6' '$$method0x6000001-5' at I_00002120
54+
.field static assembly valuetype '<PrivateImplementationDetails>{9B33BB20-87EF-4094-9948-34882DB2F001}'/'__StaticArrayInitTypeSize=16' '$$method0x6000001-6' at I_00002130
55+
} // end of class '<PrivateImplementationDetails>{9B33BB20-87EF-4094-9948-34882DB2F001}'
56+
57+
58+
// =============================================================
59+
60+
.data cil I_000020F0 = bytearray (
61+
01 02 03)
62+
.data cil I_000020F8 = bytearray (
63+
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00)
64+
.data cil I_00002108 = bytearray (
65+
04 05 06 07 08)
66+
.data cil I_00002110 = bytearray (
67+
01 00 00 00 02 00 00 00 03 00 00 00 05 00 00 00 06 00 00 00)
68+
.data cil I_00002120 = bytearray (
69+
08 00 0C 00 0D 00)
70+
.data cil I_00002130 = bytearray (
71+
01 00 00 00 02 00 00 00 03 00 00 00 05 00 00 00)

0 commit comments

Comments
 (0)