mirror of
https://github.com/acidanthera/audk.git
synced 2025-09-26 19:18:42 +02:00
893 lines
22 KiB
C
893 lines
22 KiB
C
/** @file
|
|
Copyright (c) 2021, Marvin Häuser. All rights reserved.
|
|
SPDX-License-Identifier: BSD-3-Clause
|
|
**/
|
|
|
|
#include "ImageTool.h"
|
|
|
|
// FIXME: NumSegments <= MAX_UINT8
|
|
|
|
typedef struct {
|
|
uint8_t NumSections;
|
|
uint32_t HeaderSize;
|
|
uint32_t SegmentHeadersSize;
|
|
uint32_t SectionHeadersSize;
|
|
} image_tool_emit_ue_hdr_info_t;
|
|
|
|
typedef struct {
|
|
const image_tool_image_info_t *Image;
|
|
image_tool_emit_ue_hdr_info_t HdrInfo;
|
|
uint32_t SegmentsSize;
|
|
uint8_t SegmentsEndPadding;
|
|
uint32_t SectionsSize;
|
|
uint32_t UnsignedFileSize;
|
|
uint32_t RelocTableSize;
|
|
uint32_t HiiTableSize;
|
|
uint32_t DebugTableSize;
|
|
} image_tool_ue_emit_context_t;
|
|
|
|
static
|
|
bool
|
|
EmitUeGetHeaderSizes (
|
|
const image_tool_image_info_t *Image,
|
|
image_tool_emit_ue_hdr_info_t *HdrInfo
|
|
)
|
|
{
|
|
assert (Image != NULL);
|
|
assert (HdrInfo != NULL);
|
|
|
|
if (Image->RelocInfo.NumRelocs > 0) {
|
|
++HdrInfo->NumSections;
|
|
}
|
|
|
|
if (Image->HiiInfo.DataSize > 0) {
|
|
++HdrInfo->NumSections;
|
|
}
|
|
//
|
|
// A debug section can always be generated; make conditional based on tool arg.
|
|
//
|
|
++HdrInfo->NumSections;
|
|
|
|
HdrInfo->SegmentHeadersSize = (uint32_t)Image->SegmentInfo.NumSegments * sizeof (UE_SEGMENT);
|
|
HdrInfo->SectionHeadersSize = (uint32_t)HdrInfo->NumSections * sizeof (UE_SECTION);
|
|
|
|
HdrInfo->HeaderSize = sizeof (UE_HEADER)
|
|
+ HdrInfo->SegmentHeadersSize
|
|
+ HdrInfo->SectionHeadersSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
EmitUeGetSegmentsSize (
|
|
const image_tool_image_info_t *Image,
|
|
uint32_t *SegmentsSize
|
|
)
|
|
{
|
|
uint8_t Index;
|
|
|
|
assert (Image != NULL);
|
|
assert (SegmentsSize != NULL);
|
|
|
|
*SegmentsSize = 0;
|
|
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
|
|
*SegmentsSize += Image->SegmentInfo.Segments[Index].DataSize;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
EmitUeGetRelocSectionSize (
|
|
const image_tool_image_info_t *Image,
|
|
uint32_t *RelocsSize
|
|
)
|
|
{
|
|
uint32_t RelocTableSize;
|
|
uint32_t BlockAddress;
|
|
uint32_t BlockSize;
|
|
uint32_t Index;
|
|
uint32_t RelocAddress;
|
|
|
|
assert (Image != NULL);
|
|
assert (RelocsSize != NULL);
|
|
|
|
if (Image->RelocInfo.NumRelocs == 0) {
|
|
*RelocsSize = 0;
|
|
return true;
|
|
}
|
|
|
|
assert (Image->RelocInfo.NumRelocs <= MAX_UINT32);
|
|
|
|
RelocTableSize = 0;
|
|
BlockAddress = (uint32_t)PAGE (Image->RelocInfo.Relocs[0].Target);
|
|
BlockSize = sizeof (UE_RELOCATION_BLOCK);
|
|
|
|
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
|
|
RelocAddress = PAGE (Image->RelocInfo.Relocs[Index].Target);
|
|
if (RelocAddress != BlockAddress) {
|
|
BlockSize = ALIGN_VALUE (BlockSize, UE_RELOCATION_BLOCK_ALIGNMENT);
|
|
|
|
RelocTableSize += BlockSize;
|
|
|
|
BlockAddress = RelocAddress;
|
|
BlockSize = sizeof (UE_RELOCATION_BLOCK);
|
|
}
|
|
|
|
BlockSize += sizeof (UINT16);
|
|
}
|
|
|
|
RelocTableSize += BlockSize;
|
|
|
|
*RelocsSize = RelocTableSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
EmitUeGetHiiSectionSize (
|
|
const image_tool_image_info_t *Image,
|
|
uint32_t *HiiSize
|
|
)
|
|
{
|
|
assert (Image != NULL);
|
|
assert (HiiSize != NULL);
|
|
|
|
*HiiSize = Image->HiiInfo.DataSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
EmitUeGetDebugSectionSize (
|
|
const image_tool_image_info_t *Image,
|
|
uint32_t *DebugSize
|
|
)
|
|
{
|
|
assert (Image != NULL);
|
|
assert (DebugSize != NULL);
|
|
|
|
static_assert (
|
|
MAX_UINT8 <= (MAX_UINT32 - MAX_UINT8 - sizeof (UE_DEBUG_TABLE)) / sizeof (UE_SEGMENT_NAME),
|
|
"The following arithmetics may overflow."
|
|
);
|
|
|
|
*DebugSize = sizeof (UE_DEBUG_TABLE) + Image->SegmentInfo.NumSegments * sizeof (UE_SEGMENT_NAME);
|
|
|
|
if (Image->DebugInfo.SymbolsPath != NULL) {
|
|
assert (Image->DebugInfo.SymbolsPathLen <= MAX_UINT8);
|
|
*DebugSize += Image->DebugInfo.SymbolsPathLen;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
EmitUeGetSectionsSize (
|
|
image_tool_ue_emit_context_t *Context,
|
|
uint32_t *SectionsSize
|
|
)
|
|
{
|
|
const image_tool_image_info_t *Image;
|
|
bool Result;
|
|
uint32_t AlignedRelocTableSize;
|
|
bool Overflow;
|
|
uint32_t AlignedDebugTableSize;
|
|
uint32_t AlignedHiiTableSize;
|
|
|
|
assert (Context != NULL);
|
|
assert (SectionsSize != NULL);
|
|
|
|
Image = Context->Image;
|
|
|
|
Result = EmitUeGetRelocSectionSize (Image, &Context->RelocTableSize);
|
|
if (!Result) {
|
|
raise ();
|
|
return false;
|
|
}
|
|
|
|
Result = EmitUeGetDebugSectionSize (Image, &Context->DebugTableSize);
|
|
if (!Result) {
|
|
raise ();
|
|
return false;
|
|
}
|
|
|
|
Result = EmitUeGetHiiSectionSize (Image, &Context->HiiTableSize);
|
|
if (!Result) {
|
|
raise ();
|
|
return false;
|
|
}
|
|
|
|
Overflow = BaseOverflowAlignUpU32 (
|
|
Context->RelocTableSize,
|
|
UE_SECTION_ALIGNMENT,
|
|
&AlignedRelocTableSize
|
|
);
|
|
if (Overflow) {
|
|
raise ();
|
|
return false;
|
|
}
|
|
|
|
Overflow = BaseOverflowAlignUpU32 (
|
|
Context->DebugTableSize,
|
|
UE_SECTION_ALIGNMENT,
|
|
&AlignedDebugTableSize
|
|
);
|
|
if (Overflow) {
|
|
raise ();
|
|
return false;
|
|
}
|
|
|
|
Overflow = BaseOverflowAlignUpU32 (
|
|
Context->HiiTableSize,
|
|
UE_SECTION_ALIGNMENT,
|
|
&AlignedHiiTableSize
|
|
);
|
|
if (Overflow) {
|
|
raise ();
|
|
return false;
|
|
}
|
|
|
|
Overflow = BaseOverflowAddU32 (
|
|
AlignedRelocTableSize,
|
|
AlignedDebugTableSize,
|
|
SectionsSize
|
|
);
|
|
if (Overflow) {
|
|
raise ();
|
|
return false;
|
|
}
|
|
|
|
assert (IS_ALIGNED (*SectionsSize, UE_SECTION_ALIGNMENT));
|
|
|
|
Overflow = BaseOverflowAddU32 (
|
|
*SectionsSize,
|
|
AlignedHiiTableSize,
|
|
SectionsSize
|
|
);
|
|
if (Overflow) {
|
|
raise ();
|
|
return false;
|
|
}
|
|
|
|
assert (IS_ALIGNED (*SectionsSize, UE_SECTION_ALIGNMENT));
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
uint8_t
|
|
AlignmentToExponent (
|
|
uint64_t Alignment
|
|
)
|
|
{
|
|
uint8_t Index;
|
|
|
|
assert (IS_POW2 (Alignment));
|
|
|
|
for (Index = 0; Index < 64; ++Index) {
|
|
if ((Alignment & (1ULL << Index)) == Alignment) {
|
|
return Index;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ToolImageEmitUeSegmentHeaders (
|
|
const image_tool_ue_emit_context_t *Context,
|
|
uint8_t **Buffer,
|
|
uint32_t *BufferSize
|
|
)
|
|
{
|
|
const image_tool_image_info_t *Image;
|
|
uint16_t SegmentHeadersSize;
|
|
UE_SEGMENT *Segments;
|
|
uint8_t Index;
|
|
|
|
assert (Context != NULL);
|
|
assert (Buffer != NULL);
|
|
assert (BufferSize != NULL);
|
|
|
|
Image = Context->Image;
|
|
|
|
SegmentHeadersSize = (uint16_t)(Image->SegmentInfo.NumSegments * sizeof (UE_SEGMENT));
|
|
assert (SegmentHeadersSize <= *BufferSize);
|
|
|
|
Segments = (void *)*Buffer;
|
|
|
|
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
|
|
// FIXME:
|
|
Image->SegmentInfo.Segments[Index].ImageSize = ALIGN_VALUE (Image->SegmentInfo.Segments[Index].ImageSize, Image->SegmentInfo.SegmentAlignment);
|
|
|
|
Segments[Index].ImageInfo = Image->SegmentInfo.Segments[Index].ImageSize;
|
|
|
|
if (!Image->SegmentInfo.Segments[Index].Read) {
|
|
Segments[Index].ImageInfo |= UE_SEGMENT_INFO_RP;
|
|
}
|
|
|
|
if (!Image->SegmentInfo.Segments[Index].Write) {
|
|
Segments[Index].ImageInfo |= UE_SEGMENT_INFO_RO;
|
|
}
|
|
|
|
if (!Image->SegmentInfo.Segments[Index].Execute) {
|
|
Segments[Index].ImageInfo |= UE_SEGMENT_INFO_XP;
|
|
}
|
|
|
|
assert (UE_SEGMENT_SIZE (Segments[Index].ImageInfo) == Image->SegmentInfo.Segments[Index].ImageSize);
|
|
|
|
Segments[Index].FileSize = Image->SegmentInfo.Segments[Index].DataSize;
|
|
}
|
|
|
|
*BufferSize -= SegmentHeadersSize;
|
|
*Buffer += SegmentHeadersSize;
|
|
|
|
assert (SegmentHeadersSize == Context->HdrInfo.SegmentHeadersSize);
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ToolImageEmitUeSectionHeaders (
|
|
const image_tool_ue_emit_context_t *Context,
|
|
uint8_t **Buffer,
|
|
uint32_t *BufferSize
|
|
)
|
|
{
|
|
uint32_t SectionHeadersSize;
|
|
UE_SECTION *Section;
|
|
uint32_t AlignedRelocTableSize;
|
|
uint32_t AlignedDebugTableSize;
|
|
uint32_t AlignedHiiTableSize;
|
|
|
|
assert (Context != NULL);
|
|
assert (Buffer != NULL);
|
|
assert (BufferSize != NULL);
|
|
|
|
SectionHeadersSize = 0;
|
|
|
|
if (Context->RelocTableSize > 0) {
|
|
assert (sizeof (UE_SECTION) <= *BufferSize);
|
|
|
|
Section = (void *)*Buffer;
|
|
|
|
AlignedRelocTableSize = ALIGN_VALUE (Context->RelocTableSize, UE_SECTION_ALIGNMENT);
|
|
Section->FileInfo = AlignedRelocTableSize;
|
|
Section->FileInfo |= UeSectionIdRelocTable;
|
|
|
|
assert (UE_SECTION_ID (Section->FileInfo) == UeSectionIdRelocTable);
|
|
assert (UE_SECTION_SIZE (Section->FileInfo) == AlignedRelocTableSize);
|
|
|
|
*BufferSize -= sizeof (UE_SECTION);
|
|
*Buffer += sizeof (UE_SECTION);
|
|
SectionHeadersSize += sizeof (UE_SECTION);
|
|
}
|
|
|
|
if (Context->DebugTableSize > 0) {
|
|
assert (sizeof (UE_SECTION) <= *BufferSize);
|
|
|
|
Section = (void *)*Buffer;
|
|
|
|
AlignedDebugTableSize = ALIGN_VALUE (Context->DebugTableSize, UE_SECTION_ALIGNMENT);
|
|
Section->FileInfo = AlignedDebugTableSize;
|
|
Section->FileInfo |= UeSectionIdDebugTable;
|
|
|
|
assert (UE_SECTION_ID (Section->FileInfo) == UeSectionIdDebugTable);
|
|
assert (UE_SECTION_SIZE (Section->FileInfo) == AlignedDebugTableSize);
|
|
|
|
*BufferSize -= sizeof (UE_SECTION);
|
|
*Buffer += sizeof (UE_SECTION);
|
|
SectionHeadersSize += sizeof (UE_SECTION);
|
|
}
|
|
|
|
if (Context->HiiTableSize > 0) {
|
|
assert (sizeof (UE_SECTION) <= *BufferSize);
|
|
|
|
Section = (void *)*Buffer;
|
|
|
|
AlignedHiiTableSize = ALIGN_VALUE (Context->HiiTableSize, UE_SECTION_ALIGNMENT);
|
|
Section->FileInfo = AlignedHiiTableSize;
|
|
Section->FileInfo |= UeSectionIdHiiTable;
|
|
|
|
assert (UE_SECTION_ID (Section->FileInfo) == UeSectionIdHiiTable);
|
|
assert (UE_SECTION_SIZE (Section->FileInfo) == AlignedHiiTableSize);
|
|
|
|
*BufferSize -= sizeof (UE_SECTION);
|
|
*Buffer += sizeof (UE_SECTION);
|
|
SectionHeadersSize += sizeof (UE_SECTION);
|
|
}
|
|
|
|
assert (Context->HdrInfo.SectionHeadersSize == SectionHeadersSize);
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ToolImageEmitUeHeader (
|
|
const image_tool_ue_emit_context_t *Context,
|
|
uint8_t **Buffer,
|
|
uint32_t *BufferSize
|
|
)
|
|
{
|
|
UE_HEADER *UeHdr;
|
|
const image_tool_image_info_t *Image;
|
|
uint8_t AlignmentExponent;
|
|
bool Result;
|
|
|
|
assert (Context != NULL);
|
|
assert (Buffer != NULL);
|
|
assert (BufferSize != NULL);
|
|
|
|
assert (sizeof(UE_HEADER) <= *BufferSize);
|
|
|
|
UeHdr = (void *)*Buffer;
|
|
|
|
UeHdr->Signature = UE_HEADER_SIGNATURE;
|
|
|
|
Image = Context->Image;
|
|
|
|
AlignmentExponent = AlignmentToExponent (Image->SegmentInfo.SegmentAlignment);
|
|
UeHdr->ImageInfo = AlignmentExponent;
|
|
|
|
if (Image->RelocInfo.RelocsStripped) {
|
|
UeHdr->ImageInfo |= UE_HEADER_FLAG_RELOCS_STRIPPED;
|
|
}
|
|
|
|
assert (UE_HEADER_ALIGNMENT (UeHdr->ImageInfo) == 1U << AlignmentExponent);
|
|
|
|
assert (Image->SegmentInfo.NumSegments > 0);
|
|
UeHdr->LastSegmentIndex = (UINT8)(Image->SegmentInfo.NumSegments - 1);
|
|
UeHdr->NumSections = Context->HdrInfo.NumSections;
|
|
UeHdr->Subsystem = (UINT8)Image->HeaderInfo.Subsystem;
|
|
UeHdr->Machine = (UINT8)Image->HeaderInfo.Machine;
|
|
UeHdr->PreferredAddress = Image->HeaderInfo.BaseAddress;
|
|
UeHdr->EntryPointAddress = Image->HeaderInfo.EntryPointAddress;
|
|
UeHdr->ImageInfo2 = Context->UnsignedFileSize;
|
|
assert (UeHdr->ImageInfo2 == UE_HEADER_UNSIGNED_SIZE (UeHdr->ImageInfo2));
|
|
|
|
assert (UeHdr->Reserved == 0);
|
|
|
|
STATIC_ASSERT (
|
|
OFFSET_OF (UE_HEADER, Segments) == sizeof (UE_HEADER),
|
|
"The following code needs to be updated to consider padding."
|
|
);
|
|
|
|
*BufferSize -= sizeof (UE_HEADER);
|
|
*Buffer += sizeof (UE_HEADER);
|
|
|
|
Result = ToolImageEmitUeSegmentHeaders (Context, Buffer, BufferSize);
|
|
if (!Result) {
|
|
return false;
|
|
}
|
|
|
|
Result = ToolImageEmitUeSectionHeaders (Context, Buffer, BufferSize);
|
|
if (!Result) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ToolImageEmitUeSegments (
|
|
const image_tool_ue_emit_context_t *Context,
|
|
uint8_t **Buffer,
|
|
uint32_t *BufferSize
|
|
)
|
|
{
|
|
const image_tool_image_info_t *Image;
|
|
uint32_t SegmentsSize;
|
|
uint8_t Index;
|
|
size_t DataSize;
|
|
|
|
assert (Context != NULL);
|
|
assert (Buffer != NULL);
|
|
assert (BufferSize != NULL);
|
|
|
|
Image = Context->Image;
|
|
|
|
SegmentsSize = 0;
|
|
|
|
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
|
|
assert (Image->SegmentInfo.Segments[Index].DataSize <= *BufferSize);
|
|
|
|
DataSize = Image->SegmentInfo.Segments[Index].DataSize;
|
|
|
|
memmove (*Buffer, Image->SegmentInfo.Segments[Index].Data, DataSize);
|
|
|
|
*BufferSize -= DataSize;
|
|
*Buffer += DataSize;
|
|
SegmentsSize += DataSize;
|
|
}
|
|
|
|
assert (SegmentsSize == Context->SegmentsSize);
|
|
|
|
*BufferSize -= Context->SegmentsEndPadding;
|
|
*Buffer += Context->SegmentsEndPadding;
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ToolImageEmitUeRelocTable (
|
|
const image_tool_ue_emit_context_t *Context,
|
|
uint8_t **Buffer,
|
|
uint32_t *BufferSize
|
|
)
|
|
{
|
|
const image_tool_image_info_t *Image;
|
|
uint32_t RelocTableSize;
|
|
UE_RELOCATION_BLOCK *RelocBlock;
|
|
uint32_t BlockAddress;
|
|
uint32_t BlockNumRelocs;
|
|
uint32_t BlockSize;
|
|
uint32_t Index;
|
|
uint32_t RelocAddress;
|
|
uint32_t RelocTablePadding;
|
|
|
|
assert (Context != NULL);
|
|
assert (Buffer != NULL);
|
|
assert (BufferSize != NULL);
|
|
|
|
if (Context->RelocTableSize == 0) {
|
|
return true;
|
|
}
|
|
|
|
Image = Context->Image;
|
|
|
|
assert (Image->RelocInfo.NumRelocs > 0);
|
|
assert (Image->RelocInfo.NumRelocs <= MAX_UINT32);
|
|
|
|
assert (sizeof(UE_RELOCATION_BLOCK) <= *BufferSize);
|
|
|
|
RelocTableSize = 0;
|
|
RelocBlock = (void *)*Buffer;
|
|
BlockAddress = (uint32_t)PAGE (Image->RelocInfo.Relocs[0].Target);
|
|
BlockNumRelocs = 0;
|
|
BlockSize = sizeof (*RelocBlock);
|
|
|
|
RelocBlock->BlockInfo = BlockAddress;
|
|
|
|
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
|
|
RelocAddress = PAGE (Image->RelocInfo.Relocs[Index].Target);
|
|
if (RelocAddress != BlockAddress) {
|
|
BlockSize = ALIGN_VALUE (BlockSize, UE_RELOCATION_BLOCK_ALIGNMENT);
|
|
assert (BlockSize <= *BufferSize);
|
|
|
|
*BufferSize -= BlockSize;
|
|
*Buffer += BlockSize;
|
|
RelocTableSize += BlockSize;
|
|
|
|
RelocBlock = (void *)*Buffer;
|
|
|
|
BlockAddress = RelocAddress;
|
|
BlockNumRelocs = 0;
|
|
BlockSize = sizeof (*RelocBlock);
|
|
|
|
RelocBlock->BlockInfo = BlockAddress;
|
|
}
|
|
|
|
BlockSize += sizeof (*RelocBlock->RelocInfo);
|
|
assert (BlockSize <= *BufferSize);
|
|
|
|
RelocBlock->RelocInfo[BlockNumRelocs] = PAGE_OFF (Image->RelocInfo.Relocs[Index].Target);
|
|
RelocBlock->RelocInfo[BlockNumRelocs] |= Image->RelocInfo.Relocs[Index].Type << 12U;
|
|
assert (UE_RELOC_OFFSET (RelocBlock->RelocInfo[BlockNumRelocs]) == PAGE_OFF (Image->RelocInfo.Relocs[Index].Target));
|
|
assert (UE_RELOC_TYPE (RelocBlock->RelocInfo[BlockNumRelocs]) == Image->RelocInfo.Relocs[Index].Type);
|
|
|
|
++BlockNumRelocs;
|
|
if (BlockNumRelocs > UE_RELOCATION_BLOCK_MAX_RELOCS) {
|
|
return false;
|
|
}
|
|
|
|
++RelocBlock->BlockInfo;
|
|
assert (BlockNumRelocs == UE_RELOC_BLOCK_NUM (RelocBlock->BlockInfo));
|
|
assert (BlockAddress == UE_RELOC_BLOCK_ADDRESS (RelocBlock->BlockInfo));
|
|
}
|
|
|
|
*BufferSize -= BlockSize;
|
|
*Buffer += BlockSize;
|
|
RelocTableSize += BlockSize;
|
|
|
|
assert (RelocTableSize == Context->RelocTableSize);
|
|
|
|
RelocTablePadding = ALIGN_VALUE_ADDEND (RelocTableSize, UE_SECTION_ALIGNMENT);
|
|
|
|
assert (RelocTablePadding <= *BufferSize);
|
|
|
|
*BufferSize -= RelocTablePadding;
|
|
*Buffer += RelocTablePadding;
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ToolImageEmitUeDebugTable (
|
|
const image_tool_ue_emit_context_t *Context,
|
|
uint8_t **Buffer,
|
|
uint32_t *BufferSize
|
|
)
|
|
{
|
|
uint32_t DebugTableSize;
|
|
UE_DEBUG_TABLE *DebugTable;
|
|
const image_tool_image_info_t *Image;
|
|
uint8_t Index;
|
|
UE_SEGMENT_NAME *SectionName;
|
|
uint32_t DebugTablePadding;
|
|
|
|
assert (Context != NULL);
|
|
assert (Buffer != NULL);
|
|
assert (BufferSize != NULL);
|
|
|
|
assert (sizeof (UE_DEBUG_TABLE) <= *BufferSize);
|
|
|
|
DebugTableSize = sizeof (UE_DEBUG_TABLE);
|
|
|
|
DebugTable = (void *)*Buffer;
|
|
|
|
assert (DebugTable->SymbolsBaseOffset == 0);
|
|
assert (DebugTable->Reserved == 0);
|
|
|
|
Image = Context->Image;
|
|
|
|
*BufferSize -= sizeof (UE_DEBUG_TABLE);
|
|
*Buffer += sizeof (UE_DEBUG_TABLE);
|
|
|
|
if (Image->DebugInfo.SymbolsPath != NULL) {
|
|
assert (Image->DebugInfo.SymbolsPathLen <= MAX_UINT8);
|
|
DebugTable->SymbolsPathSize = (uint8_t)Image->DebugInfo.SymbolsPathLen;
|
|
|
|
assert (Image->DebugInfo.SymbolsPathLen <= *BufferSize);
|
|
|
|
DebugTableSize += Image->DebugInfo.SymbolsPathLen;
|
|
|
|
memmove (*Buffer, Image->DebugInfo.SymbolsPath, Image->DebugInfo.SymbolsPathLen);
|
|
|
|
*BufferSize -= Image->DebugInfo.SymbolsPathLen;
|
|
*Buffer += Image->DebugInfo.SymbolsPathLen;
|
|
} else {
|
|
assert (DebugTable->SymbolsPathSize == 0);
|
|
}
|
|
|
|
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
|
|
assert (sizeof (UE_SEGMENT_NAME) <= *BufferSize);
|
|
|
|
DebugTableSize += sizeof (UE_SEGMENT_NAME);
|
|
|
|
SectionName = (void *)*Buffer;
|
|
|
|
strncpy (
|
|
(char *)SectionName,
|
|
Image->SegmentInfo.Segments[Index].Name,
|
|
sizeof (*SectionName)
|
|
);
|
|
|
|
*BufferSize -= sizeof (*SectionName);
|
|
*Buffer += sizeof (*SectionName);
|
|
}
|
|
|
|
assert (DebugTableSize == Context->DebugTableSize);
|
|
|
|
DebugTablePadding = ALIGN_VALUE_ADDEND (DebugTableSize, UE_SECTION_ALIGNMENT);
|
|
|
|
assert (DebugTablePadding <= *BufferSize);
|
|
|
|
*BufferSize -= DebugTablePadding;
|
|
*Buffer += DebugTablePadding;
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ToolImageEmitUeHiiTable (
|
|
const image_tool_ue_emit_context_t *Context,
|
|
uint8_t **Buffer,
|
|
uint32_t *BufferSize
|
|
)
|
|
{
|
|
const image_tool_image_info_t *Image;
|
|
uint32_t HiiTablePadding;
|
|
|
|
assert (Context != NULL);
|
|
assert (Buffer != NULL);
|
|
assert (BufferSize != NULL);
|
|
|
|
Image = Context->Image;
|
|
|
|
if (Context->HiiTableSize == 0) {
|
|
return true;
|
|
}
|
|
|
|
assert (Image->HiiInfo.DataSize == Context->HiiTableSize);
|
|
assert (Context->HiiTableSize <= *BufferSize);
|
|
|
|
memmove (*Buffer, Image->HiiInfo.Data, Image->HiiInfo.DataSize);
|
|
|
|
*BufferSize -= Image->HiiInfo.DataSize;
|
|
*Buffer += Image->HiiInfo.DataSize;
|
|
|
|
HiiTablePadding = ALIGN_VALUE_ADDEND (Image->HiiInfo.DataSize, UE_SECTION_ALIGNMENT);
|
|
|
|
assert (HiiTablePadding <= *BufferSize);
|
|
|
|
*BufferSize -= HiiTablePadding;
|
|
*Buffer += HiiTablePadding;
|
|
|
|
return true;
|
|
}
|
|
|
|
static
|
|
bool
|
|
ToolImageEmitUeSections (
|
|
const image_tool_ue_emit_context_t *Context,
|
|
uint8_t **Buffer,
|
|
uint32_t *BufferSize
|
|
)
|
|
{
|
|
uint32_t OldBufferSize;
|
|
bool Result;
|
|
|
|
assert (Context != NULL);
|
|
assert (Buffer != NULL);
|
|
assert (BufferSize != NULL);
|
|
|
|
OldBufferSize = *BufferSize;
|
|
|
|
Result = ToolImageEmitUeRelocTable (Context, Buffer, BufferSize);
|
|
if (!Result) {
|
|
return false;
|
|
}
|
|
|
|
Result = ToolImageEmitUeDebugTable (Context, Buffer, BufferSize);
|
|
if (!Result) {
|
|
return false;
|
|
}
|
|
|
|
Result = ToolImageEmitUeHiiTable (Context, Buffer, BufferSize);
|
|
if (!Result) {
|
|
return false;
|
|
}
|
|
|
|
assert ((OldBufferSize - *BufferSize) == Context->SectionsSize);
|
|
|
|
return true;
|
|
}
|
|
|
|
void *
|
|
ToolImageEmitUe (
|
|
const image_tool_image_info_t *Image,
|
|
uint32_t *FileSize
|
|
)
|
|
{
|
|
image_tool_ue_emit_context_t Context;
|
|
bool Result;
|
|
uint32_t SectionsOffset;
|
|
bool Overflow;
|
|
void *FileBuffer;
|
|
uint8_t *Buffer;
|
|
uint32_t RemainingSize;
|
|
uint32_t ExpectedSize;
|
|
|
|
assert (Image != NULL);
|
|
assert (FileSize != NULL);
|
|
|
|
memset (&Context, 0, sizeof (Context));
|
|
|
|
Context.Image = Image;
|
|
|
|
Result = EmitUeGetHeaderSizes (Image, &Context.HdrInfo);
|
|
if (!Result) {
|
|
raise ();
|
|
return NULL;
|
|
}
|
|
|
|
Result = EmitUeGetSegmentsSize (Image, &Context.SegmentsSize);
|
|
if (!Result) {
|
|
raise ();
|
|
return NULL;
|
|
}
|
|
|
|
Overflow = BaseOverflowAddU32 (
|
|
Context.HdrInfo.HeaderSize,
|
|
Context.SegmentsSize,
|
|
&SectionsOffset
|
|
);
|
|
if (Overflow) {
|
|
raise ();
|
|
return NULL;
|
|
}
|
|
|
|
Context.SegmentsEndPadding = ALIGN_VALUE_ADDEND (SectionsOffset, UE_SECTION_ALIGNMENT);
|
|
|
|
Overflow = BaseOverflowAddU32 (
|
|
SectionsOffset,
|
|
Context.SegmentsEndPadding,
|
|
&SectionsOffset
|
|
);
|
|
if (Overflow) {
|
|
raise ();
|
|
return NULL;
|
|
}
|
|
|
|
Result = EmitUeGetSectionsSize (&Context, &Context.SectionsSize);
|
|
if (!Result) {
|
|
raise ();
|
|
return NULL;
|
|
}
|
|
|
|
assert (IS_ALIGNED (Context.SectionsSize, UE_SECTION_ALIGNMENT));
|
|
|
|
Overflow = BaseOverflowAddU32 (
|
|
SectionsOffset,
|
|
Context.SectionsSize,
|
|
&Context.UnsignedFileSize
|
|
);
|
|
if (Overflow) {
|
|
raise ();
|
|
return NULL;
|
|
}
|
|
|
|
assert (IS_ALIGNED (Context.UnsignedFileSize, UE_SECTION_ALIGNMENT));
|
|
|
|
FileBuffer = calloc (1, Context.UnsignedFileSize);
|
|
if (FileBuffer == NULL) {
|
|
raise ();
|
|
return NULL;
|
|
}
|
|
|
|
Buffer = FileBuffer;
|
|
RemainingSize = Context.UnsignedFileSize;
|
|
ExpectedSize = Context.UnsignedFileSize;
|
|
|
|
Result = ToolImageEmitUeHeader (&Context, &Buffer, &RemainingSize);
|
|
if (!Result) {
|
|
raise ();
|
|
free (FileBuffer);
|
|
return NULL;
|
|
}
|
|
|
|
ExpectedSize -= Context.HdrInfo.HeaderSize;
|
|
|
|
assert (RemainingSize == ExpectedSize);
|
|
|
|
Result = ToolImageEmitUeSegments (&Context, &Buffer, &RemainingSize);
|
|
if (!Result) {
|
|
raise ();
|
|
free (FileBuffer);
|
|
return NULL;
|
|
}
|
|
|
|
ExpectedSize -= Context.SegmentsSize + Context.SegmentsEndPadding;
|
|
|
|
assert (RemainingSize == ExpectedSize);
|
|
|
|
Result = ToolImageEmitUeSections (&Context, &Buffer, &RemainingSize);
|
|
if (!Result) {
|
|
raise ();
|
|
free (FileBuffer);
|
|
return NULL;
|
|
}
|
|
|
|
ExpectedSize -= Context.SectionsSize;
|
|
|
|
assert (RemainingSize == ExpectedSize);
|
|
assert (RemainingSize == 0);
|
|
|
|
*FileSize = Context.UnsignedFileSize;
|
|
|
|
return FileBuffer;
|
|
}
|