Skip to content

Commit 7d18fd9

Browse files
committed
Improve handling of PEResourceDirectory
1 parent ba62b5f commit 7d18fd9

File tree

9 files changed

+279
-115
lines changed

9 files changed

+279
-115
lines changed

src/LibObjectFile/Diagnostics/DiagnosticId.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,5 @@ public enum DiagnosticId
194194
PE_ERR_InvalidResourceDirectory = 4000,
195195
PE_ERR_InvalidResourceDirectoryEntry = 4001,
196196
PE_ERR_InvalidResourceDirectoryEntryRVAOffsetToData = 4002,
197+
PE_ERR_InvalidResourceString = 4003,
197198
}

src/LibObjectFile/PE/DataDirectory/PEExportDirectory.cs

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,6 @@ public PEExportDirectory() : base(PEDataDirectoryKind.Export)
3232

3333
public PEExportOrdinalTable? ExportOrdinalTable { get; set; }
3434

35-
protected override unsafe uint ComputeHeaderSize(PELayoutContext context)
36-
{
37-
return (uint)sizeof(RawImageExportDirectory);
38-
}
39-
40-
internal override IEnumerable<PEObjectBase> CollectImplicitSectionDataList()
41-
{
42-
if (ExportFunctionAddressTable is not null)
43-
{
44-
yield return ExportFunctionAddressTable;
45-
}
46-
47-
if (ExportNameTable is not null)
48-
{
49-
yield return ExportNameTable;
50-
}
51-
52-
if (ExportOrdinalTable is not null)
53-
{
54-
yield return ExportOrdinalTable;
55-
}
56-
}
57-
5835
public override unsafe void Read(PEImageReader reader)
5936
{
6037
reader.Position = Position;
@@ -164,8 +141,8 @@ public override void Write(PEImageWriter writer)
164141
MinorVersion = MinorVersion,
165142
Base = OrdinalBase,
166143
Name = NameLink.RVA(),
167-
NumberOfFunctions = (uint)ExportFunctionAddressTable!.Values.Count,
168-
NumberOfNames = (uint)ExportNameTable!.Values.Count,
144+
NumberOfFunctions = (uint)(ExportFunctionAddressTable?.Values.Count ?? 0),
145+
NumberOfNames = (uint)(ExportNameTable?.Values.Count ?? 0),
169146
AddressOfFunctions = (RVA)(uint)(ExportFunctionAddressTable?.RVA ?? (RVA)0),
170147
AddressOfNames = (RVA)(uint)(ExportNameTable?.RVA ?? 0),
171148
AddressOfNameOrdinals = (RVA)(uint)(ExportOrdinalTable?.RVA ?? 0)
@@ -174,6 +151,30 @@ public override void Write(PEImageWriter writer)
174151
writer.Write(exportDirectory);
175152
}
176153

154+
protected override unsafe uint ComputeHeaderSize(PELayoutContext context)
155+
{
156+
return (uint)sizeof(RawImageExportDirectory);
157+
}
158+
159+
internal override IEnumerable<PEObjectBase> CollectImplicitSectionDataList()
160+
{
161+
if (ExportFunctionAddressTable is not null)
162+
{
163+
yield return ExportFunctionAddressTable;
164+
}
165+
166+
if (ExportNameTable is not null)
167+
{
168+
yield return ExportNameTable;
169+
}
170+
171+
if (ExportOrdinalTable is not null)
172+
{
173+
yield return ExportOrdinalTable;
174+
}
175+
}
176+
177+
177178
private struct RawImageExportDirectory
178179
{
179180
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value

src/LibObjectFile/PE/DataDirectory/PEImportDirectory.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,22 @@ public override void Read(PEImageReader reader)
101101
}
102102
}
103103

104+
public override void Write(PEImageWriter writer)
105+
{
106+
RawImportDirectoryEntry rawEntry = default;
107+
foreach (var entry in Entries)
108+
{
109+
rawEntry.NameRVA = (uint)entry.ImportDllNameLink.RVA();
110+
rawEntry.ImportLookupTableRVA = (uint)entry.ImportLookupTable.RVA;
111+
rawEntry.ImportAddressTableRVA = (uint)entry.ImportAddressTable.RVA;
112+
writer.Write(rawEntry);
113+
}
114+
115+
// Null entry
116+
rawEntry = default;
117+
writer.Write(rawEntry);
118+
}
119+
104120
protected override unsafe uint ComputeHeaderSize(PELayoutContext context) => CalculateSize();
105121

106122
internal override IEnumerable<PEObjectBase> CollectImplicitSectionDataList()
@@ -153,20 +169,4 @@ private unsafe uint CalculateSize()
153169
{
154170
return (uint)(((_entries.Count + 1) * sizeof(RawImportDirectoryEntry)));
155171
}
156-
157-
public override void Write(PEImageWriter writer)
158-
{
159-
RawImportDirectoryEntry rawEntry = default;
160-
foreach (var entry in Entries)
161-
{
162-
rawEntry.NameRVA = (uint)entry.ImportDllNameLink.RVA();
163-
rawEntry.ImportLookupTableRVA = (uint)entry.ImportLookupTable.RVA;
164-
rawEntry.ImportAddressTableRVA = (uint)entry.ImportAddressTable.RVA;
165-
writer.Write(rawEntry);
166-
}
167-
168-
// Null entry
169-
rawEntry = default;
170-
writer.Write(rawEntry);
171-
}
172172
}

src/LibObjectFile/PE/DataDirectory/PEResourceDataEntry.cs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,23 +96,19 @@ internal override unsafe void Read(in ReaderContext context)
9696
Position = section.Position + rawDataEntry.OffsetToData - section.RVA,
9797
Size = rawDataEntry.Size,
9898
};
99+
}
99100

