Skip to content

BaseTools: Simplify Resource-file rule and fix GCC toolchain command#79

Closed
martinezjavier wants to merge 1 commit intomicrosoft:release/202008from
martinezjavier:fix-resource-file-rule
Closed

BaseTools: Simplify Resource-file rule and fix GCC toolchain command#79
martinezjavier wants to merge 1 commit intomicrosoft:release/202008from
martinezjavier:fix-resource-file-rule

Conversation

@martinezjavier
Copy link

This rule contains several issues that causes the VERSIONINFO resource to
not be embedded into the compiled binaries, when using the GCC toolchain.

The problems with the rule when using the GCC toolchain are the following:

  • The windres command executed does not contain an --output-format option,
    so the tool tries to guess the format and just generates a .rc file.

  • The OutputFile.GCC is set to $(MODULE_NAME)Resource.rc, instead of an
    binary object file that could be included when building the ELF objects.

  • The resource is never added to a binary file so is not included in the
    final PE32+ executable binary.

One solution may be to make windres generate a COFF object file and use
the objcopy tool to convert the COFF object file to an ELF object file,
that way the resource would be picked when building the ELF executable.

That is what the commented out commands in the rule attempt to do, but it
won't work since the ELF binary built is a Position Independent Executable
(PIE). The linker then would complain that relocation symbols included in
the ELF object file created by objcopy cannot be used when making a PIE.

Another option is to convert the .rc source resource into a .res binary
format and then embed that in as a section using objcopy --add-section.

And there is already a Hii-Binary-Package.UEFI_HII rule that does exactly
that, it gets hpk files as input and adds the content of those to a .rsrc
section in the binaries. Use that rule instead to avoid duplicated logic.

Signed-off-by: Javier Martinez Canillas javierm@redhat.com

This rule contains several issues that causes the VERSIONINFO resource to
not be embedded into the compiled binaries, when using the GCC toolchain.

The problems with the rule when using the GCC toolchain are the following:

* The windres command executed does not contain an --output-format option,
  so the tool tries to guess the format and just generates a .rc file.

* The OutputFile.GCC is set to $(MODULE_NAME)Resource.rc, instead of an
  binary object file that could be included when building the ELF objects.

* The resource is never added to a binary file so is not included in the
  final PE32+ executable binary.

One solution may be to make windres generate a COFF object file and use
the objcopy tool to convert the COFF object file to an ELF object file,
that way the resource would be picked when building the ELF executable.

That is what the commented out commands in the rule attempt to do, but it
won't work since the ELF binary built is a Position Independent Executable
(PIE). The linker then would complain that relocation symbols included in
the ELF object file created by objcopy cannot be used when making a PIE.

Another option is to convert the .rc source resource into a .res binary
format and then embed that in as a section using objcopy --add-section.

And there is already a Hii-Binary-Package.UEFI_HII rule that does exactly
that, it gets hpk files as input and adds the content of those to a .rsrc
section in the binaries. Use that rule instead to avoid duplicated logic.

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
@ghost
Copy link

ghost commented Nov 2, 2020

CLA assistant check
All CLA requirements met.

<Command.MSFT, Command.INTEL, Command.CLANGPDB>
"$(RC)" /Fo${dst} ${src}
<OutputFile.MSFT, OutputFile.INTEL, OutputFile.GCC, OutputFile.CLANGPDB>
$(OUTPUT_DIR)(+)$(MODULE_NAME)Resource.hpk
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we output HPK will this mean that version resource and hii resource are exclusive since the output file of HPK rule above is the same? I like the reuse of HII but we should support a module that uses both.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we output HPK will this mean that version resource and hii resource are exclusive since the output file of HPK rule

No, because the content of all the different .hpk files will be added to the $(MODULE_NAME)hii.rc.

In other words, the $(HII_BINARY_PACKAGES) variable in the command of the Hii-Binary-Package.UEFI_HII rule gets expanded to all the .hpk files, so the final .rsrc section in the PE32+ binary will contain the data of all the hpk files.

For example, on my test machine this is the actual commands executed by the Hii-Binary-Package.UEFI_HII rule:

INFO - "GenFw" -o /home/javier/devel/mu_basecore/Build/MdeModule/DEBUG_GCC5/X64/MdeModulePkg/Application/HelloWorld/HelloWorld/OUTPUT/HelloWorldhii.rc -g 6987936E-ED34-44db-AE97-1FA5E4ED2116 --hiibinpackage /home/javier/devel/mu_basecore/Build/MdeModule/DEBUG_GCC5/X64/MdeModulePkg/Application/HelloWorld/HelloWorld/OUTPUT/HelloWorldResource.hpk /home/javier/devel/mu_basecore/Build/MdeModule/DEBUG_GCC5/X64/MdeModulePkg/Application/HelloWorld/HelloWorld/OUTPUT/HelloWorldStrDefs.hpk
INFO - "objcopy" -I binary -O elf64-x86-64 -B i386 --rename-section .data=.hii /home/javier/devel/mu_basecore/Build/MdeModule/DEBUG_GCC5/X64/MdeModulePkg/Application/HelloWorld/HelloWorld/OUTPUT/HelloWorldhii.rc /home/javier/devel/mu_basecore/Build/MdeModule/DEBUG_GCC5/X64/MdeModulePkg/Application/HelloWorld/HelloWorld/OUTPUT/HelloWorldhii.lib

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@spbrogan and thanks a lot for your feedback and review!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so they all get merged into the one .rc?

Have you tried running the version_info tool on the binary and see the results match expected? You will need at least version 0.14.0 of edk2-pytool-extensions

versioninfo_tool -d {/path/to/app.efi} {/path/to/output.JSON}

https://github.com/tianocore/edk2-pytool-extensions/blob/master/docs/usability/using_versioninfo.md

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so they all get merged into the one .rc?

Yes, my understanding is that this is already the case for other build rules that output a .hpk file.

Have you tried running the version_info tool on the binary and see the results match expected? You will need at least version 0.14.0 of edk2-pytool-extensions

I was just testing with strings -e l and objdump -s -j .rsrc but I've tried now with that script and it fails...

$ strings -e l ./Build/MdeModule/DEBUG_GCC5/X64/HelloWorld.efi
UEFI Hello World!
VS_VERSION_INFO
VS_VERSION_INFO
StringFileInfo
040904b0
CompanyName
Example Company Name
OriginalFilename
HelloWorld.efi
VarFileInfo
Translation
English
.TH HelloWorld 0 "Displays a "UEFI Hello World!" string."
.SH NAME
HelloWorld application.

$ versioninfo_tool -d ./Build/MdeModule/DEBUG_GCC5/X64/HelloWorld.efi test.json
Could not find VS_FIXEDFILEINFO.
Traceback (most recent call last):
  File "/usr/local/bin/versioninfo_tool", line 33, in <module>
    sys.exit(load_entry_point('edk2-pytool-extensions==0.14.0', 'console_scripts', 'versioninfo_tool')())
  File "/usr/local/lib/python3.9/site-packages/edk2toolext/versioninfo/versioninfo_tool.py", line 105, in main
    if not decode_version_info_dump_json(args.input_file, args.output_file):
  File "/usr/local/lib/python3.9/site-packages/edk2toolext/versioninfo/versioninfo_tool.py", line 74, in decode_version_info_dump_json
    version_info = decode_version_info(input_file)
  File "/usr/local/lib/python3.9/site-packages/edk2toolext/versioninfo/versioninfo_tool.py", line 66, in decode_version_info
    return pe.get_version_dict()
  File "/usr/local/lib/python3.9/site-packages/edk2toolext/versioninfo/versioninfo_helper.py", line 395, in get_version_dict
    for fileinfo in self._pe.FileInfo:
AttributeError: 'PE' object has no attribute 'FileInfo'

To make sure that it wasn't a problem with the script, I just tried to load the binary and print the PE class VS_FIXEDFILEINFO attribute but that doesn't work either:

>>> import pefile
>>> path = "./Build/MdeModule/DEBUG_GCC5/X64/HelloWorld.efi"
>>> pe = pefile.PE(path)
>>> print(pe.VS_FIXEDFILEINFO)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'PE' object has no attribute 'VS_FIXEDFILEINFO'
>>>

I see that the same problem happens if I just take a binary that doesn't have a .rsrc section and attempt to embed a binary .res file with objcopy HelloWorld.efi --add-section .rsrc=HelloWorldResource.rc.

I will take a look tomorrow to understand what's missing or wrong with this approach.

@martinezjavier
Copy link
Author

Comparing the PE/COFF binaries I notice that the problem is that the resource directory doesn't have the correct structure.

On a binary where the version information is reported, the resource directory looks like the following:

----------Resource directory----------                    
                                                           
