ImageTool: Make IR canonical and compare input/output IRs

This commit is contained in:
Marvin Häuser 2023-04-22 21:12:58 +02:00 committed by Mikhail Krichanov
parent 1edfc1f6b7
commit 5976987671
9 changed files with 340 additions and 93 deletions

View File

@ -622,8 +622,7 @@ CreateIntermediate (
memcpy (Segments[SIndex].Name, Name, strlen (Name)); memcpy (Segments[SIndex].Name, Name, strlen (Name));
Segments[SIndex].ImageAddress = (uint32_t)(Shdr->sh_addr - BaseAddress); Segments[SIndex].ImageAddress = (uint32_t)(Shdr->sh_addr - BaseAddress);
Segments[SIndex].DataSize = (uint32_t)Shdr->sh_size; Segments[SIndex].ImageSize = ALIGN_VALUE ((uint32_t)Shdr->sh_size, Context->Alignment);
Segments[SIndex].ImageSize = ALIGN_VALUE (Segments[SIndex].DataSize, Context->Alignment);
Segments[SIndex].Read = true; Segments[SIndex].Read = true;
Segments[SIndex].Write = (Shdr->sh_flags & SHF_WRITE) != 0; Segments[SIndex].Write = (Shdr->sh_flags & SHF_WRITE) != 0;
Segments[SIndex].Execute = (Shdr->sh_flags & SHF_EXECINSTR) != 0; Segments[SIndex].Execute = (Shdr->sh_flags & SHF_EXECINSTR) != 0;

View File

@ -29,11 +29,6 @@ CheckToolImageSegment (
return false; return false;
} }
if (Segment->ImageSize < Segment->DataSize) {
raise ();
return false;
}
// FIXME: Expand prior segment // FIXME: Expand prior segment
if (Segment->ImageAddress != *PreviousEndAddress) { if (Segment->ImageAddress != *PreviousEndAddress) {
raise (); raise ();
@ -223,6 +218,10 @@ CheckToolImageRelocInfo (
RelocInfo = &Image->RelocInfo; RelocInfo = &Image->RelocInfo;
if (RelocInfo->NumRelocs == 0) {
return true;
}
if (RelocInfo->RelocsStripped && (RelocInfo->NumRelocs > 0)) { if (RelocInfo->RelocsStripped && (RelocInfo->NumRelocs > 0)) {
raise (); raise ();
return false; return false;
@ -233,7 +232,18 @@ CheckToolImageRelocInfo (
return false; return false;
} }
for (Index = 0; Index < RelocInfo->NumRelocs; ++Index) { Result = CheckToolImageReloc (Image, ImageSize, &RelocInfo->Relocs[0]);
if (!Result) {
raise ();
return false;
}
for (Index = 1; Index < RelocInfo->NumRelocs; ++Index) {
if (RelocInfo->Relocs[Index].Target < RelocInfo->Relocs[Index - 1].Target) {
assert (false);
return false;
}
Result = CheckToolImageReloc (Image, ImageSize, &RelocInfo->Relocs[Index]); Result = CheckToolImageReloc (Image, ImageSize, &RelocInfo->Relocs[Index]);
if (!Result) { if (!Result) {
raise (); raise ();
@ -294,33 +304,8 @@ CheckToolImage (
return true; return true;
} }
bool
ImageConvertToXip (
image_tool_image_info_t *Image
)
{
image_tool_segment_info_t *SegmentInfo;
uint64_t Index;
image_tool_segment_t *Segment;
assert (Image != NULL);
SegmentInfo = &Image->SegmentInfo;
for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) {
Segment = &SegmentInfo->Segments[Index];
assert (Segment->DataSize <= Segment->ImageSize);
Segment->DataSize = Segment->ImageSize;
}
Image->HeaderInfo.IsXip = true;
return true;
}
void void
ImageShrinkSegmentData ( ImageInitUnpaddedSize (
const image_tool_image_info_t *Image const image_tool_image_info_t *Image
) )
{ {
@ -329,8 +314,14 @@ ImageShrinkSegmentData (
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) { for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
Segment = &Image->SegmentInfo.Segments[Index]; Segment = &Image->SegmentInfo.Segments[Index];
for (; Segment->DataSize > 0; --Segment->DataSize) { Segment->UnpaddedSize = Segment->ImageSize;
if (Segment->Data[Segment->DataSize - 1] != 0) {
if (Image->HeaderInfo.IsXip) {
continue;
}
for (; Segment->UnpaddedSize > 0; --Segment->UnpaddedSize) {
if (Segment->Data[Segment->UnpaddedSize - 1] != 0) {
break; break;
} }
} }
@ -348,28 +339,16 @@ ToolImageDestruct (
if (Image->SegmentInfo.Segments != NULL) { if (Image->SegmentInfo.Segments != NULL) {
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) { for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
if (Image->SegmentInfo.Segments[Index].Name != NULL) { free (Image->SegmentInfo.Segments[Index].Name);
free (Image->SegmentInfo.Segments[Index].Name); free (Image->SegmentInfo.Segments[Index].Data);
}
if (Image->SegmentInfo.Segments[Index].DataSize != 0) {
free (Image->SegmentInfo.Segments[Index].Data);
}
} }
free (Image->SegmentInfo.Segments); free (Image->SegmentInfo.Segments);
} }
if (Image->HiiInfo.Data != NULL) { free (Image->HiiInfo.Data);
free (Image->HiiInfo.Data); free (Image->RelocInfo.Relocs);
} free (Image->DebugInfo.SymbolsPath);
if (Image->RelocInfo.Relocs != NULL) {
free (Image->RelocInfo.Relocs);
}
if (Image->DebugInfo.SymbolsPath != NULL) {
free (Image->DebugInfo.SymbolsPath);
}
memset (Image, 0, sizeof (*Image)); memset (Image, 0, sizeof (*Image));
} }
@ -451,3 +430,212 @@ ToolImageRelocate (
return true; return true;
} }
static
INTN
EFIAPI
ToolImageRelocCompare (
IN CONST VOID *Buffer1,
IN CONST VOID *Buffer2
)
{
const image_tool_reloc_t *Reloc1;
const image_tool_reloc_t *Reloc2;
Reloc1 = (const image_tool_reloc_t *)Buffer1;
Reloc2 = (const image_tool_reloc_t *)Buffer2;
if (Reloc1->Target < Reloc2->Target) {
return -1;
}
if (Reloc1->Target > Reloc2->Target) {
return 1;
}
return 0;
}
void
ToolImageSortRelocs (
image_tool_image_info_t *Image
)
{
image_tool_reloc_t OneElement;
if (Image->RelocInfo.Relocs == NULL) {
return;
}
QuickSort (
Image->RelocInfo.Relocs,
Image->RelocInfo.NumRelocs,
sizeof (*Image->RelocInfo.Relocs),
ToolImageRelocCompare,
&OneElement
);
}
bool
ToolImageCompare (
const image_tool_image_info_t *Image1,
const image_tool_image_info_t *Image2
)
{
int CmpResult;
uint32_t SegIndex;
const char *Name1;
const char *Name2;
uint32_t NameIndex;
//
// Compare HeaderInfo.
//
CmpResult = memcmp (
&Image1->HeaderInfo,
&Image2->HeaderInfo,
sizeof (Image1->HeaderInfo)
);
if (CmpResult != 0) {
raise ();
return false;
}
//
// Compare SegmentInfo.
// UnpaddedSize is deliberately omitted, as it's implicit by the equality of
// ImageSize and Data.
//
CmpResult = memcmp (
&Image1->SegmentInfo,
&Image2->SegmentInfo,
OFFSET_OF (image_tool_segment_info_t, Segments)
);
if (CmpResult != 0) {
raise ();
return false;
}
for (SegIndex = 0; SegIndex < Image1->SegmentInfo.NumSegments; ++SegIndex) {
CmpResult = memcmp (
&Image1->SegmentInfo.Segments[SegIndex],
&Image2->SegmentInfo.Segments[SegIndex],
OFFSET_OF (image_tool_segment_t, Name)
);
if (CmpResult != 0) {
raise ();
return false;
}
//
// Don't assume images generally support arbitrarily long names or names in
// general. Check prefix equiality as a best effort.
//
Name1 = Image1->SegmentInfo.Segments[SegIndex].Name;
Name2 = Image2->SegmentInfo.Segments[SegIndex].Name;
if (Name1 != NULL && Name2 != NULL) {
for (
NameIndex = 0;
Name1[NameIndex] != '\0' && Name2[NameIndex] != '\0';
++NameIndex
) {
if (Name1[NameIndex] != Name2[NameIndex]) {
raise ();
return false;
}
}
}
CmpResult = memcmp (
Image1->SegmentInfo.Segments[SegIndex].Data,
Image2->SegmentInfo.Segments[SegIndex].Data,
Image1->SegmentInfo.Segments[SegIndex].ImageSize
);
if (CmpResult != 0) {
raise ();
return false;
}
}
//
// Compare RelocInfo.
//
CmpResult = memcmp (
&Image1->RelocInfo,
&Image2->RelocInfo,
OFFSET_OF (image_tool_reloc_info_t, Relocs)
);
if (CmpResult != 0) {
raise ();
return false;
}
CmpResult = memcmp (
Image1->RelocInfo.Relocs,
Image2->RelocInfo.Relocs,
Image1->RelocInfo.NumRelocs * sizeof (*Image1->RelocInfo.Relocs)
);
if (CmpResult != 0) {
raise ();
return false;
}
//
// Compare HiiInfo.
//
CmpResult = memcmp (
&Image1->HiiInfo,
&Image2->HiiInfo,
OFFSET_OF (image_tool_hii_info_t, Data)
);
if (CmpResult != 0) {
raise ();
return false;
}
CmpResult = memcmp (
Image1->HiiInfo.Data,
Image2->HiiInfo.Data,
Image1->HiiInfo.DataSize
);
if (CmpResult != 0) {
raise ();
return false;
}
//
// Compare DebugInfo.
//
CmpResult = memcmp (
&Image1->DebugInfo,
&Image2->DebugInfo,
OFFSET_OF (image_tool_debug_info_t, SymbolsPath)
);
if (CmpResult != 0) {
raise ();
return false;
}
if ((Image1->DebugInfo.SymbolsPath != NULL) != (Image2->DebugInfo.SymbolsPath != NULL)) {
raise ();
return false;
}
if (Image1->DebugInfo.SymbolsPath != NULL) {
CmpResult = strcmp (
Image1->DebugInfo.SymbolsPath,
Image2->DebugInfo.SymbolsPath
);
if (CmpResult != 0) {
raise ();
return false;
}
}
return true;
}

View File

@ -270,6 +270,43 @@ ImageSetModuleType (
return true; return true;
} }
static
RETURN_STATUS
ValidateOutputFile (
void *OutputFile,
uint32_t OutputFileSize,
const image_tool_image_info_t *ImageInfo
)
{
RETURN_STATUS Status;
bool Result;
image_tool_image_info_t OutputImageInfo;
Status = ToolContextConstructPe (&OutputImageInfo, OutputFile, OutputFileSize);
if (EFI_ERROR (Status)) {
assert (false);
return Status;
}
Result = CheckToolImage (&OutputImageInfo);
if (!Result) {
raise ();
ToolImageDestruct (&OutputImageInfo);
return RETURN_UNSUPPORTED;
}
Result = ToolImageCompare (&OutputImageInfo, ImageInfo);
ToolImageDestruct (&OutputImageInfo);
if (!Result) {
assert (false);
return RETURN_VOLUME_CORRUPTED;
}
return RETURN_SUCCESS;
}
static static
RETURN_STATUS RETURN_STATUS
GenExecutable ( GenExecutable (
@ -331,6 +368,8 @@ GenExecutable (
ImageInfo.HiiInfo.DataSize = HiiFileSize; ImageInfo.HiiInfo.DataSize = HiiFileSize;
} }
ToolImageSortRelocs (&ImageInfo);
Result = CheckToolImage (&ImageInfo); Result = CheckToolImage (&ImageInfo);
if (!Result) { if (!Result) {
ToolImageDestruct (&ImageInfo); ToolImageDestruct (&ImageInfo);
@ -359,10 +398,18 @@ GenExecutable (
assert (false); assert (false);
} }
if (OutputFile == NULL) {
ToolImageDestruct (&ImageInfo);
return RETURN_ABORTED;
}
Status = ValidateOutputFile (OutputFile, OutputFileSize, &ImageInfo);
ToolImageDestruct (&ImageInfo); ToolImageDestruct (&ImageInfo);
if (OutputFile == NULL) { if (EFI_ERROR (Status)) {
return RETURN_ABORTED; assert (false);
return Status;
} }
UserWriteFile (OutputFileName, OutputFile, OutputFileSize); UserWriteFile (OutputFileName, OutputFile, OutputFileSize);

View File

@ -39,40 +39,49 @@ typedef struct {
uint32_t EntryPointAddress; uint32_t EntryPointAddress;
uint16_t Machine; uint16_t Machine;
uint16_t Subsystem; uint16_t Subsystem;
bool IsXip; uint8_t IsXip;
uint8_t Reserved[7];
} image_tool_header_info_t; } image_tool_header_info_t;
typedef struct { typedef struct {
char *Name;
uint8_t *Data;
uint32_t DataSize;
uint32_t ImageAddress; uint32_t ImageAddress;
uint32_t ImageSize; uint32_t ImageSize;
bool Read; uint8_t Read;
bool Write; uint8_t Write;
bool Execute; uint8_t Execute;
uint8_t Reserved[1];
char *Name;
uint8_t *Data;
uint32_t UnpaddedSize;
} image_tool_segment_t; } image_tool_segment_t;
typedef struct { typedef struct {
uint32_t SegmentAlignment; uint32_t SegmentAlignment;
uint32_t NumSegments; uint32_t NumSegments;
image_tool_segment_t *Segments; image_tool_segment_t *Segments;
} image_tool_segment_info_t; } image_tool_segment_info_t;
typedef struct { typedef struct {
uint8_t Type; uint8_t Type;
uint8_t Reserved[3];
uint32_t Target; uint32_t Target;
} image_tool_reloc_t; } image_tool_reloc_t;
typedef struct { typedef struct {
uint32_t NumRelocs; uint32_t NumRelocs;
bool RelocsStripped; uint8_t RelocsStripped;
uint8_t Reserved[3];
image_tool_reloc_t *Relocs; image_tool_reloc_t *Relocs;
} image_tool_reloc_info_t; } image_tool_reloc_info_t;
typedef struct { typedef struct {
char *SymbolsPath;
uint32_t SymbolsPathLen; uint32_t SymbolsPathLen;
char *SymbolsPath;
} image_tool_debug_info_t; } image_tool_debug_info_t;
typedef struct { typedef struct {
@ -81,8 +90,9 @@ typedef struct {
} image_tool_pe_datadir_info_t; } image_tool_pe_datadir_info_t;
typedef struct { typedef struct {
void *Data;
uint32_t DataSize; uint32_t DataSize;
void *Data;
} image_tool_hii_info_t; } image_tool_hii_info_t;
typedef struct { typedef struct {
@ -99,21 +109,27 @@ ToolImageDestruct (
); );
void void
ImageShrinkSegmentData ( ImageInitUnpaddedSize (
const image_tool_image_info_t *Image const image_tool_image_info_t *Image
); );
bool
ImageConvertToXip (
image_tool_image_info_t *Image
);
bool bool
ToolImageRelocate ( ToolImageRelocate (
image_tool_image_info_t *Image, image_tool_image_info_t *Image,
uint64_t BaseAddress uint64_t BaseAddress
); );
void
ToolImageSortRelocs (
image_tool_image_info_t *Image
);
bool
ToolImageCompare (
const image_tool_image_info_t *Image1,
const image_tool_image_info_t *Image2
);
RETURN_STATUS RETURN_STATUS
ToolContextConstructPe ( ToolContextConstructPe (
OUT image_tool_image_info_t *Image, OUT image_tool_image_info_t *Image,
@ -128,8 +144,8 @@ CheckToolImage (
void * void *
ToolImageEmitPe ( ToolImageEmitPe (
const image_tool_image_info_t *Image, image_tool_image_info_t *Image,
uint32_t *FileSize uint32_t *FileSize
); );
RETURN_STATUS RETURN_STATUS

View File

@ -30,7 +30,7 @@ ERRO = $(UDK_PATH)\MdePkg\Library\BaseDebugPrintErrorLevelLib
BMPN = $(UDK_PATH)\MdeModulePkg\Library\BaseMemoryProfileLibNull BMPN = $(UDK_PATH)\MdeModulePkg\Library\BaseMemoryProfileLibNull
CMEM = $(UDK_PATH)\MdeModulePkg\Library\CommonMemoryAllocationLib CMEM = $(UDK_PATH)\MdeModulePkg\Library\CommonMemoryAllocationLib
USER = $(OC_USER)\User\Library USER = $(OC_USER)\User\Library
OBJECTS = $(OBJECTS) {$(BASE)}SafeString.obj String.obj SwapBytes16.obj SwapBytes32.obj CpuDeadLoop.obj CheckSum.obj OBJECTS = $(OBJECTS) {$(BASE)}SafeString.obj String.obj SwapBytes16.obj SwapBytes32.obj CpuDeadLoop.obj CheckSum.obj QuickSort.obj
OBJECTS = $(OBJECTS) {$(OUT)}DebugLib.obj {$(PRIN)}PrintLib.obj PrintLibInternal.obj {$(ERRO)}BaseDebugPrintErrorLevelLib.obj OBJECTS = $(OBJECTS) {$(OUT)}DebugLib.obj {$(PRIN)}PrintLib.obj PrintLibInternal.obj {$(ERRO)}BaseDebugPrintErrorLevelLib.obj
OBJECTS = $(OBJECTS) {$(USER)}UserFile.obj UserBaseMemoryLib.obj UserMath.obj UserPcd.obj UserMisc.obj UserGlobalVar.obj UserBootServices.obj OBJECTS = $(OBJECTS) {$(USER)}UserFile.obj UserBaseMemoryLib.obj UserMath.obj UserPcd.obj UserMisc.obj UserGlobalVar.obj UserBootServices.obj
OBJECTS = $(OBJECTS) {$(BMPN)}BaseMemoryProfileLibNull.obj {$(CMEM)}CommonMemoryAllocationLib.obj {$(CMEM)}CommonMemoryAllocationLibEx.obj OBJECTS = $(OBJECTS) {$(BMPN)}BaseMemoryProfileLibNull.obj {$(CMEM)}CommonMemoryAllocationLib.obj {$(CMEM)}CommonMemoryAllocationLibEx.obj

View File

@ -99,7 +99,7 @@ EmitPeGetSectionsSize (
for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) { for (Index = 0; Index < Image->SegmentInfo.NumSegments; ++Index) {
Overflow = BaseOverflowAlignUpU32 ( Overflow = BaseOverflowAlignUpU32 (
Image->SegmentInfo.Segments[Index].DataSize, Image->SegmentInfo.Segments[Index].UnpaddedSize,
Context->FileAlignment, Context->FileAlignment,
&DataSize &DataSize
); );
@ -325,7 +325,7 @@ ToolImageEmitPeSectionHeaders (
Sections[Index].PointerToRawData = SectionOffset; Sections[Index].PointerToRawData = SectionOffset;
Sections[Index].VirtualAddress = SectionOffset; Sections[Index].VirtualAddress = SectionOffset;
Sections[Index].SizeOfRawData = ALIGN_VALUE (Image->SegmentInfo.Segments[Index].DataSize, Context->FileAlignment); Sections[Index].SizeOfRawData = ALIGN_VALUE (Image->SegmentInfo.Segments[Index].UnpaddedSize, Context->FileAlignment);
Sections[Index].VirtualSize = Image->SegmentInfo.Segments[Index].ImageSize; Sections[Index].VirtualSize = Image->SegmentInfo.Segments[Index].ImageSize;
strncpy ( strncpy (
@ -591,16 +591,16 @@ ToolImageEmitPeSections (
} }
#endif #endif
assert (Segment->DataSize <= *BufferSize); assert (Segment->UnpaddedSize <= *BufferSize);
memmove (*Buffer, Segment->Data, Segment->DataSize); memmove (*Buffer, Segment->Data, Segment->UnpaddedSize);
*BufferSize -= Segment->DataSize; *BufferSize -= Segment->UnpaddedSize;
*Buffer += Segment->DataSize; *Buffer += Segment->UnpaddedSize;
SectionsSize += Segment->DataSize; SectionsSize += Segment->UnpaddedSize;
SectionPadding = ALIGN_VALUE_ADDEND ( SectionPadding = ALIGN_VALUE_ADDEND (
Segment->DataSize, Segment->UnpaddedSize,
Context->FileAlignment Context->FileAlignment
); );
@ -885,8 +885,8 @@ ToolImageEmitPeExtraSections (
#define ToolImageEmitPe PE_SUFFIX (ToolImageEmitPe) #define ToolImageEmitPe PE_SUFFIX (ToolImageEmitPe)
void * void *
ToolImageEmitPe ( ToolImageEmitPe (
const image_tool_image_info_t *Image, image_tool_image_info_t *Image,
uint32_t *FileSize uint32_t *FileSize
) )
{ {
image_tool_pe_emit_context_t Context; image_tool_pe_emit_context_t Context;
@ -906,11 +906,9 @@ ToolImageEmitPe (
// FIXME: Non-XIP is not well-supported right now. // FIXME: Non-XIP is not well-supported right now.
Context.FileAlignment = Image->SegmentInfo.SegmentAlignment; Context.FileAlignment = Image->SegmentInfo.SegmentAlignment;
Result = ImageConvertToXip ((image_tool_image_info_t *)Image); Image->HeaderInfo.IsXip = true;
if (!Result) {
raise (); ImageInitUnpaddedSize (Image);
return NULL;
}
Context.Image = Image; Context.Image = Image;

View File

@ -7,8 +7,8 @@
void * void *
ToolImageEmitPe ( ToolImageEmitPe (
const image_tool_image_info_t *Image, image_tool_image_info_t *Image,
uint32_t *FileSize uint32_t *FileSize
) )
{ {
switch (Image->HeaderInfo.Machine) { switch (Image->HeaderInfo.Machine) {

View File

@ -219,7 +219,6 @@ ScanPeGetSegmentInfo (
memmove (ImageSegment->Name, Section->Name, sizeof (Section->Name)); memmove (ImageSegment->Name, Section->Name, sizeof (Section->Name));
ImageSegment->ImageAddress = Section->VirtualAddress; ImageSegment->ImageAddress = Section->VirtualAddress;
ImageSegment->DataSize = MIN (Section->SizeOfRawData, Section->VirtualSize);
ImageSegment->ImageSize = ALIGN_VALUE (Section->VirtualSize, SegmentInfo->SegmentAlignment); ImageSegment->ImageSize = ALIGN_VALUE (Section->VirtualSize, SegmentInfo->SegmentAlignment);
ImageSegment->Read = (Section->Characteristics & EFI_IMAGE_SCN_MEM_READ) != 0; ImageSegment->Read = (Section->Characteristics & EFI_IMAGE_SCN_MEM_READ) != 0;
ImageSegment->Write = (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0; ImageSegment->Write = (Section->Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0;

@ -1 +1 @@
Subproject commit 76a69c5486477a3c3b2ab2924d4b8b288e44ff8e Subproject commit d185827c701dace24f32f7042ab05a9b0d50d6ec