Skip to content

Use more accurate ELF flags on MIPS #140634

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

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

Conversation

smrobtzz
Copy link

@smrobtzz smrobtzz commented May 4, 2025

Changes the MIPS ELF flags used for metadata objects to be closer to what LLVM uses so the linker doesn't complain

@rustbot
Copy link
Collaborator

rustbot commented May 4, 2025

r? @workingjubilee

rustbot has assigned @workingjubilee.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot
Copy link
Collaborator

rustbot commented May 4, 2025

These commits modify compiler targets.
(See the Target Tier Policy.)

Some changes occurred in compiler/rustc_codegen_ssa

cc @WaffleLapkin

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 4, 2025
@workingjubilee
Copy link
Member

Changes the MIPS ELF flags used for metadata objects to be closer to what LLVM uses so the linker doesn't complain

@smrobtzz what linker were you using from what distro to build what crate such that the linker complained?

Comment on lines 299 to 301
if !sess.target.options.features.contains("noabicalls") {
e_flags |= elf::EF_MIPS_CPIC;
}
Copy link
Member

@workingjubilee workingjubilee May 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is defining whether it uses position independent calls for the entire emitted artifact, then no, I do not intend to have rustc respect another LLVM "feature" that defines a necessarily global quality of compilation, much less a negative feature. Rust has a model of what a target feature is that conflicts with that.

At the very least, respecting new CLI inputs like this is certainly something I would prefer we decide separately from what is a mere fix.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, I'll remove that check.

