ImageTool: Relocate using the IR

This commit is contained in:
Marvin Häuser 2023-04-16 18:31:33 +02:00 committed by Mikhail Krichanov
parent 3a4c288fd3
commit 75662ff41a
5 changed files with 188 additions and 85 deletions

View File

@ -717,7 +717,7 @@ CreateIntermediate (
memcpy (Segments[SIndex].Name, Name, strlen (Name)); memcpy (Segments[SIndex].Name, Name, strlen (Name));
Segments[SIndex].ImageAddress = Shdr->sh_addr - BaseAddress; Segments[SIndex].ImageAddress = (uint32_t)(Shdr->sh_addr - BaseAddress);
Segments[SIndex].DataSize = (uint32_t)Shdr->sh_size; Segments[SIndex].DataSize = (uint32_t)Shdr->sh_size;
Segments[SIndex].ImageSize = ALIGN_VALUE (Segments[SIndex].DataSize, Context->Alignment); Segments[SIndex].ImageSize = ALIGN_VALUE (Segments[SIndex].DataSize, Context->Alignment);
Segments[SIndex].Read = true; Segments[SIndex].Read = true;

View File

@ -41,7 +41,7 @@ CheckToolImageSegment (
} }
Overflow = BaseOverflowAddU32 ( Overflow = BaseOverflowAddU32 (
(uint32_t)Segment->ImageAddress, Segment->ImageAddress,
Segment->ImageSize, Segment->ImageSize,
PreviousEndAddress PreviousEndAddress
); );
@ -81,7 +81,7 @@ CheckToolImageSegmentInfo (
return false; return false;
} }
*ImageSize = (uint32_t)SegmentInfo->Segments[0].ImageAddress; *ImageSize = SegmentInfo->Segments[0].ImageAddress;
for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) { for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) {
Result = CheckToolImageSegment ( Result = CheckToolImageSegment (
SegmentInfo, SegmentInfo,
@ -100,17 +100,21 @@ CheckToolImageSegmentInfo (
static static
const image_tool_segment_t * const image_tool_segment_t *
ImageGetSegmentByAddress ( ImageGetSegmentByAddress (
const image_tool_segment_info_t *SegmentInfo, uint32_t *Address,
uint64_t Address uint32_t *RemainingSize,
const image_tool_segment_info_t *SegmentInfo
) )
{ {
uint64_t Index; uint32_t Index;
assert (Address != NULL);
assert (SegmentInfo != NULL); assert (SegmentInfo != NULL);
for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) { for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) {
if ((SegmentInfo->Segments[Index].ImageAddress <= Address) if ((SegmentInfo->Segments[Index].ImageAddress <= *Address)
&& (Address < SegmentInfo->Segments[Index].ImageAddress + SegmentInfo->Segments[Index].ImageSize)) { && (*Address < SegmentInfo->Segments[Index].ImageAddress + SegmentInfo->Segments[Index].ImageSize)) {
*Address -= SegmentInfo->Segments[Index].ImageAddress;
*RemainingSize = SegmentInfo->Segments[Index].ImageSize - *Address;
return &SegmentInfo->Segments[Index]; return &SegmentInfo->Segments[Index];
} }
} }
@ -122,20 +126,81 @@ static
bool bool
CheckToolImageReloc ( CheckToolImageReloc (
const image_tool_image_info_t *Image, const image_tool_image_info_t *Image,
uint32_t ImageSize,
const image_tool_reloc_t *Reloc const image_tool_reloc_t *Reloc
) )
{ {
uint32_t RelocOffset;
uint32_t RemainingSize;
const image_tool_segment_t *Segment; const image_tool_segment_t *Segment;
uint16_t MovHigh;
uint16_t MovLow;
assert (Image != NULL); assert (Image != NULL);
assert (Reloc != NULL); assert (Reloc != NULL);
Segment = ImageGetSegmentByAddress (&Image->SegmentInfo, Reloc->Target); RelocOffset = Reloc->Target;
Segment = ImageGetSegmentByAddress (
&RelocOffset,
&RemainingSize,
&Image->SegmentInfo
);
if (Segment == NULL) { if (Segment == NULL) {
raise (); raise ();
return false; return false;
} }
switch (Reloc->Type) {
case EFI_IMAGE_REL_BASED_HIGHLOW:
{
if (RemainingSize < sizeof (UINT32)) {
raise ();
return false;
}
break;
}
case EFI_IMAGE_REL_BASED_DIR64:
{
if (RemainingSize < sizeof (UINT64)) {
raise ();
return false;
}
break;
}
case EFI_IMAGE_REL_BASED_ARM_MOV32T:
{
if (RemainingSize < sizeof (UINT32)) {
raise ();
return false;
}
if (!IS_ALIGNED (Reloc->Target, ALIGNOF (UINT16))) {
raise ();
return false;
}
MovHigh = *(const uint16_t *)&Segment->Data[RelocOffset];
MovLow = *(const uint16_t *)&Segment->Data[RelocOffset + 2];
if (((MovHigh & 0xFBF0U) != 0xF200U && (MovHigh & 0xFBF0U) != 0xF2C0U) ||
(MovLow & 0x8000U) != 0) {
raise ();
return false;
}
break;
}
default:
{
raise ();
return false;
}
}
/*if (Segment->Write) { /*if (Segment->Write) {
printf("!!! writable reloc at %x !!!\n", Reloc->Target); printf("!!! writable reloc at %x !!!\n", Reloc->Target);
}*/ }*/
@ -146,7 +211,8 @@ CheckToolImageReloc (
static static
bool bool
CheckToolImageRelocInfo ( CheckToolImageRelocInfo (
const image_tool_image_info_t *Image const image_tool_image_info_t *Image,
uint32_t ImageSize
) )
{ {
const image_tool_reloc_info_t *RelocInfo; const image_tool_reloc_info_t *RelocInfo;
@ -168,7 +234,7 @@ CheckToolImageRelocInfo (
} }
for (Index = 0; Index < RelocInfo->NumRelocs; ++Index) { for (Index = 0; Index < RelocInfo->NumRelocs; ++Index) {
Result = CheckToolImageReloc (Image, &RelocInfo->Relocs[Index]); Result = CheckToolImageReloc (Image, ImageSize, &RelocInfo->Relocs[Index]);
if (!Result) { if (!Result) {
raise (); raise ();
return false; return false;
@ -213,7 +279,7 @@ CheckToolImage (
return false; return false;
} }
Result = CheckToolImageRelocInfo (Image); Result = CheckToolImageRelocInfo (Image, ImageSize);
if (!Result) { if (!Result) {
raise (); raise ();
return false; return false;
@ -307,3 +373,81 @@ ToolImageDestruct (
memset (Image, 0, sizeof (*Image)); memset (Image, 0, sizeof (*Image));
} }
bool
ToolImageRelocate (
image_tool_image_info_t *Image,
uint64_t BaseAddress
)
{
uint64_t Adjust;
const image_tool_reloc_t *Reloc;
uint32_t RelocOffset;
uint32_t RemainingSize;
const image_tool_segment_t *Segment;
uint32_t Index;
uint32_t RelocTarget32;
uint64_t RelocTarget64;
Adjust = BaseAddress - Image->HeaderInfo.BaseAddress;
if (Adjust == 0) {
return TRUE;
}
for (Index = 0; Index < Image->RelocInfo.NumRelocs; ++Index) {
Reloc = &Image->RelocInfo.Relocs[Index];
RelocOffset = Reloc->Target;
Segment = ImageGetSegmentByAddress (
&RelocOffset,
&RemainingSize,
&Image->SegmentInfo
);
if (Segment == NULL) {
raise ();
return false;
}
switch (Reloc->Type) {
case EFI_IMAGE_REL_BASED_HIGHLOW:
{
assert (RemainingSize >= sizeof (UINT32));
RelocTarget32 = ReadUnaligned32 ((CONST VOID *)&Segment->Data[RelocOffset]);
RelocTarget32 += (uint32_t)Adjust;
WriteUnaligned32 ((VOID *)&Segment->Data[RelocOffset], RelocTarget32);
break;
}
case EFI_IMAGE_REL_BASED_DIR64:
{
assert (RemainingSize >= sizeof (UINT64));
RelocTarget64 = ReadUnaligned64 ((CONST VOID *)&Segment->Data[RelocOffset]);
RelocTarget64 += Adjust;
WriteUnaligned64 ((VOID *)&Segment->Data[RelocOffset], RelocTarget64);
break;
}
case EFI_IMAGE_REL_BASED_ARM_MOV32T:
{
assert (RemainingSize >= sizeof (UINT32));
assert (IS_ALIGNED (Reloc->Target, ALIGNOF (UINT16)));
PeCoffThumbMovwMovtImmediateFixup (&Segment->Data[RelocOffset], Adjust);
break;
}
default:
{
raise ();
return false;
}
}
}
Image->HeaderInfo.BaseAddress = BaseAddress;
return true;
}

View File

@ -50,71 +50,6 @@ HiiBin (
return RETURN_SUCCESS; return RETURN_SUCCESS;
} }
static
RETURN_STATUS
Rebase (
IN const char *BaseAddress,
IN const char *OldName,
IN const char *NewName
)
{
RETURN_STATUS Status;
void *Pe;
uint32_t PeSize;
UINT64 NewBaseAddress;
PE_COFF_LOADER_IMAGE_CONTEXT Context;
EFI_IMAGE_NT_HEADERS32 *PeHdr32;
EFI_IMAGE_NT_HEADERS64 *PeHdr64;
assert (BaseAddress != NULL);
assert (OldName != NULL);
assert (NewName != NULL);
Status = AsciiStrHexToUint64S (BaseAddress, NULL, &NewBaseAddress);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not convert ASCII string to UINT64\n");
return Status;
}
Pe = UserReadFile (OldName, &PeSize);
if (Pe == NULL) {
fprintf (stderr, "ImageTool: Could not open %s: %s\n", OldName, strerror (errno));
return RETURN_ABORTED;
}
Status = PeCoffInitializeContext (&Context, Pe, (UINT32)PeSize);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not initialise Context\n");
free (Pe);
return Status;
}
Context.ImageBuffer = (void *)Context.FileBuffer;
Status = PeCoffRelocateImage (&Context, NewBaseAddress, NULL, 0);
if (EFI_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not relocate image\n");
free (Pe);
return Status;
}
if (Context.ImageType == PeCoffLoaderTypePe32) {
PeHdr32 = (EFI_IMAGE_NT_HEADERS32 *)(void *)((char *)Context.ImageBuffer + Context.ExeHdrOffset);
PeHdr32->ImageBase = (UINT32)NewBaseAddress;
} else if (Context.ImageType == PeCoffLoaderTypePe32Plus) {
PeHdr64 = (EFI_IMAGE_NT_HEADERS64 *)(void *)((char *)Context.ImageBuffer + Context.ExeHdrOffset);
PeHdr64->ImageBase = NewBaseAddress;
} else {
assert (false);
}
UserWriteFile (NewName, Pe, PeSize);
free (Pe);
return RETURN_SUCCESS;
}
static static
RETURN_STATUS RETURN_STATUS
CheckAcpiTable ( CheckAcpiTable (
@ -342,7 +277,8 @@ GenExecutable (
IN const char *OutputFileName, IN const char *OutputFileName,
IN const char *InputFileName, IN const char *InputFileName,
IN const char *FormatName, IN const char *FormatName,
IN const char *TypeName IN const char *TypeName,
IN const char *BaseAddress
) )
{ {
UINT32 InputFileSize; UINT32 InputFileSize;
@ -350,6 +286,7 @@ GenExecutable (
RETURN_STATUS Status; RETURN_STATUS Status;
bool Result; bool Result;
image_tool_image_info_t ImageInfo; image_tool_image_info_t ImageInfo;
UINT64 NewBaseAddress;
void *OutputFile; void *OutputFile;
uint32_t OutputFileSize; uint32_t OutputFileSize;
@ -385,6 +322,22 @@ GenExecutable (
return RETURN_UNSUPPORTED; return RETURN_UNSUPPORTED;
} }
if (BaseAddress != NULL) {
Status = AsciiStrHexToUint64S (BaseAddress, NULL, &NewBaseAddress);
if (RETURN_ERROR (Status)) {
fprintf (stderr, "ImageTool: Could not convert ASCII string to UINT64\n");
ToolImageDestruct (&ImageInfo);
return Status;
}
Result = ToolImageRelocate (&ImageInfo, NewBaseAddress);
if (!Result) {
fprintf (stderr, "ImageTool: Failed to relocate input file %s\n", InputFileName);
ToolImageDestruct (&ImageInfo);
return RETURN_UNSUPPORTED;
}
}
if (strcmp (FormatName, "PE") == 0) { if (strcmp (FormatName, "PE") == 0) {
OutputFile = ToolImageEmitPe (&ImageInfo, &OutputFileSize); OutputFile = ToolImageEmitPe (&ImageInfo, &OutputFileSize);
} else { } else {
@ -423,7 +376,7 @@ int main (int argc, const char *argv[])
return -1; return -1;
} }
Status = GenExecutable (argv[3], argv[2], "PE", argv[4]); Status = GenExecutable (argv[3], argv[2], "PE", argv[4], NULL);
if (RETURN_ERROR (Status)) { if (RETURN_ERROR (Status)) {
raise (); raise ();
return -1; return -1;
@ -466,7 +419,7 @@ int main (int argc, const char *argv[])
return -1; return -1;
} }
Status = Rebase (argv[2], argv[3], argv[4]); Status = GenExecutable (argv[4], argv[3], "PE", NULL, argv[2]);
if (RETURN_ERROR (Status)) { if (RETURN_ERROR (Status)) {
raise (); raise ();
return -1; return -1;

View File

@ -46,7 +46,7 @@ typedef struct {
char *Name; char *Name;
uint8_t *Data; uint8_t *Data;
uint32_t DataSize; uint32_t DataSize;
uint64_t ImageAddress; uint32_t ImageAddress;
uint32_t ImageSize; uint32_t ImageSize;
bool Read; bool Read;
bool Write; bool Write;
@ -108,6 +108,12 @@ ImageConvertToXip (
image_tool_image_info_t *Image image_tool_image_info_t *Image
); );
bool
ToolImageRelocate (
image_tool_image_info_t *Image,
uint64_t BaseAddress
);
RETURN_STATUS RETURN_STATUS
ToolContextConstructPe ( ToolContextConstructPe (
OUT image_tool_image_info_t *Image, OUT image_tool_image_info_t *Image,

View File

@ -563,14 +563,14 @@ ToolImageEmitPeSections (
if (Segment->Execute) { if (Segment->Execute) {
if (FirstCode) { if (FirstCode) {
Context->PeHdr->BaseOfCode = (UINT32)Segment->ImageAddress; Context->PeHdr->BaseOfCode = Segment->ImageAddress;
FirstCode = false; FirstCode = false;
} }
} }
#if PE_ARCH == 32 #if PE_ARCH == 32
else { else {
if (FirstData) { if (FirstData) {
Context->PeHdr->BaseOfData = (UINT32)Segment->ImageAddress; Context->PeHdr->BaseOfData = Segment->ImageAddress;
FirstData = false; FirstData = false;
} }
} }
@ -596,11 +596,11 @@ ToolImageEmitPeSections (
SectionsSize += SectionPadding; SectionsSize += SectionPadding;
if (Segment->Execute) { if (Segment->Execute) {
Context->PeHdr->BaseOfCode = MIN(Context->PeHdr->BaseOfCode, (UINT32)Segment->ImageAddress); Context->PeHdr->BaseOfCode = MIN(Context->PeHdr->BaseOfCode, Segment->ImageAddress);
Context->PeHdr->SizeOfCode += Segment->ImageSize; Context->PeHdr->SizeOfCode += Segment->ImageSize;
} else { } else {
#if PE_ARCH == 32 #if PE_ARCH == 32
Context->PeHdr->BaseOfData = MIN(Context->PeHdr->BaseOfData, (UINT32)Segment->ImageAddress); Context->PeHdr->BaseOfData = MIN(Context->PeHdr->BaseOfData, Segment->ImageAddress);
#endif #endif
Context->PeHdr->SizeOfInitializedData += Segment->ImageSize; Context->PeHdr->SizeOfInitializedData += Segment->ImageSize;
} }