BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=557
The XCODE toolchain does not suport injecting resource sections via
libraries so add --rc to GenFw to inject $(MODULE_NAME)hii.rc into
the final PE/COFF image.
Since moving exiting code around would break source level debugging
we must reuse an existing empty section, or add a new section header.
If there is not space to add a new section header append to the
last section. The resource entry if found via a directory entry
so the PE/COFF loading code does not depend on the section type.
Signed-off-by: Andrew Fish <afish@apple.com>
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
---
BaseTools/Source/C/GenFw/GenFw.c | 370 +++++++++++++++++++++++++++++++
1 file changed, 370 insertions(+)
diff --git a/BaseTools/Source/C/GenFw/GenFw.c b/BaseTools/Source/C/GenFw/GenFw.c
index 8cab70ba4d5f..748af5dff259 100644
--- a/BaseTools/Source/C/GenFw/GenFw.c
+++ b/BaseTools/Source/C/GenFw/GenFw.c
@@ -96,6 +96,16 @@ ZeroDebugData (
BOOLEAN ZeroDebug
);
+STATIC
+EFI_STATUS
+PatchResourceData (
+ IN UINT32 Type,
+ IN UINT8 *ResourceData,
+ IN UINT32 ResourceDataSize,
+ IN OUT UINT8 **PeCoff,
+ IN OUT UINT32 *PeCoffSize
+ );
+
STATIC
EFI_STATUS
SetStamp (
@@ -267,6 +277,11 @@ Returns:
except for -o option. It is a action option.\n\
If it is combined with other action options, the later\n\
input action option will override the previous one.\n");
+ fprintf (stdout, " --rc FlieName Append a Hii resource section to the\n\
+ last PE/COFF section. The FileName is the resource section to append\n\
+ If FileName does not exist this operation is skipped. This feature is\n\
+ only intended for toolchains, like XCODE, that don't suport $(RC).\n\
+ This option can only be combined with -e\n");
fprintf (stdout, " --rebase NewAddress Rebase image to new base address. New address \n\
is also set to the first none code section header.\n\
It can't be combined with other action options\n\
@@ -1059,10 +1074,12 @@ Returns:
CHAR8 **InputFileName;
char *OutImageName;
char *ModuleType;
+ char *RcFileName;
CHAR8 *TimeStamp;
FILE *fpIn;
FILE *fpOut;
FILE *fpInOut;
+ FILE *fpRc;
UINT32 Data;
UINT32 *DataPointer;
UINT32 *OldDataPointer;
@@ -1080,6 +1097,8 @@ Returns:
UINT32 OutputFileLength;
UINT8 *InputFileBuffer;
UINT32 InputFileLength;
+ UINT8 *RcFileBuffer;
+ UINT32 RcFileLength;
RUNTIME_FUNCTION *RuntimeFunction;
UNWIND_INFO *UnwindInfo;
STATUS Status;
@@ -1116,6 +1135,7 @@ Returns:
time_t OutputFileTime;
struct stat Stat_Buf;
BOOLEAN ZeroDebugFlag;
+ BOOLEAN InsertRcFile;
SetUtilityName (UTILITY_NAME);
@@ -1128,6 +1148,7 @@ Returns:
mInImageName = NULL;
OutImageName = NULL;
ModuleType = NULL;
+ RcFileName = NULL;
Type = 0;
Status = STATUS_SUCCESS;
FileBuffer = NULL;
@@ -1164,6 +1185,7 @@ Returns:
InputFileTime = 0;
OutputFileTime = 0;
ZeroDebugFlag = FALSE;
+ InsertRcFile = FALSE;
if (argc == 1) {
Error (NULL, 0, 1001, "Missing options", "No input options.");
@@ -1436,6 +1458,20 @@ Returns:
continue;
}
+ if (stricmp (argv[0], "--rc") == 0) {
+ RcFileName = argv[1];
+ argc -= 2;
+ argv += 2;
+
+ if (stat (RcFileName, &Stat_Buf) == 0) {
+ //
+ // File exists
+ //
+ InsertRcFile = TRUE;
+ }
+ continue;
+ }
+
if (argv[0][0] == '-') {
Error (NULL, 0, 1000, "Unknown option", argv[0]);
goto Finish;
@@ -1568,6 +1604,10 @@ Returns:
break;
}
+ if (InsertRcFile) {
+ VerboseMsg ("RC input file %s", RcFileName);
+ }
+
if (ReplaceFlag) {
VerboseMsg ("Overwrite the input file with the output content.");
}
@@ -2052,6 +2092,52 @@ Returns:
}
}
+ //
+ // Insert Resources into the image.
+ //
+ if (InsertRcFile) {
+ fpRc = fopen (LongFilePath (RcFileName), "rb");
+ if (fpRc == NULL) {
+ Error (NULL, 0, 0001, "Error opening file", RcFileName);
+ goto Finish;
+ }
+
+ RcFileLength = _filelength (fileno (fpRc));
+ RcFileBuffer = malloc (RcFileLength);
+ if (FileBuffer == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
+ fclose (fpRc);
+ goto Finish;
+ }
+
+ fread (RcFileBuffer, 1, RcFileLength, fpRc);
+ fclose (fpRc);
+
+ Status = PatchResourceData (Type, RcFileBuffer, RcFileLength, &FileBuffer, &FileLength);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "RC Patch Data Error status is 0x%x", (int) Status);
+ goto Finish;
+ }
+
+ fpOut = fopen (LongFilePath (OutImageName), "wb");
+ if (fpOut == NULL) {
+ Error (NULL, 0, 0001, "Error opening output file", OutImageName);
+ goto Finish;
+ }
+
+ fwrite (FileBuffer, 1, FileLength, fpOut);
+
+ fclose (fpOut);
+ fpOut = NULL;
+ VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength);
+
+ //
+ // Write the updated Image
+ //
+ goto Finish;
+ }
+
+
//
// Convert ELF image to PeImage
//
@@ -2761,6 +2847,290 @@ Finish:
return GetUtilityStatus ();
}
+#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))
+
+STATIC
+EFI_STATUS
+PatchResourceData (
+ IN UINT32 Type,
+ IN UINT8 *ResourceData,
+ IN UINT32 ResourceDataSize,
+ IN OUT UINT8 **PeCoff,
+ IN OUT UINT32 *PeCoffSize
+ )
+/*++
+
+Routine Description:
+
+ Embed Resource data into a PE/COFF image.
+
+ If there is free space between the header and the image add a new
+ .rsrc section to the PE/COFF image. If no space exists then append
+ the resource data to the last section.
+
+Arguments:
+
+ Type - If not zero them update PE/COFF header module type.
+ ResourceData - *hii.rc data to insert into the image.
+ ResourceDataSize - Size of ResourceData in bytes.
+ PeCoff - On input existing PE/COFF, on output input PE/COFF with
+ ResourceData embedded.
+ PeCoffSize - Size of PeCoff in bytes.
+
+Returns:
+
+ EFI_ABORTED - PeImage is invalid.
+ EFI_SUCCESS - Zero debug data successfully.
+
+--*/
+{
+ UINT8 *FileBuffer;
+ UINT32 FileBufferSize;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_FILE_HEADER *FileHdr;
+ EFI_IMAGE_OPTIONAL_HEADER32 *Optional32Hdr;
+ EFI_IMAGE_OPTIONAL_HEADER64 *Optional64Hdr;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+ UINT32 FileAlignment;
+ UINT32 Max;
+ INTN LastSection;
+ INTN EmptySection;
+ UINT32 ActualHeaderSize;
+ UINT32 StartingPeCoffSize;
+ UINT32 NewHeaderSize;
+ CHAR8 *Base;
+ EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;
+ EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;
+ EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;
+ EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;
+ EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
+ CHAR16 *String;
+ UINT32 Offset;
+ UINT32 Index;
+
+ //
+ // Grow the file in units of FileAlignment
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) *PeCoff;
+ if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ // NO DOS header, must start with PE/COFF header
+ FileHdr = (EFI_IMAGE_FILE_HEADER *)(*PeCoff + sizeof (UINT32));
+ } else {
+ FileHdr = (EFI_IMAGE_FILE_HEADER *)(*PeCoff + DosHdr->e_lfanew + sizeof (UINT32));
+ }
+
+ Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));
+ Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));
+ if (Optional32Hdr->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ FileAlignment = Optional32Hdr->FileAlignment;
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader);
+ } else {
+ FileAlignment = Optional64Hdr->FileAlignment;
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader);
+ }
+
+ LastSection = -1;
+ for (Index = 0, Max = 0; Index < FileHdr->NumberOfSections; Index++) {
+ if (SectionHeader[Index].PointerToRawData > Max) {
+ Max = SectionHeader[Index].PointerToRawData;
+ LastSection = Index;
+ }
+ }
+
+ EmptySection = -1;
+ for (Index = 0; Index < FileHdr->NumberOfSections; Index++) {
+ if ((SectionHeader[Index].Misc.VirtualSize == 0) && (SectionHeader[Index].SizeOfRawData == 0)) {
+ //
+ // No Data or Zero Fill so we can repurpose this entry.
+ //
+ EmptySection = Index;
+ break;
+ }
+ }
+
+ if (EmptySection == -1) {
+ ActualHeaderSize = (UINTN)(&SectionHeader[FileHdr->NumberOfSections]) - (UINTN)*PeCoff;
+ if ((ActualHeaderSize + sizeof (EFI_IMAGE_SECTION_HEADER)) <= Optional32Hdr->SizeOfHeaders) {
+ //
+ // There is space to inject a new section.
+ //
+ FileHdr->NumberOfSections += 1;
+ EmptySection = Index;
+ }
+ }
+
+ StartingPeCoffSize = SectionHeader[LastSection].PointerToRawData + SectionHeader[LastSection].SizeOfRawData;
+ if (SectionHeader[LastSection].Misc.VirtualSize > SectionHeader[LastSection].SizeOfRawData) {
+ StartingPeCoffSize += SectionHeader[LastSection].Misc.VirtualSize - SectionHeader[LastSection].SizeOfRawData;
+ }
+
+ FileBufferSize = ALIGN_VALUE(StartingPeCoffSize + ResourceDataSize, FileAlignment);
+ FileBuffer = malloc (FileBufferSize);
+ if (FileBuffer == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ memset (FileBuffer, 0, FileBufferSize);
+
+ //
+ // Append the Resource Data to the end of the PE/COFF image.
+ //
+ NewHeaderSize = Optional32Hdr->SizeOfHeaders;
+ CopyMem (FileBuffer, *PeCoff, (StartingPeCoffSize > *PeCoffSize) ? *PeCoffSize: StartingPeCoffSize);
+ CopyMem (FileBuffer + StartingPeCoffSize, ResourceData, ResourceDataSize);
+
+ free (*PeCoff);
+ *PeCoff = FileBuffer;
+ *PeCoffSize = FileBufferSize;
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;
+ if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ // NO DOS header, must start with PE/COFF header
+ FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + sizeof (UINT32));
+ } else {
+ FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof (UINT32));
+ }
+
+ //
+ // Get Resource EntryTable offset, and Section header
+ //
+ Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));
+ Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));
+ DirectoryEntry = NULL;
+ if (Optional32Hdr->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader);
+ if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) {
+ DirectoryEntry = &Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
+ }
+ } else {
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader);
+ if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) {
+ DirectoryEntry = &Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
+ }
+ }
+
+ if (DirectoryEntry == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ if (EmptySection != -1) {
+ //
+ // Create a new section
+ //
+ CopyMem (SectionHeader[EmptySection].Name, ".rsrc\0\0\0", EFI_IMAGE_SIZEOF_SHORT_NAME);
+ SectionHeader[EmptySection].Misc.VirtualSize = ResourceDataSize;
+ SectionHeader[EmptySection].VirtualAddress = StartingPeCoffSize;
+ SectionHeader[EmptySection].SizeOfRawData = ALIGN_VALUE(ResourceDataSize, FileAlignment);
+ SectionHeader[EmptySection].PointerToRawData = StartingPeCoffSize;
+
+ SectionHeader[EmptySection].Characteristics = EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_READ;
+ SectionHeader[EmptySection].Characteristics |= EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | EFI_IMAGE_SCN_CNT_CODE;
+
+ DirectoryEntry->VirtualAddress = SectionHeader[EmptySection].VirtualAddress;
+ } else {
+ //
+ // Grow the last section to include the resources.
+ // For Xcode this is always the .debug section.
+ //
+ SectionHeader[LastSection].SizeOfRawData = ALIGN_VALUE(SectionHeader[LastSection].SizeOfRawData + ResourceDataSize, FileAlignment);
+
+ //
+ // Make sure the Virtual Size uses the file aligned actual size, since we are growing the file.
+ //
+ SectionHeader[LastSection].Misc.VirtualSize = SectionHeader[LastSection].SizeOfRawData;
+
+ DirectoryEntry->VirtualAddress = StartingPeCoffSize;
+ }
+ DirectoryEntry->Size = ResourceDataSize;
+
+ Optional32Hdr->SizeOfImage = ALIGN_VALUE(*PeCoffSize, Optional32Hdr->SectionAlignment);
+ if (Type != 0) {
+ Optional32Hdr->Subsystem = Type;
+ }
+
+ //
+ // It looks like the ResourceDataEntry->OffsetToData is relative to the rc file,
+ // but PeCoffLoaderLoadImage() assumes it is a PE/COFF VirtualAddress so we need
+ // to fix it up. Walk the ResourceDataEntry just like PeCoffLoaderLoadImage() and
+ // patch it.
+ //
+ Base = (CHAR8 *)(FileBuffer + StartingPeCoffSize);
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)Base;
+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
+
+ for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
+ if (ResourceDirectoryEntry->u1.s.NameIsString) {
+ //
+ // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
+ //
+ if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {
+ return RETURN_UNSUPPORTED;
+ }
+ ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);
+ String = &ResourceDirectoryString->String[0];
+
+ if (ResourceDirectoryString->Length == 3 &&
+ String[0] == L'H' &&
+ String[1] == L'I' &&
+ String[2] == L'I') {
+ //
+ // Resource Type "HII" found
+ //
+ if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
+ //
+ // Move to next level - resource Name
+ //
+ if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
+ return RETURN_UNSUPPORTED;
+ }
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
+ Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
+ if (Offset > DirectoryEntry->Size) {
+ return RETURN_UNSUPPORTED;
+ }
+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
+
+ if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
+ //
+ // Move to next level - resource Language
+ //
+ if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
+ return RETURN_UNSUPPORTED;
+ }
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
+ Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
+ if (Offset > DirectoryEntry->Size) {
+ return RETURN_UNSUPPORTED;
+ }
+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
+ }
+ }
+
+ //
+ // Now it ought to be resource Data
+ //
+ if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
+ if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {
+ return RETURN_UNSUPPORTED;
+ }
+ ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);
+
+ //
+ // Adjust OffsetToData to be a PE/COFF Virtual address in the updated image.
+ //
+ ResourceDataEntry->OffsetToData += (UINTN)DirectoryEntry->VirtualAddress;
+ break;
+ }
+ }
+ }
+ ResourceDirectoryEntry++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
STATIC
EFI_STATUS
ZeroDebugData (
--
2.24.1 (Apple Git-126)
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#60195): https://edk2.groups.io/g/devel/message/60195
Mute This Topic: https://groups.io/mt/74445735/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Hi Andrew, This patch cause building GenFw failure. cl.exe -c /nologo /Zi /c /O2 /MT /W4 /WX /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE -I . -I D:\Edk2Maintain\edk2head\edk2\BaseTools\Source\C\Include -I D:\Edk2Maintain\edk2head\edk2\BaseTools\Source\C\Include\Ia32 -I D:\Edk2Maintain\edk2head\edk2\BaseTools\Source\C\Common GenFw.c -FoGenFw.obj GenFw.c GenFw.c(3047): error C2220: the following warning is treated as an error GenFw.c(3047): warning C4244: '=': conversion from 'UINT32' to 'UINT16', possible loss of data NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\bin\HostX86\x86\cl.exe"' : return code '0x2' Stop. The possible fix could be change the parameter Type as UINT16 data type. Would you update the patch? + +STATIC +EFI_STATUS +PatchResourceData ( + IN UINT32 Type, + IN UINT8 *ResourceData, + IN UINT32 ResourceDataSize, + IN OUT UINT8 **PeCoff, + IN OUT UINT32 *PeCoffSize + ) +/*++ And a minor comment is about the commit message. BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=557 should change to REF: https://bugzilla.tianocore.org/show_bug.cgi?id=557 Thanks, Bob -----Original Message----- From: Andrew Fish <afish@apple.com> Sent: Monday, May 25, 2020 5:20 AM To: devel@edk2.groups.io Cc: Andrew Fish <afish@apple.com>; Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com> Subject: [PATCH 1/3] BaseTools/GenFv: Add PE/COFF resource sections injection to GenFw BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=557 The XCODE toolchain does not suport injecting resource sections via libraries so add --rc to GenFw to inject $(MODULE_NAME)hii.rc into the final PE/COFF image. Since moving exiting code around would break source level debugging we must reuse an existing empty section, or add a new section header. If there is not space to add a new section header append to the last section. The resource entry if found via a directory entry so the PE/COFF loading code does not depend on the section type. Signed-off-by: Andrew Fish <afish@apple.com> Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <liming.gao@intel.com> --- BaseTools/Source/C/GenFw/GenFw.c | 370 +++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) diff --git a/BaseTools/Source/C/GenFw/GenFw.c b/BaseTools/Source/C/GenFw/GenFw.c index 8cab70ba4d5f..748af5dff259 100644 --- a/BaseTools/Source/C/GenFw/GenFw.c +++ b/BaseTools/Source/C/GenFw/GenFw.c @@ -96,6 +96,16 @@ ZeroDebugData ( BOOLEAN ZeroDebug ); +STATIC+EFI_STATUS+PatchResourceData (+ IN UINT32 Type,+ IN UINT8 *ResourceData,+ IN UINT32 ResourceDataSize,+ IN OUT UINT8 **PeCoff,+ IN OUT UINT32 *PeCoffSize+ );+ STATIC EFI_STATUS SetStamp (@@ -267,6 +277,11 @@ Returns: except for -o option. It is a action option.\n\ If it is combined with other action options, the later\n\ input action option will override the previous one.\n");+ fprintf (stdout, " --rc FlieName Append a Hii resource section to the\n\+ last PE/COFF section. The FileName is the resource section to append\n\+ If FileName does not exist this operation is skipped. This feature is\n\+ only intended for toolchains, like XCODE, that don't suport $(RC).\n\+ This option can only be combined with -e\n"); fprintf (stdout, " --rebase NewAddress Rebase image to new base address. New address \n\ is also set to the first none code section header.\n\ It can't be combined with other action options\n\@@ -1059,10 +1074,12 @@ Returns: CHAR8 **InputFileName; char *OutImageName; char *ModuleType;+ char *RcFileName; CHAR8 *TimeStamp; FILE *fpIn; FILE *fpOut; FILE *fpInOut;+ FILE *fpRc; UINT32 Data; UINT32 *DataPointer; UINT32 *OldDataPointer;@@ -1080,6 +1097,8 @@ Returns: UINT32 OutputFileLength; UINT8 *InputFileBuffer; UINT32 InputFileLength;+ UINT8 *RcFileBuffer;+ UINT32 RcFileLength; RUNTIME_FUNCTION *RuntimeFunction; UNWIND_INFO *UnwindInfo; STATUS Status;@@ -1116,6 +1135,7 @@ Returns: time_t OutputFileTime; struct stat Stat_Buf; BOOLEAN ZeroDebugFlag;+ BOOLEAN InsertRcFile; SetUtilityName (UTILITY_NAME); @@ -1128,6 +1148,7 @@ Returns: mInImageName = NULL; OutImageName = NULL; ModuleType = NULL;+ RcFileName = NULL; Type = 0; Status = STATUS_SUCCESS; FileBuffer = NULL;@@ -1164,6 +1185,7 @@ Returns: InputFileTime = 0; OutputFileTime = 0; ZeroDebugFlag = FALSE;+ InsertRcFile = FALSE; if (argc == 1) { Error (NULL, 0, 1001, "Missing options", "No input options.");@@ -1436,6 +1458,20 @@ Returns: continue; } + if (stricmp (argv[0], "--rc") == 0) {+ RcFileName = argv[1];+ argc -= 2;+ argv += 2;++ if (stat (RcFileName, &Stat_Buf) == 0) {+ //+ // File exists+ //+ InsertRcFile = TRUE;+ }+ continue;+ }+ if (argv[0][0] == '-') { Error (NULL, 0, 1000, "Unknown option", argv[0]); goto Finish;@@ -1568,6 +1604,10 @@ Returns: break; } + if (InsertRcFile) {+ VerboseMsg ("RC input file %s", RcFileName);+ }+ if (ReplaceFlag) { VerboseMsg ("Overwrite the input file with the output content."); }@@ -2052,6 +2092,52 @@ Returns: } } + //+ // Insert Resources into the image.+ //+ if (InsertRcFile) {+ fpRc = fopen (LongFilePath (RcFileName), "rb");+ if (fpRc == NULL) {+ Error (NULL, 0, 0001, "Error opening file", RcFileName);+ goto Finish;+ }++ RcFileLength = _filelength (fileno (fpRc));+ RcFileBuffer = malloc (RcFileLength);+ if (FileBuffer == NULL) {+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");+ fclose (fpRc);+ goto Finish;+ }++ fread (RcFileBuffer, 1, RcFileLength, fpRc);+ fclose (fpRc);++ Status = PatchResourceData (Type, RcFileBuffer, RcFileLength, &FileBuffer, &FileLength);+ if (EFI_ERROR (Status)) {+ Error (NULL, 0, 3000, "Invalid", "RC Patch Data Error status is 0x%x", (int) Status);+ goto Finish;+ }++ fpOut = fopen (LongFilePath (OutImageName), "wb");+ if (fpOut == NULL) {+ Error (NULL, 0, 0001, "Error opening output file", OutImageName);+ goto Finish;+ }++ fwrite (FileBuffer, 1, FileLength, fpOut);++ fclose (fpOut);+ fpOut = NULL;+ VerboseMsg ("the size of output file is %u bytes", (unsigned) FileLength);++ //+ // Write the updated Image+ //+ goto Finish;+ }++ // // Convert ELF image to PeImage //@@ -2761,6 +2847,290 @@ Finish: return GetUtilityStatus (); } +#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1)))++STATIC+EFI_STATUS+PatchResourceData (+ IN UINT32 Type,+ IN UINT8 *ResourceData,+ IN UINT32 ResourceDataSize,+ IN OUT UINT8 **PeCoff,+ IN OUT UINT32 *PeCoffSize+ )+/*++++Routine Description:++ Embed Resource data into a PE/COFF image.++ If there is free space between the header and the image add a new+ .rsrc section to the PE/COFF image. If no space exists then append+ the resource data to the last section.++Arguments:++ Type - If not zero them update PE/COFF header module type.+ ResourceData - *hii.rc data to insert into the image.+ ResourceDataSize - Size of ResourceData in bytes.+ PeCoff - On input existing PE/COFF, on output input PE/COFF with+ ResourceData embedded.+ PeCoffSize - Size of PeCoff in bytes.++Returns:++ EFI_ABORTED - PeImage is invalid.+ EFI_SUCCESS - Zero debug data successfully.++--*/+{+ UINT8 *FileBuffer;+ UINT32 FileBufferSize;+ EFI_IMAGE_DOS_HEADER *DosHdr;+ EFI_IMAGE_FILE_HEADER *FileHdr;+ EFI_IMAGE_OPTIONAL_HEADER32 *Optional32Hdr;+ EFI_IMAGE_OPTIONAL_HEADER64 *Optional64Hdr;+ EFI_IMAGE_SECTION_HEADER *SectionHeader;+ UINT32 FileAlignment;+ UINT32 Max;+ INTN LastSection;+ INTN EmptySection;+ UINT32 ActualHeaderSize;+ UINT32 StartingPeCoffSize;+ UINT32 NewHeaderSize;+ CHAR8 *Base;+ EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;+ EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;+ EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;+ EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;+ EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;+ CHAR16 *String;+ UINT32 Offset;+ UINT32 Index;++ //+ // Grow the file in units of FileAlignment+ //+ DosHdr = (EFI_IMAGE_DOS_HEADER *) *PeCoff;+ if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {+ // NO DOS header, must start with PE/COFF header+ FileHdr = (EFI_IMAGE_FILE_HEADER *)(*PeCoff + sizeof (UINT32));+ } else {+ FileHdr = (EFI_IMAGE_FILE_HEADER *)(*PeCoff + DosHdr->e_lfanew + sizeof (UINT32));+ }++ Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));+ Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));+ if (Optional32Hdr->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {+ FileAlignment = Optional32Hdr->FileAlignment;+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader);+ } else {+ FileAlignment = Optional64Hdr->FileAlignment;+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader);+ }++ LastSection = -1;+ for (Index = 0, Max = 0; Index < FileHdr->NumberOfSections; Index++) {+ if (SectionHeader[Index].PointerToRawData > Max) {+ Max = SectionHeader[Index].PointerToRawData;+ LastSection = Index;+ }+ }++ EmptySection = -1;+ for (Index = 0; Index < FileHdr->NumberOfSections; Index++) {+ if ((SectionHeader[Index].Misc.VirtualSize == 0) && (SectionHeader[Index].SizeOfRawData == 0)) {+ //+ // No Data or Zero Fill so we can repurpose this entry.+ //+ EmptySection = Index;+ break;+ }+ }++ if (EmptySection == -1) {+ ActualHeaderSize = (UINTN)(&SectionHeader[FileHdr->NumberOfSections]) - (UINTN)*PeCoff;+ if ((ActualHeaderSize + sizeof (EFI_IMAGE_SECTION_HEADER)) <= Optional32Hdr->SizeOfHeaders) {+ //+ // There is space to inject a new section.+ //+ FileHdr->NumberOfSections += 1;+ EmptySection = Index;+ }+ }++ StartingPeCoffSize = SectionHeader[LastSection].PointerToRawData + SectionHeader[LastSection].SizeOfRawData;+ if (SectionHeader[LastSection].Misc.VirtualSize > SectionHeader[LastSection].SizeOfRawData) {+ StartingPeCoffSize += SectionHeader[LastSection].Misc.VirtualSize - SectionHeader[LastSection].SizeOfRawData;+ }++ FileBufferSize = ALIGN_VALUE(StartingPeCoffSize + ResourceDataSize, FileAlignment);+ FileBuffer = malloc (FileBufferSize);+ if (FileBuffer == NULL) {+ return RETURN_OUT_OF_RESOURCES;+ }+ memset (FileBuffer, 0, FileBufferSize);++ //+ // Append the Resource Data to the end of the PE/COFF image.+ //+ NewHeaderSize = Optional32Hdr->SizeOfHeaders;+ CopyMem (FileBuffer, *PeCoff, (StartingPeCoffSize > *PeCoffSize) ? *PeCoffSize: StartingPeCoffSize);+ CopyMem (FileBuffer + StartingPeCoffSize, ResourceData, ResourceDataSize);++ free (*PeCoff);+ *PeCoff = FileBuffer;+ *PeCoffSize = FileBufferSize;++ DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;+ if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {+ // NO DOS header, must start with PE/COFF header+ FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + sizeof (UINT32));+ } else {+ FileHdr = (EFI_IMAGE_FILE_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof (UINT32));+ }++ //+ // Get Resource EntryTable offset, and Section header+ //+ Optional32Hdr = (EFI_IMAGE_OPTIONAL_HEADER32 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));+ Optional64Hdr = (EFI_IMAGE_OPTIONAL_HEADER64 *) ((UINT8*) FileHdr + sizeof (EFI_IMAGE_FILE_HEADER));+ DirectoryEntry = NULL;+ if (Optional32Hdr->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional32Hdr + FileHdr->SizeOfOptionalHeader);+ if (Optional32Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) {+ DirectoryEntry = &Optional32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];+ }+ } else {+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) Optional64Hdr + FileHdr->SizeOfOptionalHeader);+ if (Optional64Hdr->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) {+ DirectoryEntry = &Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];+ }+ }++ if (DirectoryEntry == NULL) {+ return RETURN_OUT_OF_RESOURCES;+ }++ if (EmptySection != -1) {+ //+ // Create a new section+ //+ CopyMem (SectionHeader[EmptySection].Name, ".rsrc\0\0\0", EFI_IMAGE_SIZEOF_SHORT_NAME);+ SectionHeader[EmptySection].Misc.VirtualSize = ResourceDataSize;+ SectionHeader[EmptySection].VirtualAddress = StartingPeCoffSize;+ SectionHeader[EmptySection].SizeOfRawData = ALIGN_VALUE(ResourceDataSize, FileAlignment);+ SectionHeader[EmptySection].PointerToRawData = StartingPeCoffSize;++ SectionHeader[EmptySection].Characteristics = EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_READ;+ SectionHeader[EmptySection].Characteristics |= EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | EFI_IMAGE_SCN_CNT_CODE;++ DirectoryEntry->VirtualAddress = SectionHeader[EmptySection].VirtualAddress;+ } else {+ //+ // Grow the last section to include the resources.+ // For Xcode this is always the .debug section.+ //+ SectionHeader[LastSection].SizeOfRawData = ALIGN_VALUE(SectionHeader[LastSection].SizeOfRawData + ResourceDataSize, FileAlignment);++ //+ // Make sure the Virtual Size uses the file aligned actual size, since we are growing the file.+ //+ SectionHeader[LastSection].Misc.VirtualSize = SectionHeader[LastSection].SizeOfRawData;++ DirectoryEntry->VirtualAddress = StartingPeCoffSize;+ }+ DirectoryEntry->Size = ResourceDataSize;++ Optional32Hdr->SizeOfImage = ALIGN_VALUE(*PeCoffSize, Optional32Hdr->SectionAlignment);+ if (Type != 0) {+ Optional32Hdr->Subsystem = Type;+ }++ //+ // It looks like the ResourceDataEntry->OffsetToData is relative to the rc file,+ // but PeCoffLoaderLoadImage() assumes it is a PE/COFF VirtualAddress so we need+ // to fix it up. Walk the ResourceDataEntry just like PeCoffLoaderLoadImage() and+ // patch it.+ //+ Base = (CHAR8 *)(FileBuffer + StartingPeCoffSize);+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)Base;+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);++ for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {+ if (ResourceDirectoryEntry->u1.s.NameIsString) {+ //+ // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.+ //+ if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {+ return RETURN_UNSUPPORTED;+ }+ ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);+ String = &ResourceDirectoryString->String[0];++ if (ResourceDirectoryString->Length == 3 &&+ String[0] == L'H' &&+ String[1] == L'I' &&+ String[2] == L'I') {+ //+ // Resource Type "HII" found+ //+ if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {+ //+ // Move to next level - resource Name+ //+ if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {+ return RETURN_UNSUPPORTED;+ }+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);+ Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) ++ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);+ if (Offset > DirectoryEntry->Size) {+ return RETURN_UNSUPPORTED;+ }+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);++ if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {+ //+ // Move to next level - resource Language+ //+ if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {+ return RETURN_UNSUPPORTED;+ }+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);+ Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) ++ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);+ if (Offset > DirectoryEntry->Size) {+ return RETURN_UNSUPPORTED;+ }+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);+ }+ }++ //+ // Now it ought to be resource Data+ //+ if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {+ if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {+ return RETURN_UNSUPPORTED;+ }+ ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);++ //+ // Adjust OffsetToData to be a PE/COFF Virtual address in the updated image.+ //+ ResourceDataEntry->OffsetToData += (UINTN)DirectoryEntry->VirtualAddress;+ break;+ }+ }+ }+ ResourceDirectoryEntry++;+ }++ return EFI_SUCCESS;+}++ STATIC EFI_STATUS ZeroDebugData (-- 2.24.1 (Apple Git-126) -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#60313): https://edk2.groups.io/g/devel/message/60313 Mute This Topic: https://groups.io/mt/74445735/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2025 Red Hat, Inc.