[PATCH] D61670: [RFC] [MinGW] Allow opting out from .refptr stubs

Martin Storsjö via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 18 05:24:00 PDT 2023


mstorsjo added subscribers: alvinhochun, jeremyd2019, jacek, aaron.ballman.
mstorsjo added a comment.

I'm looking to pick this up again - hopefully @rnk has time to discuss what would be a good way forward.

So taking it from the top; both GCC and Clang generate `.refptr` stubs when referencing variables that might be autoimported. The exact circumstances differ a little bit though.

In GCC this is done by making GCC for Windows/x86_64 default to a medium code model, and under this code model, references to variables without a visible definition get indirection via a `.refptr` stub. This doesn't happen for i386. By building with `-mcmodel=small`, one can opt out of them.

In Clang, we generate such `.refptr` stubs with similar heuristics (variables without a visible definition), but we do it for all architectures. There are three different reasons for wanting to do this:

- Normally, when code references a variable (in the default code model), it is done with a 32 bit relative (or absolute) relocation. If the variable turns out to end up imported from a different DLL, in a 64 bit address space it may end up loaded too far away for a 32 bit relocation.
- If we don't use a `.refptr` stub, the mingw runtime pseudo relocation mechanism needs to patch the address at runtime. If this is referenced in a code section, it means that the code section needs to be mapped RWX while patching it. Changing the memory protection to RWX is generally undesireable (and is disallowed outright, within the UWP app model).
- The runtime pseudo relocation format works on N-bit relative or absolute addresses. With the x86 instruction encoding, this turns out to work fine - an instruction that refers to a different memory location generally is a couple bytes of instruction prefix, followed by a 32 bit relative or absolute address, easily patchable. In the case of ARM and AArch64, there are no such instructions, and loading e.g. a 32 bit immediate constant is often done by a pair of instructions, with the actual payload bits scattered throughout the instructions. The runtime pseudo relocation format obviously doesn't support patching this.

Therefore, with Clang we generate `.refptr` stubs on all architectures. However it would be good to be able to opt out from them. When the variables actually end up autoimported, LLD has got a couple neat tricks that makes the actual pseudo relocations go away in most cases (when it can alias the `.refptr.variable` stub with the `__imp_variable` IAT entry). But for the cases when the variable isn't autoimported, the `.refptr` stub has to be kept, and it produces larger/slower code and more data than necessary. And for low level projects like Wine, it might be desireable to be able to tune exactly what is done.

So within the Clang context, it is not entirely about range (where the code model might be a reasonable fit), but about whether to be prepared for autoimports or not.

Within Clang, it is handled by marking variables we know are in the same DLL as `dso_local`, while variables that might be autoimported don't get that flag. Within LLVM, references to variables that aren't marked `dso_local` get indirection via a `.refptr` stub.

Possible ways of handling it would be to invent a new flag for this purpose; e.g. `-fno-autoimport` (with the corresponding `-fautoimport` meaning the default mode). That makes the use fairly clear, but its role is also a bit unclear; there are linker flags `--disable-auto-import` and `--disable-runtime-pseudo-reloc` which disable either autoimports of all sorts, or only autoimports that end up with an actual pseudo reloc (allowing the zero-cost ones that are aliased to IAT entries).

If we make the flag only affect code generation, having it named `-fno-autoimport` when the linker still may do something different (ending up with a pseudo relocation in executable code, which possibly still works fine, just less elegant) is unclear. If we on the other hand make the same flag imply either of `--disable-auto-import` or `--disable-runtime-pseudo-reloc`, then that name is rather clear.

If we only make it affect code generation, something like `-fdso-local` or `-fno-refptr` might be more precise.

If we make the flag imply linker options, then it becomes much clearer to spot the error, if you enabled this but the code base still would need autoimports somewhere. (This has happened - see https://code.videolan.org/videolan/dav1d/-/merge_requests/1303#note_301859, https://code.videolan.org/videolan/dav1d/-/merge_requests/1349 and https://code.videolan.org/videolan/dav1d/-/merge_requests/1361.) If we make the flag only affect code generation, it becomes a more clear match for projects using `-mcmodel=small` with GCC today.

I'm open for opinions on how to name these options, @alvinhochun @mati865 @jeremyd2019 and @jacek. Also requesting early guidance from @aaron.ballman.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61670/new/

https://reviews.llvm.org/D61670



More information about the cfe-commits mailing list