-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Add a freestanding target #106
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
- Start Date: 2014-06-03 | ||
- RFC PR #: (leave this empty) | ||
- Rust Issue #: (leave this empty) | ||
|
||
# Summary | ||
|
||
Add support for the "unknown" OS in target triples, and disable split stack | ||
checking on them by default. | ||
|
||
# Motivation | ||
|
||
One of Rust's important use cases is embedded, OS, or otherwise "bare metal" | ||
software. At the moment, we still depend on LLVM's split-stack prologue for | ||
stack safety. In certain situations, it is impossible or undesirable to | ||
support what LLVM requires to enable this (on x86, a certain thread-local | ||
storage setup). We also link to some libraries unconditionally, making it | ||
difficult to produce freestanding binaries without stubbing them out. | ||
|
||
# Detailed design | ||
|
||
A target triple consists of three strings separated by a hyphen, with a | ||
possible fourth string at the end preceded by a hyphen. The first is the | ||
architecture, the second is the "vendor", the third is the OS type, and the | ||
optional fourth is environment type. In theory, this specifies precisely what | ||
platform the generated binary will be able to run on. All of this is | ||
determined not by us but by LLVM and other tools. When on bare metal or a | ||
similar environment, there essentially is no OS, and to handle this there is | ||
the concept of "unknown" in the target triple. When the OS is "unknown" many | ||
features can be assumed to be missing, such as dynamic linking (which requires | ||
surprisingly complicated runtime support), thread-local storage (threads are | ||
inherently an OS concept), presence of any given IO routines, etc. | ||
|
||
When the compiler encounters such a target, it will never attempt to use | ||
dynamic linking, will disable emitting the split stack prologue, and will not | ||
link to any support libraries. These targets, of the form `*-unknown-unknown`, | ||
will never be a valid platform for rustc itself to run on, and can only be | ||
used for cross-compiling a crate. Statically linking to other crates will | ||
still be valid. | ||
|
||
"Support libraries" means libmorestack and compiler-rt. The crate author will | ||
need to provide compiler-rt or a similar library themselves if they use a | ||
feature requiring it, and libmorestack is just not required without split | ||
stacks. The goal is to have 0 dependencies on the environment, at compile time | ||
and runtime, reducing unnecessary surprises for the freestanding author and | ||
allowing the use of only rustc to compile the crate, rather than manually | ||
assembling and linking LLVM bitcode. Providing linker arguments manually is | ||
probably unavoidable in these cases. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My previous discussion has now been folded away by github, so I'll reiterate my point here original link. I don't understand the use case for not wanting to link to compiler-rt. Is there a concrete reason for why this is undesirable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yet another thing you need to download and build, for features you're probably not using (floats, 64-bit math on 32-bit targets, emulating atomics with locks, fixed point arith, ...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to talk concretely here. The compiler-rt library is tiny and very easy to build. It has one function per object, so the linker strips out everything you don't use. Without a conrete reason as to why, I don't see why the compiler should stop linking to compiler-rt. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree there are instances where you probably do want compiler-rt, but that those would be outweighed by the cases where you don't. (Some fun reading, though only slightly topical: http://yarchive.net/comp/linux/libgcc.html) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The concrete reason being it's just another dependency you need. I'm not going to argue that it's large or a runtime burden (because that would just be false). Should we instead add build system support for building and distributing it for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Avoiding compiler-rt means providing all of the support functions expected by LLVM's code generation on your own. You can almost get away with using
That's pretty much how the LLVM project works right now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't run into any of these support functions being missing on arm-none-eabi (thumb2). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The features provided by compiler-rt are well known and we don't need to rely on anecdotes to know that significant portions of the language are missing without it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What do you mean by "being missing"? I do link to libgcc.a for some of those on thumbv7m, as I don't use compiler-rt. They are definitely required in lots of cases. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My apologies - the build system is linking against libgcc.a, so I must be getting them from there. |
||
|
||
# Drawbacks | ||
|
||
All function calls become unsafe in such a target, since guards against stack | ||
overflow are not inserted by the compiler. The crate author must be careful | ||
not to overflow the stack, or set up their own stack safety mechanism. | ||
|
||
# Alternatives | ||
|
||
We could allow disabling split stacks on a per-crate basis. Then calling | ||
functions from that crate is then unsafe, and we would need to compensate for | ||
this somehow. We would still need to add a way to not link to | ||
libc/libm/copmiler-rt. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Spelling. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we could not explicitly deny dynamic linking, but rather let the linker duke it out? If the system linker does in fact support dynamic linking, it seems like we shouldn't prevent you from doing so. It often doesn't make sense in a "freestanding setting", but linker error messages will make that pretty apparent pretty quickly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not always true. You could be using ELF but it dies at runtime on the dynamic object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand. Each dynamic library has implicit dependencies for various symbols (or so I am led to believe) which are resolved by system libraries. When you you successfully link a dynamic library, and then fail to use it at runtime?
I'm basically thinking that this require explicit code in the compiler to reject this situation, when it should naturally be rejected by the linker as it will ultimately have more knowledge than we do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we support dynamic linkers, we're going to need to provide a way to set the ELF interpeter at the very least... and I don't really want to dig into the nitty-gritty of supporting dynamic executables for All The Things we could support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still not understanding what you're saying here. What is an ELF interpreter? How are we supporting dynamic linkers? Is a regular linker different from a dynamic linker? How is this digging into the nitty gritty of supporting dynamic executables?
I don't understand why specifically blacklisting particular platforms is more nitty-gritty than not doing anything at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dynamic linker being the runtime relocator (I'll just call it rtld to avoid confusion in the future), the interpreter being the
.interp
section which is just a string that specified the path to the rtld to use. I don't even know what PE/COFF or Mach-O do. If there isn't an OS, it doesn't make a lot of sense to be using/lib64/ld-linux-x86-64.so.2
as the rtld, for example. I suppose not doing anything at all is fine. Especially if it were combined with -C linker.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like things can go wrong very quickly, but I'm still not seeing what we're losing by saying "let the linker duke it out?"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's something annoying that we could avoid entirely on our end, with a nicer user experience.