SizeOfImage calculation for PECOFF

Jeffrey Naset jnaset@rsn.hp.com
Tue Mar 26 14:40:00 GMT 2002


I'm seeing what might be an error in the way the SizeOfImage field in 
the PECOFF Optional Header is calculated.

Using the gnu-efi-3.0 package to generate IA-64 EFI executables results 
in the SizeOfImage being too small.  Here's why:

The linking scheme for this package is to use the linker to generate an 
ELF shared library [to get position-independent code generation] and 
then objcopy to move the appropriate sections into the PECOFF-format 
.EFI executable.

Not all sections of the shared library are copied; in particular, the 
first section in the linker script, .hash, is not copied.  (There is a 
reason, which I do not know, why .hash must come first in the linker 
script)  The .text section has its VMA (load address) bumped up to 
accommodate the space taken by the .hash section.  It keeps this address 
when copied into the PECOFF executable by objcopy.

The result is that I get a PECOFF with an ImageBase of 0x000000, but 
whose first section actually starts at 0x002000.  That is, there is a 
"hole" in the address space of this file.  (This problem also occurs if 
there is a hole between sections)

Now, the SizeOfImage calculation done by BFD (peXXigen.c:666) reflects 
what the "Microsoft Portable Executable and Common Object File Format 
Specification" says:
... Size, in bytes, of image, including all headers; must be a multiple 
of section alignment. ...

BFD adds up the section sizes (rounding each section up to a multiple of 
section alignment) and sets SizeOfImage.  In this case, I get a 
SizeOfImage of 0x66000.

Now, when loading the executable from an IA-64 EFI firmware prompt, it 
fails loading the last section, because the section begins at 0x64000 
and extends for 0x2c00 bytes... past the 0x66000 mark.

I can fix this by changing the SizeOfImage calculation to be the 
distance between the ImageBase and the highest address used by any 
section.  It appears this is compatible with the EFI firmware's 
interpretation, which is using SizeOfImage as an indication of how much 
contiguous memory to allocate to hold the image.

In making this calculation, I ignore the part of the MS spec that says 
"...including all headers..." -- this doesn't apply to this type of 
calculation.

Is there any interest for/against changing this calculation?  Here's the 
new method:

{
     asection *sec;
     bfd_vma dsize = 0;
     bfd_vma isize = SA(abfd->sections->filepos);
     bfd_vma tsize = 0;
     bfd_vma sec_end;

     for (sec = abfd->sections; sec; sec = sec->next)
       {
	int rounded = FA(sec->_raw_size);

	if (sec->flags & SEC_DATA)
	  dsize += rounded;
	if (sec->flags & SEC_CODE)
	  tsize += rounded;
	sec_end = SA( FA( pei_section_data (abfd, sec)->virt_size +
			sec->vma));
	if (sec_end-ib > isize) isize = sec_end-ib;
       }

     aouthdr_in->dsize = dsize;
     aouthdr_in->tsize = tsize;
     extra->SizeOfImage = isize;
   }

- Jeffrey Naset
jnaset@rsn.hp.com



More information about the Binutils mailing list