diff options
author | Michael Brown <mcb30@ipxe.org> | 2023-11-24 15:55:41 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2023-11-24 16:45:11 +0000 |
commit | 03ff1bb99a28230397fb583853ab2160ff227e77 (patch) | |
tree | e820b89dd53c6e9c9572aaf5d059054f759aec87 | |
parent | 18582a05fc65fc8835220c27528ef8902f5da60e (diff) | |
download | ipxe-03ff1bb99a28230397fb583853ab2160ff227e77.zip ipxe-03ff1bb99a28230397fb583853ab2160ff227e77.tar.gz ipxe-03ff1bb99a28230397fb583853ab2160ff227e77.tar.bz2 |
[efi] Do not assume canonical PE section ordering
The BaseOfCode (and, in PE32, BaseOfData) fields imply an assumption
that binaries are laid out as code followed by initialised data
followed by uninitialised data. This assumption may not be valid for
complex binaries such as wimboot.
Remove this implicit assumption, and use arguably justifiable values
for the assorted summary start and size fields within the PE headers.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/util/elf2efi.c | 93 |
1 files changed, 37 insertions, 56 deletions
diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 171e2b5..72d50d3 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -602,31 +602,29 @@ static struct pe_section * process_section ( struct elf_file *elf, size_t name_len; size_t section_memsz; size_t section_filesz; - unsigned long code_start; - unsigned long code_end; - unsigned long data_start; - unsigned long data_mid; - unsigned long data_end; - unsigned long start; - unsigned long end; - unsigned long *applicable_start; - unsigned long *applicable_end; + uint32_t start; + uint32_t end; + uint32_t *code_start; + uint32_t *data_start; + uint32_t *code_size; + uint32_t *data_size; + uint32_t *bss_size; + uint32_t *applicable_start; + uint32_t *applicable_size; /* Get section name */ name = elf_string ( elf, elf->ehdr->e_shstrndx, shdr->sh_name ); - /* Extract current RVA limits from file header */ - code_start = pe_header->nt.OptionalHeader.BaseOfCode; - code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode ); + /* Identify start and size limit fields from file header */ + code_start = &pe_header->nt.OptionalHeader.BaseOfCode; + code_size = &pe_header->nt.OptionalHeader.SizeOfCode; #if defined(EFI_TARGET32) - data_start = pe_header->nt.OptionalHeader.BaseOfData; + data_start = &pe_header->nt.OptionalHeader.BaseOfData; #elif defined(EFI_TARGET64) - data_start = code_end; + data_start = NULL; #endif - data_mid = ( data_start + - pe_header->nt.OptionalHeader.SizeOfInitializedData ); - data_end = ( data_mid + - pe_header->nt.OptionalHeader.SizeOfUninitializedData ); + data_size = &pe_header->nt.OptionalHeader.SizeOfInitializedData; + bss_size = &pe_header->nt.OptionalHeader.SizeOfUninitializedData; /* Allocate PE section */ section_memsz = shdr->sh_size; @@ -659,7 +657,7 @@ static struct pe_section * process_section ( struct elf_file *elf, new->hidden = 1; } - /* Fill in section characteristics and update RVA limits */ + /* Fill in section characteristics and identify applicable limits */ if ( ( shdr->sh_type == SHT_PROGBITS ) && ( shdr->sh_flags & SHF_WRITE ) ) { /* .data-type section */ @@ -668,8 +666,8 @@ static struct pe_section * process_section ( struct elf_file *elf, EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_MEM_WRITE ); - applicable_start = &data_start; - applicable_end = &data_mid; + applicable_start = data_start; + applicable_size = data_size; } else if ( ( shdr->sh_type == SHT_PROGBITS ) && ( shdr->sh_flags & SHF_EXECINSTR ) ) { /* .text-type section */ @@ -678,16 +676,16 @@ static struct pe_section * process_section ( struct elf_file *elf, EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_READ ); - applicable_start = &code_start; - applicable_end = &code_end; + applicable_start = code_start; + applicable_size = code_size; } else if ( shdr->sh_type == SHT_PROGBITS ) { /* .rodata-type section */ new->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_READ ); - applicable_start = &data_start; - applicable_end = &data_mid; + applicable_start = data_start; + applicable_size = data_size; } else if ( shdr->sh_type == SHT_NOBITS ) { /* .bss-type section */ new->hdr.Characteristics = @@ -695,8 +693,8 @@ static struct pe_section * process_section ( struct elf_file *elf, EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_MEM_WRITE ); - applicable_start = &data_mid; - applicable_end = &data_end; + applicable_start = data_start; + applicable_size = bss_size; } else { eprintf ( "Unrecognised characteristics for section %s\n", name ); @@ -709,41 +707,24 @@ static struct pe_section * process_section ( struct elf_file *elf, shdr->sh_size ); } - /* Update RVA limits */ + /* Update file header fields */ start = new->hdr.VirtualAddress; - end = ( start + new->hdr.Misc.VirtualSize ); - if ( ! new->hidden ) { - if ( ( ! *applicable_start ) || ( *applicable_start >= start ) ) - *applicable_start = start; - if ( *applicable_end < end ) - *applicable_end = end; - } - if ( data_start < code_end ) - data_start = code_end; - if ( data_mid < data_start ) - data_mid = data_start; - if ( data_end < data_mid ) - data_end = data_mid; - - /* Write RVA limits back to file header */ - pe_header->nt.OptionalHeader.BaseOfCode = code_start; - pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start ); -#if defined(EFI_TARGET32) - pe_header->nt.OptionalHeader.BaseOfData = data_start; -#endif - pe_header->nt.OptionalHeader.SizeOfInitializedData = - ( data_mid - data_start ); - pe_header->nt.OptionalHeader.SizeOfUninitializedData = - ( data_end - data_mid ); - - /* Update remaining file header fields */ if ( ! new->hidden ) { pe_header->nt.FileHeader.NumberOfSections++; pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr ); + if ( applicable_start && ( ( *applicable_start == 0 ) || + ( start < *applicable_start ) ) ) { + *applicable_start = start; + } + if ( applicable_size ) { + *applicable_size += section_memsz; + } + } + end = efi_image_align ( start + section_memsz ); + if ( end > pe_header->nt.OptionalHeader.SizeOfImage ) { + pe_header->nt.OptionalHeader.SizeOfImage = end; } - pe_header->nt.OptionalHeader.SizeOfImage = - efi_image_align ( data_end ); return new; } |