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

Add a freestanding target #106

Closed
wants to merge 3 commits into from
Closed

Add a freestanding target #106

wants to merge 3 commits into from

Conversation

emberian
Copy link
Member

@emberian emberian commented Jun 4, 2014

No description provided.

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

cc @Tobba @thestinger @alexcrichton @vhbit @bharrisau

This supercedes PR #7.

@mcpherrinm
Copy link

This looks like good work! I'm very excited to see more bare-metal Rust users!

@bharrisau
Copy link

cc @farcaller @bgamari

@taralx
Copy link

taralx commented Jun 4, 2014

The issue with libc/m/etc. could be avoided if we had the option to output an object file. Thoughts?

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

We already do (--emit=obj) but I want rustc to be able to make the executable.

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

I want a single line calling rustc in my build script, that makes my kernel (possibly involving linker scripts etc).

@bharrisau
Copy link

We have managed to "get something working" for zinc.rs, but there are a few hacks needed at the moment to support building with a single rustc call (creating empty libmorestack, for example). That being said, stack safety is a nice thing to have (on the supported platforms), and LLVM supports thumbv[67]m for this.

In the future it would be great to have a syntax extension for a custom prelude/epilogue for stack safety, but until then is it better to experiment with Rust on bare-metal without stack safety? I think so; stack safety is important for production, but if we can ignore that one issue for the moment it gives us the ability to find any other issues with rust on bare-metal.

That being said, zinc.rs uses stack safety for the task model. So we may end up continuing to use the *-unknown-linux triple if that is needed to keep the segmented stack prologue.

@thestinger
Copy link

On any platform with an MMU, the segmented stack feature is a poor way of providing stack safety. It's only used as a temporary hack before a portable equivalent to -fcheck-stack exists in LLVM.

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

(And on ARM even when you don't have MMU, you have an MPU you can use)

On Tue, Jun 3, 2014 at 10:01 PM, Daniel Micay notifications@github.com
wrote:

On any platform with an MMU, the segmented stack feature is a poor way of
providing stack safety.


Reply to this email directly or view it on GitHub
#106 (comment).

http://octayn.net/

@bharrisau
Copy link

Yeah, it might be a decision to only support stack safety on devices that include the optional MPU.

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

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

@bharrisau I still have plans for allowing stack safety, through static analysis (I need to write up another blog post on this subject), but it does forgo most uses of dynamic dispatch (and require annotating maximum stack size usage for them).

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

@alexcrichton I've reworded some of the misguided bits.

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.

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?

Copy link
Member Author

Choose a reason for hiding this comment

The 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, ...)

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

The 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)

Copy link
Member Author

Choose a reason for hiding this comment

The 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 *-unknown-unknown? I wouldn't be against that.

Choose a reason for hiding this comment

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

My experience with compiler-rt was a complete nightmare. So if it is possible to go without it - it's better to go without it.

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 libgcc_s, but it's missing functions required by Rust's code generation.

  1. While working on proper backport I've "worked" with one of code owners. Worked in this case means I've pinged him every 2-3 days for about a month until full despair.

That's pretty much how the LLVM project works right now.

Copy link

Choose a reason for hiding this comment

The 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).

Choose a reason for hiding this comment

The 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).

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.

Choose a reason for hiding this comment

The 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).

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.

Copy link

Choose a reason for hiding this comment

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

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

@alexcrichton I feel like a good target for freestanding is "only requires a stack". I feel like with that baseline, everything else can be built up?

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

I don't feel very strongly about any of this except that we really ought to have a target where we do the minimum possible work to get Rust up and going, without having to stub out anything.

@alexcrichton
Copy link
Member

I do agree that seems like a good target. I believe that the components needed to meet that target include libcore and libcompiler-rt, but I would believe that split-stacks are not part of that target.

In general, it seems to me that we would want to consider whitelisting platforms for segmented-stack support and just turn it off on all other platforms (but that's it for now).

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

Yeah, a whitelist probably makes more sense, but I feel like having to opt-into stack unsafety is a better idea :(

@Tobba
Copy link

Tobba commented Jun 4, 2014

Excellent, this took long enough

Whitelist or blacklist is probably the way to go about the segmented stack problem, I think the issues with libc can be sorted out with some additional cfg's to not try to link those on an unknown OS

@farcaller
Copy link

I actually like the __morestack prologue in a way it is implemented right now with a few issues.

Given that we run on platforms without even an MPU, I would like to have at least some stack safety between threads, which the prologue does.

I'm kind of ok with how it works with __STACK_LIMIT. Two problems are: it's still broken for some arm MCUs and I'd like to make it forced-on for other arm MCUs (e.g. compile a test case on armv7 that still uses __STACK_LIMIT).

I'm not ok with reserving 256 bytes after the stack (on arm), that one should at least be configurable.

There's one more thing with running on metal and crates (that's a bit out of the scope of this RFC though) — you cannot reliably export the symbols from within the crate. libzinc currently provides a few ISRs, it's compiled to rlib and later linked into libapp, which is end user code (also an rlib). libapp geets linked into final wrapper, which is app.rs (staticlib emitted as obj) which re-exports a few required symbols from libzinc. That obj file is further linked with another rlib emitted as obj, that provides other globally visible symbols. I'm not sure how to actually fix that (other than make some "super-export" that ignores other visibility rules and forcefully publishes the "C" symbol).

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

@farcaller I believe I can do better than __morestack for 98% of usecases, possibly excluding interrupt handlers, those either need to not use stack, pay for the check, or complicate the analysis significantly (and possibly deserve their own analysis, assuming a fixed stack size for "user" code).

@thestinger
Copy link

@farcaller: You should use a re-export if you want it re-exported. There's no need for additional feature, but perhaps there are bugs to be fixed.

I actually like the __morestack prologue in a way it is implemented right now with a few issues.

It's fine on platforms without an MMU, but it's needless overhead on most.

@taralx
Copy link

taralx commented Jun 4, 2014

@cmr: with os unknown what is an executable? Do you mean a static ELF object with the executable bits in?

@Tobba
Copy link

Tobba commented Jun 4, 2014

@thestinger: That doesnt actually work. Currently this needs delicately unpacking the bitcode, unfucking it to remove split stacks and then doing a maze of linking, which probably includes several pages of hacks

@emberian
Copy link
Member Author

emberian commented Jun 4, 2014

@taralx yeah.

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.

@bharrisau
Copy link

TL;DL - Add UnknownOs, disable dylibs, disable segmented-stack, do not include any default link time libraries. Developer is responsible for unsafe stacks, defining LLVM intrinsics, and lots of linker arguments.

I'm in favour of this, but it shouldn't be the end solution. We need a portable solution for stack safety on systems without MPU or MMU.

@Ericson2314
Copy link
Contributor

I'd like this a lot. Also it would be nice if rlibs for cross-compiling were build nightly too.

@farcaller
Copy link

Given that rust-lang/rust#14715 landed today which includes disabling split-stack for iOS target, I think it would be quite trivial to push freestanding forward. I can actually go and provide a test implementation for that if of any use.

@bharrisau
Copy link

I had something done up in rust-lang/rust#12841.

@emberian
Copy link
Member Author

I'm closing this in favor of #131

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

Successfully merging this pull request may close these issues.

10 participants