Fix the virtual memory addresses and sizes in the EFI image headers.

When the reloc and sbat sections were added by PR #34, three bugs were
introduced:

1. The virtual address and size fields in the PE headers were set to the
same values as the raw address and size fields. This is incorrect, because
the sections in the image file are aligned on 512 byte boundaries, but when
loaded into memory they need to be aligned on 4096 byte boundaries.

2. The value programmed into the SizeOfImage field was too large, as it
double-counted the region before the start of the .text section.

3. The value programmed into the SizeOfImage field no longer included the bss
size. That potentially allowed the EFI loader to load the image immediately
before a reserved region of memory without leaving enough space for the bss
section.

This commit fixes those bugs by calculating both file and virtual memory
offsets & sizes in the ld script. Note that we can't add a bss section to the
EFI image because many EFI loaders fail to load images that have uninitialised
data sections. Instead the text region size in virtual memory is increased
to include the bss size.

This fixes issue #243. It also eliminates the gaps between sections
observed in issue #202.
This commit is contained in:
Martin Whitaker 2023-01-29 21:52:59 +00:00 committed by Sam Demeulemeester
parent 485bfa46a3
commit a4c9adc445
3 changed files with 87 additions and 58 deletions

View File

@ -7,7 +7,7 @@
// end of the boot sector), with the remainder of the header being provided by
// setup.S.
//
// Copyright (C) 2020 Martin Whitaker.
// Copyright (C) 2020-2023 Martin Whitaker.
//
// Derived from Linux 5.6 arch/x86/boot/header.S:
//
@ -28,7 +28,6 @@
# address well away from HIGH_LOAD_ADDR, to avoid overlap when relocating the code.
#define IMAGE_BASE 0x200000
#define BASE_OF_CODE 0x1000
.section ".header", "ax", @progbits
.code16
@ -117,15 +116,15 @@ optional_header:
.byte 0x02 # MajorLinkerVersion
.byte 0x14 # MinorLinkerVersion
.long _text_size # SizeOfCode
.long _sbat_size # SizeOfInitializedData
.long _virt_text_size # SizeOfCode
.long _virt_sbat_size # SizeOfInitializedData
.long 0 # SizeOfUninitializedData
.long BASE_OF_CODE + 0x1e0 # AddressOfEntryPoint
.long _virt_text_start + 0x1e0 # AddressOfEntryPoint
.long BASE_OF_CODE # BaseOfCode
.long _virt_text_start # BaseOfCode
#ifndef __x86_64__
.long _sbat_start # BaseOfData
.long _virt_sbat_start # BaseOfData
#endif
extra_header_fields:
@ -144,7 +143,7 @@ extra_header_fields:
.word 0 # MinorSubsystemVersion
.long 0 # Win32VersionValue
.long BASE_OF_CODE + _img_end # SizeOfImage
.long _virt_img_size # SizeOfImage
.long end_of_headers # SizeOfHeaders
.long 0 # CheckSum
.word 10 # Subsystem (EFI application)
@ -173,8 +172,8 @@ extra_header_fields:
.long 0 # DataDirectory.Exception.Size
.long 0 # DataDirectory.Certs.VirtualAddress
.long 0 # DataDirectory.Certs.Size
.long _reloc_start # DataDirectory.BaseReloc.VirtualAddress
.long _reloc_size # DataDirectory.BaseReloc.Size
.long _virt_reloc_start # DataDirectory.BaseReloc.VirtualAddress
.long _real_reloc_size # DataDirectory.BaseReloc.Size
# Section table
section_table:
@ -182,10 +181,10 @@ section_table:
.byte 0
.byte 0
.byte 0
.long _text_size # VirtualSize
.long BASE_OF_CODE # VirtualAddress
.long _text_size # SizeOfRawData
.long _text_start # PointerToRawData
.long _virt_text_size # VirtualSize
.long _virt_text_start # VirtualAddress
.long _file_text_size # SizeOfRawData
.long _file_text_start # PointerToRawData
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
@ -198,10 +197,10 @@ section_table:
.ascii ".reloc"
.byte 0
.byte 0
.long _reloc_size # VirtualSize
.long _reloc_start # VirtualAddress
.long _reloc_size # SizeOfRawData
.long _reloc_start # PointerToRawData
.long _virt_reloc_size # VirtualSize
.long _virt_reloc_start # VirtualAddress
.long _file_reloc_size # SizeOfRawData
.long _file_reloc_start # PointerToRawData
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
@ -214,10 +213,10 @@ section_table:
.byte 0
.byte 0
.byte 0
.long _sbat_size # VirtualSize
.long _sbat_start # VirtualAddress
.long _sbat_size # SizeOfRawData
.long _sbat_start # PointerToRawData
.long _virt_sbat_size # VirtualSize
.long _virt_sbat_start # VirtualAddress
.long _file_sbat_size # SizeOfRawData
.long _file_sbat_start # PointerToRawData
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations

View File

@ -12,32 +12,47 @@ SECTIONS {
}
. = ALIGN(512);
.text : {
_text_start = . ;
_file_text_start = . ;
*(.data)
_real_text_end = . ;
. = ALIGN(512);
_text_end = . ;
_file_text_end = . ;
}
. = ALIGN(512);
.reloc : {
_reloc_start = . ;
_file_reloc_start = . ;
*(.reloc)
_reloc_end = . ;
}
_real_reloc_end = . ;
. = ALIGN(512);
_file_reloc_end = . ;
}
.sbat : {
_sbat_start = . ;
_file_sbat_start = . ;
*(.sbat)
_real_sbat_end = . ;
. = ALIGN(512);
_sbat_end = . ;
_file_sbat_end = . ;
}
. = ALIGN(4096);
_img_end = . ;
/DISCARD/ : { *(*) }
_text_size = (_text_end - _text_start);
_real_text_size = _real_text_end - _file_text_start;
_real_reloc_size = _real_reloc_end - _file_reloc_start;
_real_sbat_size = _real_sbat_end - _file_sbat_start;
_reloc_size = (_reloc_end - _reloc_start);
_sbat_size = (_sbat_end - _sbat_start);
_sys_size = _text_size >> 4;
_init_size = _text_size + _bss_size;
_file_text_size = _file_text_end - _file_text_start;
_file_reloc_size = _file_reloc_end - _file_reloc_start;
_file_sbat_size = _file_sbat_end - _file_sbat_start;
_sys_size = (_real_text_size + 15) >> 4;
_init_size = _real_text_size + _bss_size;
_virt_head_size = ((_file_text_start + 4095) >> 12) << 12;
_virt_text_size = ((_init_size + 4095) >> 12) << 12;
_virt_reloc_size = ((_file_reloc_size + 4095) >> 12) << 12;
_virt_sbat_size = ((_file_sbat_size + 4095) >> 12) << 12;
_virt_text_start = _virt_head_size;
_virt_reloc_start = _virt_text_start + _virt_text_size;
_virt_sbat_start = _virt_reloc_start + _virt_reloc_size;
_virt_img_size = _virt_sbat_start + _virt_sbat_size;
}

View File

@ -12,32 +12,47 @@ SECTIONS {
}
. = ALIGN(512);
.text : {
_text_start = . ;
_file_text_start = . ;
*(.data)
_real_text_end = . ;
. = ALIGN(512);
_text_end = . ;
_file_text_end = . ;
}
. = ALIGN(512);
.reloc : {
_reloc_start = . ;
_file_reloc_start = . ;
*(.reloc)
_reloc_end = . ;
}
_real_reloc_end = . ;
. = ALIGN(512);
_file_reloc_end = . ;
}
.sbat : {
_sbat_start = . ;
_file_sbat_start = . ;
*(.sbat)
_real_sbat_end = . ;
. = ALIGN(512);
_sbat_end = . ;
_file_sbat_end = . ;
}
. = ALIGN(4096);
_img_end = . ;
/DISCARD/ : { *(*) }
_text_size = (_text_end - _text_start);
_real_text_size = _real_text_end - _file_text_start;
_real_reloc_size = _real_reloc_end - _file_reloc_start;
_real_sbat_size = _real_sbat_end - _file_sbat_start;
_reloc_size = (_reloc_end - _reloc_start);
_sbat_size = (_sbat_end - _sbat_start);
_sys_size = _text_size >> 4;
_init_size = _text_size + _bss_size;
_file_text_size = _file_text_end - _file_text_start;
_file_reloc_size = _file_reloc_end - _file_reloc_start;
_file_sbat_size = _file_sbat_end - _file_sbat_start;
_sys_size = (_real_text_size + 15) >> 4;
_init_size = _real_text_size + _bss_size;
_virt_head_size = ((_file_text_start + 4095) >> 12) << 12;
_virt_text_size = ((_init_size + 4095) >> 12) << 12;
_virt_reloc_size = ((_file_reloc_size + 4095) >> 12) << 12;
_virt_sbat_size = ((_file_sbat_size + 4095) >> 12) << 12;
_virt_text_start = _virt_head_size;
_virt_reloc_start = _virt_text_start + _virt_text_size;
_virt_sbat_start = _virt_reloc_start + _virt_reloc_size;
_virt_img_size = _virt_sbat_start + _virt_sbat_size;
}