-
Notifications
You must be signed in to change notification settings - Fork 58
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
Should we have a way to give functions a stable address? #515
Comments
It's possible on ELF and Mach-O platforms, but not PE (like windows) when dynamic linking is in the picture - PE doesn't have a way to collapse every dynamic export of a symbol into a single canonical definition. |
If it's critically important, we could (probably) fake it in PE by adding additional hidden indirection, i.e. exporting a symbol that is a static with the address of the actual function instead of exporting the function symbol directly, then transparently projecting through that indirection in codegen, kind of similar to how In fact, it's already possible to write stable code that manually does this: pub fn f() { /* ... */ }
pub const F: fn() = f; // or static I would hope that As far as how to directly request the non-usage of LLVM- |
Already for |
That solves the issue of the stub you get if you're missing dllimport on the caller side (i.e. rust-lang/rust#27438). But that's not the hardest part. The hardest part is a situation like:
B and C both need to instantiate the generic, because neither depends on the other or is aware of the other. But for the address to be unique, you need only one of those instantiations to be actually used. ELF platforms and Darwin support this by having a way to do process-wide symbol deduplication by name, and rely on this to uphold C++'s guarantee of a stable address for template instantiations. Windows does not support it, and just violates the C++ spec when it comes to instantiations across DLL boundaries. This is still possible to fake with hidden indirection, but it's more complex. Either D would need to have a static initializer that patches up references in B and C, or libstd (or even libcore) would need to have some kind of hash table and basically pretend to be a dynamic linker. |
I don't think this is too severe a limitation. The monomorphic requirement seems entirely unsurprising, and we might be able to lift the |
Nominally we currently do not guarantee anything about a function's address -- the same function can have different addresses when it is turned into a function pointer multiple times, and different functions can have the same address. (The mechanics why that can happen is that we set the
unnamed_addr
flag in LLVM, so the duplicates of this function that are generated in different CGUs can have visibly different addresses, and LLVM can deduplicate different functions if they have identical assembly code.)Following that, Miri used to generate a fresh address each time a function item is turned into a function pointer. However, that turned out to be problematic: the std formatting machinery used to depend on one function having a fixed address (but this got fixed recently), and the backtrace machinery uses function pointer comparison to shorten the backtrace and hide frames that are part of the std pre-main life. So we now have a sort of hack in Miri where we do give specific functions a stable address, namely if they are monomorphic and
inline(never)
. But of course this is not actually a semantic guarantee.So maybe it would make sense to have an attribute we can attach to a function that disables
unnamed_addr
? Then we should not see any de-duplication any more, I hope. I am not sure about duplication -- is there a way that all the copies of a function that exist for inlining and generics can be given a consistent address, or is that not possible and we have to enforce such "functions with stable address" to be monomorphic andinline(never)
?The text was updated successfully, but these errors were encountered: