From 2d0c1f95fa2902e65eabbb96311867a21253d7b5 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 28 Oct 2025 13:32:40 -0400 Subject: [PATCH 1/7] post-process-pe: fix a minor getopt bug This fixes a case where we're not handling getopt_long()'s return value properly. Signed-off-by: Peter Jones --- post-process-pe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/post-process-pe.c b/post-process-pe.c index 008da93b8..56c40956d 100644 --- a/post-process-pe.c +++ b/post-process-pe.c @@ -590,6 +590,9 @@ int main(int argc, char **argv) case 'x': require_nx_compat = true; break; + default: + usage(1); + break; } } From b14a675d649dcd10adb27507872d99624d1ab53b Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 28 Oct 2025 13:31:06 -0400 Subject: [PATCH 2/7] post-process-pe: Move file alignment to context. This moves FileAlignment from being a local in load_pe() to being in the PE context header, so that later functions can more easily access it. Signed-off-by: Peter Jones --- include/peimage.h | 1 + post-process-pe.c | 17 ++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/peimage.h b/include/peimage.h index 5d049686e..8c84d18f1 100644 --- a/include/peimage.h +++ b/include/peimage.h @@ -819,6 +819,7 @@ typedef struct { UINTN SizeOfHeaders; UINT16 ImageType; UINT16 NumberOfSections; + UINT32 FileAlignment; UINT32 SectionAlignment; EFI_IMAGE_SECTION_HEADER *FirstSection; EFI_IMAGE_DATA_DIRECTORY *RelocDir; diff --git a/post-process-pe.c b/post-process-pe.c index 56c40956d..3d1bb5305 100644 --- a/post-process-pe.c +++ b/post-process-pe.c @@ -124,7 +124,6 @@ load_pe(const char *const file, void *const data, const size_t datasize, EFI_IMAGE_DOS_HEADER *DOSHdr = data; EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr = data; size_t HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize; - size_t FileAlignment = 0; size_t sz0 = 0, sz1 = 0; uintptr_t loc = 0; @@ -164,7 +163,7 @@ load_pe(const char *const file, void *const data, const size_t datasize, ctx->SectionAlignment = PEHdr->Pe32Plus.OptionalHeader.SectionAlignment; ctx->DllCharacteristics = PEHdr->Pe32Plus.OptionalHeader.DllCharacteristics; - FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment; + ctx->FileAlignment = PEHdr->Pe32Plus.OptionalHeader.FileAlignment; OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64); } else { debug(NOISE, "image is 32bit\n"); @@ -175,19 +174,19 @@ load_pe(const char *const file, void *const data, const size_t datasize, ctx->SectionAlignment = PEHdr->Pe32.OptionalHeader.SectionAlignment; ctx->DllCharacteristics = PEHdr->Pe32.OptionalHeader.DllCharacteristics; - FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment; + ctx->FileAlignment = PEHdr->Pe32.OptionalHeader.FileAlignment; OptHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32); } - if (FileAlignment % 2 != 0) - errx(1, "%s: Invalid file alignment %zu", file, FileAlignment); + if (ctx->FileAlignment % 2 != 0) + errx(1, "%s: Invalid file alignment 0x%08x", file, ctx->FileAlignment); - if (FileAlignment == 0) - FileAlignment = 0x200; + if (ctx->FileAlignment == 0) + ctx->FileAlignment = 0x200; if (ctx->SectionAlignment == 0) ctx->SectionAlignment = PAGE_SIZE; - if (ctx->SectionAlignment < FileAlignment) - ctx->SectionAlignment = FileAlignment; + if (ctx->SectionAlignment < ctx->FileAlignment) + ctx->SectionAlignment = ctx->FileAlignment; ctx->NumberOfSections = PEHdr->Pe32.FileHeader.NumberOfSections; From fa21e1e3836dd51d6b8806e15978532f976081e0 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 28 Oct 2025 13:31:45 -0400 Subject: [PATCH 3/7] post-process-pe: Add debug and tests to the FileAlignment header. This adds some debug information and a test that FileAlignment is compatible with PAGE_SIZE to the validate_nx_compat() function. Signed-off-by: Peter Jones --- post-process-pe.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/post-process-pe.c b/post-process-pe.c index 3d1bb5305..35a35e2c2 100644 --- a/post-process-pe.c +++ b/post-process-pe.c @@ -381,6 +381,14 @@ validate_nx_compat(PE_COFF_LOADER_IMAGE_CONTEXT *ctx) ret = -1; } + debug(NOISE, "File alignment is 0x%x, page size is 0x%x\n", + ctx->FileAlignment, PAGE_SIZE); + if (ctx->FileAlignment % PAGE_SIZE != 0) { + debug(level, "File alignment is not a multiple of page size\n"); + if (require_nx_compat) + ret = -1; + } + debug(NOISE, "Section alignment is 0x%x, page size is 0x%x\n", ctx->SectionAlignment, PAGE_SIZE); if (ctx->SectionAlignment != PAGE_SIZE) { From 21c12c0a25047072beb5a437403abff9f9e49373 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 28 Oct 2025 13:32:09 -0400 Subject: [PATCH 4/7] post-process-pe: be better at section alignment complaints In validate_nx_compat() we're testing SectionAlignment against our 4kB page size, but the requirement is actually only that it should be a multiple of it. This tests for that instead. Signed-off-by: Peter Jones --- post-process-pe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/post-process-pe.c b/post-process-pe.c index 35a35e2c2..e4e4f0487 100644 --- a/post-process-pe.c +++ b/post-process-pe.c @@ -391,8 +391,9 @@ validate_nx_compat(PE_COFF_LOADER_IMAGE_CONTEXT *ctx) debug(NOISE, "Section alignment is 0x%x, page size is 0x%x\n", ctx->SectionAlignment, PAGE_SIZE); - if (ctx->SectionAlignment != PAGE_SIZE) { - debug(level, "Section alignment is not page aligned\n"); + if (ctx->SectionAlignment & (PAGE_SIZE - 1)) { + debug(level, "Section alignment is not page aligned: SectionAlignment & PAGE_MASK = 0x%08x & 0x%08x = 0x%08x\n", + ctx->SectionAlignment, PAGE_SIZE-1, ctx->SectionAlignment & (PAGE_SIZE-1)); if (require_nx_compat) ret = -1; } From 58822a7a6aa1b1760be887ddd9ea4290703aa00f Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 28 Oct 2025 13:32:28 -0400 Subject: [PATCH 5/7] post-process-pe: complain about section VMA alignment This adds a test to verify_nx_compat() to check if section VMAs are aligned with our PE header's SectionAlignment. Signed-off-by: Peter Jones --- post-process-pe.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/post-process-pe.c b/post-process-pe.c index e4e4f0487..4b71d8aa4 100644 --- a/post-process-pe.c +++ b/post-process-pe.c @@ -410,6 +410,13 @@ validate_nx_compat(PE_COFF_LOADER_IMAGE_CONTEXT *ctx) if (require_nx_compat) ret = -1; } + + debug(NOISE, "Section %d has VA of 0x%08x\n", i, Section->VirtualAddress); + if (Section->VirtualAddress != 0 && + ((Section->VirtualAddress) & (ctx->SectionAlignment - 1))) { + debug(level, "Section %d has Virtual Address 0x%08x that isn't section aligned (0x%08x)\n", + i, Section->VirtualAddress, ctx->SectionAlignment); + } } return ret; From a84655cb00537e2d7c922b233a8558ae6ccd6000 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 28 Oct 2025 13:29:32 -0400 Subject: [PATCH 6/7] make: set PE section alignment everywhere This changes our linking to have a per-arch section alignment and apply it when we link. Note that this will produce incorrect results if the alignment used in the linker scripts do not match. Signed-off-by: Peter Jones --- Make.defaults | 4 ++++ Makefile | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Make.defaults b/Make.defaults index 9b40b7f4a..a1389e8c3 100644 --- a/Make.defaults +++ b/Make.defaults @@ -68,6 +68,7 @@ ifeq ($(ARCH),x86_64) ARCH_SUFFIX ?= x64 ARCH_SUFFIX_UPPER ?= X64 ARCH_LDFLAGS ?= + ARCH_SECTION_ALIGNMENT ?= 0x1000 endif ifeq ($(ARCH),ia32) ARCH_CFLAGS ?= -mno-mmx -mno-sse -mno-red-zone -nostdinc \ @@ -78,6 +79,7 @@ ifeq ($(ARCH),ia32) ARCH_SUFFIX_UPPER ?= IA32 ARCH_LDFLAGS ?= ARCH_CFLAGS ?= -m32 + ARCH_SECTION_ALIGNMENT ?= 0x1000 endif ifeq ($(ARCH),aarch64) ARCH_CFLAGS ?= -DMDE_CPU_AARCH64 -DPAGE_SIZE=4096 -mstrict-align @@ -86,6 +88,7 @@ ifeq ($(ARCH),aarch64) ARCH_SUFFIX_UPPER ?= AA64 ARCH_LDFLAGS ?= ARCH_CFLAGS ?= + ARCH_SECTION_ALIGNMENT ?= 0x1000 endif ifeq ($(ARCH),arm) ARCH_CFLAGS ?= -DMDE_CPU_ARM -DPAGE_SIZE=4096 -mno-unaligned-access @@ -95,6 +98,7 @@ ifeq ($(ARCH),arm) FORMAT := -O binary SUBSYSTEM := 0xa ARCH_LDFLAGS += --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM) + ARCH_SECTION_ALIGNMENT ?= 0x1000 endif DEFINES = -DDEFAULT_LOADER='L"$(DEFAULT_LOADER)"' \ diff --git a/Makefile b/Makefile index 9a39cd13f..f03b7f386 100644 --- a/Makefile +++ b/Makefile @@ -282,6 +282,7 @@ endif -j .rela* -j .dyn -j .reloc -j .eh_frame \ -j .vendor_cert -j .sbat -j .sbatlevel \ --file-alignment 0x1000 \ + --section-alignment $(ARCH_SECTION_ALIGNMENT) \ $(FORMAT) $< $@ ./post-process-pe -vv $(POST_PROCESS_PE_FLAGS) $@ @@ -302,6 +303,7 @@ endif -j .debug_line -j .debug_str -j .debug_ranges \ -j .note.gnu.build-id \ --file-alignment 0x1000 \ + --section-alignment $(ARCH_SECTION_ALIGNMENT) \ $< $@ ifneq ($(origin ENABLE_SBSIGN),undefined) From 1b2d73f908eca99d775aa69a5033300522306e0a Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 22 Oct 2025 16:44:44 -0400 Subject: [PATCH 7/7] Aarch64: use bigger section alignment In UEFI Mantis 2549, ARM proposes to recommend 64kB section alignment in UEFI binaries. The reason for this is that some machines may be configured to have no pages smaller than 64kB for performance reasons, and in such a scenario things like W^X will be impossible to correctly implement on binaries where one section ends and another begins on the same 64kB page. This change makes aarch64 binaries use a 64kB rather than 4kB section alignment. Note that this only actually changes virtual addresses, not file addresses, so the size is unchanged: Before: SectionAlignment 00001000 FileAlignment 00001000 Sections: Idx Name Size VMA LMA File off Algn 0 .eh_frame 00018c64 0000000000005000 0000000000005000 00001000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .text 0006bd9c 000000000001e000 000000000001e000 0001a000 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .reloc 0000000a 000000000008a000 000000000008a000 00086000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .data.ident 00000088 000000000008c000 000000000008c000 00087000 2**2 CONTENTS, ALLOC, LOAD, DATA 4 .sbatlevel 0000006c 000000000008d000 000000000008d000 00088000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .data 0002f268 000000000008e000 000000000008e000 00089000 2**2 CONTENTS, ALLOC, LOAD, DATA 6 .vendor_cert 00000010 00000000000be000 00000000000be000 000b9000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .dynamic 000000f0 00000000000bf000 00000000000bf000 000ba000 2**2 CONTENTS, ALLOC, LOAD, DATA 8 .rela 0001d760 00000000000c0000 00000000000c0000 000bb000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 9 .sbat 00000083 00000000000de000 00000000000de000 000d9000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA $ /bin/ls -l shimaa64.efi -rwxr-xr-x. 1 pjones pjones 1036357 Oct 28 13:34 shimaa64.efi After: SectionAlignment 00010000 FileAlignment 00001000 Sections: Idx Name Size VMA LMA File off Algn 0 .eh_frame 00018c64 0000000000010000 0000000000010000 00001000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .text 0006bd9c 0000000000030000 0000000000030000 0001a000 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .reloc 0000000a 00000000000a0000 00000000000a0000 00086000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .data.ident 00000088 00000000000c0000 00000000000c0000 00087000 2**2 CONTENTS, ALLOC, LOAD, DATA 4 .sbatlevel 0000006c 00000000000d0000 00000000000d0000 00088000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .data 0002f268 00000000000e0000 00000000000e0000 00089000 2**2 CONTENTS, ALLOC, LOAD, DATA 6 .vendor_cert 00000010 0000000000110000 0000000000110000 000b9000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .dynamic 000000f0 0000000000120000 0000000000120000 000ba000 2**2 CONTENTS, ALLOC, LOAD, DATA 8 .rela 0001d760 0000000000130000 0000000000130000 000bb000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 9 .sbat 00000083 0000000000150000 0000000000150000 000d9000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA $ /bin/ls -l shimaa64.efi -rwxr-xr-x. 1 pjones pjones 1036357 Oct 28 13:18 shimaa64.efi On my test machine, that changes the text and data load addresses (both physical and virtual, we're still on a 1:1 map) as follows: Before: _text:0x0000000092FF7000 _data:0x0000000093067000 After: _text:0x0000000092F80000 _data:0x0000000093030000 Signed-off-by: Peter Jones --- Make.defaults | 2 +- elf_aarch64_efi.lds | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Make.defaults b/Make.defaults index a1389e8c3..afbf44d0a 100644 --- a/Make.defaults +++ b/Make.defaults @@ -88,7 +88,7 @@ ifeq ($(ARCH),aarch64) ARCH_SUFFIX_UPPER ?= AA64 ARCH_LDFLAGS ?= ARCH_CFLAGS ?= - ARCH_SECTION_ALIGNMENT ?= 0x1000 + ARCH_SECTION_ALIGNMENT ?= 0x10000 endif ifeq ($(ARCH),arm) ARCH_CFLAGS ?= -DMDE_CPU_ARM -DPAGE_SIZE=4096 -mno-unaligned-access diff --git a/elf_aarch64_efi.lds b/elf_aarch64_efi.lds index 0861f5e8a..ff2e408ae 100644 --- a/elf_aarch64_efi.lds +++ b/elf_aarch64_efi.lds @@ -6,12 +6,12 @@ SECTIONS . = 0; ImageBase = .; .hash : { *(.hash) } /* this MUST come first! */ - . = ALIGN(4096); + . = ALIGN(65536); .eh_frame : { *(.eh_frame) } - . = ALIGN(4096); + . = ALIGN(65536); .text : { _text = .; @@ -20,26 +20,26 @@ SECTIONS *(.gnu.linkonce.t.*) _etext = .; } - . = ALIGN(4096); + . = ALIGN(65536); .reloc : { *(.reloc) } - . = ALIGN(4096); + . = ALIGN(65536); .note.gnu.build-id : { *(.note.gnu.build-id) } - . = ALIGN(4096); + . = ALIGN(65536); .data.ident : { *(.data.ident) } - . = ALIGN(4096); + . = ALIGN(65536); .sbatlevel : { *(.sbatlevel) } - . = ALIGN(4096); + . = ALIGN(65536); .data : { _data = .; @@ -58,14 +58,14 @@ SECTIONS *(.rel.local) } - . = ALIGN(4096); + . = ALIGN(65536); .vendor_cert : { *(.vendor_cert) } - . = ALIGN(4096); + . = ALIGN(65536); .dynamic : { *(.dynamic) } - . = ALIGN(4096); + . = ALIGN(65536); .rela : { *(.rela.data*) @@ -74,7 +74,7 @@ SECTIONS } _edata = .; _data_size = . - _data; - . = ALIGN(4096); + . = ALIGN(65536); .sbat : { _sbat = .; @@ -84,11 +84,11 @@ SECTIONS _esbat = .; _sbat_size = . - _sbat; - . = ALIGN(4096); + . = ALIGN(65536); .dynsym : { *(.dynsym) } - . = ALIGN(4096); + . = ALIGN(65536); .dynstr : { *(.dynstr) } - . = ALIGN(4096); + . = ALIGN(65536); .ignored.reloc : { *(.rela.reloc)