• R/O
  • SSH
  • HTTPS

peframework: Commit


Commit MetaInfo

Revision33 (tree)
Time2019-11-10 21:22:05
Authorquiret

Log Message

- began working on ARM/ARM64/MIPS support based on runtime function data directory
- disabled spectre mitigation because it ain't required (meh, MSFT decided to push this as default)

Change Summary

Incremental Difference

--- library/include/peloader.freg.arm.h (nonexistent)
+++ library/include/peloader.freg.arm.h (revision 33)
@@ -0,0 +1,22 @@
1+// ARM/ARM64 implementation of function registry entries.
2+
3+#ifndef _PELOADER_FUNCTIONS_REGISTRY_ARM_
4+#define _PELOADER_FUNCTIONS_REGISTRY_ARM_
5+
6+#include "peloader.h"
7+
8+namespace PEFileDetails
9+{
10+
11+struct PERuntimeFunctionARM
12+{
13+ PEFile::PESectionDataReference beginAddr;
14+ std::uint32_t prologLength : 8;
15+ std::uint32_t functionLength : 22;
16+ std::uint32_t is32Bit : 1;
17+ std::uint32_t hasExceptionHandler : 1;
18+};
19+
20+}
21+
22+#endif //_PELOADER_FUNCTIONS_REGISTRY_ARM_
\ No newline at end of file
--- library/include/peloader.freg.h (nonexistent)
+++ library/include/peloader.freg.h (revision 33)
@@ -0,0 +1,15 @@
1+// PEFile .pdata section data structs for storing runtime function registration entries.
2+// Due to the complexity of being divided across multiple platforms we decided to create it's own header.
3+// Known implementations: X64, MIPS, ARM
4+
5+#ifndef _PELOADER_FUNCTIONS_REGISTRY_
6+#define _PELOADER_FUNCTIONS_REGISTRY_
7+
8+namespace PEFileDetails
9+{
10+
11+// TODO.
12+
13+};
14+
15+#endif //_PELOADER_FUNCTIONS_REGISTRY_
\ No newline at end of file
--- library/include/peloader.freg.mips32.h (nonexistent)
+++ library/include/peloader.freg.mips32.h (revision 33)
@@ -0,0 +1,22 @@
1+// MIPS 32bit implementation of function registry entries.
2+
3+#ifndef _PELOADER_FUNCTIONS_REGISTRY_MIPS_
4+#define _PELOADER_FUNCTIONS_REGISTRY_MIPS_
5+
6+#include "peloader.h"
7+
8+namespace PEFileDetails
9+{
10+
11+struct PERuntimeFunctionMIPS
12+{
13+ PEFile::PESectionDataReference begAddr;
14+ PEFile::PESectionDataReference endAddr;
15+ PEFile::PESectionDataReference exceptHandlerAddr;
16+ PEFile::PESectionDataReference userDataAddr;
17+ PEFile::PESectionDataReference endOfPrologAddr;
18+};
19+
20+}
21+
22+#endif //_PELOADER_FUNCTIONS_REGISTRY_MIPS_
\ No newline at end of file
--- library/include/peloader.freg.x64.h (nonexistent)
+++ library/include/peloader.freg.x64.h (revision 33)
@@ -0,0 +1,20 @@
1+// X64 and Itanium implementation of runtime functions registry.
2+
3+#ifndef _PELOADER_FUNCTIONS_REGISTRY_X64_
4+#define _PELOADER_FUNCTIONS_REGISTRY_X64_
5+
6+#include "peloader.h"
7+
8+namespace PEFileDetails
9+{
10+
11+struct PERuntimeFunctionX64
12+{
13+ PEFile::PESectionDataReference beginAddrRef;
14+ PEFile::PESectionDataReference endAddrRef;
15+ PEFile::PESectionDataReference unwindInfoRef;
16+};
17+
18+}
19+
20+#endif //_PELOADER_FUNCTIONS_REGISTRY_X64_
\ No newline at end of file
--- library/include/peloader.h (revision 32)
+++ library/include/peloader.h (revision 33)
@@ -3,6 +3,7 @@
33
44 // Target spec: Revision 10 – June 15, 2016
55 // https://www.microsoft.com/en-us/download/details.aspx?id=19509
6+// https://docs.microsoft.com/de-de/windows/win32/debug/pe-format
67
78 #ifndef _PELOADER_CORE_
89 #define _PELOADER_CORE_
@@ -118,11 +119,10 @@
118119 std::uint16_t number;
119120 };
120121
121-private:
122+ // Had to be turned public because we process some data directories in different C++ source files now.
123+ struct PEDataStream;
122124 struct PESectionMan;
123- struct PEDataStream;
124125
125-public:
126126 struct PESection
127127 {
128128 friend struct PESectionMan;
@@ -852,7 +852,6 @@
852852 };
853853 PEOptHeader peOptHeader;
854854
855-private:
856855 // Data inside of a PE file is stored in sections which have special
857856 // rules if they ought to be "zero padded".
858857 struct PEDataStream
@@ -871,6 +870,14 @@
871870 this->seek_off = 0;
872871 }
873872
873+ inline PEDataStream( const PEDataStream& ) = default;
874+ inline PEDataStream( PEDataStream&& ) = default;
875+
876+ inline ~PEDataStream( void ) = default;
877+
878+ inline PEDataStream& operator = ( const PEDataStream& ) = default;
879+ inline PEDataStream& operator = ( PEDataStream&& ) = default;
880+
874881 static inline PEDataStream fromDataRef( const PESectionDataReference& dataRef )
875882 {
876883 return PEDataStream( dataRef.theSect, dataRef.sectOffset );
@@ -987,11 +994,11 @@
987994 {
988995 PESectionMan( std::uint32_t sectionAlignment, std::uint32_t imageBase );
989996 PESectionMan( const PESectionMan& right ) = delete;
990- PESectionMan( PESectionMan&& right );
997+ PESectionMan( PESectionMan&& right ) noexcept;
991998 ~PESectionMan( void );
992999
9931000 PESectionMan& operator = ( const PESectionMan& right ) = delete;
994- PESectionMan& operator = ( PESectionMan&& right );
1001+ PESectionMan& operator = ( PESectionMan&& right ) noexcept;
9951002
9961003 // Private section management API.
9971004 PESection* AddSection( PESection&& theSection );
@@ -1302,6 +1309,7 @@
13021309
13031310 PESectionMan sections;
13041311
1312+private:
13051313 // We need to know about file-space section allocations.
13061314 // This is mainly used for reflection purposes during PE serialization.
13071315 struct sect_allocInfo
@@ -1734,16 +1742,6 @@
17341742
17351743 PESectionAllocation resAllocEntry;
17361744
1737- struct PERuntimeFunction
1738- {
1739- PESectionDataReference beginAddrRef;
1740- PESectionDataReference endAddrRef;
1741- PESectionDataReference unwindInfoRef;
1742- };
1743- peVector <PERuntimeFunction> exceptRFs;
1744-
1745- PESectionAllocation exceptAllocEntry;
1746-
17471745 struct PESecurity
17481746 {
17491747 // We just keep the certificate data around for anyone to care about
@@ -1991,6 +1989,67 @@
19911989 };
19921990 PECommonLanguageRuntimeInfo clrInfo;
19931991
1992+ // Generic data directory entry.
1993+ struct PEDataDirectoryGeneric
1994+ {
1995+ inline PEDataDirectoryGeneric( void ) = default;
1996+ inline PEDataDirectoryGeneric( const PEDataDirectoryGeneric& ) = delete;
1997+ inline PEDataDirectoryGeneric( PEDataDirectoryGeneric&& ) = default;
1998+
1999+ virtual ~PEDataDirectoryGeneric( void ) {}
2000+
2001+ inline PEDataDirectoryGeneric& operator = ( const PEDataDirectoryGeneric& ) = delete;
2002+ inline PEDataDirectoryGeneric& operator = ( PEDataDirectoryGeneric&& ) = default;
2003+
2004+ virtual void SerializeDataDirectory( PESection *targetSect ) = 0;
2005+
2006+ virtual void* GetDirectoryData( void ) = 0;
2007+ virtual size_t GetDirectoryEntrySize( void ) const = 0;
2008+ virtual size_t GetDirectoryEntryCount( void ) const = 0;
2009+
2010+ // Location of said data on PE section space (non-empty only if synchronized).
2011+ PESectionAllocation allocEntry;
2012+ };
2013+
2014+ // Generic data directory parser. Should be a static extension.
2015+ struct PEDataDirectoryParser
2016+ {
2017+ virtual PEDataDirectoryGeneric* DeserializeData( std::uint16_t machine_id, PESectionMan& sections, PEDataStream stream, std::uint32_t va, std::uint32_t vsize ) const = 0;
2018+ };
2019+
2020+ // Storage of generic data directories.
2021+ // For off-shoring readers and writers into multiple source files.
2022+ struct PEGenericDataDirectories
2023+ {
2024+ inline PEGenericDataDirectories( void ) = default;
2025+ inline PEGenericDataDirectories( const PEGenericDataDirectories& ) = delete;
2026+ inline PEGenericDataDirectories( PEGenericDataDirectories&& right ) noexcept : entries( std::move( right.entries ) )
2027+ {
2028+ return;
2029+ }
2030+
2031+ inline ~PEGenericDataDirectories( void )
2032+ {
2033+ // Clear any generic data directories.
2034+ for ( auto *genDataDirNode : this->entries )
2035+ {
2036+ eir::static_del_struct <PEDataDirectoryGeneric, PEGlobalStaticAllocator> ( nullptr, genDataDirNode->GetValue() );
2037+ }
2038+ this->entries.Clear();
2039+ }
2040+
2041+ inline PEGenericDataDirectories& operator = ( const PEGenericDataDirectories& ) = delete;
2042+ inline PEGenericDataDirectories& operator = ( PEGenericDataDirectories&& right ) noexcept
2043+ {
2044+ this->entries = std::move( right.entries );
2045+
2046+ return *this;
2047+ }
2048+
2049+ peMap <std::uint32_t, PEDataDirectoryGeneric*> entries;
2050+ };
2051+ PEGenericDataDirectories genDataDirs;
2052+
19942053 // Meta-data.
19952054 bool isExtendedFormat; // if true then we are PE32+ format.
19962055 // NOTE: it is (theoretically) valid to travel a 32bit executable in PE32+ format.
@@ -2025,4 +2084,7 @@
20252084 void CommitDataDirectories( void );
20262085 };
20272086
2087+// Include submodules.
2088+#include "peloader.freg.h"
2089+
20282090 #endif //_PELOADER_CORE_
--- library/include/peloader.serialize.h (revision 32)
+++ library/include/peloader.serialize.h (revision 33)
@@ -328,6 +328,24 @@
328328 #define PEL_IMAGE_ORDINAL_FLAG64 0x8000000000000000
329329 #define PEL_IMAGE_ORDINAL_FLAG32 0x80000000
330330
331+struct IMAGE_RUNTIME_FUNCTION_ENTRY_MIPS
332+{
333+ std::uint32_t BeginAddress; // absolute VA
334+ std::uint32_t EndAddress; // absolute VA
335+ std::uint32_t ExceptHandler;
336+ std::uint32_t HandlerData;
337+ std::uint32_t PrologEndAddress; // absolute VA
338+};
339+
340+struct IMAGE_RUNTIME_FUNCTION_ENTRY_ARM
341+{
342+ std::uint32_t BeginAddress; // absolute VA
343+ std::uint32_t PrologLength : 8;
344+ std::uint32_t FunctionLength : 22;
345+ std::uint32_t is32Bit : 1;
346+ std::uint32_t hasExceptHandler : 1;
347+};
348+
331349 struct IMAGE_RUNTIME_FUNCTION_ENTRY_X64
332350 {
333351 std::uint32_t BeginAddress;
--- library/src/peloader.cpp (revision 32)
+++ library/src/peloader.cpp (revision 33)
@@ -725,7 +725,7 @@
725725 this->imageBase = imageBase;
726726 }
727727
728-PEFile::PESectionMan::PESectionMan( PESectionMan&& right )
728+PEFile::PESectionMan::PESectionMan( PESectionMan&& right ) noexcept
729729 : sectionAlignment( std::move( right.sectionAlignment ) ),
730730 imageBase( std::move( right.imageBase ) ),
731731 sectVirtualAllocMan( std::move( right.sectVirtualAllocMan ) ),
@@ -756,7 +756,7 @@
756756 this->numSections = 0;
757757 }
758758
759-PEFile::PESectionMan& PEFile::PESectionMan::operator = ( PESectionMan&& right )
759+PEFile::PESectionMan& PEFile::PESectionMan::operator = ( PESectionMan&& right ) noexcept
760760 {
761761 // We do the default way of move-assignment.
762762 this->~PESectionMan();
--- library/src/peloader.datadirs.cpp (nonexistent)
+++ library/src/peloader.datadirs.cpp (revision 33)
@@ -0,0 +1,47 @@
1+// Generic data directory parsing manager.
2+
3+#include "peloader.h"
4+
5+#include "peloader.internal.hxx"
6+
7+#include "peloader.datadirs.hxx"
8+
9+// Include modules.
10+extern void registerRuntimeFunctionParser( void );
11+
12+extern void unregisterRuntimeFunctionParser( void );
13+
14+// Now the manager implementation/initializer.
15+struct PEDataDirectoryManager
16+{
17+ inline PEDataDirectoryManager( void )
18+ {
19+ // Initialize modules.
20+ registerRuntimeFunctionParser();
21+ }
22+
23+ inline ~PEDataDirectoryManager( void )
24+ {
25+ // Shutdown modules.
26+ unregisterRuntimeFunctionParser();
27+ }
28+
29+ peMap <std::uint32_t, PEFile::PEDataDirectoryParser*> parserMap;
30+};
31+
32+static PEDataDirectoryManager dataDirMan;
33+
34+void registerDataDirectoryParser( std::uint32_t idx, PEFile::PEDataDirectoryParser *parser )
35+{
36+ dataDirMan.parserMap[ idx ] = parser;
37+}
38+
39+void unregisterDataDirectoryParser( std::uint32_t idx )
40+{
41+ dataDirMan.parserMap.RemoveByKey( idx );
42+}
43+
44+PEFile::PEDataDirectoryParser* findDataDirectoryParser( std::uint32_t idx )
45+{
46+ return ( dataDirMan.parserMap.FindOrDefault( idx ) );
47+}
\ No newline at end of file
--- library/src/peloader.datadirs.hxx (nonexistent)
+++ library/src/peloader.datadirs.hxx (revision 33)
@@ -0,0 +1,13 @@
1+// Internal header for data directory extension API.
2+
3+#ifndef _PELOADER_DATA_DIRECTORY_EXT_INTERNALS_
4+#define _PELOADER_DATA_DIRECTORY_EXT_INTERNALS_
5+
6+#include "peloader.h"
7+
8+// These functions should be called within sub-module (de-)initializers of data directory parsers.
9+void registerDataDirectoryParser( std::uint32_t idx, PEFile::PEDataDirectoryParser *parser );
10+void unregisterDataDirectoryParser( std::uint32_t idx );
11+PEFile::PEDataDirectoryParser* findDataDirectoryParser( std::uint32_t idx );
12+
13+#endif //_PELOADER_DATA_DIRECTORY_EXT_INTERNALS_
\ No newline at end of file
--- library/src/peloader.freg.cpp (nonexistent)
+++ library/src/peloader.freg.cpp (revision 33)
@@ -0,0 +1,181 @@
1+#include "peframework.h"
2+
3+#include "peloader.serialize.h"
4+
5+#include "peloader.datadirs.hxx"
6+
7+// Include all possible implementations.
8+#include "peloader.freg.x64.h"
9+#include "peloader.freg.arm.h"
10+#include "peloader.freg.mips32.h"
11+
12+struct PEFunctionRegistryX64 : public PEFile::PEDataDirectoryGeneric
13+{
14+ inline PEFunctionRegistryX64( void ) = default;
15+ inline PEFunctionRegistryX64( const PEFunctionRegistryX64& ) = delete;
16+ inline PEFunctionRegistryX64( PEFunctionRegistryX64&& ) = default;
17+
18+ void SerializeDataDirectory( PEFile::PESection *targetSect ) override
19+ {
20+ // TODO: remember that exception data is machine dependent.
21+ // revisit this if we need multi-architecture support.
22+ // (currently we specialize on x86/AMD64)
23+
24+ const auto& exceptRFs = this->entries;
25+
26+ std::uint32_t numExceptEntries = (std::uint32_t)exceptRFs.GetCount();
27+
28+ const std::uint32_t exceptTableSize = ( sizeof(PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64) * numExceptEntries );
29+
30+ if ( numExceptEntries != 0 )
31+ {
32+ PEFile::PESectionAllocation exceptTableAlloc;
33+ targetSect->Allocate( exceptTableAlloc, exceptTableSize, sizeof(std::uint32_t) );
34+
35+ // Now write all entries.
36+ // TODO: documentation says that these entries should be address sorted.
37+ for ( std::uint32_t n = 0; n < numExceptEntries; n++ )
38+ {
39+ const PEFileDetails::PERuntimeFunctionX64& rfEntry = exceptRFs[ n ];
40+
41+ PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64 funcInfo;
42+ funcInfo.BeginAddress = rfEntry.beginAddrRef.GetRVA();
43+ funcInfo.EndAddress = rfEntry.endAddrRef.GetRVA();
44+ funcInfo.UnwindInfoAddress = rfEntry.unwindInfoRef.GetRVA();
45+
46+ const std::uint32_t rfEntryOff = ( n * sizeof(PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64) );
47+
48+ exceptTableAlloc.WriteToSection( &funcInfo, sizeof(funcInfo), rfEntryOff );
49+ }
50+
51+ // Remember this valid exception table.
52+ this->allocEntry = std::move( exceptTableAlloc );
53+ }
54+ }
55+
56+ void* GetDirectoryData( void ) override
57+ {
58+ return this->entries.GetData();
59+ }
60+
61+ size_t GetDirectoryEntrySize( void ) const override
62+ {
63+ return sizeof(PEFileDetails::PERuntimeFunctionX64);
64+ }
65+
66+ size_t GetDirectoryEntryCount( void ) const override
67+ {
68+ return this->entries.GetCount();
69+ }
70+
71+ peVector <PEFileDetails::PERuntimeFunctionX64> entries;
72+};
73+
74+struct PEFunctionRegistryDataDirectoryParser : public PEFile::PEDataDirectoryParser
75+{
76+ PEFile::PEDataDirectoryGeneric* DeserializeData( std::uint16_t machine_id, PEFile::PESectionMan& sections, PEFile::PEDataStream stream, std::uint32_t va, std::uint32_t vsize ) const override
77+ {
78+ if ( machine_id == PEL_IMAGE_FILE_MACHINE_ARM || machine_id == PEL_IMAGE_FILE_MACHINE_ARMNT ||
79+ machine_id == PEL_IMAGE_FILE_MACHINE_POWERPC ||
80+ machine_id == PEL_IMAGE_FILE_MACHINE_SH3 || machine_id == PEL_IMAGE_FILE_MACHINE_SH3DSP || machine_id == PEL_IMAGE_FILE_MACHINE_SH3E ||
81+ machine_id == PEL_IMAGE_FILE_MACHINE_SH4 )
82+ {
83+
84+ }
85+ else if ( machine_id == PEL_IMAGE_FILE_MACHINE_AMD64 || machine_id == PEL_IMAGE_FILE_MACHINE_IA64 )
86+ {
87+ PEFunctionRegistryX64 exceptRFs;
88+
89+ const std::uint32_t numFuncs = ( vsize / sizeof( PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64 ) );
90+
91+ for ( size_t n = 0; n < numFuncs; n++ )
92+ {
93+ PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64 func;
94+ stream.Read( &func, sizeof(func) );
95+
96+ // Since the runtime function entry stores RVAs, we want to remember them
97+ // relocation independent.
98+ PEFile::PESection *beginAddrSect = nullptr;
99+ std::uint32_t beginAddrSectOff = 0;
100+
101+ if ( std::uint32_t BeginAddress = func.BeginAddress )
102+ {
103+ bool gotLocation = sections.GetPEDataLocation( BeginAddress, &beginAddrSectOff, &beginAddrSect );
104+
105+ if ( !gotLocation )
106+ {
107+ throw peframework_exception(
108+ ePEExceptCode::CORRUPT_PE_STRUCTURE,
109+ "invalid PE runtime function begin address"
110+ );
111+ }
112+ }
113+ PEFile::PESection *endAddrSect = nullptr;
114+ std::uint32_t endAddrSectOff = 0;
115+
116+ if ( std::uint32_t EndAddress = func.EndAddress )
117+ {
118+ bool gotLocation = sections.GetPEDataLocation( EndAddress, &endAddrSectOff, &endAddrSect );
119+
120+ if ( !gotLocation )
121+ {
122+ throw peframework_exception(
123+ ePEExceptCode::CORRUPT_PE_STRUCTURE,
124+ "invalid PE runtime function end address"
125+ );
126+ }
127+ }
128+ PEFile::PESection *unwindInfoSect = nullptr;
129+ std::uint32_t unwindInfoSectOff = 0;
130+
131+ if ( std::uint32_t UnwindInfoAddress = func.UnwindInfoAddress )
132+ {
133+ bool gotLocation = sections.GetPEDataLocation( UnwindInfoAddress, &unwindInfoSectOff, &unwindInfoSect );
134+
135+ if ( !gotLocation )
136+ {
137+ throw peframework_exception(
138+ ePEExceptCode::CORRUPT_PE_STRUCTURE,
139+ "invalid PE runtime function unwind info address"
140+ );
141+ }
142+ }
143+
144+ PEFileDetails::PERuntimeFunctionX64 funcInfo;
145+ funcInfo.beginAddrRef = PEFile::PESectionDataReference( beginAddrSect, beginAddrSectOff );
146+ funcInfo.endAddrRef = PEFile::PESectionDataReference( endAddrSect, endAddrSectOff );
147+ funcInfo.unwindInfoRef = PEFile::PESectionDataReference( unwindInfoSect, unwindInfoSectOff );
148+
149+ exceptRFs.entries.AddToBack( std::move( funcInfo ) );
150+ }
151+
152+ return eir::static_new_struct <PEFunctionRegistryX64, PEGlobalStaticAllocator> ( nullptr, std::move( exceptRFs ) );
153+ }
154+ else if ( machine_id == PEL_IMAGE_FILE_MACHINE_MIPSFPU )
155+ {
156+
157+ }
158+
159+ // Unknown machine type.
160+ return nullptr;
161+ }
162+};
163+
164+static optional_struct_space <PEFunctionRegistryDataDirectoryParser> parser;
165+
166+// We need one static component called the data directory extension registry that manages all such extensions as this and
167+// stores their handlers inside.
168+
169+void registerRuntimeFunctionParser( void )
170+{
171+ parser.Construct();
172+
173+ registerDataDirectoryParser( PEL_IMAGE_DIRECTORY_ENTRY_EXCEPTION, &parser.get() );
174+}
175+
176+void unregisterRuntimeFunctionParser( void )
177+{
178+ unregisterDataDirectoryParser( PEL_IMAGE_DIRECTORY_ENTRY_EXCEPTION );
179+
180+ parser.Destroy();
181+}
\ No newline at end of file
--- library/src/peloader.read.cpp (revision 32)
+++ library/src/peloader.read.cpp (revision 33)
@@ -8,6 +8,8 @@
88
99 #include "peloader.internal.hxx"
1010
11+#include "peloader.datadirs.hxx"
12+
1113 void PEFile::PEFileSpaceData::ReadFromFile( PEStream *peStream, const PESectionMan& sections, std::uint32_t rva, std::uint32_t filePtr, std::uint32_t dataSize )
1214 {
1315 // Determine the storage type of this debug information.
@@ -282,6 +284,7 @@
282284 // Cache some properties.
283285 std::uint16_t numSections;
284286 std::uint16_t peOptHeaderSize;
287+ std::uint16_t machineType;
285288 {
286289 bool seekSuccess = peStream->Seek( peFileStartOffset );
287290
@@ -310,7 +313,7 @@
310313 }
311314
312315 // Read the machine type.
313- std::uint16_t machineType = peHeader.FileHeader.Machine;
316+ machineType = peHeader.FileHeader.Machine;
314317
315318 // Store stuff.
316319 peInfo.machine_id = machineType;
@@ -770,6 +773,7 @@
770773 // Load the directory information now.
771774 // We decide to create meta-data structs out of them.
772775 // If possible, delete the section that contains the meta-data.
776+
773777 // * EXPORT INFORMATION.
774778 PEExportDir expInfo;
775779 {
@@ -1300,98 +1304,6 @@
13001304 }
13011305 }
13021306
1303- // * Exception Information.
1304- peVector <PERuntimeFunction> exceptRFs;
1305- {
1306- const PEStructures::IMAGE_DATA_DIRECTORY& rtDir = dataDirs[ PEL_IMAGE_DIRECTORY_ENTRY_EXCEPTION ];
1307-
1308- if ( rtDir.VirtualAddress != 0 )
1309- {
1310- // TODO: apparently exception data is machine dependent, so we should
1311- // deserialize this in a special way depending on machine_id.
1312- // (currently we specialize on x86/AMD64)
1313-
1314- PESection *rtFuncsSect;
1315- PEDataStream rtFuncsStream;
1316- {
1317- bool gotStream = sections.GetPEDataStream( rtDir.VirtualAddress, rtFuncsStream, &rtFuncsSect );
1318-
1319- if ( !gotStream )
1320- {
1321- throw peframework_exception(
1322- ePEExceptCode::CORRUPT_PE_STRUCTURE,
1323- "invalid PE exception directory"
1324- );
1325- }
1326- }
1327-
1328- rtFuncsSect->SetPlacedMemory( this->exceptAllocEntry, rtDir.VirtualAddress, rtDir.Size );
1329-
1330- const std::uint32_t numFuncs = ( rtDir.Size / sizeof( PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64 ) );
1331-
1332- for ( size_t n = 0; n < numFuncs; n++ )
1333- {
1334- PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64 func;
1335- rtFuncsStream.Read( &func, sizeof(func) );
1336-
1337- // Since the runtime function entry stores RVAs, we want to remember them
1338- // relocation independent.
1339- PESection *beginAddrSect = nullptr;
1340- std::uint32_t beginAddrSectOff = 0;
1341-
1342- if ( std::uint32_t BeginAddress = func.BeginAddress )
1343- {
1344- bool gotLocation = sections.GetPEDataLocation( BeginAddress, &beginAddrSectOff, &beginAddrSect );
1345-
1346- if ( !gotLocation )
1347- {
1348- throw peframework_exception(
1349- ePEExceptCode::CORRUPT_PE_STRUCTURE,
1350- "invalid PE runtime function begin address"
1351- );
1352- }
1353- }
1354- PESection *endAddrSect = nullptr;
1355- std::uint32_t endAddrSectOff = 0;
1356-
1357- if ( std::uint32_t EndAddress = func.EndAddress )
1358- {
1359- bool gotLocation = sections.GetPEDataLocation( EndAddress, &endAddrSectOff, &endAddrSect );
1360-
1361- if ( !gotLocation )
1362- {
1363- throw peframework_exception(
1364- ePEExceptCode::CORRUPT_PE_STRUCTURE,
1365- "invalid PE runtime function end address"
1366- );
1367- }
1368- }
1369- PESection *unwindInfoSect = nullptr;
1370- std::uint32_t unwindInfoSectOff = 0;
1371-
1372- if ( std::uint32_t UnwindInfoAddress = func.UnwindInfoAddress )
1373- {
1374- bool gotLocation = sections.GetPEDataLocation( UnwindInfoAddress, &unwindInfoSectOff, &unwindInfoSect );
1375-
1376- if ( !gotLocation )
1377- {
1378- throw peframework_exception(
1379- ePEExceptCode::CORRUPT_PE_STRUCTURE,
1380- "invalid PE runtime function unwind info address"
1381- );
1382- }
1383- }
1384-
1385- PERuntimeFunction funcInfo;
1386- funcInfo.beginAddrRef = PESectionDataReference( beginAddrSect, beginAddrSectOff );
1387- funcInfo.endAddrRef = PESectionDataReference( endAddrSect, endAddrSectOff );
1388- funcInfo.unwindInfoRef = PESectionDataReference( unwindInfoSect, unwindInfoSectOff );
1389-
1390- exceptRFs.AddToBack( std::move( funcInfo ) );
1391- }
1392- }
1393- }
1394-
13951307 // * ATTRIBUTE CERTIFICATES.
13961308 PESecurity securityCookie;
13971309 {
@@ -2026,6 +1938,60 @@
20261938 clrInfo.dataSize = clrDataDir.Size;
20271939 }
20281940
1941+ // * all other Generic Data Directories.
1942+ PEGenericDataDirectories genDataDirs;
1943+ {
1944+ for ( std::uint32_t idx = 0; idx < countof(dataDirs); idx++ )
1945+ {
1946+ PEDataDirectoryParser *parser = findDataDirectoryParser( idx );
1947+
1948+ if ( parser != nullptr )
1949+ {
1950+ const PEStructures::IMAGE_DATA_DIRECTORY& dataDir = dataDirs[ idx ];
1951+
1952+ std::uint32_t va = dataDir.VirtualAddress;
1953+ std::uint32_t vsize = dataDir.Size;
1954+
1955+ if ( va != 0 )
1956+ {
1957+ PESection *dataDirSect;
1958+ PEDataStream dataDirStream;
1959+ {
1960+ bool gotStream = sections.GetPEDataStream( va, dataDirStream, &dataDirSect );
1961+
1962+ if ( !gotStream )
1963+ {
1964+ throw peframework_exception(
1965+ ePEExceptCode::CORRUPT_PE_STRUCTURE,
1966+ "invalid PE generic data directory"
1967+ );
1968+ }
1969+ }
1970+
1971+ // Try to load the stuff from the serialized image.
1972+ PEDataDirectoryGeneric *genDataDir = parser->DeserializeData( machineType, sections, std::move( dataDirStream ), va, vsize );
1973+
1974+ if ( genDataDir != nullptr )
1975+ {
1976+ dataDirSect->SetPlacedMemory( genDataDir->allocEntry, va, vsize );
1977+
1978+ // Store it.
1979+ try
1980+ {
1981+ genDataDirs.entries[ idx ] = genDataDir;
1982+ }
1983+ catch( ... )
1984+ {
1985+ eir::static_del_struct <PEDataDirectoryGeneric, PEGlobalStaticAllocator> ( nullptr, genDataDir );
1986+
1987+ throw;
1988+ }
1989+ }
1990+ }
1991+ }
1992+ }
1993+ }
1994+
20291995 // TODO: maybe validate all structures more explicitly in context now.
20301996
20311997 // Successfully loaded!
@@ -2039,7 +2005,6 @@
20392005 this->exportDir = std::move( expInfo );
20402006 this->imports = std::move( impDescs );
20412007 this->resourceRoot = std::move( resourceRoot );
2042- this->exceptRFs = std::move( exceptRFs );
20432008 this->securityCookie = std::move( securityCookie );
20442009 this->baseRelocs = std::move( baseRelocs );
20452010 this->debugDescs = std::move( debugDescs );
@@ -2050,6 +2015,7 @@
20502015 this->iatThunkAll = std::move( thunkIAT );
20512016 this->delayLoads = std::move( delayLoads );
20522017 this->clrInfo = std::move( clrInfo );
2018+ this->genDataDirs = std::move( genDataDirs );
20532019
20542020 // Store some meta-data.
20552021 this->isExtendedFormat = isExtendedFormat; // important for casting certain offsets.
--- library/src/peloader.write.cpp (revision 32)
+++ library/src/peloader.write.cpp (revision 33)
@@ -1018,45 +1018,6 @@
10181018 }
10191019 }
10201020
1021- // * Exception Information.
1022- const auto& exceptRFs = this->exceptRFs;
1023-
1024- std::uint32_t numExceptEntries = (std::uint32_t)exceptRFs.GetCount();
1025-
1026- if ( numExceptEntries != 0 )
1027- {
1028- // TODO: remember that exception data is machine dependent.
1029- // revisit this if we need multi-architecture support.
1030- // (currently we specialize on x86/AMD64)
1031-
1032- if ( this->exceptAllocEntry.IsAllocated() == false )
1033- {
1034- const std::uint32_t exceptTableSize = ( sizeof(PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64) * numExceptEntries );
1035-
1036- PESectionAllocation exceptTableAlloc;
1037- rdonlySect.Allocate( exceptTableAlloc, exceptTableSize, sizeof(std::uint32_t) );
1038-
1039- // Now write all entries.
1040- // TODO: documentation says that these entries should be address sorted.
1041- for ( std::uint32_t n = 0; n < numExceptEntries; n++ )
1042- {
1043- const PERuntimeFunction& rfEntry = this->exceptRFs[ n ];
1044-
1045- PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64 funcInfo;
1046- funcInfo.BeginAddress = rfEntry.beginAddrRef.GetRVA();
1047- funcInfo.EndAddress = rfEntry.endAddrRef.GetRVA();
1048- funcInfo.UnwindInfoAddress = rfEntry.unwindInfoRef.GetRVA();
1049-
1050- const std::uint32_t rfEntryOff = ( n * sizeof(PEStructures::IMAGE_RUNTIME_FUNCTION_ENTRY_X64) );
1051-
1052- exceptTableAlloc.WriteToSection( &funcInfo, sizeof(funcInfo), rfEntryOff );
1053- }
1054-
1055- // Remember this valid exception table.
1056- this->exceptAllocEntry = std::move( exceptTableAlloc );
1057- }
1058- }
1059-
10601021 // nothing to allocate for security cookie.
10611022
10621023 // *** BASE RELOC has to be written last because commit operations can spawn relocations.
@@ -1444,6 +1405,18 @@
14441405 this->delayLoadsAllocEntry = std::move( delayLoadsAlloc );
14451406 }
14461407 }
1408+
1409+ // * GENERIC DATA DIRECTORIES.
1410+ for ( auto *genDataDirNode : this->genDataDirs.entries )
1411+ {
1412+ PEDataDirectoryGeneric *genDataDir = genDataDirNode->GetValue();
1413+
1414+ if ( genDataDir->allocEntry.IsAllocated() == false )
1415+ {
1416+ // Commit any uncommitted data directory, if it wants to of course.
1417+ genDataDir->SerializeDataDirectory( &rdonlySect );
1418+ }
1419+ }
14471420 }
14481421
14491422 // SECTION-ALLOC PHASE.
@@ -1571,7 +1544,7 @@
15711544
15721545 void PEFile::WriteToStream( PEStream *peStream )
15731546 {
1574- // Write data that requires writing.
1547+ // Prepare data that requires writing.
15751548 this->CommitDataDirectories();
15761549
15771550 // Prepare the data directories.
@@ -1597,7 +1570,6 @@
15971570 dirRegHelper( peDataDirs[ PEL_IMAGE_DIRECTORY_ENTRY_EXPORT ], this->exportDir.allocEntry );
15981571 dirRegHelper( peDataDirs[ PEL_IMAGE_DIRECTORY_ENTRY_IMPORT ], this->importsAllocEntry );
15991572 dirRegHelper( peDataDirs[ PEL_IMAGE_DIRECTORY_ENTRY_RESOURCE ], this->resAllocEntry );
1600- dirRegHelper( peDataDirs[ PEL_IMAGE_DIRECTORY_ENTRY_EXCEPTION ], this->exceptAllocEntry );
16011573
16021574 // Attribute certificate table needs to be written after the sections!
16031575
@@ -1642,6 +1614,18 @@
16421614 comDescDataDir.VirtualAddress = this->clrInfo.dataOffset;
16431615 comDescDataDir.Size = this->clrInfo.dataSize;
16441616 }
1617+
1618+ // Write all other generic data directory references.
1619+ for ( auto *genDataDirNode : this->genDataDirs.entries )
1620+ {
1621+ std::uint32_t idx = genDataDirNode->GetKey();
1622+ PEFile::PEDataDirectoryGeneric *genDataDir = genDataDirNode->GetValue();
1623+
1624+ // For now we limit ourselves to official data directories.
1625+ assert( idx < countof(peDataDirs) );
1626+
1627+ dirRegHelper( peDataDirs[ idx ], genDataDir->allocEntry );
1628+ }
16451629 }
16461630
16471631 // TODO: properly write the PE file onto disk.
Show on old repository browser