[IMAGE_RESOURCE_DIRECTORY]                                 
0x1D600    0x0   Characteristics:               0x0       
0x1D604    0x4   TimeDateStamp:                 0x0        [Thu Jan  1 00:00:00 1970 UTC]                              
0x1D608    0x8   MajorVersion:                  0x0       
0x1D60A    0xA   MinorVersion:                  0x0       
0x1D60C    0xC   NumberOfNamedEntries:          0x0       
0x1D60E    0xE   NumberOfIdEntries:             0x1       
  Id: [0x10] (RT_VERSION)                                  
  [IMAGE_RESOURCE_DIRECTORY_ENTRY]                                                                                     
  0x1D610    0x0   Name:                          0x10                                                                 
  0x1D614    0x4   OffsetToData:                  0x80000018                                                           
    [IMAGE_RESOURCE_DIRECTORY]                                                                                         
    0x1D618    0x0   Characteristics:               0x0        
    0x1D61C    0x4   TimeDateStamp:                 0x0        [Thu Jan  1 00:00:00 1970 UTC]
    0x1D620    0x8   MajorVersion:                  0x0        
    0x1D622    0xA   MinorVersion:                  0x0        
    0x1D624    0xC   NumberOfNamedEntries:          0x0        
    0x1D626    0xE   NumberOfIdEntries:             0x1        
      Id: [0x1]
      [IMAGE_RESOURCE_DIRECTORY_ENTRY]
      0x1D628    0x0   Name:                          0x1        
      0x1D62C    0x4   OffsetToData:                  0x80000030
        [IMAGE_RESOURCE_DIRECTORY]
        0x1D630    0x0   Characteristics:               0x0        
        0x1D634    0x4   TimeDateStamp:                 0x0        [Thu Jan  1 00:00:00 1970 UTC]
        0x1D638    0x8   MajorVersion:                  0x0        
        0x1D63A    0xA   MinorVersion:                  0x0        
        0x1D63C    0xC   NumberOfNamedEntries:          0x0        
        0x1D63E    0xE   NumberOfIdEntries:             0x1        
        \--- LANG [9,1][LANG_ENGLISH,SUBLANG_ENGLISH_US]
          [IMAGE_RESOURCE_DIRECTORY_ENTRY]
          0x1D640    0x0   Name:                          0x409     
          0x1D644    0x4   OffsetToData:                  0x48      
            [IMAGE_RESOURCE_DATA_ENTRY]
            0x1D648    0x0   OffsetToData:                  0x22060   
            0x1D64C    0x4   Size:                          0x2BC     
            0x1D650    0x8   CodePage:                      0x0       
            0x1D654    0xC   Reserved:                      0x0

while my HelloWorld.efi has the following:

----------Resource directory----------                    
                                                           
[IMAGE_RESOURCE_DIRECTORY]                                 
0x2080     0x0   Characteristics:               0x0        
0x2084     0x4   TimeDateStamp:                 0x0        [Thu Jan  1 00:00:00 1970 UTC]
0x2088     0x8   MajorVersion:                  0x0                                                                    
0x208A     0xA   MinorVersion:                  0x0                                                                    
0x208C     0xC   NumberOfNamedEntries:          0x1                                                                    
0x208E     0xE   NumberOfIdEntries:             0x0                                                                                                                                                                                           
  Name: [HII]                                              
  [IMAGE_RESOURCE_DIRECTORY_ENTRY]
  0x2090     0x0   Name:                          0x80000048
  0x2094     0x4   OffsetToData:                  0x80000018
    [IMAGE_RESOURCE_DIRECTORY]
    0x2098     0x0   Characteristics:               0x0        
    0x209C     0x4   TimeDateStamp:                 0x0        [Thu Jan  1 00:00:00 1970 UTC]
    0x20A0     0x8   MajorVersion:                  0x0        
    0x20A2     0xA   MinorVersion:                  0x0        
    0x20A4     0xC   NumberOfNamedEntries:          0x1        
    0x20A6     0xE   NumberOfIdEntries:             0x0        
      Name: [EFI]                                          
      [IMAGE_RESOURCE_DIRECTORY_ENTRY]
      0x20A8     0x0   Name:                          0x80000050
      0x20AC     0x4   OffsetToData:                  0x80000030
        [IMAGE_RESOURCE_DIRECTORY]
        0x20B0     0x0   Characteristics:               0x0        
        0x20B4     0x4   TimeDateStamp:                 0x0        [Thu Jan  1 00:00:00 1970 UTC]
        0x20B8     0x8   MajorVersion:                  0x0        
        0x20BA     0xA   MinorVersion:                  0x0        
        0x20BC     0xC   NumberOfNamedEntries:          0x1        
        0x20BE     0xE   NumberOfIdEntries:             0x0        
        \--- LANG [88,2097152][LANG_MANIPURI,*unknown*]
          [IMAGE_RESOURCE_DIRECTORY_ENTRY]
          0x20C0     0x0   Name:                          0x80000058
          0x20C4     0x4   OffsetToData:                  0x60      
            [IMAGE_RESOURCE_DATA_ENTRY]
            0x20E0     0x0   OffsetToData:                  0x20F0    
            0x20E4     0x4   Size:                          0x2E9     
            0x20E8     0x8   CodePage:                      0x0       
            0x20EC     0xC   Reserved:                      0x0

I wrongly assumed that GenFw --hiibinpackage would just create a proper resource directory with all the needed entries, but it seems that it only creates a named HII entry that has all the merged data.

I believe that BaseTools/Source/C/GenFw/Elf64Convert.c would need to be extended to be aware of the VERSIONINFO data and create the entry with id [0x10] (RT_VERSION).

I'll close this since the approach is not correct and seems to be more complicated than I thought. Sorry @spbrogan for the noise and thanks again for your review.

@spbrogan
Copy link
Member

spbrogan commented Nov 3, 2020

@martinezjavier Thanks for the PR. I think more has definitely been learned and the information in the commit and PR looks helpful. I agree that there is more investigation needed. Anyway I appreciate the information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants