Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions active/0000-freestanding-target.md
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.
Copy link
Member

Choose a reason for hiding this comment

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

I had some comments down below about this last sentence. Do you have examples of this being difficult? The compiler does not unconditionally link to any system library, and the two libraries it does link to should have 0 dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tobba claimed to have a bunch of issues with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And the build system isn't going to make compiler-rt for these targets, since you wouldn't ever be targetting them with --target to configure.

Copy link
Member

Choose a reason for hiding this comment

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

I would prefer to talk concretely about these problems.

When talking about "freestanding support", there is a huge realm of use cases, many of which conflict with each other. I have very frequently run into problems which are already solved or when the solution in mind isn't quite solving the real problem. Talking about concrete use cases is much easier to grapple than a bygone story of a difficult time wrangling with the compiler.


# 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.
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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?"

Copy link
Contributor Author

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.


"Support libraries" includes libc, libm, and compiler-rt. libc and libm
are clearly not available on the unknown OS, and the crate author will need to
provide compiler-rt or a similar library themselves if they use a feature
requiring it. 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.
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure I entirely understand this section. The compiler forcibly links to only two libraries, libmorestack and libcompiler-rt. The morestack library is used to provide the __morestack function required by LLVM's implementation of segmented stacks. This library would be omitted if the compiler is not compiling the current crate with segmented stacks disabled.

The other library, compiler-rt, is also required by LLVM. This library is not a dependency per-se in that I am unaware of any libc functions it depends on. No matter what your target is, I am under the impression that you want to link compiler-rt. This includes any "freestading platform" it sounds like you're describing here.

You mention libc and libm, but the compiler knows nothing about these libraries. They are linked to when you manually link to the liblibc crate, but never implicitly by the compiler.

Also, when you say "providing linker arguments manually is probably unavoidable", what are you referring to?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops, don't know where I thought libc/libm came from. As for compiler-rt, if you need it, you can build it for your platform -- or just avoid the features that require it. As to linker arguments, I'm thinking things like linker scripts.

Choose a reason for hiding this comment

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

We have been compiling zinc.rs without compiler-rt, I'm not exactly sure of what it supports. From memory, many of the #ifdef directives were about linux (i.e. it doesn't build properly for some targets).

Example of linker arguments would be linker scripts -T and map file -Map.

Copy link
Member

Choose a reason for hiding this comment

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

My understanding is that LLVM will lower intrinsics and other functionality in your program into calls to functions in libcompiler-rt. From this, it is my understanding that if you do not link compiler-rt you will eventually run into linker errors.

With this understanding, why do you not want to link to compiler-rt? Is it difficult to build?


# 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.

Choose a reason for hiding this comment

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

Spelling.