100-
// If we find that the position is not aligned on 4 bytes as we expect, reset it to 1 byte alignment
101-
var checkPosition = AlignHelper.AlignUp(Data.Position, Data.RequiredPositionAlignment);
102-
if (checkPosition != Data.Position)
103-
{
104-
Data.RequiredPositionAlignment = 1;
105-
}
106-
else if (context.ResourceDataList.Count == 0 && (Data.Position & 0xF) == 0)
101+
internal override void Write(in WriterContext context) => Write(context.Writer);
102+
103+
public override void Write(PEImageWriter writer)
104+
{
105+
var rawDataEntry = new RawImageResourceDataEntry
107106
{
108-
// If we are the first resource data entry and the position is aligned on 16 bytes, we can assume this alignment
109-
Data.RequiredPositionAlignment = 16;
110-
}
111-
112-
// Read the data
113-
Data.Read(reader);
107+
CodePage = (uint)(CodePage?.CodePage ?? 0),
108+
OffsetToData = Data.RVA,
109+
Size = (uint)Data.Size,
110+
};
114111

115-
// Register the list of data being loaded
116-
context.ResourceDataList.Add(Data);
112+
writer.Write(rawDataEntry);
117113
}
118114
}

src/LibObjectFile/PE/DataDirectory/PEResourceDirectory.cs

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// This file is licensed under the BSD-Clause 2 license.
33
// See the license.txt file in the project root for more information.
44

5+
using LibObjectFile.Utils;
56
using System;
67
using System.Collections.Generic;
8+
using static System.Runtime.InteropServices.JavaScript.JSType;
79

810
namespace LibObjectFile.PE;
911

@@ -12,9 +14,9 @@ namespace LibObjectFile.PE;
1214
/// </summary>
1315
public sealed class PEResourceDirectory : PEDataDirectory
1416
{
15-
private List<PEResourceData>? _tempResourceDataList;
16-
17-
17+
private List<PEResourceString>? _tempResourceStrings;
18+
private List<PEResourceEntry>? _tempResourceEntries;
19+
1820
/// <summary>
1921
/// Initializes a new instance of the <see cref="PEResourceDirectory"/> class.
2022
/// </summary>
@@ -45,31 +47,86 @@ public override void Read(PEImageReader reader)
4547

4648
Root.Position = Position;
4749

48-
_tempResourceDataList = new();
49-
var readerContext = new PEResourceEntry.ReaderContext(reader, this, _tempResourceDataList);
50+
_tempResourceStrings = new();
51+
_tempResourceEntries = new();
52+
53+
// Read the resource directory recursively
54+
var readerContext = new PEResourceEntry.ReaderContext(reader, this, _tempResourceStrings, _tempResourceEntries);
5055
Root.Read(readerContext);
5156

57+
// Read the resource strings (that should follow the resource directory)
58+
foreach (var resourceString in _tempResourceStrings)
59+
{
60+
resourceString.Read(reader);
61+
}
62+
63+
// Read the content of the resource data (that should usually be stored after the resource strings)
64+
bool isFirstDataEntry = true;
65+
foreach (var resourceEntry in _tempResourceEntries)
66+
{
67+
if (resourceEntry is not PEResourceDataEntry dataEntry)
68+
{
69+
continue;
70+
}
71+
72+
var resourceData = dataEntry.Data;
73+
74+
// If we find that the position is not aligned on 4 bytes as we expect, reset it to 1 byte alignment
75+
var checkPosition = AlignHelper.AlignUp(resourceData.Position, resourceData.RequiredPositionAlignment);
76+
if (checkPosition != resourceData.Position)
77+
{
78+
resourceData.RequiredPositionAlignment = 1;
79+
}
80+
else if (isFirstDataEntry && (resourceData.Position & 0xF) == 0)
81+
{
82+
// If we are the first resource data entry and the position is aligned on 16 bytes, we can assume this alignment
83+
resourceData.RequiredPositionAlignment = 16;
84+
}
85+
86+
// Read the data
87+
resourceData.Read(reader);
88+
89+
isFirstDataEntry = true;
90+
}
91+
5292
HeaderSize = ComputeHeaderSize(reader);
5393
}
5494

5595
internal override IEnumerable<PEObjectBase> CollectImplicitSectionDataList()
5696
{
57-
if (_tempResourceDataList is not null)
97+
if (_tempResourceStrings is not null)
98+
{
99+
foreach (var data in _tempResourceStrings)
100+
{
101+
yield return data;
102+
}
103+
104+
// We clear the list after being used - as this method is called once and we don't want to hold a reference
105+
_tempResourceStrings.Clear();
106+
_tempResourceStrings = null;
107+
}
108+
109+
if (_tempResourceEntries is not null)
58110
{
59-
foreach (var data in _tempResourceDataList)
111+
foreach (var data in _tempResourceEntries)
60112
{
61113
yield return data;
114+
115+
if (data is PEResourceDataEntry dataEntry)
116+
{
117+
yield return dataEntry.Data;
118+
}
62119
}
63120

64121
// We clear the list after being used - as this method is called once and we don't want to hold a reference
65-
_tempResourceDataList.Clear();
66-
_tempResourceDataList = null;
122+
_tempResourceEntries.Clear();
123+
_tempResourceEntries = null;
67124
}
68125
}
69126

70127
/// <inheritdoc/>
71128
public override void Write(PEImageWriter writer)
72129
{
73-
throw new NotImplementedException();
130+
Root.Write(writer);
74131
}
75132
}

0 commit comments

Comments
 (0)