Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<TargetFrameworks>$(NetCoreAppCurrent);netstandard2.0;net461</TargetFrameworks>
<Nullable>enable</Nullable>
<IsPackable>true</IsPackable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW the versioning info here

<ServicingVersion>1</ServicingVersion>
<PackageDescription>This packages provides a low-level .NET (ECMA-335) metadata reader and writer. It's geared for performance and is the ideal choice for building higher-level libraries that intend to provide their own object model, such as compilers.

Commonly Used Types:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public ManagedTextSection(

public const int MappedFieldDataAlignment = 8;

public int CalculateOffsetToMappedFieldDataStream()
internal int CalculateOffsetToMappedFieldDataStreamUnaligned()
{
int result = ComputeOffsetToImportTable();

Expand All @@ -135,6 +135,16 @@ public int CalculateOffsetToMappedFieldDataStream()
return result;
}

public int CalculateOffsetToMappedFieldDataStream()
{
int result = CalculateOffsetToMappedFieldDataStreamUnaligned();
if (MappedFieldDataSize != 0)
{
result = BitArithmetic.Align(result, MappedFieldDataAlignment);
}
return result;
}

internal int ComputeOffsetToDebugDirectory()
{
Debug.Assert(MetadataSize % 4 == 0);
Expand Down Expand Up @@ -185,7 +195,7 @@ public int GetEntryPointAddress(int rva)
{
// TODO: constants
return RequiresStartupStub ?
rva + CalculateOffsetToMappedFieldDataStream() - (Is32Bit ? 6 : 10) :
rva + CalculateOffsetToMappedFieldDataStreamUnaligned() - (Is32Bit ? 6 : 10) :
0;
}

Expand Down Expand Up @@ -293,6 +303,8 @@ public void Serialize(
// mapped field data:
if (mappedFieldDataBuilderOpt != null)
{
if (mappedFieldDataBuilderOpt.Count != 0)
builder.Align(MappedFieldDataAlignment);
builder.LinkSuffix(mappedFieldDataBuilderOpt);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ private static void WritePEImage(
Blob mvidFixup = default(Blob),
byte[] privateKeyOpt = null,
bool publicSigned = false,
Machine machine = 0)
Machine machine = 0,
BlobBuilder? mappedFieldData = null)
{
var peHeaderBuilder = new PEHeaderBuilder(imageCharacteristics: entryPointHandle.IsNil ? Characteristics.Dll : Characteristics.ExecutableImage,
machine: machine);
Expand All @@ -75,7 +76,8 @@ private static void WritePEImage(
ilBuilder,
entryPoint: entryPointHandle,
flags: CorFlags.ILOnly | (privateKeyOpt != null || publicSigned ? CorFlags.StrongNameSigned : 0),
deterministicIdProvider: content => s_contentId);
deterministicIdProvider: content => s_contentId,
mappedFieldData: mappedFieldData);

var peBlob = new BlobBuilder();

Expand Down Expand Up @@ -487,6 +489,98 @@ private static MethodDefinitionHandle ComplexEmit(MetadataBuilder metadata, Blob
return default(MethodDefinitionHandle);
}

[Theory] // Validate FieldRVA alignment on common machine types
[MemberData(nameof(AllMachineTypes))]
public void FieldRVAAlignmentVerify(Machine machine)
{
using (var peStream = new MemoryStream())
{
var ilBuilder = new BlobBuilder();
var mappedRVADataBuilder = new BlobBuilder();
var metadataBuilder = new MetadataBuilder();
double validationNumber = 0.100001;
var fieldDef = FieldRVAValidationEmit(metadataBuilder, mappedRVADataBuilder, validationNumber);

WritePEImage(peStream, metadataBuilder, ilBuilder, default(MethodDefinitionHandle),
mappedFieldData: mappedRVADataBuilder,
machine: machine);

// Validate FieldRVA is aligned as ManagedPEBuilder.MappedFieldDataAlignemnt
peStream.Position = 0;
using (var peReader = new PEReader(peStream, PEStreamOptions.LeaveOpen))
{
var mdReader = peReader.GetMetadataReader();

// Validate that there is only 1 field rva entry
Assert.Equal(1, mdReader.FieldRvaTable.NumberOfRows);

// Validate that the RVA is aligned properly (which should be at least an 8 byte alignment
Assert.Equal(0, mdReader.FieldRvaTable.GetRva(1) % ManagedPEBuilder.MappedFieldDataAlignment);

// Validate that the correct data is at the RVA
var fieldRVAData = peReader.GetSectionData(mdReader.FieldRvaTable.GetRva(1));
Assert.Equal(validationNumber, fieldRVAData.GetReader().ReadDouble());
}

VerifyPE(peStream, machine);
}
}

private static FieldDefinitionHandle FieldRVAValidationEmit(MetadataBuilder metadata, BlobBuilder mappedRVAData, double doubleToWriteAsData)
{
metadata.AddModule(
0,
metadata.GetOrAddString("ConsoleApplication.exe"),
metadata.GetOrAddGuid(s_guid),
default(GuidHandle),
default(GuidHandle));

metadata.AddAssembly(
metadata.GetOrAddString("ConsoleApplication"),
version: new Version(1, 0, 0, 0),
culture: default(StringHandle),
publicKey: metadata.GetOrAddBlob(ImmutableArray.Create(Misc.KeyPair_PublicKey)),
flags: AssemblyFlags.PublicKey,
hashAlgorithm: AssemblyHashAlgorithm.Sha1);

var mscorlibAssemblyRef = metadata.AddAssemblyReference(
name: metadata.GetOrAddString("mscorlib"),
version: new Version(4, 0, 0, 0),
culture: default(StringHandle),
publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create<byte>(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)),
flags: default(AssemblyFlags),
hashValue: default(BlobHandle));

var systemObjectTypeRef = metadata.AddTypeReference(
mscorlibAssemblyRef,
metadata.GetOrAddString("System"),
metadata.GetOrAddString("Object"));

mappedRVAData.WriteDouble(doubleToWriteAsData);

var rvaFieldSignature = new BlobBuilder();

new BlobEncoder(rvaFieldSignature).
FieldSignature().Double();

var fieldRVADef = metadata.AddFieldDefinition(
FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.HasFieldRVA,
metadata.GetOrAddString("RvaField"),
metadata.GetOrAddBlob(rvaFieldSignature));

metadata.AddFieldRelativeVirtualAddress(fieldRVADef, 0);

metadata.AddTypeDefinition(
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.BeforeFieldInit,
metadata.GetOrAddString("ConsoleApplication"),
metadata.GetOrAddString("Program"),
systemObjectTypeRef,
fieldList: fieldRVADef,
methodList: MetadataTokens.MethodDefinitionHandle(1));

return fieldRVADef;
}

private class TestResourceSectionBuilder : ResourceSectionBuilder
{
public TestResourceSectionBuilder()
Expand Down