2020-12-15 09:27:44 -04:00
// Copyright 2011-2020 Molecular Matters GmbH, all rights reserved.
2019-03-05 18:49:25 -05:00
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
//#include PCH_INCLUDE
// END EPIC MOD
2019-03-05 18:49:25 -05:00
# include "LC_Coff.h"
# include "LC_CoffDetail.h"
# include "LC_StringUtil.h"
# include "LC_PointerUtil.h"
2020-12-15 09:27:44 -04:00
# include "LC_Filesystem.h"
2019-03-05 18:49:25 -05:00
# include "LC_SymbolPatterns.h"
# include "LC_Symbols.h"
2019-05-24 11:51:54 -04:00
# include "LC_MemoryStream.h"
2019-03-05 18:49:25 -05:00
# include "LC_UniqueId.h"
2020-12-15 09:27:44 -04:00
# include "LC_MemoryMappedFile.h"
2022-08-08 11:29:32 -04:00
# include "LC_Assembler.h"
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
2019-03-05 18:49:25 -05:00
# include "LC_Allocators.h"
2020-12-15 09:27:44 -04:00
# include "LC_Assert.h"
2019-03-05 18:49:25 -05:00
# include <algorithm>
2020-12-15 09:27:44 -04:00
// END EPIC MOD
2019-03-05 18:49:25 -05:00
namespace
{
static const uint32_t INVALID_CRT_SECTION = 0xFFFFFFFFu ;
// this is not used as a character in mangled names
static const char COFF_SUFFIX = ' % ' ;
static const wchar_t COFF_SUFFIX_WIDE = L ' % ' ;
static const ImmutableString TLS_SECTION ( " .tls " ) ;
}
namespace coff
{
ObjFile * OpenObj ( const wchar_t * filename )
{
ObjFile * objFile = LC_NEW ( & g_objFileAllocator , ObjFile ) ;
objFile - > filename = string : : ToUtf8String ( filename ) ;
2020-12-15 09:27:44 -04:00
objFile - > memoryFile = Filesystem : : OpenMemoryMappedFile ( filename , Filesystem : : OpenMode : : READ ) ;
2019-03-05 18:49:25 -05:00
return objFile ;
}
void CloseObj ( ObjFile * & objFile )
{
2020-12-15 09:27:44 -04:00
Filesystem : : CloseMemoryMappedFile ( objFile - > memoryFile ) ;
2019-03-05 18:49:25 -05:00
LC_DELETE ( & g_objFileAllocator , objFile , sizeof ( ObjFile ) ) ;
objFile = nullptr ;
}
static size_t FindSymbolShortNameLength ( const char * shortName )
{
size_t length = 0u ;
while ( ( shortName [ length ] ! = ' \0 ' ) & & ( length < 8u ) )
{
// find (optional!) null-terminator
+ + length ;
}
return length ;
}
static ImmutableString GetSymbolShortName ( const BYTE * shortName )
{
const char * str = reinterpret_cast < const char * > ( shortName ) ;
return ImmutableString ( str , FindSymbolShortNameLength ( str ) ) ;
}
static ImmutableString DisambiguateStaticSymbolName ( const char * name , size_t nameLength , uint32_t uniqueCoffId , uint16_t uniqueCounter )
{
// static symbols are not necessarily unique across different translation units, hence we need something
// to disambiguate them. this is done by appending the unique ID of the .obj file in which this symbol is defined.
// the new name has the form "name%ID" (plus a null terminator), e.g. "g_counter2%AF20"
const size_t frontLength = nameLength ;
const size_t uniqueIdLength = 8u ;
const bool needsCounter = ( uniqueCounter ! = 0u ) ;
const size_t length = needsCounter
? frontLength + 1u + uniqueIdLength + 1u + 4u // unlikely case, add a unique counter to the name of the symbol
: frontLength + 1u + uniqueIdLength + 1u ; // more likely case, no unique counter needed
char * temp = static_cast < char * > ( _alloca ( length ) ) ;
char * finalName = temp ;
memcpy ( temp , name , frontLength ) ;
if ( needsCounter )
{
temp [ frontLength + 0u ] = " 0123456789ABCDEF " [ ( uniqueCounter > > 12u ) & 0x0F ] ;
temp [ frontLength + 1u ] = " 0123456789ABCDEF " [ ( uniqueCounter > > 8u ) & 0x0F ] ;
temp [ frontLength + 2u ] = " 0123456789ABCDEF " [ ( uniqueCounter > > 4u ) & 0x0F ] ;
temp [ frontLength + 3u ] = " 0123456789ABCDEF " [ ( uniqueCounter > > 0u ) & 0x0F ] ;
temp + = 4u ;
}
temp [ frontLength ] = COFF_SUFFIX ;
// store unique ID in hex, no leading zeros
bool wasValueWritten = false ;
temp + = frontLength + 1u ;
for ( unsigned int i = 0u ; i < 8u ; + + i )
{
const uint32_t shift = ( 7u - i ) * 4u ; // 28, 24, 20, 16, ...
const uint32_t index = ( uniqueCoffId > > shift ) & 0x0F ;
// if no value != zero has been written yet, don't advance to the next position.
// this makes sure that no leading zeros are written and automatically handles the case of ID == 0,
// where at least one zero has to be written.
if ( wasValueWritten )
{
+ + temp ;
}
* temp = " 0123456789ABCDEF " [ index ] ;
if ( index ! = 0u )
{
wasValueWritten = true ;
}
}
temp [ 1 ] = ' \0 ' ;
return ImmutableString ( finalName ) ;
}
template < typename T >
static ImmutableString GetSymbolName ( const char * stringTable , const T * symbol )
{
/*
From the COFF spec:
The ShortName field in a symbol table consists of 8 bytes that contain the name
itself, if it is not more than 8 bytes long, or the ShortName field gives an offset into
the string table. To determine whether the name itself or an offset is given, test the
first 4 bytes for equality to zero.
*/
if ( symbol - > N . Name . Short ! = 0 )
{
// short name
return GetSymbolShortName ( symbol - > N . ShortName ) ;
}
else
{
// long name, points into string table
return ImmutableString ( stringTable + symbol - > N . Name . Long ) ;
}
}
template < typename T >
2020-12-15 09:27:44 -04:00
static ImmutableString GetSymbolName ( const char * stringTable , const T * symbol , uint32_t uniqueId , uint16_t uniqueCounter )
2019-03-05 18:49:25 -05:00
{
/*
From the COFF spec:
The ShortName field in a symbol table consists of 8 bytes that contain the name
itself, if it is not more than 8 bytes long, or the ShortName field gives an offset into
the string table. To determine whether the name itself or an offset is given, test the
first 4 bytes for equality to zero.
*/
// static symbols must have their name disambiguated across several translation units.
// this is true even for COMDAT symbols, because COMDAT folding done by the linker depends on linker settings
// and (seemingly) the type/name of the symbol, e.g. folding is done for template functions, but not for
// identical static inline functions in several translation units.
const bool isStatic = ( symbol - > StorageClass = = IMAGE_SYM_CLASS_STATIC ) ;
if ( symbol - > N . Name . Short ! = 0 )
{
// short name
if ( isStatic )
{
const char * str = reinterpret_cast < const char * > ( symbol - > N . ShortName ) ;
return DisambiguateStaticSymbolName ( str , FindSymbolShortNameLength ( str ) , uniqueId , uniqueCounter ) ;
}
else
{
return GetSymbolShortName ( symbol - > N . ShortName ) ;
}
}
else
{
// long name, points into string table
const char * str = stringTable + symbol - > N . Name . Long ;
return isStatic
? DisambiguateStaticSymbolName ( str , strlen ( str ) , uniqueId , uniqueCounter )
: ImmutableString ( str ) ;
}
}
static ImmutableString GetSectionName ( const char * stringTable , const IMAGE_SECTION_HEADER * section )
{
/*
From the COFF spec:
An 8-byte, null-padded UTF-8 encoded string. If the string is exactly 8 characters long, there is no
terminating null. For longer names, this field contains a slash (/) that is followed by an ASCII
representation of a decimal number that is an offset into the string table. Executable images do
not use a string table and do not support section names longer than 8 characters. Long names in
object files are truncated if they are emitted to an executable file.
*/
if ( section - > Name [ 0 ] = = ' / ' )
{
// potentially a long name, but could also be a section starting with '/'
unsigned int offset = 0 ;
const int convertedCount = sscanf_s ( reinterpret_cast < const char * > ( & section - > Name [ 1 ] ) , " %u " , & offset ) ;
if ( convertedCount > 0 )
{
return ImmutableString ( stringTable + offset ) ;
}
// could not convert decimal number, hence the section short name starts with '/'
}
// short name
return GetSymbolShortName ( section - > Name ) ;
}
static bool SortSymbolByAscendingRVA ( const Symbol * lhs , const Symbol * rhs )
{
return lhs - > rva < rhs - > rva ;
}
template < typename T >
static coff : : SymbolType : : Enum DetermineDataSymbolType ( const T * symbol )
{
LC_ASSERT ( ! coffDetail : : IsFunctionSymbol ( symbol ) , " Symbol must be a data symbol " ) ;
if ( symbol - > StorageClass = = IMAGE_SYM_CLASS_EXTERNAL )
{
return coff : : SymbolType : : EXTERNAL_DATA ;
}
if ( ( symbol - > StorageClass = = IMAGE_SYM_CLASS_STATIC ) | | ( symbol - > Value = = 0u ) )
{
return coff : : SymbolType : : STATIC_DATA ;
}
return coff : : SymbolType : : UNKNOWN_DATA ;
}
template < typename T >
static coff : : SymbolType : : Enum DetermineFunctionSymbolType ( const T * symbol )
{
LC_ASSERT ( coffDetail : : IsFunctionSymbol ( symbol ) , " Symbol must be a function symbol " ) ;
if ( symbol - > StorageClass = = IMAGE_SYM_CLASS_EXTERNAL )
{
return coff : : SymbolType : : EXTERNAL_FUNCTION ;
}
if ( symbol - > StorageClass = = IMAGE_SYM_CLASS_STATIC )
{
return coff : : SymbolType : : STATIC_FUNCTION ;
}
return coff : : SymbolType : : UNKNOWN_FUNCTION ;
}
template < typename T >
static coff : : SymbolType : : Enum DetermineSymbolType ( const T * symbol )
{
return coffDetail : : IsFunctionSymbol ( symbol ) ? DetermineFunctionSymbolType ( symbol ) : DetermineDataSymbolType ( symbol ) ;
}
template < typename RawCoffType , coffDetail : : CoffType : : Enum Type >
2020-12-15 09:27:44 -04:00
static RawCoffType * ReadRaw ( ObjFile * file , uint32_t uniqueId )
2019-03-05 18:49:25 -05:00
{
2019-08-22 10:52:35 -04:00
using CoffHeader = typename coffDetail : : CoffType : : TypeMap < Type > : : HeaderType ;
using CoffSymbol = typename coffDetail : : CoffType : : TypeMap < Type > : : SymbolType ;
using CoffAuxSymbol = typename coffDetail : : CoffType : : TypeMap < Type > : : AuxSymbolType ;
2019-03-05 18:49:25 -05:00
RawCoffType * rawCoff = new RawCoffType ;
{
2020-12-15 09:27:44 -04:00
const Filesystem : : PathAttributes & attributes = Filesystem : : GetAttributes ( string : : ToWideString ( file - > filename ) . c_str ( ) ) ;
rawCoff - > size = Filesystem : : GetSize ( attributes ) ;
2019-03-05 18:49:25 -05:00
}
rawCoff - > type = RawCoffType : : TYPE ;
2020-12-15 09:27:44 -04:00
const void * objFileBase = Filesystem : : GetMemoryMappedFileData ( file - > memoryFile ) ;
2019-03-05 18:49:25 -05:00
// section header is first
2020-12-15 09:27:44 -04:00
const CoffHeader * rawCoffHeader = pointer : : As < const CoffHeader * > ( objFileBase ) ;
2019-03-05 18:49:25 -05:00
rawCoff - > header = * rawCoffHeader ;
// section headers follow after that
2020-12-15 09:27:44 -04:00
const IMAGE_SECTION_HEADER * rawSectionHeaders = coffDetail : : GetSectionHeader < CoffHeader > ( objFileBase ) ;
const uint32_t sectionCount = coffDetail : : GetNumberOfSections < CoffHeader > ( objFileBase ) ;
2019-03-05 18:49:25 -05:00
rawCoff - > sections . reserve ( sectionCount ) ;
for ( uint32_t i = 0u ; i < sectionCount ; + + i )
{
const IMAGE_SECTION_HEADER * rawSection = rawSectionHeaders + i ;
RawSection section ;
// header
{
section . header = * rawSection ;
}
// raw data
if ( rawSection - > PointerToRawData ! = 0u )
{
// some sections like .bss don't store (uninitialized) data
const DWORD rawDataSize = rawSection - > SizeOfRawData ;
section . data = LC_ALLOC ( & g_rawCoffAllocator , rawDataSize , 8u ) ;
2020-12-15 09:27:44 -04:00
memcpy ( section . data , pointer : : Offset < const void * > ( objFileBase , rawSection - > PointerToRawData ) , rawDataSize ) ;
2019-03-05 18:49:25 -05:00
}
// relocations
{
2020-12-15 09:27:44 -04:00
const IMAGE_RELOCATION * rawRelocations = pointer : : Offset < const IMAGE_RELOCATION * > ( objFileBase , rawSection - > PointerToRelocations ) ;
const size_t count = coffDetail : : GetRelocationCount ( objFileBase , rawSection ) ;
2019-03-05 18:49:25 -05:00
// if relocation count in section has overflown, ignore the first relocation
const size_t startRelocation = ( count > 0xFFFFu ) ? 1u : 0u ;
section . relocations . reserve ( count - startRelocation ) ;
for ( size_t j = 0u ; j < count - startRelocation ; + + j )
{
section . relocations . push_back ( rawRelocations [ j + startRelocation ] ) ;
}
}
// line numbers
{
2020-12-15 09:27:44 -04:00
const IMAGE_LINENUMBER * rawLineNumbers = pointer : : Offset < const IMAGE_LINENUMBER * > ( objFileBase , rawSection - > PointerToLinenumbers ) ;
2019-03-05 18:49:25 -05:00
const size_t count = rawSection - > NumberOfLinenumbers ;
section . lineNumbers . reserve ( count ) ;
for ( size_t j = 0u ; j < count ; + + j )
{
section . lineNumbers . push_back ( rawLineNumbers [ j ] ) ;
}
}
rawCoff - > sections . emplace_back ( std : : move ( section ) ) ;
}
// symbol table follows after section headers, but offset is stored in COFF header directly
2020-12-15 09:27:44 -04:00
const void * rawSymbolTable = coffDetail : : GetSymbolTable < CoffHeader > ( objFileBase ) ;
const uint32_t symbolCount = coffDetail : : GetNumberOfSymbols < CoffHeader > ( objFileBase ) ;
2019-03-05 18:49:25 -05:00
rawCoff - > symbols . reserve ( symbolCount ) ;
for ( uint32_t i = 0u ; i < symbolCount ; + + i )
{
const CoffSymbol * rawSymbol = coffDetail : : GetSymbol < CoffSymbol > ( rawSymbolTable , i ) ;
rawCoff - > symbols . push_back ( * rawSymbol ) ;
}
// string table follows after symbol table
const char * rawStringTable = coffDetail : : GetStringTable < CoffSymbol > ( rawSymbolTable , symbolCount ) ;
// first 4 bytes contain the total size of the string table (including these 4 bytes)
rawCoff - > rawStringTable . size = * pointer : : As < const uint32_t * > ( rawStringTable ) ;
rawCoff - > rawStringTable . data = static_cast < char * > ( LC_ALLOC ( & g_rawCoffAllocator , rawCoff - > rawStringTable . size , 8u ) ) ;
memcpy ( rawCoff - > rawStringTable . data , rawStringTable , rawCoff - > rawStringTable . size ) ;
// construct string table
{
rawCoff - > stringTable . resize ( symbolCount ) ;
types : : StringMap < uint16_t > uniqueStaticDataSymbols ;
uniqueStaticDataSymbols . reserve ( 16u ) ;
for ( uint32_t i = 0u ; i < symbolCount ; + + i )
{
const CoffSymbol * symbol = coffDetail : : GetSymbol < CoffSymbol > ( rawSymbolTable , i ) ;
if ( coffDetail : : IsAbsoluteSymbol ( symbol ) )
{
continue ;
}
else if ( coffDetail : : IsDebugSymbol ( symbol ) )
{
continue ;
}
else if ( coffDetail : : IsSectionSymbol ( symbol ) )
{
continue ;
}
const SymbolType : : Enum type = DetermineSymbolType ( symbol ) ;
2020-12-15 09:27:44 -04:00
rawCoff - > stringTable [ i ] = GetSymbolName ( rawStringTable , symbol , uniqueId , 0u ) ;
2019-03-05 18:49:25 -05:00
const ImmutableString & name = rawCoff - > stringTable [ i ] ;
if ( type = = SymbolType : : STATIC_DATA )
{
// make sure this symbol is unique
auto insertIterator = uniqueStaticDataSymbols . emplace ( name , static_cast < uint16_t > ( 0u ) ) ;
if ( insertIterator . second = = false )
{
// the name of this symbol is not unique.
// as a workaround, try generating a unique name for it.
// this does not fix potential issues in all cases, but works successfully in cases where
// this compiland is never recompiled, or where the order of variables in the file doesn't change.
// increase the counter associated with this name and generate a new name from it
+ + insertIterator . first - > second ;
2020-12-15 09:27:44 -04:00
rawCoff - > stringTable [ i ] = GetSymbolName ( rawStringTable , symbol , uniqueId , insertIterator . first - > second ) ;
2019-03-05 18:49:25 -05:00
}
}
}
}
// construct look-up table of associated COMDAT sections
{
for ( uint32_t i = 0u ; i < symbolCount ; + + i )
{
const CoffSymbol * symbol = coffDetail : : GetSymbol < CoffSymbol > ( rawSymbolTable , i ) ;
// ignore absolute, debug and undefined symbols
if ( coffDetail : : IsAbsoluteSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsDebugSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsUndefinedSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsSectionSymbol ( symbol ) )
{
// if this is a COMDAT section, grab its selection number from the auxiliary record
const uint32_t symbolSectionIndex = coffDetail : : GetSectionIndex ( symbol ) ;
RawSection & section = rawCoff - > sections [ symbolSectionIndex ] ;
if ( coffDetail : : IsComdatSection ( & section . header ) )
{
// the auxiliary record holds information about the COMDAT section. according to the COFF spec 5.5.6,
// a COMDAT section always has one auxiliary record which is "the COMDAT symbol".
if ( symbol - > NumberOfAuxSymbols = = 1u )
{
const CoffAuxSymbol * auxSymbol = coffDetail : : GetSymbol < CoffAuxSymbol > ( rawSymbolTable , i + 1u ) ;
const uint8_t selection = auxSymbol - > Section . Selection ;
if ( selection = = IMAGE_COMDAT_SELECT_ASSOCIATIVE )
{
const uint32_t associatedSectionIndex = coffDetail : : GetAssociatedComdatSectionIndex < CoffAuxSymbol > ( auxSymbol ) ;
rawCoff - > associatedComdatSections [ associatedSectionIndex ] . push_back ( symbolSectionIndex ) ;
}
else if ( selection = = IMAGE_COMDAT_SELECT_ANY )
{
section . isSelectAnyComdat = true ;
}
}
}
}
}
}
return rawCoff ;
}
2020-12-15 09:27:44 -04:00
RawCoff * ReadRaw ( ObjFile * file , uint32_t uniqueId )
2019-03-05 18:49:25 -05:00
{
2020-12-15 09:27:44 -04:00
const coffDetail : : CoffType : : Enum type = coffDetail : : GetCoffType ( Filesystem : : GetMemoryMappedFileData ( file - > memoryFile ) ) ;
2019-03-05 18:49:25 -05:00
if ( type = = coffDetail : : CoffType : : COFF )
{
2020-12-15 09:27:44 -04:00
return ReadRaw < RawCoffRegular , coffDetail : : CoffType : : COFF > ( file , uniqueId ) ;
2019-03-05 18:49:25 -05:00
}
else if ( type = = coffDetail : : CoffType : : BIGOBJ )
{
2020-12-15 09:27:44 -04:00
return ReadRaw < RawCoffBigObj , coffDetail : : CoffType : : BIGOBJ > ( file , uniqueId ) ;
2019-03-05 18:49:25 -05:00
}
return nullptr ;
}
template < coffDetail : : CoffType : : Enum Type , typename RawCoffType >
static void WriteRaw ( const wchar_t * filename , const RawCoffType * rawCoff , SymbolRemovalStrategy : : Enum removalStrategy )
{
2019-08-22 10:52:35 -04:00
using CoffHeader = typename coffDetail : : CoffType : : TypeMap < Type > : : HeaderType ;
using CoffSymbol = typename coffDetail : : CoffType : : TypeMap < Type > : : SymbolType ;
2019-03-05 18:49:25 -05:00
// the file structure is as follows:
// - COFF file header
// - all section headers
// - all symbols
// - string table
// - raw data for section 0
// - relocations for section 0
// - line numbers for section 0
// - ...
// - raw data for section N
// - relocations for section N
// - line numbers for section N
// keeping the section data, relocations, and line numbers at the end of the file makes it easier to keep track
// of file offsets that are stored in the section headers.
2019-05-24 11:51:54 -04:00
memoryStream : : Writer outputData ( static_cast < size_t > ( rawCoff - > size ) ) ;
2019-03-05 18:49:25 -05:00
CoffHeader coffHeader ( rawCoff - > header ) ;
// careful: the number of sections is of type WORD, but DWORD in files compiled with /bigobj!
typedef decltype ( CoffHeader : : NumberOfSections ) SectionCountType ;
coffHeader . NumberOfSections = static_cast < SectionCountType > ( rawCoff - > sections . size ( ) ) ;
coffHeader . NumberOfSymbols = static_cast < DWORD > ( rawCoff - > symbols . size ( ) ) ;
coffHeader . PointerToSymbolTable = static_cast < DWORD > ( sizeof ( CoffHeader ) + rawCoff - > sections . size ( ) * sizeof ( IMAGE_SECTION_HEADER ) ) ;
2019-05-24 11:51:54 -04:00
outputData . Write ( coffHeader ) ;
2019-03-05 18:49:25 -05:00
const size_t baseOffset =
sizeof ( CoffHeader ) +
rawCoff - > sections . size ( ) * sizeof ( IMAGE_SECTION_HEADER ) +
rawCoff - > symbols . size ( ) * sizeof ( CoffSymbol ) +
rawCoff - > rawStringTable . size ;
size_t fileOffset = baseOffset ;
for ( size_t i = 0u ; i < rawCoff - > sections . size ( ) ; + + i )
{
const RawSection & section ( rawCoff - > sections [ i ] ) ;
IMAGE_SECTION_HEADER sectionHeader ( rawCoff - > sections [ i ] . header ) ;
if ( sectionHeader . PointerToRawData ! = 0u )
{
// .bss and sections with uninitialized data have a size, but don't store any actual data
sectionHeader . PointerToRawData = static_cast < DWORD > ( fileOffset ) ;
fileOffset + = sectionHeader . SizeOfRawData ;
}
if ( section . relocations . size ( ) = = 0u )
{
sectionHeader . PointerToRelocations = 0u ;
sectionHeader . NumberOfRelocations = 0u ;
}
else
{
sectionHeader . PointerToRelocations = static_cast < DWORD > ( fileOffset ) ;
size_t relocationCount = section . relocations . size ( ) ;
if ( relocationCount > = 0xFFFFu )
{
// relocation count would overflow, so we need to add one extra relocation that stores
// the actual number of relocations.
sectionHeader . NumberOfRelocations = 0xFFFFu ;
sectionHeader . Characteristics | = IMAGE_SCN_LNK_NRELOC_OVFL ;
+ + relocationCount ;
}
else
{
sectionHeader . NumberOfRelocations = static_cast < WORD > ( relocationCount ) ;
}
fileOffset + = relocationCount * sizeof ( IMAGE_RELOCATION ) ;
}
if ( section . lineNumbers . size ( ) = = 0u )
{
sectionHeader . PointerToLinenumbers = 0u ;
}
else
{
sectionHeader . PointerToLinenumbers = static_cast < DWORD > ( fileOffset ) ;
fileOffset + = section . lineNumbers . size ( ) * sizeof ( IMAGE_LINENUMBER ) ;
}
sectionHeader . NumberOfLinenumbers = static_cast < WORD > ( section . lineNumbers . size ( ) ) ;
2019-05-24 11:51:54 -04:00
outputData . Write ( sectionHeader ) ;
2019-03-05 18:49:25 -05:00
}
for ( size_t i = 0u ; i < rawCoff - > symbols . size ( ) ; + + i )
{
2019-05-24 11:51:54 -04:00
outputData . Write ( rawCoff - > symbols [ i ] ) ;
2019-03-05 18:49:25 -05:00
}
2019-05-24 11:51:54 -04:00
outputData . Write ( rawCoff - > rawStringTable . data , rawCoff - > rawStringTable . size ) ;
2019-03-05 18:49:25 -05:00
for ( size_t i = 0u ; i < rawCoff - > sections . size ( ) ; + + i )
{
const RawSection & section = rawCoff - > sections [ i ] ;
if ( section . header . PointerToRawData ! = 0u )
{
2019-05-24 11:51:54 -04:00
outputData . Write ( section . data , section . header . SizeOfRawData ) ;
2019-03-05 18:49:25 -05:00
}
const size_t relocationCount = section . relocations . size ( ) ;
if ( relocationCount > = 0xFFFFu )
{
// relocation count would overflow, so we need to add one extra relocation that stores
// the actual number of relocations.
IMAGE_RELOCATION dummyRelocation = { } ;
dummyRelocation . RelocCount = static_cast < DWORD > ( relocationCount ) ;
2019-05-24 11:51:54 -04:00
outputData . Write ( dummyRelocation ) ;
2019-03-05 18:49:25 -05:00
}
if ( removalStrategy = = SymbolRemovalStrategy : : Enum : : MSVC_COMPATIBLE )
{
for ( size_t j = 0u ; j < relocationCount ; + + j )
{
const IMAGE_RELOCATION & relocation = section . relocations [ j ] ;
2019-05-24 11:51:54 -04:00
outputData . Write ( relocation ) ;
2019-03-05 18:49:25 -05:00
}
}
else if ( removalStrategy = = SymbolRemovalStrategy : : Enum : : LLD_COMPATIBLE )
{
// LLD does not allow SECREL relocations to absolute symbols (which are our fake stripped symbols),
// unless these relocations are contained in a debug section.
// debug sections can be identified by checking if the section in question is marked as being discardable.
for ( size_t j = 0u ; j < relocationCount ; + + j )
{
IMAGE_RELOCATION relocation = section . relocations [ j ] ;
if ( relocation . Type = = Relocation : : Type : : SECTION_RELATIVE )
{
// only "fix" section-relative relocations in non-debug sections
if ( ! coffDetail : : IsDiscardableSection ( & section . header ) )
{
// only "fix" section-relative relocations pointing to a removed symbol
if ( IsRemovedSymbol ( rawCoff , relocation . SymbolTableIndex , removalStrategy ) )
{
// fix by whatever means necessary in order to make LLD happy.
// this is a stripped symbol, so its relocation will be patched anyway.
relocation . Type = Relocation : : Type : : RVA_32 ;
}
}
}
2019-05-24 11:51:54 -04:00
outputData . Write ( relocation ) ;
2019-03-05 18:49:25 -05:00
}
}
for ( size_t j = 0u ; j < section . lineNumbers . size ( ) ; + + j )
{
2019-05-24 11:51:54 -04:00
outputData . Write ( section . lineNumbers [ j ] ) ;
2019-03-05 18:49:25 -05:00
}
}
2020-12-15 09:27:44 -04:00
Filesystem : : CreateFileWithData ( filename , outputData . GetData ( ) , outputData . GetSize ( ) ) ;
2019-03-05 18:49:25 -05:00
}
void WriteRaw ( const wchar_t * filename , const RawCoff * rawCoff , SymbolRemovalStrategy : : Enum removalStrategy )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
WriteRaw < coffDetail : : CoffType : : Enum : : COFF > ( filename , static_cast < const RawCoffRegular * > ( rawCoff ) , removalStrategy ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
WriteRaw < coffDetail : : CoffType : : Enum : : BIGOBJ > ( filename , static_cast < const RawCoffBigObj * > ( rawCoff ) , removalStrategy ) ;
}
}
template < typename RawCoffType >
static void DestroyRaw ( RawCoffType * rawCoff )
{
for ( size_t i = 0u ; i < rawCoff - > sections . size ( ) ; + + i )
{
const RawSection & section = rawCoff - > sections [ i ] ;
LC_FREE ( & g_rawCoffAllocator , section . data , section . header . SizeOfRawData ) ;
}
LC_FREE ( & g_rawCoffAllocator , rawCoff - > rawStringTable . data , rawCoff - > rawStringTable . size ) ;
delete rawCoff ;
}
void DestroyRaw ( RawCoff * rawCoff )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
DestroyRaw ( static_cast < RawCoffRegular * > ( rawCoff ) ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
DestroyRaw ( static_cast < RawCoffBigObj * > ( rawCoff ) ) ;
}
}
size_t GetSymbolCount ( const RawCoff * rawCoff )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
return static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols . size ( ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
return static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols . size ( ) ;
}
return 0u ;
}
size_t GetSectionCount ( const RawCoff * rawCoff )
{
return rawCoff - > sections . size ( ) ;
}
size_t GetAuxSymbolCount ( const RawCoff * rawCoff , size_t symbolIndex )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
const auto & symbol = static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols [ symbolIndex ] ;
return symbol . NumberOfAuxSymbols ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
const auto & symbol = static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols [ symbolIndex ] ;
return symbol . NumberOfAuxSymbols ;
}
return 0u ;
}
SymbolType : : Enum GetSymbolType ( const RawCoff * rawCoff , size_t index )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
const auto & symbol = static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols [ index ] ;
return DetermineSymbolType ( & symbol ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
const auto & symbol = static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols [ index ] ;
return DetermineSymbolType ( & symbol ) ;
}
return SymbolType : : UNKNOWN_FUNCTION ;
}
const ImmutableString & GetSymbolName ( const RawCoff * rawCoff , size_t index )
{
return rawCoff - > stringTable [ index ] ;
}
2020-12-15 09:27:44 -04:00
ImmutableString GetSectionName ( const RawCoff * rawCoff , size_t index )
{
const IMAGE_SECTION_HEADER * header = & rawCoff - > sections [ index ] . header ;
return GetSectionName ( rawCoff - > rawStringTable . data , header ) ;
}
2019-03-05 18:49:25 -05:00
uint32_t GetSymbolSectionIndex ( const RawCoff * rawCoff , size_t index )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
const auto & symbol = static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : GetSectionIndex ( & symbol ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
const auto & symbol = static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : GetSectionIndex ( & symbol ) ;
}
return 0u ;
}
bool IsAbsoluteSymbol ( const RawCoff * rawCoff , size_t index )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
const auto & symbol = static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : IsAbsoluteSymbol ( & symbol ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
const auto & symbol = static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : IsAbsoluteSymbol ( & symbol ) ;
}
return false ;
}
bool IsDebugSymbol ( const RawCoff * rawCoff , size_t index )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
const auto & symbol = static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : IsDebugSymbol ( & symbol ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
const auto & symbol = static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : IsDebugSymbol ( & symbol ) ;
}
return false ;
}
bool IsSectionSymbol ( const RawCoff * rawCoff , size_t index )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
const auto & symbol = static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : IsSectionSymbol ( & symbol ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
const auto & symbol = static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : IsSectionSymbol ( & symbol ) ;
}
return false ;
}
bool IsUndefinedSymbol ( const RawCoff * rawCoff , size_t index )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
const auto & symbol = static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : IsUndefinedSymbol ( & symbol ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
const auto & symbol = static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols [ index ] ;
return coffDetail : : IsUndefinedSymbol ( & symbol ) ;
}
return false ;
}
bool IsRemovedSymbol ( const RawCoff * rawCoff , size_t index , SymbolRemovalStrategy : : Enum removalStrategy )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
const auto & symbol = static_cast < const RawCoffRegular * > ( rawCoff ) - > symbols [ index ] ;
return ( ( symbol . Type = = IMAGE_SYM_TYPE_NULL ) & & ( symbol . StorageClass = = IMAGE_SYM_CLASS_NULL ) & & ( symbol . SectionNumber = = removalStrategy ) ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
const auto & symbol = static_cast < const RawCoffBigObj * > ( rawCoff ) - > symbols [ index ] ;
return ( ( symbol . Type = = IMAGE_SYM_TYPE_NULL ) & & ( symbol . StorageClass = = IMAGE_SYM_CLASS_NULL ) & & ( symbol . SectionNumber = = removalStrategy ) ) ;
}
return false ;
}
bool IsSelectAnyComdatSection ( const RawCoff * rawCoff , size_t sectionIndex )
{
return ( rawCoff - > sections [ sectionIndex ] . isSelectAnyComdat ) ;
}
static types : : vector < std : : string > TokenizeLinkerDirectives ( const char * sectionData , size_t size )
{
types : : vector < std : : string > directives ;
// gather all linker commands by tokenizing raw data.
// individual commands are separated by spaces.
const char * start = sectionData ;
for ( size_t i = 0u ; i < size ; + + i )
{
// look for spaces
if ( sectionData [ i ] = = ' ' )
{
if ( sectionData + i > start )
{
std : : string directive ( start , sectionData + i ) ;
directives . emplace_back ( directive ) ;
}
start = sectionData + i + 1u ;
}
}
return directives ;
}
template < coffDetail : : CoffType : : Enum Type >
2020-12-15 09:27:44 -04:00
static types : : vector < std : : string > ExtractLinkerDirectives ( const ObjFile * objFile )
2019-03-05 18:49:25 -05:00
{
2019-08-22 10:52:35 -04:00
using CoffHeader = typename coffDetail : : CoffType : : TypeMap < Type > : : HeaderType ;
2019-03-05 18:49:25 -05:00
2020-12-15 09:27:44 -04:00
const void * objFileBase = Filesystem : : GetMemoryMappedFileData ( objFile - > memoryFile ) ;
const uint32_t sectionCount = coffDetail : : GetNumberOfSections < CoffHeader > ( objFileBase ) ;
const IMAGE_SECTION_HEADER * sectionHeader = coffDetail : : GetSectionHeader < CoffHeader > ( objFileBase ) ;
2019-03-05 18:49:25 -05:00
for ( unsigned int i = 0u ; i < sectionCount ; + + i )
{
const IMAGE_SECTION_HEADER * section = sectionHeader + i ;
if ( coffDetail : : IsDirectiveSection ( section ) )
{
2020-12-15 09:27:44 -04:00
const char * rawData = pointer : : Offset < const char * > ( objFileBase , section - > PointerToRawData ) ;
2019-03-05 18:49:25 -05:00
return TokenizeLinkerDirectives ( rawData , section - > SizeOfRawData ) ;
}
}
return types : : vector < std : : string > ( ) ;
}
types : : vector < std : : string > ExtractLinkerDirectives ( const ObjFile * file )
{
2020-12-15 09:27:44 -04:00
const coffDetail : : CoffType : : Enum type = coffDetail : : GetCoffType ( Filesystem : : GetMemoryMappedFileData ( file - > memoryFile ) ) ;
2019-03-05 18:49:25 -05:00
if ( type = = coffDetail : : CoffType : : COFF )
{
return ExtractLinkerDirectives < coffDetail : : CoffType : : COFF > ( file ) ;
}
else if ( type = = coffDetail : : CoffType : : BIGOBJ )
{
return ExtractLinkerDirectives < coffDetail : : CoffType : : BIGOBJ > ( file ) ;
}
return types : : vector < std : : string > ( ) ;
}
types : : vector < std : : string > ExtractLinkerDirectives ( const RawCoff * rawCoff )
{
const size_t sectionCount = rawCoff - > sections . size ( ) ;
for ( size_t i = 0u ; i < sectionCount ; + + i )
{
const RawSection & section = rawCoff - > sections [ i ] ;
if ( coffDetail : : IsDirectiveSection ( & section . header ) )
{
return TokenizeLinkerDirectives ( static_cast < const char * > ( section . data ) , section . header . SizeOfRawData ) ;
}
}
return types : : vector < std : : string > ( ) ;
}
void ReplaceLinkerDirectives ( RawCoff * rawCoff , const types : : vector < std : : string > & directives )
{
const size_t sectionCount = rawCoff - > sections . size ( ) ;
for ( size_t i = 0u ; i < sectionCount ; + + i )
{
RawSection & section = rawCoff - > sections [ i ] ;
if ( coffDetail : : IsDirectiveSection ( & section . header ) )
{
std : : string newDirectives ;
newDirectives . reserve ( 1024u ) ;
// separate directives with spaces
const size_t count = directives . size ( ) ;
for ( size_t j = 0u ; j < count ; + + j )
{
newDirectives + = directives [ j ] ;
newDirectives + = ' ' ;
}
LC_FREE ( & g_rawCoffAllocator , section . data , section . header . SizeOfRawData ) ;
section . header . SizeOfRawData = static_cast < DWORD > ( newDirectives . length ( ) ) ;
section . data = LC_ALLOC ( & g_rawCoffAllocator , newDirectives . length ( ) , 8u ) ;
memcpy ( section . data , newDirectives . data ( ) , newDirectives . length ( ) ) ;
// we assume that there's only one directive section in a COFF file
return ;
}
}
}
2022-08-08 11:29:32 -04:00
template < typename RawCoffType >
static void PatchFunctionSymbol ( RawCoffType * rawCoff , size_t symbolIndex , uint32_t sectionIndex )
{
LC_LOG_DEV ( " Patching function symbol %d (%s) " , symbolIndex , rawCoff - > stringTable [ symbolIndex ] . c_str ( ) ) ;
coff : : RawSection & section = rawCoff - > sections [ sectionIndex ] ;
uint8_t * code = static_cast < uint8_t * > ( section . data ) ;
code [ 0 ] = Assembler : : Opcode : : RET [ 0 ] ;
}
void PatchFunctionSymbol ( RawCoff * rawCoff , size_t symbolIndex , uint32_t sectionIndex )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
PatchFunctionSymbol ( static_cast < RawCoffRegular * > ( rawCoff ) , symbolIndex , sectionIndex ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
PatchFunctionSymbol ( static_cast < RawCoffBigObj * > ( rawCoff ) , symbolIndex , sectionIndex ) ;
}
}
2019-03-05 18:49:25 -05:00
template < typename RawCoffType >
static void RemoveSymbol ( RawCoffType * rawCoff , size_t symbolIndex , SymbolRemovalStrategy : : Enum removalStrategy )
{
LC_LOG_DEV ( " Removing symbol %d (%s) " , symbolIndex , rawCoff - > stringTable [ symbolIndex ] . c_str ( ) ) ;
auto & symbol = rawCoff - > symbols [ symbolIndex ] ;
symbol . Type = IMAGE_SYM_TYPE_NULL ;
symbol . StorageClass = IMAGE_SYM_CLASS_NULL ;
// rather than removing the symbol, we fake the removed symbol by putting it in an "appropriate" section.
// we need two different strategies, depending on the linker used.
// MSVC can be tricked by putting the symbol into the debug section, but LLD will report
// "error: relocation against symbol in discarded section" in this case.
// LLD can be tricked by putting the symbol into an absolute section, but MSVC will report
// "error LNK2016: absolute symbol '&' used as target of REL32 relocation in section" in this case.
symbol . SectionNumber = removalStrategy ;
symbol . Value = 0u ;
// replace the symbol name with the shortest possible (illegal in C++) identifier
memcpy ( symbol . N . ShortName , " & " , 2u ) ;
}
void RemoveSymbol ( RawCoff * rawCoff , size_t symbolIndex , SymbolRemovalStrategy : : Enum removalStrategy )
{
if ( rawCoff - > type = = RawCoffRegular : : TYPE )
{
RemoveSymbol ( static_cast < RawCoffRegular * > ( rawCoff ) , symbolIndex , removalStrategy ) ;
}
else if ( rawCoff - > type = = RawCoffBigObj : : TYPE )
{
RemoveSymbol ( static_cast < RawCoffBigObj * > ( rawCoff ) , symbolIndex , removalStrategy ) ;
}
}
void RemoveRelocations ( RawCoff * rawCoff , size_t symbolIndex )
{
LC_LOG_DEV ( " Removing relocations pointing to symbol %d (%s) " , symbolIndex , rawCoff - > stringTable [ symbolIndex ] . c_str ( ) ) ;
for ( size_t i = 0u ; i < rawCoff - > sections . size ( ) ; + + i )
{
RawSection & section = rawCoff - > sections [ i ] ;
for ( auto it = section . relocations . begin ( ) ; it ! = section . relocations . end ( ) ; /*nothing*/ )
{
const IMAGE_RELOCATION & relocation = * it ;
if ( relocation . SymbolTableIndex = = symbolIndex )
{
it = section . relocations . erase ( it ) ;
}
else
{
+ + it ;
}
}
}
}
void RemoveSection ( RawCoff * rawCoff , size_t sectionIndex )
{
LC_LOG_DEV ( " Removing section %d (%s) " , sectionIndex , GetSectionName ( rawCoff - > rawStringTable . data , & rawCoff - > sections [ sectionIndex ] . header ) . c_str ( ) ) ;
// rather than really removing the section, we make it zero-sized without raw data, relocations, or line numbers.
// otherwise, we would have to update the section numbers of all symbols for each removed section, which could
// get complicated if we want to do it efficiently.
RawSection & section = rawCoff - > sections [ sectionIndex ] ;
LC_FREE ( & g_rawCoffAllocator , section . data , section . header . SizeOfRawData ) ;
section . header . SizeOfRawData = 0u ;
section . header . PointerToRawData = 0u ;
section . data = nullptr ;
section . header . NumberOfRelocations = 0u ;
section . header . PointerToRelocations = 0u ;
section . relocations . clear ( ) ;
section . header . NumberOfLinenumbers = 0u ;
section . header . PointerToLinenumbers = 0u ;
section . lineNumbers . clear ( ) ;
// furthermore, we also rename the section and set our own flags that tell the linker that this section
// can and should be discarded.
memcpy ( section . header . Name , " .remove " , 8u ) ;
section . header . Characteristics = IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_MEM_DISCARDABLE ;
section . wasRemoved = true ;
}
void RemoveAssociatedComdatSections ( RawCoff * rawCoff , size_t sectionIndex )
{
LC_LOG_DEV ( " Removing COMDAT sections associated with section %d " , sectionIndex ) ;
LC_LOG_INDENT_DEV ;
const types : : vector < uint32_t > & associatedSections = rawCoff - > associatedComdatSections [ static_cast < uint32_t > ( sectionIndex ) ] ;
const size_t count = associatedSections . size ( ) ;
for ( size_t i = 0u ; i < count ; + + i )
{
RemoveSection ( rawCoff , associatedSections [ i ] ) ;
}
}
template < coffDetail : : CoffType : : Enum Type >
2020-12-15 09:27:44 -04:00
static CoffDB * GatherDatabase ( ObjFile * objFile , uint32_t uniqueId )
2019-03-05 18:49:25 -05:00
{
2019-08-22 10:52:35 -04:00
using CoffHeader = typename coffDetail : : CoffType : : TypeMap < Type > : : HeaderType ;
using CoffSymbol = typename coffDetail : : CoffType : : TypeMap < Type > : : SymbolType ;
using CoffAuxSymbol = typename coffDetail : : CoffType : : TypeMap < Type > : : AuxSymbolType ;
2019-03-05 18:49:25 -05:00
CoffDB * coffDb = new CoffDB ;
coffDb - > symbolAllocator = new PoolAllocator < PoolAllocatorSingleThreadPolicy > ( " COFF symbols " , sizeof ( coff : : Symbol ) , alignof ( coff : : Symbol ) , 8192u ) ;
coffDb - > relocationAllocator = new PoolAllocator < PoolAllocatorSingleThreadPolicy > ( " Relocations " , sizeof ( coff : : Relocation ) , alignof ( coff : : Relocation ) , 8192u ) ;
2020-12-15 09:27:44 -04:00
const void * objFileBase = Filesystem : : GetMemoryMappedFileData ( objFile - > memoryFile ) ;
const uint32_t sectionCount = coffDetail : : GetNumberOfSections < CoffHeader > ( objFileBase ) ;
const uint32_t symbolCount = coffDetail : : GetNumberOfSymbols < CoffHeader > ( objFileBase ) ;
const IMAGE_SECTION_HEADER * sectionHeader = coffDetail : : GetSectionHeader < CoffHeader > ( objFileBase ) ;
const void * symbolTable = coffDetail : : GetSymbolTable < CoffHeader > ( objFileBase ) ;
2019-03-05 18:49:25 -05:00
const char * stringTable = coffDetail : : GetStringTable < CoffSymbol > ( symbolTable , symbolCount ) ;
// pre-allocate data structures
coffDb - > sections . resize ( sectionCount ) ;
coffDb - > stringTable . resize ( symbolCount ) ;
coffDb - > symbols . reserve ( symbolCount ) ;
// temporarily hold symbols per section in order to make assigning relocations to symbols easier
types : : vector < types : : vector < Symbol * > > symbolsForSection ;
symbolsForSection . resize ( sectionCount ) ;
// grab all sections and store CRT sections in a separate data structure, because they are needed for
// finding dynamic initializers. we additionally use a lookup-table to make assigning symbols to CRT
// sections faster.
types : : vector < uint32_t > lutSectionIndexToCrtSection ;
lutSectionIndexToCrtSection . resize ( sectionCount , INVALID_CRT_SECTION ) ;
for ( unsigned int i = 0u ; i < sectionCount ; + + i )
{
const IMAGE_SECTION_HEADER * section = sectionHeader + i ;
Section & s = coffDb - > sections [ i ] ;
s . name = GetSectionName ( stringTable , section ) ;
s . rawDataSize = section - > SizeOfRawData ;
s . rawDataRva = section - > PointerToRawData ;
s . characteristics = section - > Characteristics ;
s . comdatSelection = 0u ;
// store CRT sections in a separate data structure, they are needed for finding dynamic initializers
if ( string : : Contains ( s . name . c_str ( ) , " .CRT$ " ) )
{
// add this section to the lookup-table
lutSectionIndexToCrtSection [ i ] = static_cast < uint32_t > ( coffDb - > crtSections . size ( ) ) ;
2020-12-15 09:27:44 -04:00
const CrtSection crtSection { s . name , section - > SizeOfRawData , section - > PointerToRawData , { } } ;
2019-03-05 18:49:25 -05:00
coffDb - > crtSections . push_back ( crtSection ) ;
}
// we would like to reserve space for the symbols of each section to avoid allocations where possible.
// because we don't know yet how many symbols a section holds, using the number of relocations is a
// good approximation.
2020-12-15 09:27:44 -04:00
const unsigned int relocationCount = coffDetail : : GetRelocationCount ( objFileBase , section ) ;
2019-03-05 18:49:25 -05:00
symbolsForSection [ i ] . reserve ( relocationCount ) ;
}
// unfortunately, some compilers such as VS 2013 and earlier do *not* generate fully unique names in COFFs
// for certain symbols.
// the simplest example are static (internal) data symbols with the same name in different namespaces:
// namespace a
// {
// static int g_counter = 10;
// }
// namespace b
// {
// static int g_counter = 20;
// }
// the corresponding COFF file will have two symbols that are both named "g_counter", so there is no way
// to distinguish them. at least the compiler only does this for data symbols, never for function symbols.
// this means that we need to keep track of non-unique data symbols and try to fix them accordingly.
types : : StringMap < uint16_t > uniqueStaticDataSymbols ;
uniqueStaticDataSymbols . reserve ( 16u ) ;
for ( unsigned int i = 0u ; i < symbolCount ; + + i )
{
const CoffSymbol * symbol = coffDetail : : GetSymbol < CoffSymbol > ( symbolTable , i ) ;
// ignore absolute, debug and section symbols
if ( coffDetail : : IsAbsoluteSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsDebugSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsUndefinedSymbol ( symbol ) )
{
2020-12-15 09:27:44 -04:00
coffDb - > stringTable [ i ] = GetSymbolName ( stringTable , symbol , uniqueId , 0u ) ;
2019-03-05 18:49:25 -05:00
}
else if ( coffDetail : : IsSectionSymbol ( symbol ) )
{
// if this is a COMDAT section, grab its selection number from the auxiliary record
const uint32_t sectionIndex = coffDetail : : GetSectionIndex ( symbol ) ;
const IMAGE_SECTION_HEADER * section = sectionHeader + sectionIndex ;
if ( coffDetail : : IsComdatSection ( section ) )
{
// the auxiliary record holds information about the COMDAT section. according to the COFF spec 5.5.6,
// a COMDAT section always has one auxiliary record which is "the COMDAT symbol".
if ( symbol - > NumberOfAuxSymbols = = 1u )
{
const CoffAuxSymbol * auxSymbol = coffDetail : : GetSymbol < CoffAuxSymbol > ( symbolTable , i + 1u ) ;
coffDb - > sections [ sectionIndex ] . comdatSelection = auxSymbol - > Section . Selection ;
}
}
2020-12-15 09:27:44 -04:00
coffDb - > stringTable [ i ] = GetSectionName ( stringTable , section ) ;
2019-03-05 18:49:25 -05:00
}
else
{
// this symbol is stored in the COFF.
2020-12-15 09:27:44 -04:00
coffDb - > stringTable [ i ] = GetSymbolName ( stringTable , symbol , uniqueId , 0u ) ;
2019-03-05 18:49:25 -05:00
const ImmutableString & name = coffDb - > stringTable [ i ] ;
// we are not interested in certain types of symbols.
// they never store any relocations and don't convey any kind of meaningful information regarding
// relocations.
if ( ! coffDetail : : IsLabelSymbol ( symbol ) & & IsInterestingSymbol ( name ) )
{
const uint32_t sectionIndex = coffDetail : : GetSectionIndex ( symbol ) ;
const IMAGE_SECTION_HEADER * section = sectionHeader + sectionIndex ;
const uint32_t rva = section - > PointerToRawData + symbol - > Value ;
const SymbolType : : Enum type = DetermineSymbolType ( symbol ) ;
2020-12-15 09:27:44 -04:00
Symbol * newSymbol = LC_NEW ( coffDb - > symbolAllocator , Symbol ) { i , rva , sectionIndex , type , { } } ;
2019-03-05 18:49:25 -05:00
newSymbol - > relocations . reserve ( 32u ) ;
coffDb - > symbols . push_back ( newSymbol ) ;
// add the symbol to the corresponding CRT section, if any
const uint32_t crtSectionIndex = lutSectionIndexToCrtSection [ sectionIndex ] ;
if ( crtSectionIndex ! = INVALID_CRT_SECTION )
{
CrtSection & crtSection = coffDb - > crtSections [ crtSectionIndex ] ;
crtSection . symbols . push_back ( newSymbol ) ;
}
if ( type = = SymbolType : : STATIC_DATA )
{
// make sure this symbol is unique
auto insertIterator = uniqueStaticDataSymbols . emplace ( name , static_cast < uint16_t > ( 0u ) ) ;
if ( insertIterator . second = = false )
{
// the name of this symbol is not unique, inform the user.
// when compiling with control-flow guard (CFG), the compiler will generate
// non-unique __guard_fids__ symbols - ignore those.
const ImmutableString & symbolName = GetSymbolName ( stringTable , symbol ) ;
if ( ! string : : Matches ( symbolName . c_str ( ) , " __guard_fids__ " ) )
{
2020-12-11 14:21:20 -04:00
// BEGIN EPIC MOD
// VS2019 seems to generate duplicate unwind and pdata block for the "dynamic atexit destructor" method (__F) under some conditions that I can't determine.
2021-06-10 08:48:47 -04:00
// Also, do not generate warnings for symbols in COMDATs
if ( ! coffDetail : : IsComdatSection ( section ) )
2020-12-11 14:21:20 -04:00
{
2021-06-10 08:48:47 -04:00
if ( ! string : : StartsWith ( symbolName . c_str ( ) , " $unwind$??__F " ) & &
! string : : StartsWith ( symbolName . c_str ( ) , " $pdata$??__F " ) )
{
LC_WARNING_USER ( " Non-unique symbol %s found in COFF file %s. Do not change the order of these variables while live coding, or consider upgrading to a newer compiler (VS 2015 or later) " ,
symbolName . c_str ( ) , objFile - > filename . c_str ( ) ) ;
}
else
{
LC_LOG_USER ( " Non-unique at-exit symbol %s found in COFF file %s. These sometimes appear in debug builds " ,
symbolName . c_str ( ) , objFile - > filename . c_str ( ) ) ;
}
2020-12-11 14:21:20 -04:00
}
// END EPIC MOD
2019-03-05 18:49:25 -05:00
}
// as a workaround, try generating a unique name for it.
// this does not fix potential issues in all cases, but works successfully in cases where
// this compiland is never recompiled, or where the order of variables in the file doesn't change.
// increase the counter associated with this name and generate a new name from it
+ + insertIterator . first - > second ;
2020-12-15 09:27:44 -04:00
coffDb - > stringTable [ i ] = GetSymbolName ( stringTable , symbol , uniqueId , insertIterator . first - > second ) ;
2019-03-05 18:49:25 -05:00
}
}
symbolsForSection [ sectionIndex ] . push_back ( newSymbol ) ;
}
}
// skip auxiliary symbols
const BYTE auxSymbolCount = symbol - > NumberOfAuxSymbols ;
i + = auxSymbolCount ;
}
// walk through all relocations
{
for ( unsigned int i = 0u ; i < sectionCount ; + + i )
{
const IMAGE_SECTION_HEADER * section = sectionHeader + i ;
// ignore relocations inside sections that will either not be part of the final image, or can be
// discarded at will. those are mostly ".drectve" and ".debug" sections.
if ( coffDetail : : IsDiscardableSection ( section ) )
{
continue ;
}
if ( ! coffDetail : : IsPartOfImage ( section ) )
{
continue ;
}
2020-12-15 09:27:44 -04:00
const unsigned int relocationCount = coffDetail : : GetRelocationCount ( objFileBase , section ) ;
const IMAGE_RELOCATION * relocations = pointer : : Offset < const IMAGE_RELOCATION * > ( objFileBase , section - > PointerToRelocations ) ;
2019-03-05 18:49:25 -05:00
const types : : vector < Symbol * > & symbolsForCurrentSection = symbolsForSection [ i ] ;
if ( symbolsForCurrentSection . size ( ) = = 0u )
{
// this section does not hold any symbols to which we could assign relocations
continue ;
}
// sort symbols in this section by RVA in order to make associating relocations with symbols much easier
std : : sort ( symbolsForSection [ i ] . begin ( ) , symbolsForSection [ i ] . end ( ) , & SortSymbolByAscendingRVA ) ;
unsigned int currentSymbolIndex = 0u ;
// if relocation count in section has overflown, ignore the first relocation
const unsigned int startRelocation = ( relocationCount > 0xFFFFu ) ? 1u : 0u ;
for ( unsigned int j = 0u ; j < relocationCount - startRelocation ; + + j )
{
const IMAGE_RELOCATION * relocation = relocations + j + startRelocation ;
// ignore debug relocations
if ( coffDetail : : IsDebugRelocation ( relocation ) )
{
continue ;
}
const CoffSymbol * symbol = coffDetail : : GetSymbol < CoffSymbol > ( symbolTable , relocation - > SymbolTableIndex ) ;
const ImmutableString & dstSymbolName = coffDb - > stringTable [ relocation - > SymbolTableIndex ] ;
// ignore relocations to line numbers and string literals
if ( ! IsInterestingSymbol ( dstSymbolName ) )
{
continue ;
}
else if ( symbols : : IsRttiObjectLocator ( dstSymbolName ) )
{
// RTTI Complete Object Locators are a strange thing.
// they are always located before the first entry in the vtable, but they cannot be found using the vtable
// symbol because that symbol starts at "section + 4", "skipping" the object locator.
// example:
// symbol "const SFV_Base::`vftable'" (??_7SFV_Base@@6B@)" has relocations to:
// 00000000 ??_R4SFV_Base@@6B@ (const SFV_Base::`RTTI Complete Object Locator')
// 00000004 ??_ESFV_Base@@UAEPAXI@Z (public: virtual void * __thiscall SFV_Base::`vector deleting destructor'(unsigned int))
// 00000008 ?TestFunction@SFV_Base@@UAEXXZ (public: virtual void __thiscall SFV_Base::TestFunction(void))
// according to the symbol table, the vtable symbol sits in section .rdata, #1E, but at offset 4:
// 00000004 SECT1E External ??_7SFV_Base@@6B@ (const SFV_Base::`vftable')
// this means that we don't have a symbol for which we can store this relocation.
// it would be vtable - 4, but we don't handle that. it doesn't matter because the object locators
// are public symbols anyway.
continue ;
}
const DWORD relocationRva = section - > PointerToRawData + relocation - > VirtualAddress ;
// find the symbol that contains this relocation and determine the RVA relative to the start
// of the data or function. note that walking through the symbols of this section like this only
// works because both the relocations as well as the symbols are sorted by their RVA.
while ( currentSymbolIndex < symbolsForCurrentSection . size ( ) - 1u )
{
const uint32_t nextIndex = currentSymbolIndex + 1u ;
const uint32_t nextSymbolRva = symbolsForCurrentSection [ nextIndex ] - > rva ;
if ( relocationRva < nextSymbolRva )
{
// found symbol that holds this relocation
break ;
}
// relocation does not belong to this symbol, but possibly to the next
currentSymbolIndex = nextIndex ;
}
Symbol * srcSymbol = symbolsForCurrentSection [ currentSymbolIndex ] ;
if ( relocationRva < srcSymbol - > rva )
{
2020-12-15 09:27:44 -04:00
LC_ERROR_DEV ( " Cannot find symbol that contains relocation at 0x%X for destination symbol %s in file %s " , relocationRva , dstSymbolName . c_str ( ) , objFile - > filename . c_str ( ) ) ;
2019-03-05 18:49:25 -05:00
continue ;
}
// RVA relative to the RVA of the symbol that holds the relocation
const uint32_t srcRva = relocationRva - srcSymbol - > rva ;
const int32_t sectionIndex = symbol - > SectionNumber - 1 ;
switch ( relocation - > Type )
{
case Relocation : : Type : : SECTION_RELATIVE :
case Relocation : : Type : : RELATIVE :
case Relocation : : Type : : VA_32 :
case Relocation : : Type : : RVA_32 :
# if LC_64_BIT
case Relocation : : Type : : RELATIVE_OFFSET_1 :
case Relocation : : Type : : RELATIVE_OFFSET_2 :
case Relocation : : Type : : RELATIVE_OFFSET_3 :
case Relocation : : Type : : RELATIVE_OFFSET_4 :
case Relocation : : Type : : RELATIVE_OFFSET_5 :
# endif
{
2020-12-15 09:27:44 -04:00
const uint32_t * relocationAddress = pointer : : Offset < const uint32_t * > ( objFileBase , relocationRva ) ;
2019-03-05 18:49:25 -05:00
const uint32_t destinationOffset = * relocationAddress ;
Relocation * newRelocation = LC_NEW ( coffDb - > relocationAllocator , Relocation )
{
relocation - > SymbolTableIndex ,
srcRva ,
destinationOffset ,
sectionIndex ,
static_cast < Relocation : : Type : : Enum > ( relocation - > Type ) ,
srcSymbol - > type ,
2020-12-15 09:27:44 -04:00
DetermineSymbolType ( symbol ) ,
coffDetail : : IsSectionSymbol ( symbol )
2019-03-05 18:49:25 -05:00
} ;
srcSymbol - > relocations . emplace_back ( newRelocation ) ;
}
break ;
# if LC_64_BIT
case Relocation : : Type : : VA_64 :
{
2020-12-15 09:27:44 -04:00
const uint64_t * relocationAddress = pointer : : Offset < const uint64_t * > ( objFileBase , relocationRva ) ;
2019-03-05 18:49:25 -05:00
// read the destination offset as 64-bit, but convert it into a 32-bit offset.
// no symbol can ever be larger than 4 GB.
const uint64_t destinationOffset = * relocationAddress ;
Relocation * newRelocation = LC_NEW ( coffDb - > relocationAllocator , Relocation )
{
relocation - > SymbolTableIndex ,
srcRva ,
static_cast < uint32_t > ( destinationOffset ) ,
sectionIndex ,
static_cast < Relocation : : Type : : Enum > ( relocation - > Type ) ,
srcSymbol - > type ,
2020-12-15 09:27:44 -04:00
DetermineSymbolType ( symbol ) ,
coffDetail : : IsSectionSymbol ( symbol )
2019-03-05 18:49:25 -05:00
} ;
srcSymbol - > relocations . emplace_back ( newRelocation ) ;
}
break ;
# endif
default :
LC_ERROR_DEV ( " Unknown relocation %d " , relocation - > Type ) ;
break ;
} ;
}
}
}
// minimize amount of memory needed and generate lookup table
coffDb - > symbols . shrink_to_fit ( ) ;
{
coffDb - > indexToSymbol . resize ( symbolCount ) ;
const size_t count = coffDb - > symbols . size ( ) ;
for ( size_t i = 0u ; i < count ; + + i )
{
Symbol * symbol = coffDb - > symbols [ i ] ;
symbol - > relocations . shrink_to_fit ( ) ;
coffDb - > indexToSymbol [ symbol - > nameIndex ] = symbol ;
}
}
// sort symbols in CRT sections by RVA
{
const size_t count = coffDb - > crtSections . size ( ) ;
for ( size_t i = 0u ; i < count ; + + i )
{
std : : sort ( coffDb - > crtSections [ i ] . symbols . begin ( ) , coffDb - > crtSections [ i ] . symbols . end ( ) , & SortSymbolByAscendingRVA ) ;
}
}
return coffDb ;
}
2020-12-15 09:27:44 -04:00
CoffDB * GatherDatabase ( ObjFile * file , uint32_t uniqueId )
2019-03-05 18:49:25 -05:00
{
2020-12-15 09:27:44 -04:00
const coffDetail : : CoffType : : Enum type = coffDetail : : GetCoffType ( Filesystem : : GetMemoryMappedFileData ( file - > memoryFile ) ) ;
2019-03-05 18:49:25 -05:00
if ( type = = coffDetail : : CoffType : : COFF )
{
2020-12-15 09:27:44 -04:00
return GatherDatabase < coffDetail : : CoffType : : COFF > ( file , uniqueId ) ;
2019-03-05 18:49:25 -05:00
}
else if ( type = = coffDetail : : CoffType : : BIGOBJ )
{
2020-12-15 09:27:44 -04:00
return GatherDatabase < coffDetail : : CoffType : : BIGOBJ > ( file , uniqueId ) ;
2019-03-05 18:49:25 -05:00
}
return nullptr ;
}
void DestroyDatabase ( CoffDB * db )
{
const size_t count = db - > symbols . size ( ) ;
for ( size_t i = 0u ; i < count ; + + i )
{
Symbol * symbol = db - > symbols [ i ] ;
const size_t relocationCount = symbol - > relocations . size ( ) ;
for ( size_t j = 0u ; j < relocationCount ; + + j )
{
Relocation * relocation = symbol - > relocations [ j ] ;
LC_DELETE ( db - > relocationAllocator , relocation , sizeof ( Relocation ) ) ;
}
LC_DELETE ( db - > symbolAllocator , symbol , sizeof ( Symbol ) ) ;
}
delete db - > symbolAllocator ;
delete db - > relocationAllocator ;
delete db ;
}
template < coffDetail : : CoffType : : Enum Type >
2020-12-15 09:27:44 -04:00
static UnresolvedSymbolDB * GatherUnresolvedSymbolDatabase ( ObjFile * objFile , uint32_t uniqueId )
2019-03-05 18:49:25 -05:00
{
2019-08-22 10:52:35 -04:00
using CoffHeader = typename coffDetail : : CoffType : : TypeMap < Type > : : HeaderType ;
using CoffSymbol = typename coffDetail : : CoffType : : TypeMap < Type > : : SymbolType ;
2019-03-05 18:49:25 -05:00
UnresolvedSymbolDB * symbolDb = new UnresolvedSymbolDB ;
2020-12-15 09:27:44 -04:00
const void * objFileBase = Filesystem : : GetMemoryMappedFileData ( objFile - > memoryFile ) ;
2019-03-05 18:49:25 -05:00
2020-12-15 09:27:44 -04:00
const uint32_t symbolCount = coffDetail : : GetNumberOfSymbols < CoffHeader > ( objFileBase ) ;
const void * symbolTable = coffDetail : : GetSymbolTable < CoffHeader > ( objFileBase ) ;
const char * stringTable = coffDetail : : GetStringTable < CoffSymbol > ( symbolTable , symbolCount ) ;
2019-03-05 18:49:25 -05:00
// pre-allocate data structures
symbolDb - > symbols . reserve ( symbolCount ) ;
symbolDb - > symbolIndex . reserve ( symbolCount ) ;
for ( uint32_t i = 0u ; i < symbolCount ; + + i )
{
const CoffSymbol * symbol = coffDetail : : GetSymbol < CoffSymbol > ( symbolTable , i ) ;
// ignore absolute, debug and section symbols
if ( coffDetail : : IsAbsoluteSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsDebugSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsUndefinedSymbol ( symbol ) )
{
2020-12-15 09:27:44 -04:00
ImmutableString name = GetSymbolName ( stringTable , symbol , uniqueId , 0u ) ;
2019-03-05 18:49:25 -05:00
symbolDb - > symbols . emplace_back ( std : : move ( name ) ) ;
symbolDb - > symbolIndex . emplace_back ( i ) ;
}
else if ( coffDetail : : IsSectionSymbol ( symbol ) )
{
}
// skip auxiliary symbols
const BYTE auxSymbolCount = symbol - > NumberOfAuxSymbols ;
i + = auxSymbolCount ;
}
return symbolDb ;
}
2020-12-15 09:27:44 -04:00
UnresolvedSymbolDB * GatherUnresolvedSymbolDatabase ( ObjFile * file , uint32_t uniqueId )
2019-03-05 18:49:25 -05:00
{
2020-12-15 09:27:44 -04:00
const coffDetail : : CoffType : : Enum type = coffDetail : : GetCoffType ( Filesystem : : GetMemoryMappedFileData ( file - > memoryFile ) ) ;
2019-03-05 18:49:25 -05:00
if ( type = = coffDetail : : CoffType : : COFF )
{
2020-12-15 09:27:44 -04:00
return GatherUnresolvedSymbolDatabase < coffDetail : : CoffType : : COFF > ( file , uniqueId ) ;
2019-03-05 18:49:25 -05:00
}
else if ( type = = coffDetail : : CoffType : : BIGOBJ )
{
2020-12-15 09:27:44 -04:00
return GatherUnresolvedSymbolDatabase < coffDetail : : CoffType : : BIGOBJ > ( file , uniqueId ) ;
2019-03-05 18:49:25 -05:00
}
return nullptr ;
}
void DestroyDatabase ( UnresolvedSymbolDB * db )
{
delete db ;
}
template < coffDetail : : CoffType : : Enum Type >
2020-12-15 09:27:44 -04:00
static ExternalSymbolDB * GatherExternalSymbolDatabase ( ObjFile * objFile , uint32_t uniqueId )
2019-03-05 18:49:25 -05:00
{
2019-08-22 10:52:35 -04:00
using CoffHeader = typename coffDetail : : CoffType : : TypeMap < Type > : : HeaderType ;
using CoffSymbol = typename coffDetail : : CoffType : : TypeMap < Type > : : SymbolType ;
2019-03-05 18:49:25 -05:00
ExternalSymbolDB * symbolDb = new ExternalSymbolDB ;
2020-12-15 09:27:44 -04:00
const void * objFileBase = Filesystem : : GetMemoryMappedFileData ( objFile - > memoryFile ) ;
2019-03-05 18:49:25 -05:00
2020-12-15 09:27:44 -04:00
const uint32_t symbolCount = coffDetail : : GetNumberOfSymbols < CoffHeader > ( objFileBase ) ;
const void * symbolTable = coffDetail : : GetSymbolTable < CoffHeader > ( objFileBase ) ;
const char * stringTable = coffDetail : : GetStringTable < CoffSymbol > ( symbolTable , symbolCount ) ;
2019-03-05 18:49:25 -05:00
// pre-allocate data structures
symbolDb - > symbols . reserve ( symbolCount ) ;
symbolDb - > types . reserve ( symbolCount ) ;
for ( uint32_t i = 0u ; i < symbolCount ; + + i )
{
const CoffSymbol * symbol = coffDetail : : GetSymbol < CoffSymbol > ( symbolTable , i ) ;
// ignore absolute, debug, section and undefined symbols
if ( coffDetail : : IsAbsoluteSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsDebugSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsUndefinedSymbol ( symbol ) )
{
}
else if ( coffDetail : : IsSectionSymbol ( symbol ) )
{
}
else
{
const SymbolType : : Enum type = DetermineSymbolType ( symbol ) ;
if ( ( type = = SymbolType : : EXTERNAL_DATA ) | | ( type = = SymbolType : : EXTERNAL_FUNCTION ) )
{
// this is an external symbol stored in the COFF
2020-12-15 09:27:44 -04:00
ImmutableString name = GetSymbolName ( stringTable , symbol , uniqueId , 0u ) ;
2019-03-05 18:49:25 -05:00
symbolDb - > symbols . emplace_back ( std : : move ( name ) ) ;
symbolDb - > types . emplace_back ( type ) ;
}
}
// skip auxiliary symbols
const BYTE auxSymbolCount = symbol - > NumberOfAuxSymbols ;
i + = auxSymbolCount ;
}
return symbolDb ;
}
2020-12-15 09:27:44 -04:00
ExternalSymbolDB * GatherExternalSymbolDatabase ( ObjFile * file , uint32_t uniqueId )
2019-03-05 18:49:25 -05:00
{
2020-12-15 09:27:44 -04:00
const coffDetail : : CoffType : : Enum type = coffDetail : : GetCoffType ( Filesystem : : GetMemoryMappedFileData ( file - > memoryFile ) ) ;
2019-03-05 18:49:25 -05:00
if ( type = = coffDetail : : CoffType : : COFF )
{
2020-12-15 09:27:44 -04:00
return GatherExternalSymbolDatabase < coffDetail : : CoffType : : COFF > ( file , uniqueId ) ;
2019-03-05 18:49:25 -05:00
}
else if ( type = = coffDetail : : CoffType : : BIGOBJ )
{
2020-12-15 09:27:44 -04:00
return GatherExternalSymbolDatabase < coffDetail : : CoffType : : BIGOBJ > ( file , uniqueId ) ;
2019-03-05 18:49:25 -05:00
}
return nullptr ;
}
void DestroyDatabase ( ExternalSymbolDB * db )
{
delete db ;
}
size_t GetIndexCount ( const CoffDB * coffDb )
{
return coffDb - > indexToSymbol . size ( ) ;
}
const Symbol * GetSymbolByIndex ( const CoffDB * coffDb , size_t index )
{
return coffDb - > indexToSymbol [ index ] ;
}
const ImmutableString & GetSymbolName ( const CoffDB * coffDb , const Symbol * symbol )
{
return coffDb - > stringTable [ symbol - > nameIndex ] ;
}
const ImmutableString & GetRelocationDstSymbolName ( const CoffDB * coffDb , const Relocation * relocation )
{
return coffDb - > stringTable [ relocation - > dstSymbolNameIndex ] ;
}
const ImmutableString & GetUnresolvedSymbolName ( const CoffDB * coffDb , size_t unresolvedSymbolIndex )
{
return coffDb - > stringTable [ unresolvedSymbolIndex ] ;
}
SymbolType : : Enum GetRelocationSrcSymbolType ( const Relocation * relocation )
{
return relocation - > srcSymbolType ;
}
SymbolType : : Enum GetRelocationDstSymbolType ( const Relocation * relocation )
{
return relocation - > dstSymbolType ;
}
const CrtSection * FindCrtSection ( const CoffDB * coffDb , const ImmutableString & sectionName , uint32_t sectionSize )
{
const CrtSection * foundSection = nullptr ;
const size_t count = coffDb - > crtSections . size ( ) ;
for ( size_t i = 0u ; i < count ; + + i )
{
const CrtSection * section = & coffDb - > crtSections [ i ] ;
if ( section - > rawDataSize ! = sectionSize )
{
continue ;
}
else if ( section - > name ! = sectionName )
{
continue ;
}
else if ( foundSection )
{
// matching section has been found more than once
return nullptr ;
}
foundSection = section ;
}
return foundSection ;
}
std : : vector < const CrtSection * > FindMatchingCrtSections ( const CoffDB * coffDb , const ImmutableString & sectionName , uint32_t sectionSize )
{
std : : vector < const CrtSection * > result ;
result . reserve ( 4u ) ;
const size_t count = coffDb - > crtSections . size ( ) ;
for ( size_t i = 0u ; i < count ; + + i )
{
const CrtSection * section = & coffDb - > crtSections [ i ] ;
if ( section - > rawDataSize ! = sectionSize )
{
continue ;
}
else if ( section - > name ! = sectionName )
{
continue ;
}
result . push_back ( section ) ;
}
return result ;
}
uint32_t FindCoffSuffix ( const ImmutableString & symbolName )
{
return symbolName . Find ( COFF_SUFFIX ) ;
}
uint32_t GetRelocationDestinationSectionCharacteristics ( const coff : : CoffDB * coffDb , const coff : : Relocation * relocation )
{
if ( relocation - > dstSectionIndex < 0 )
{
return 0u ;
}
const uint32_t index = static_cast < uint32_t > ( relocation - > dstSectionIndex ) ;
const coff : : Section & section = coffDb - > sections [ index ] ;
return section . characteristics ;
}
const void * GetBaseAddress ( const ObjFile * file )
{
2020-12-15 09:27:44 -04:00
return Filesystem : : GetMemoryMappedFileData ( file - > memoryFile ) ;
2019-03-05 18:49:25 -05:00
}
bool IsFunctionSymbol ( SymbolType : : Enum type )
{
switch ( type )
{
case SymbolType : : EXTERNAL_DATA :
return false ;
case SymbolType : : EXTERNAL_FUNCTION :
return true ;
case SymbolType : : STATIC_DATA :
return false ;
case SymbolType : : STATIC_FUNCTION :
return true ;
case SymbolType : : UNKNOWN_DATA :
return false ;
case SymbolType : : UNKNOWN_FUNCTION :
return true ;
default :
LC_ERROR_DEV ( " Unexpected SymbolType value %d " , type ) ;
return false ;
}
}
char GetCoffSuffix ( void )
{
return COFF_SUFFIX ;
}
wchar_t GetWideCoffSuffix ( void )
{
return COFF_SUFFIX_WIDE ;
}
const ImmutableString & GetTlsSectionName ( void )
{
return TLS_SECTION ;
}
bool IsInterestingSymbol ( const ImmutableString & name )
{
if ( symbols : : IsStringLiteral ( name ) )
{
return false ;
}
else if ( symbols : : IsFloatingPointSseAvxConstant ( name ) )
{
return false ;
}
else if ( symbols : : IsLineNumber ( name ) )
{
return false ;
}
return true ;
}
2020-12-15 09:27:44 -04:00
bool IsMSVCJustMyCodeSection ( const char * sectionName )
{
return string : : Matches ( sectionName , " .msvcjmc " ) ;
}
2019-03-05 18:49:25 -05:00
}