Comment on lines 292 to 307
_ => {
if architecture == Architecture::Mips {
e_flags |= elf::EF_MIPS_ABI_O32
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not like this continued guessing. Either

  • do nothing on this branch
  • explicitly recognize "n64" as a possible variant, add it to all the 64-bit MIPS targets, and panic if llvm_abiname is unset

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how that change is worse than the current implementation since it's exactly the same logic, but I'll add better validation here and require llvm_abiname on 64-bit MIPS

Copy link
Member

@workingjubilee workingjubilee May 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am at about the point where I think we should require the field on all MIPSy targets, just like it is required on RISCV (last I checked) and a similar-but-different field is required on x86. Especially for ABI-affecting fields, we generally trend towards making the fields hard requirements so that there's no ambiguity.

It's kinda the same thing as the lowercase issue: if there is a sensible default for or normalization of the data, then we should probably address that during deserialization and emit a warning if the field was not specified. Otherwise, we should usually panic on the field being unspecified.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am okay with the 32-bit case, I think, being inferred, due to LLVM not supporting other alternative MIPS ABIs for 32-bit MIPS (though supposedly they exist)

Copy link
Member

@workingjubilee workingjubilee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice a number of changes that seem to be acting on a matter of "thoroughness" or otherwise changing things that don't seem to need to be changed in order for the compiler to be used to its current range of ability for the existing targets we support. With the somewhat terse PR description that did not describe the actual errors you encountered, I can't tell if all of these changes are actually required, and some of them seem to allow new forms of being incorrect.

While we are allowed to arbitrarily trash compilation if the target-spec.json (or our own target definitions!) are incorrect, so we can corrupt our artifacts (or preferably fail to compile) if the llvm_abiname is set in an incorrect or clashing way? I would prefer it if the change was slightly more guarded against other forms of incorrectness like the target.options.cpu or target.options.features, which can be set by ordinary compiler users giving it input, last I checked.

Comment on lines 3570 to 3582
"mips64" | "mips64r6" => (Architecture::Mips64, None),
"mips64" | "mips64r6" => (
if self.options.llvm_abiname.to_lowercase().as_str() == "n32" {
Architecture::Mips64_N32
} else {
Architecture::Mips64
},
None,
),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't support any N32 targets so this change is not required, really.

But more puzzlingly, I'm not sure why we are spending the effort to be case-indifferent when we're not even case-indifferent for "mips64" vs. "MIPS64"? If we want to normalize the case then we should have done it elsewhere instead of complicating every time we check.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using a custom target spec with n32, so I need this change most. Will remove the to_lowercase though

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. That makes sense.

It would be slightly more productive if we had an actual N32 target as a skeleton for understanding what we are supposed to be supporting, even if it was extremely rudimentary.

Copy link
Member

@jieyouxu jieyouxu May 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please leave a comment to that effect to save some headscratching down the line? i.e.

a custom target spec with n32

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 273 to 295
Architecture::Mips | Architecture::Mips64 | Architecture::Mips64_N32 => {
let mut e_flags = match sess.target.options.cpu.as_ref() {
"mips1" => elf::EF_MIPS_ARCH_1,
"mips2" => elf::EF_MIPS_ARCH_2,
"mips3" => elf::EF_MIPS_ARCH_3,
"mips4" => elf::EF_MIPS_ARCH_4,
"mips5" => elf::EF_MIPS_ARCH_5,
s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
"mips32r2" => elf::EF_MIPS_ARCH_32R2,
"mips32r6" => elf::EF_MIPS_ARCH_32R6,
"mips64r2" => elf::EF_MIPS_ARCH_64R2,
"mips64r6" => elf::EF_MIPS_ARCH_64R6,
_ => elf::EF_MIPS_ARCH_32R2,
};
Copy link
Member

@workingjubilee workingjubilee May 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmh. If we set EF_MIPS_ARCH_32R2 for Architecture::Mips64 then I'm pretty sure that all further compilation logic is, uh, I believe the technical term is "totally fucked"? Please do not allow invalid combinations, so split things along the 32-bit and 64-bit lines and use panic!() or bug!() appropriately. If this means you need to extract code shared across the different MIPS bitnesses and ABIs into another function or just double-down on an initial guard for some cases then that's fine.

Copy link
Member

@workingjubilee workingjubilee May 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can find a DiagCtxt a few steps up the callstack and want to thread it down (or pass more data up from here?) to make a nicer error, that would be fine too. I just want to make sure we don't support obviously incorrect pairs.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, will fix

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 4, 2025
@smrobtzz
Copy link
Author

smrobtzz commented May 4, 2025

Sorry, should've explained more. I'm using a custom target specification with this combination of options:

"arch": "mips64",
"cpu": "mips3",
"llvm-abiname": "n32",
"features": "+noabicalls",

With these options, Rust's metadata objects (not sure what they're called) are always ELF64 mips64r2 objects, whereas the code objects emitted by LLVM are ELF32 mips3 objects. So, linking an executable (or, making an rlib and trying to link that with something else) fails because the objects are obviously incompatible.

My changes are attempting to be "thorough" because the criteria for what the GNU and LLVM linkers consider compatible objects is pretty unclear. They can complain about nan2008 not matching, the ABI not matching, the CPU not matching, etc. So, I figured that it would be at better (resulting in the least amount of linker complaints for whatever custom or builtin targets people may be using) to at least put some effort into making sure the ELF files emitted are close to what LLVM outputs, rather than (for mips64 at least) defaulting to what mips64el-linux-gnuabi64-gcc foo.c -c did, and assuming that's fine.

@smrobtzz
Copy link
Author

smrobtzz commented May 4, 2025

I've added better validation that should catch the obviously wrong combinations of CPU, architecture, ABI, and removed the explicit check for noabicalls

@smrobtzz smrobtzz requested a review from workingjubilee May 4, 2025 19:32
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 4, 2025
@rust-log-analyzer

This comment has been minimized.

Copy link
Member

@workingjubilee workingjubilee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Things look good overall now. I have some notes that might be useful to reference for later revisions of this code. Please feel free to reword them as you prefer, especially if they need corrections for accuracy.

Comment on lines 292 to 307
_ => {
if architecture == Architecture::Mips {
e_flags |= elf::EF_MIPS_ABI_O32
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am okay with the 32-bit case, I think, being inferred, due to LLVM not supporting other alternative MIPS ABIs for 32-bit MIPS (though supposedly they exist)

@workingjubilee
Copy link
Member

Thanks!

Hopefully this fixes the thing you're trying to wrangle.

@bors r+

@bors
Copy link
Collaborator

bors commented May 5, 2025

📌 Commit 57941af has been approved by workingjubilee

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 5, 2025
@workingjubilee
Copy link
Member

Note that if you develop a need for a MIPS N32 target for rustc to continue to work on an ongoing basis, it would be somewhat more to-the-point to add a tier 3 target by sending a PR for it and agreeing to be the point of contact for it. Until then we may arbitrarily stomp on this code, depending on the reviewer's whimsy. We technically may do so to tier 3 targets, but at that point we have someone to ask for help and will try to do so as a matter of courtesy, so that we can together explore options that aren't simply shrugging and blithely paving over the target's supporting code.

Zalathar added a commit to Zalathar/rust that referenced this pull request May 6, 2025
…jubilee

Use more accurate ELF flags on MIPS

Changes the MIPS ELF flags used for metadata objects to be closer to what LLVM uses so the linker doesn't complain
bors added a commit to rust-lang-ci/rust that referenced this pull request May 6, 2025
Rollup of 12 pull requests

Successful merges:

 - rust-lang#139550 (Fix `-Zremap-path-scope` rmeta handling)
 - rust-lang#139773 (Implement `Iterator::last` for `vec::IntoIter`)
 - rust-lang#140035 (Implement RFC 3503: frontmatters)
 - rust-lang#140176 (Fix linking statics on Arm64EC)
 - rust-lang#140251 (coverage-dump: Resolve global file IDs to filenames)
 - rust-lang#140393 (std: get rid of `sys_common::process`)
 - rust-lang#140532 (Fix RustAnalyzer discovery of rustc's `stable_mir` crate)
 - rust-lang#140598 (Steer docs to `utf8_chunks` and `Iterator::take`)
 - rust-lang#140634 (Use more accurate ELF flags on MIPS)
 - rust-lang#140673 (Clean rustdoc tests folder)
 - rust-lang#140678 (Be a bit more relaxed about not yet constrained infer vars in closure upvar analysis)
 - rust-lang#140687 (Update mdbook to 0.4.49)

r? `@ghost`
`@rustbot` modify labels: rollup
Zalathar added a commit to Zalathar/rust that referenced this pull request May 6, 2025
…jubilee

Use more accurate ELF flags on MIPS

Changes the MIPS ELF flags used for metadata objects to be closer to what LLVM uses so the linker doesn't complain
bors added a commit to rust-lang-ci/rust that referenced this pull request May 6, 2025
Rollup of 12 pull requests

Successful merges:

 - rust-lang#139550 (Fix `-Zremap-path-scope` rmeta handling)
 - rust-lang#139764 (Consistent trait bounds for ExtractIf Debug impls)
 - rust-lang#139773 (Implement `Iterator::last` for `vec::IntoIter`)
 - rust-lang#140035 (Implement RFC 3503: frontmatters)
 - rust-lang#140251 (coverage-dump: Resolve global file IDs to filenames)
 - rust-lang#140393 (std: get rid of `sys_common::process`)
 - rust-lang#140532 (Fix RustAnalyzer discovery of rustc's `stable_mir` crate)
 - rust-lang#140598 (Steer docs to `utf8_chunks` and `Iterator::take`)
 - rust-lang#140634 (Use more accurate ELF flags on MIPS)
 - rust-lang#140673 (Clean rustdoc tests folder)
 - rust-lang#140678 (Be a bit more relaxed about not yet constrained infer vars in closure upvar analysis)
 - rust-lang#140687 (Update mdbook to 0.4.49)

r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants