Files
2025-05-18 13:04:45 +08:00

306 lines
8.9 KiB
C++

// Copyright 2011-2020 Molecular Matters GmbH, all rights reserved.
#pragma once
#if LC_VERSION == 1
// BEGIN EPIC MOD
#include "CoreTypes.h"
// END EPIC MOD
#include "LC_PointerUtil.h"
// BEGIN EPIC MOD
#include "LC_Platform.h"
#include <inttypes.h>
#include "Windows/WindowsHWrapper.h"
// END EPIC MOD
namespace coffDetail
{
struct CoffType
{
enum Enum
{
COFF, // regular COFF/OBJ files
BIGOBJ, // OBJ files compiled with /bigobj
IMPORT_LIBRARY, // import libraries (DLL stubs)
UNKNOWN
};
// template helper to map from CoffType::Enum values to types
template <Enum>
struct TypeMap {};
template <>
struct TypeMap<Enum::COFF>
{
typedef IMAGE_FILE_HEADER HeaderType;
typedef IMAGE_SYMBOL SymbolType;
typedef IMAGE_AUX_SYMBOL AuxSymbolType;
};
template <>
struct TypeMap<Enum::BIGOBJ>
{
typedef ANON_OBJECT_HEADER_BIGOBJ HeaderType;
typedef IMAGE_SYMBOL_EX SymbolType;
typedef IMAGE_AUX_SYMBOL_EX AuxSymbolType;
};
};
CoffType::Enum GetCoffType(const void* imageBase);
// returns the number of relocations
unsigned int GetRelocationCount(const void* imageBase, const IMAGE_SECTION_HEADER* section);
template <typename SymbolType>
inline uint32_t GetSectionIndex(const SymbolType* symbol)
{
// according to COFF spec, section number is a one-based (because zero is taken by UNDEFINED symbols)
// signed integer, and signed values like 0, -1 and -2 have special meaning. note that
// in cases where the index is a negative value that does not correspond to any of
// the special values, the section number *must* be treated as an unsigned value, which is not
// stated in the spec.
// e.g. some non-bigobj COFF files that have more than 32767 sections will have symbols with
// section numbers like 0x8000, 0x8001, etc. which need to be treated as unsigned values.
typedef typename std::make_unsigned<decltype(symbol->SectionNumber)>::type UnsignedSectionNumberType;
const uint32_t sectionIndex = static_cast<uint32_t>(static_cast<UnsignedSectionNumberType>(symbol->SectionNumber) - 1u);
return sectionIndex;
}
template <typename AuxSymbolType>
// BEGIN EPIC MOD
uint32_t GetAssociatedComdatSectionIndex(const AuxSymbolType* symbol);
// END EPIC MOD
template <>
inline uint32_t GetAssociatedComdatSectionIndex(const IMAGE_AUX_SYMBOL* symbol)
{
typedef std::make_unsigned<decltype(symbol->Section.Number)>::type UnsignedSectionNumberType;
const uint32_t sectionIndex = static_cast<uint32_t>(static_cast<UnsignedSectionNumberType>(symbol->Section.Number) - 1u);
return sectionIndex;
}
template <>
inline uint32_t GetAssociatedComdatSectionIndex(const IMAGE_AUX_SYMBOL_EX* symbol)
{
typedef std::make_unsigned<decltype(symbol->Section.Number)>::type UnsignedSectionNumberType;
typedef std::make_unsigned<decltype(symbol->Section.HighNumber)>::type UnsignedHighSectionNumberType;
const uint32_t sectionIndex = static_cast<uint32_t>(static_cast<UnsignedSectionNumberType>(symbol->Section.Number) - 1u);
// note that the high number is zero-based instead of one-based
const uint32_t highSectionIndex = static_cast<uint32_t>(static_cast<UnsignedHighSectionNumberType>(symbol->Section.HighNumber));
return (highSectionIndex << 16u) | sectionIndex;
}
template <typename SymbolType>
inline bool IsFunctionSymbol(const SymbolType* symbol)
{
return ISFCN(symbol->Type);
}
/*
From the COFF spec: 5.4.2 Section Number Values
Normally, the Section Value field in a symbol table entry is a one-based index into the section table.
However, this field is a signed integer and can take negative values. The following values, less than one,
have special meanings.
IMAGE_SYM_UNDEFINED The symbol record is not yet assigned a section. A value of zero indicates that a reference
to an external symbol is defined elsewhere. A value of non-zero is a common symbol with a size that is specified
by the value.
IMAGE_SYM_ABSOLUTE The symbol has an absolute (non-relocatable) value and is not an address.
IMAGE_SYM_DEBUG The symbol provides general type or debugging information but does not correspond to a section.
Microsoft tools use this setting along with .file records (storage class FILE).
*/
template <typename SymbolType>
inline bool IsUndefinedSymbol(const SymbolType* symbol)
{
return (symbol->SectionNumber == IMAGE_SYM_UNDEFINED);
}
template <typename SymbolType>
inline bool IsAbsoluteSymbol(const SymbolType* symbol)
{
return (symbol->SectionNumber == IMAGE_SYM_ABSOLUTE);
}
template <typename SymbolType>
inline bool IsDebugSymbol(const SymbolType* symbol)
{
return (symbol->SectionNumber == IMAGE_SYM_DEBUG);
}
template <typename SymbolType>
inline bool IsSectionSymbol(const SymbolType* symbol)
{
/*
From the COFF spec: 5.5.5 Auxiliary Format 5: Section Definitions
Follows a symbol-table record that defines a section. The auxiliary record provides information
about the section to which it refers.
*/
if (symbol->NumberOfAuxSymbols > 0u)
{
/*
From the COFF spec: 5.4.4 Storage Class
IMAGE_SYM_CLASS_STATIC: The offset of the symbol within the section. If the Value field is zero,
then the symbol represents a section name.
*/
if ((symbol->StorageClass == IMAGE_SYM_CLASS_STATIC) && (symbol->Value == 0u))
{
return true;
}
}
return false;
}
template <typename SymbolType>
inline bool IsLabelSymbol(const SymbolType* symbol)
{
if (symbol->StorageClass == IMAGE_SYM_CLASS_LABEL)
{
return true;
}
else if (symbol->StorageClass == IMAGE_SYM_CLASS_UNDEFINED_LABEL)
{
return true;
}
return false;
}
/*
From the COFF spec: 5.2.1 Type Indicators
*/
inline bool IsDebugRelocation(const IMAGE_RELOCATION* relocation)
{
#if LC_64_BIT
return (relocation->Type == IMAGE_REL_AMD64_SECTION);
#else
return (relocation->Type == IMAGE_REL_I386_SECTION);
#endif
}
/*
From the COFF spec: 4.1 Section Flags
*/
inline bool IsDiscardableSection(const IMAGE_SECTION_HEADER* section)
{
return (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0u;
}
inline bool IsPartOfImage(const IMAGE_SECTION_HEADER* section)
{
// if the LNK_REMOVE flag is not set, the section becomes part of the final image
return (section->Characteristics & IMAGE_SCN_LNK_REMOVE) == 0u;
}
inline bool IsComdatSection(const IMAGE_SECTION_HEADER* section)
{
return (section->Characteristics & IMAGE_SCN_LNK_COMDAT) != 0u;
}
inline bool IsDirectiveSection(const IMAGE_SECTION_HEADER* section)
{
// sections containing info/comments/directives are mostly named ".drectve", but are more
// easily identified using IMAGE_SCN_LNK_INFO.
return (section->Characteristics & IMAGE_SCN_LNK_INFO) != 0u;
}
inline bool IsCodeSection(uint32_t characteristics)
{
return (characteristics & IMAGE_SCN_MEM_EXECUTE) != 0u;
}
inline bool IsReadSection(uint32_t characteristics)
{
return (characteristics & IMAGE_SCN_MEM_READ) != 0u;
}
inline bool IsWriteSection(uint32_t characteristics)
{
return (characteristics & IMAGE_SCN_MEM_WRITE) != 0u;
}
template <typename HeaderType>
inline uint32_t GetNumberOfSections(const void* imageBase)
{
const HeaderType* header = pointer::As<const HeaderType*>(imageBase);
return header->NumberOfSections;
}
template <typename HeaderType>
inline uint32_t GetNumberOfSymbols(const void* imageBase)
{
const HeaderType* header = pointer::As<const HeaderType*>(imageBase);
return header->NumberOfSymbols;
}
template <typename HeaderType>
inline const IMAGE_SECTION_HEADER* GetSectionHeader(const void* imageBase)
{
return pointer::Offset<const IMAGE_SECTION_HEADER*>(imageBase, sizeof(HeaderType));
}
template <typename HeaderType>
inline const void* GetSymbolTable(const void* imageBase)
{
const HeaderType* header = pointer::As<const HeaderType*>(imageBase);
return pointer::Offset<const void*>(imageBase, header->PointerToSymbolTable);
}
template <typename SymbolType>
inline const char* GetStringTable(const void* symbolTable, uint32_t symbolCount)
{
// string table comes after the symbol table
return pointer::Offset<const char*>(symbolTable, sizeof(SymbolType)*symbolCount);
}
template <typename SymbolType>
inline const SymbolType* GetSymbol(const void* symbolTable, size_t index)
{
return pointer::Offset<const SymbolType*>(symbolTable, index * sizeof(SymbolType));
}
// archives/libraries
inline uint32_t GetArchiveMemberSize(const IMAGE_ARCHIVE_MEMBER_HEADER* header)
{
// COFF Spec, 7.2. Archive Member Headers:
// Field "Size" at offset 48: An ASCII decimal representation of the total size of the archive member, not including the size of the header.
uint32_t size = 0u;
sscanf_s(reinterpret_cast<const char*>(header->Size), "%" SCNu32, &size);
return size;
}
inline uint32_t PadArchiveMemberSize(uint32_t size)
{
// COFF Spec, 7.2. Archive Member Headers:
// "Each member header starts on the first even address after the end of the previous archive member."
return size + (size & 1u);
}
}
#endif