From dba325ef17e254815e9848378956fcf9642ac51e Mon Sep 17 00:00:00 2001 From: Yuta Hayama Date: Fri, 28 Jul 2023 16:22:31 +0900 Subject: [PATCH 1/2] align startOffset with p_align instead of pagesize for compatibility According to the ELF specification, the alignment of loadable process segments should satisfy (p_vaddr mod pagesize) == (p_offset mod pagesize). However, glibc earlier than 2.35 incorrectly requires that the LOAD segment be (p_vaddr mod p_align) == (p_offset mod p_align), and will output the error message "ELF load command address/offset not properly aligned" if this is not met. Since there are many systems that use glibc earlier than 2.35, it is preferable that newly added LOAD segments satisfy (p_vaddr mod p_align) == (p_offset mod p_align) for compatibility. --- src/patchelf.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 82b4b46c..6edb81ac 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -843,7 +843,13 @@ void ElfFile::rewriteSectionsLibrary() neededSpace += headerTableSpace; debug("needed space is %d\n", neededSpace); - Elf_Off startOffset = roundUp(fileContents->size(), getPageSize()); + /* glibc earlier than 2.35 requires that the LOAD segment satisfies + (p_vaddr mod p_align) == (p_offset mod p_align). + The ELF specification requires that loadable process segments satisfy + (p_vaddr mod pagesize) == (p_offset mod pagesize), so glibc is probably + wrong, but here startOffset is calculated according to p_align for + compatibility. */ + Elf_Off startOffset = roundUp(fileContents->size(), alignStartPage); // In older version of binutils (2.30), readelf would check if the dynamic // section segment is strictly smaller than the file (and not same size). From 9188cb8612b918f3319bcd4656f34e07f2327bd3 Mon Sep 17 00:00:00 2001 From: Yuta Hayama Date: Mon, 31 Jul 2023 11:58:49 +0900 Subject: [PATCH 2/2] make LOAD segment extensions based on p_align instead of pagesize Since the p_align of the LOAD segment is no longer pagesize, the actual p_align value is used to calculate for the LOAD segment extension. If calculated with pagesize, new LOAD segment may be added even though the existing LOAD segment can be extended. --- src/patchelf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 6edb81ac..86429c41 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -885,7 +885,7 @@ void ElfFile::rewriteSectionsLibrary() rdi(lastSeg.p_type) == PT_LOAD && rdi(lastSeg.p_flags) == (PF_R | PF_W) && rdi(lastSeg.p_align) == alignStartPage) { - auto segEnd = roundUp(rdi(lastSeg.p_offset) + rdi(lastSeg.p_memsz), getPageSize()); + auto segEnd = roundUp(rdi(lastSeg.p_offset) + rdi(lastSeg.p_memsz), alignStartPage); if (segEnd == startOffset) { auto newSz = startOffset + neededSpace - rdi(lastSeg.p_offset); wri(lastSeg.p_filesz, wri(lastSeg.p_memsz, newSz));