Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Align startOffset with p_align instead of pagesize for compatibility #510

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

yuta-hayama
Copy link

According to the ELF specification, the alignment of loadable process segments should satisfy (p_vaddr mod pagesize) == (p_offset mod pagesize).

By 9f1c0af, p_align of the LOAD segment newly added by patchelf is no longer a fixed value pagesize. Then patchelf calculates p_offset to satisfy (p_vaddr mod pagesize) == (p_offset mod pagesize) according to the ELF specification. (p_offset is rounded up by pagesize.)

However, glibc earlier than 2.35 incorrectly requires that the LOAD segment be (p_vaddr mod p_align) == (p_offset mod p_align). Since patchelf rounds up p_vaddr by p_align, (p_vaddr mod p_align) == 0, but if p_align is not equal to pagesize, (p_offset mod p_align) == 0 may not be true. glibc will output the following error message if the LOAD segment does not satisfy the alignment requirement.

ELF load command address/offset not properly aligned

This is the commit when the issue is fixed in glibc.
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=163f625cf9becbb82dfec63a29e566324129c0cd

Now, this is a regression caused by an older glibc, and the output of patchelf is correct in terms of the ELF specification. However, there are many systems that use glibc earlier than 2.35 (such as Ubuntu 20.04). For compatibility, it is preferable to calculate p_offset according to glibc requirements.

Note that patchelf always places the section to be rewritten at the end of the file, as described in the comment at the top of rewriteSectionsLibrary(). This can be a problem when p_align is large (For example, gcc on Ubuntu 18.04 seems to output a binary with p_align=0x200000) because the output file size expands per unit of p_align each time rewriteSectionsLibrary() is called.

Although, considering the restrictions of glibc, I think the code intended by 9f1c0af would be like this. To solve the problem of file size growth, it will be necessary to change the concept of "for dynamic libraries, we just place the replacement sections at the end of the file". For example, if a section rewrite results in a LOAD segment where no section is placed, then the section to be rewritten could be placed over it.

This may resolve issue #492.

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.
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant