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

[RuntimeDyld][ELF] Unwanted sign-extension when computing stub addresses. #94478

Closed
al45tair opened this issue Jun 5, 2024 · 3 comments · Fixed by #94482
Closed

[RuntimeDyld][ELF] Unwanted sign-extension when computing stub addresses. #94478

al45tair opened this issue Jun 5, 2024 · 3 comments · Fixed by #94482

Comments

@al45tair
Copy link
Contributor

al45tair commented Jun 5, 2024

The RuntimeDyldELF implementation tries to make a stub, it uses an expression like

reinterpret_cast<uint64_t>(Section.getAddressWithOffset(Section.getStubOffset()))

to get the address of the stub it's generating as a uint64_t.

Sadly, on 32-bit platforms where addresses are regarded as signed, because getAddressWithOffset() returns a uint8_t * pointer, this can cause unwanted sign-extension, so if (for instance) the code has been loaded at 0xf1a10000, and the stub is at offset 4, the resulting uint64_t will be 0xfffffffff1a10004 instead of the expected 0xf1a10004.

@DavidSpickett
Copy link
Collaborator

I tried to reproduce this issue on Arm 32 bit and couldn't so -

Sadly, on 32-bit platforms where addresses are regarded as signed

Makes sense here.

In Arm's 32 bit ABI it notes that "Pointer arithmetic should be unsigned." (https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst). So this will be why it didn't show up on that platform.

al45tair added a commit to al45tair/llvm-project that referenced this issue Jun 5, 2024
Casting the result of `Section.getAddressWithOffset()` goes wrong if
we are on a 32-bit platform whose addresses are regarded as signed;
in that case, just doing
```
(uint64_t)Section.getAddressWithOffset(...)
```
or
```
reinterpret_cast<uint64_t>(Section.getAddressWithOffset(...))
```
will result in sign-extension.

We use these expressions when constructing branch stubs, which is
before we know the final load address, so we can just switch to the
`Section.getLoadAddressWithOffset(...)` method instead.

Doing that is also more consistent, since when calculating relative
offsets for relocations, we use the load address anyway, so the
code currently only works because `Section.Address` is equal to
`Section.LoadAddress` at this point.

Fixes llvm#94478.
@al45tair
Copy link
Contributor Author

al45tair commented Jun 5, 2024

I tried to reproduce this issue on Arm 32 bit and couldn't so -

Sadly, on 32-bit platforms where addresses are regarded as signed

Makes sense here.

In Arm's 32 bit ABI it notes that "Pointer arithmetic should be unsigned." (https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst). So this will be why it didn't show up on that platform.

Yeah, @mgorny noticed it on 32-bit x86, where they are treated as signed. In that case, it caused my new test for cross-section branches on AArch64 to fail with an assertion failure, because of the unwanted sign extension. I'm raising a PR to fix the problem at the moment.

@al45tair
Copy link
Contributor Author

al45tair commented Jun 5, 2024

(See the comments on the end of #92245.)

lhames pushed a commit that referenced this issue Jun 6, 2024
Casting the result of `Section.getAddressWithOffset()` goes wrong if we
are on a 32-bit platform whose addresses are regarded as signed; in that
case, just doing
```
(uint64_t)Section.getAddressWithOffset(...)
```
or
```
reinterpret_cast<uint64_t>(Section.getAddressWithOffset(...))
```
will result in sign-extension.

We use these expressions when constructing branch stubs, which is before
we know the final load address, so we can just switch to the
`Section.getLoadAddressWithOffset(...)` method instead.

Doing that is also more consistent, since when calculating relative
offsets for relocations, we use the load address anyway, so the code
currently only works because `Section.Address` is equal to
`Section.LoadAddress` at this point.

Fixes #94478.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants