mstorsjo added a comment.

In, @smeenai wrote:

> FYI, binutils auto-import actually creates a fake IAT entry rather than using 
> a dynamic initializer. I think it's actually a pretty cute trick. 
>  has details. That only works when you're referencing an external imported 
> symbol directly though, and breaks when you need an offset from the imported 
> symbol.

Yup - except that it also can emit "pseudo-relocs" that require making the code 
segment writable, and these relocations are fixed by the mingw runtime on load. 
These are exceptional/ugly enough that they're not enabled by default but 
require a linker flag.

In, @rnk wrote:

> You can see it that way, but having the linker synthesize a dynamic 
> initializer to initialize dllimport data seems a bit heroic to me. MSVC link 
> doesn't do it. It requires making assumptions about how your C runtime runs 
> dynamic initializers. Your DLL might not even link msvcrt, so how does the 
> linker know where to put the initializer?

As @smeenai said, it's done by IAT tricks, not actually creating runtime 

> On the other hand, you can be assured that users will ask us for this bfd 
> linker feature indefinitely if we don't implement it. It papers over 
> differences between the COFF and ELF object models, and mingw usually papers 
> things over rather than pushing the cost onto ELF-oriented codebases.
> Clang already creates dynamic initializers for stuff like:
>   __declspec(dllimport) int imported;
>   int *const pi = &imported;
>   int foo() { return *pi; }

A related observation on the topic of this: There's a subtle difference between 
what both GCC and MSVC does here, compared to clang. The case with a single 
variable works the same in all of them, but if you have a struct with many 
initialized elements, GCC and MSVC will initialize as many as possible of them 
statically, and only fill in the dllimport ones via a dynamic initializer. 
clang, on the other hand, will not initialize anything statically at all if it 
emits a dynamic initializer.

> So, it doesn't seem like a bridge too far to make dynamic initializers for 
> globals with vtables. It's dicey, though. It means there's a point in your 
> program when your vptr is null. =/

Yes, and that case is also already present with the normal struct members with 
dllimport. That case actually turned into a real bug in trying to run Qt. Qt 
has got constructors that will touch a struct that contains a dllimported 
field. The constructor doesn't touch or use the dllimported field, only the 
others. This means that as long as it's built with GCC and MSVC, there's no 
race condition/static initialization order fiasco between the 
struct-with-dllimport and the constructor, since GCC and MSVC fill in all the 
other members statically. When built with clang though, if you're unlucky, the 
Qt defined constructor may run before the clang generated initializer fills in 
all of the struct.

I managed to work around this issue by adding a constructor priority to these 
structs, making sure that all the clang generated initializers run before the 
normal constructors:

In this PoC, I also emit the initializers with a high priority (actually higher 
priority than can be set from normal user code) - so I think the fact that 
these pointers are null originally shouldn't be observable, unless using 
special runtime internals to hook up code to run before normal constructors.

> Do you think we should do something like local vftables for itanium instead? 
> Can we assume all methods in the vtable will be exported by the DLL exporting 
> the class?

This I don't know yet (I only know the details in cases that I've had to study 
when debugging some issue), but if you think it'd (and can hint about what to 
change in order to use that), I can try it and see if it works for my testcase.

  rC Clang

cfe-commits mailing list

Reply via email to