diff --git a/BaseTools/ImageTool/ElfScan.c b/BaseTools/ImageTool/ElfScan.c index 1ab31f3c08..e42b624bab 100644 --- a/BaseTools/ImageTool/ElfScan.c +++ b/BaseTools/ImageTool/ElfScan.c @@ -717,7 +717,7 @@ CreateIntermediate ( 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].ImageSize = ALIGN_VALUE (Segments[SIndex].DataSize, Context->Alignment); Segments[SIndex].Read = true; diff --git a/BaseTools/ImageTool/Image.c b/BaseTools/ImageTool/Image.c index e1d69f0186..2245521c60 100644 --- a/BaseTools/ImageTool/Image.c +++ b/BaseTools/ImageTool/Image.c @@ -41,7 +41,7 @@ CheckToolImageSegment ( } Overflow = BaseOverflowAddU32 ( - (uint32_t)Segment->ImageAddress, + Segment->ImageAddress, Segment->ImageSize, PreviousEndAddress ); @@ -81,7 +81,7 @@ CheckToolImageSegmentInfo ( return false; } - *ImageSize = (uint32_t)SegmentInfo->Segments[0].ImageAddress; + *ImageSize = SegmentInfo->Segments[0].ImageAddress; for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) { Result = CheckToolImageSegment ( SegmentInfo, @@ -100,17 +100,21 @@ CheckToolImageSegmentInfo ( static const image_tool_segment_t * ImageGetSegmentByAddress ( - const image_tool_segment_info_t *SegmentInfo, - uint64_t Address + uint32_t *Address, + uint32_t *RemainingSize, + const image_tool_segment_info_t *SegmentInfo ) { - uint64_t Index; + uint32_t Index; + assert (Address != NULL); assert (SegmentInfo != NULL); for (Index = 0; Index < SegmentInfo->NumSegments; ++Index) { - if ((SegmentInfo->Segments[Index].ImageAddress <= Address) - && (Address < SegmentInfo->Segments[Index].ImageAddress + SegmentInfo->Segments[Index].ImageSize)) { + if ((SegmentInfo->Segments[Index].ImageAddress <= *Address) + && (*Address < SegmentInfo->Segments[Index].ImageAddress + SegmentInfo->Segments[Index].ImageSize)) { + *Address -= SegmentInfo->Segments[Index].ImageAddress; + *RemainingSize = SegmentInfo->Segments[Index].ImageSize - *Address; return &SegmentInfo->Segments[Index]; } } @@ -122,20 +126,81 @@ static bool CheckToolImageReloc ( const image_tool_image_info_t *Image, + uint32_t ImageSize, const image_tool_reloc_t *Reloc ) { + uint32_t RelocOffset; + uint32_t RemainingSize; const image_tool_segment_t *Segment; + uint16_t MovHigh; + uint16_t MovLow; assert (Image != NULL); assert (Reloc != NULL); - Segment = ImageGetSegmentByAddress (&Image->SegmentInfo, Reloc->Target); + RelocOffset = Reloc->Target; + Segment = ImageGetSegmentByAddress ( + &RelocOffset, + &RemainingSize, + &Image->SegmentInfo + ); if (Segment == NULL) { raise (); 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) { printf("!!! writable reloc at %x !!!\n", Reloc->Target); }*/ @@ -146,7 +211,8 @@ CheckToolImageReloc ( static bool 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; @@ -168,7 +234,7 @@ CheckToolImageRelocInfo ( } for (Index = 0; Index < RelocInfo->NumRelocs; ++Index) { - Result = CheckToolImageReloc (Image, &RelocInfo->Relocs[Index]); + Result = CheckToolImageReloc (Image, ImageSize, &RelocInfo->Relocs[Index]); if (!Result) { raise (); return false; @@ -213,7 +279,7 @@ CheckToolImage ( return false; } - Result = CheckToolImageRelocInfo (Image); + Result = CheckToolImageRelocInfo (Image, ImageSize); if (!Result) { raise (); return false; @@ -307,3 +373,81 @@ ToolImageDestruct ( 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; +} diff --git a/BaseTools/ImageTool/ImageTool.c b/BaseTools/ImageTool/ImageTool.c index 3dfcdc319d..711723367b 100644 --- a/BaseTools/ImageTool/ImageTool.c +++ b/BaseTools/ImageTool/ImageTool.c @@ -50,71 +50,6 @@ HiiBin ( 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 RETURN_STATUS CheckAcpiTable ( @@ -342,7 +277,8 @@ GenExecutable ( IN const char *OutputFileName, IN const char *InputFileName, IN const char *FormatName, - IN const char *TypeName + IN const char *TypeName, + IN const char *BaseAddress ) { UINT32 InputFileSize; @@ -350,6 +286,7 @@ GenExecutable ( RETURN_STATUS Status; bool Result; image_tool_image_info_t ImageInfo; + UINT64 NewBaseAddress; void *OutputFile; uint32_t OutputFileSize; @@ -385,6 +322,22 @@ GenExecutable ( 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) { OutputFile = ToolImageEmitPe (&ImageInfo, &OutputFileSize); } else { @@ -423,7 +376,7 @@ int main (int argc, const char *argv[]) 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)) { raise (); return -1; @@ -466,7 +419,7 @@ int main (int argc, const char *argv[]) return -1; } - Status = Rebase (argv[2], argv[3], argv[4]); + Status = GenExecutable (argv[4], argv[3], "PE", NULL, argv[2]); if (RETURN_ERROR (Status)) { raise (); return -1; diff --git a/BaseTools/ImageTool/ImageTool.h b/BaseTools/ImageTool/ImageTool.h index efa4a8dab0..efb0b23a75 100644 --- a/BaseTools/ImageTool/ImageTool.h +++ b/BaseTools/ImageTool/ImageTool.h @@ -46,7 +46,7 @@ typedef struct { char *Name; uint8_t *Data; uint32_t DataSize; - uint64_t ImageAddress; + uint32_t ImageAddress; uint32_t ImageSize; bool Read; bool Write; @@ -108,6 +108,12 @@ ImageConvertToXip ( image_tool_image_info_t *Image ); +bool +ToolImageRelocate ( + image_tool_image_info_t *Image, + uint64_t BaseAddress + ); + RETURN_STATUS ToolContextConstructPe ( OUT image_tool_image_info_t *Image, diff --git a/BaseTools/ImageTool/PeEmit.c b/BaseTools/ImageTool/PeEmit.c index e3a3747367..f937cdf002 100644 --- a/BaseTools/ImageTool/PeEmit.c +++ b/BaseTools/ImageTool/PeEmit.c @@ -563,14 +563,14 @@ ToolImageEmitPeSections ( if (Segment->Execute) { if (FirstCode) { - Context->PeHdr->BaseOfCode = (UINT32)Segment->ImageAddress; + Context->PeHdr->BaseOfCode = Segment->ImageAddress; FirstCode = false; } } #if PE_ARCH == 32 else { if (FirstData) { - Context->PeHdr->BaseOfData = (UINT32)Segment->ImageAddress; + Context->PeHdr->BaseOfData = Segment->ImageAddress; FirstData = false; } } @@ -596,11 +596,11 @@ ToolImageEmitPeSections ( SectionsSize += SectionPadding; 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; } else { #if PE_ARCH == 32 - Context->PeHdr->BaseOfData = MIN(Context->PeHdr->BaseOfData, (UINT32)Segment->ImageAddress); + Context->PeHdr->BaseOfData = MIN(Context->PeHdr->BaseOfData, Segment->ImageAddress); #endif Context->PeHdr->SizeOfInitializedData += Segment->ImageSize; }