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

Linking fails on nightly rustc due to mismatched ABI flags #9

Closed
ayrtonm opened this issue May 1, 2022 · 1 comment
Closed

Linking fails on nightly rustc due to mismatched ABI flags #9

ayrtonm opened this issue May 1, 2022 · 1 comment

Comments

@ayrtonm
Copy link
Owner

ayrtonm commented May 1, 2022

Since upstream LLVM now supports load delay slots, I tried updating the rustc patch in this repo. I was able to build nightly rustc, but it's unusable since all builds fail with the following linker error.

rust-lld: error: foo-cgu.0.rcgu.o: ABI 'o32' is incompatible with target ABI 'n64'

This issue occurs on nightly rustc for both the psx and psp (@sajattack) targets and is likely an issue for other 32-bit MIPS targets.

This is caused by a recent change that adds a temporary symbols.o to the linker invocation. The change itself is fine, but the temporary object file is created with an e_flags which is invalid for 32-bit MIPS targets. The main issue is that it omits the ABI bits (EF_MIPS_ABI_O32) which implies it uses the N64 ABI. Even though symbols.o doesn't contain code, lld fails since the ABI bits in all files don't match.

The fix is pretty straightforward and I have a patch to determine e_flags from the target options, but the object crate is missing some ABI constants so it needs to be updated first.

@ayrtonm ayrtonm changed the title Linking fails on nightly rustc Linking fails on nightly rustc due to mismatched ABI flags May 1, 2022
ayrtonm added a commit to ayrtonm/rust that referenced this issue May 11, 2022
In rust-lang#95604 the compiler started generating a temporary symbols.o which is added
to the linker invocation. This object file has an `e_flags` which may be invalid
for 32-bit MIPS targets. Even though symbols.o doesn't contain code, linking
    with [lld fails](https://github.com/llvm/llvm-project/blob/main/lld/ELF/Arch/MipsArchTree.cpp#L79) with
```
rust-lld: error: foo-cgu.0.rcgu.o: ABI 'o32' is incompatible with target ABI 'n64'
```
because it omits the ABI bits (EF_MIPS_ABI_O32) so lld assumes it's using the
N64 ABI. This breaks linking on nightly for the out-of-tree [psx
target](ayrtonm/psx-sdk-rs#9), the builtin
mipsel-sony-psp target (cc @overdrivenpotato) and any other 32-bit MIPS
target using lld.

This PR sets the ABI in `e_flags` to O32 since that's the only ABI for 32-bit
MIPS that LLVM supports. It also sets other `e_flags` bits based on the target.
I had to bump the object crate version since some of these constants were [added
recently](gimli-rs/object#433). I'm not sure if this
PR needs a test, but I can confirm that it fixes the linking issue on both
targets I mentioned.
bors added a commit to rust-lang-ci/rust that referenced this issue May 13, 2022
Fix e_flags for 32-bit MIPS targets in generated object file

In rust-lang#95604 the compiler started generating a temporary symbols.o which is added to the linker invocation. This object file has an `e_flags` which is invalid for 32-bit MIPS targets. Even though symbols.o doesn't contain code, linking these targets with [lld fails](https://github.com/llvm/llvm-project/blob/main/lld/ELF/Arch/MipsArchTree.cpp#L76-L79) with
```
rust-lld: error: foo-cgu.0.rcgu.o: ABI 'o32' is incompatible with target ABI 'n64'
```
because it omits the ABI bits (`EF_MIPS_ABI_O32`) so lld assumes it's using the N64 ABI. This breaks linking on nightly for the out-of-tree [mipsel-sony-psx target](ayrtonm/psx-sdk-rs#9), the builtin mipsel-sony-psp target (cc `@overdrivenpotato)` and probably any other 32-bit MIPS target using lld.

This PR sets the ABI in `e_flags` to O32 since that's the only ABI for 32-bit MIPS that LLVM supports. It also sets other `e_flags` bits based on the target to avoid similar issues with the object file arch and PIC. I had to bump the object crate version since some of these constants were [added recently](gimli-rs/object#433). I'm not sure if this PR needs a test, but I can confirm that it fixes the linking issue on both targets I mentioned.
@ayrtonm
Copy link
Owner Author

ayrtonm commented May 13, 2022

Closed by rust-lang/rust#96930

@ayrtonm ayrtonm closed this as completed May 13, 2022
xSetech added a commit to xSetech/rust that referenced this issue Jul 9, 2023
PR rust-lang#95604 introduced a "synthetic object file to ensure all exported and
used symbols participate in the linking". One constraint on this file is
that for MIPS-based targets, its architecture-specific ELF flags must be
the same as all other object files passed to the linker. That's enforced
by LLD, here:
https://github.com/llvm/llvm-project/blob/llvmorg-16.0.6/lld/ELF/Arch/MipsArchTree.cpp#L77

The current approach to determining e_flags for 32-bit was implemented
in PR rust-lang#96930, which links to this issue that summarizes the problem well:
ayrtonm/psx-sdk-rs#9

> ... the temporary object file is created with an e_flags which is
> invalid for 32-bit MIPS targets. The main issue is that it omits the ABI
> bits (EF_MIPS_ABI_O32) which implies it uses the N64 ABI.

To enable the N32 MIPS ABI (which succeeded O32), this patch enables
setting the synthetic object's ABI based on the target "llvm-abiname"
field, if it's given; otherwise, the O32 ABI is assumed for 32-bit MIPS
targets.

More information about the N32 ABI can be found here:
https://web.archive.org/web/20160121005457/http://techpubs.sgi.com/library/manuals/2000/007-2816-005/pdf/007-2816-005.pdf
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jul 11, 2023
Support explicit 32-bit MIPS ABI for the synthetic object

PR rust-lang#95604 introduced a "synthetic object file to ensure all exported and used symbols participate in the linking". One constraint on this file is that for MIPS-based targets, its architecture-specific ELF flags must be the same as all other object files passed to the linker. That's enforced by LLD, here:
https://github.com/llvm/llvm-project/blob/llvmorg-16.0.6/lld/ELF/Arch/MipsArchTree.cpp#L77

The current approach to determining e_flags for 32-bit was implemented in PR rust-lang#96930, which links to this issue that summarizes the problem well: ayrtonm/psx-sdk-rs#9

> ... the temporary object file is created with an e_flags which is
> invalid for 32-bit MIPS targets. The main issue is that it omits the ABI
> bits (EF_MIPS_ABI_O32) which implies it uses the N64 ABI.

To enable the N32 MIPS ABI (which succeeded O32), this patch enables setting the synthetic object's ABI based on the target "llvm-abiname" field, if it's given; otherwise, the O32 ABI is assumed for 32-bit MIPS targets.

More information about the N32 ABI can be found here: https://web.archive.org/web/20160121005457/http://techpubs.sgi.com/library/manuals/2000/007-2816-005/pdf/007-2816-005.pdf
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

No branches or pull requests

1 participant