From 2a7464e8ececb815db4c44372e8caad29a4a8847 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Tue, 3 Jun 2014 19:40:57 -0700 Subject: [PATCH 1/3] RFC: Add a freestanding target --- active/0000-freestanding-target.md | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 active/0000-freestanding-target.md diff --git a/active/0000-freestanding-target.md b/active/0000-freestanding-target.md new file mode 100644 index 00000000000..1c7463b49b3 --- /dev/null +++ b/active/0000-freestanding-target.md @@ -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. + +# 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" 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. + +# 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. From aaf23f440f7db1d8713f792f9e6e351b313e00f3 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Tue, 3 Jun 2014 22:22:44 -0700 Subject: [PATCH 2/3] Remove language about libc/libm --- active/0000-freestanding-target.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/active/0000-freestanding-target.md b/active/0000-freestanding-target.md index 1c7463b49b3..727e0f312e4 100644 --- a/active/0000-freestanding-target.md +++ b/active/0000-freestanding-target.md @@ -14,7 +14,7 @@ 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. +difficult to produce freestanding binaries without stubbing them out. # Detailed design @@ -37,14 +37,14 @@ 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" 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. +"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. # Drawbacks From d713313a4caf430269b4bc25e416aaf9c55ea8b3 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Wed, 18 Jun 2014 17:39:36 -0700 Subject: [PATCH 3/3] Rewrite the freestanding RFC --- active/0000-freestanding-target.md | 86 +++++++++++++++++++----------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/active/0000-freestanding-target.md b/active/0000-freestanding-target.md index 727e0f312e4..39f18cf48de 100644 --- a/active/0000-freestanding-target.md +++ b/active/0000-freestanding-target.md @@ -4,8 +4,13 @@ # Summary -Add support for the "unknown" OS in target triples, and disable split stack -checking on them by default. +*Note:* This RFC discusses the behavior of `rustc`, and not any changes to the +language. + +Change how target specification is done to be more flexible for unexpected +usecases. Additionally, add support for the "unknown" OS in target triples, +providing a minimum set of target specifications that is valid for bare-metal +situations. # Motivation @@ -13,8 +18,7 @@ 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. +storage setup). # Detailed design @@ -25,36 +29,56 @@ 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. +the concept of "unknown" in the target triple. When the OS is "unknown", +no runtime environment is assumed to be present (including things such as +dynamic linking, threads/thread-local storage, IO, etc). + +Rather than listing specific targets for special treatment, introduce a +general mechanism for specifying certain characteristics of a target triple. +Redesign how targets are handled around this specification, including for the +built-in targets. Add a `T` family of flags, similar to `C`, for target +specification, as well as `-T from-file=targ.json` which will load the +configuration from a JSON file. A table of the flags and their meaning: + +* `data-layout`: The [LLVM data +layout](http://llvm.org/docs/LangRef.html#data-layout) to use. Mostly included +for completeness; changing this is unlikely to be used. +* `link-args`: Arguments to pass to the linker, unconditionally. +* `cpu`: Default CPU to use for the target, overridable with `-C target-cpu` +* `features`: Default target features to enable, augmentable with `-C + target-features`. +* `dynamic-linking-available`: Whether the `dylib` crate type is allowed. +* `split-stacks-supported`: Whether there is runtime support that will allow + LLVM's split stack prologue to function as intended. +* `target-name`: What name to use for `targ_os` for use in `cfg`. + +Rather than hardcoding a specific set of behaviors per-target, with no +recourse for escaping them, the compiler would also use this mechanism when +deciding how to build for a given target. The process would look like: + +1. Look up the target triple in an internal map, and load that configuration + if it exists. +2. If `-T from-file` is given, load any options from that file. +3. For every other `-T` flag, let it override both of the above. +4. If `-C target-cpu` is specified, replace the `cpu` with it. +5. If `-C features` is specified, add those to the ones specified by `-T`. + +Then during compilation, this information is used at the proper places rather +than matching against an enum listing the OSes we recognize. # 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. +More complexity. However, this is very flexible and allows one to use Rust on +a new or non-standard target *incredibly easy*, without having to modify the +compiler. rustc is the only compiler I know of that would allow that. # 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. +One possible extension is to load `.json` from some directory, rather +than having to require `-T from-file`. + +A less holistic approach would be to just allow disabling split stacks on a +per-crate basis. Another solution could be adding a family of targets, +`-unknown-unknown`, which omits all of the above complexity but does not +allow extending to new targets easily. `-T` can easily be extended for the +future needs of other targets.