gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Multiple _OBJC_Module in the same shared library/framework, not so g


From: David Chisnall
Subject: Re: Multiple _OBJC_Module in the same shared library/framework, not so good
Date: Sat, 7 Jan 2012 15:32:02 +0000

On 7 Jan 2012, at 15:19, Nat! wrote:

> Why is +load crucial ? +load is a convenient initialization place, when you 
> are mixing C/ObjC and you can't guarantee that +initialize is called before 
> the C-code. You can use it for augmenting categories, where the +load method 
> initializes some stuff. Also it should be a reliable way to patch third-party 
> objc libraries one links against. Not having the last capability means, that 
> you are possibly maneuvering yourself in a dead-end (on the objc level). 
> 
> A +load with only the most minimal semantic guarantees is therefore useless 
> to me.

You won't get that guarantee in any language.  Global initialisers in C++, 
__attribute__((constructor)) in GNU C, and +load in Objective-C all EXPLICITLY 
come with no ordering guarantee between compilation units.

+load actually comes with the strongest guarantee, because it guarantees not to 
be run until after all superclasses have been loaded.

> So lets see what we have. In the simple C case
> 
> main.o:  main(){ b(); }
> b.so  :  b() { a(); } 
> a.so  :  a() {} 
> 
> I would have thought, because of the dependencies, that the library 
> initializers in a.so must run first then b.so then main.o. (This would imply, 
> that classes get +load in a.so before b.so.) The dependencies are noted by 
> the linker and the objects are ordered an initialized this way. Ha! That's 
> the way it works on OS X, but in Linux the linker doesn't care and just links.

On OS X, it may work by coincidence.  However, this is EXPLICITLY not 
guaranteed.  It depends on the interaction between dlyd and ld or ld64.  Both 
the language references and the ABI specification agree on this.

> When you link main.o a.o b.o on Linux the initializers being called are 
> dependent on the link order (main being last
> though). Most of the linking logic, it seems, is deferred to the runtime 
> linker ld-linux.

Much of it is in OS X too.

> My technical solutions are:
> 
> a) hack the mainline objc runtime, to delay all +load calls, then sort them 
> appropriately and call them on the first +initialize ever. (This may be too 
> surprising to some code, which may expect certain functionality not to have 
> run already or other initializers that trigger objc code. May have political 
> obstacles.)

This would mean that no Objective-C +load methods would run until some 
Objective-C message had been sent.  This is explicitly wrong, because +load 
methods are supposed to run before main().

> b) deal with the linking order as is, getting bugs whenever ld-linux changes. 
> (That's OK short term, but not in the long run)

This is the only real solution.  If your code is depending on undefined 
behaviour, then you are doing something badly wrong.

> c) hack ld-linux.so in some way to get the right initializer order in some 
> sort of dependencies and get it accepted into mainline. (Doesn't work for 
> non-linux, there may be political obstacles)
> 
> d) always link against my custom ld-linux.so. (A pain to maintain)
> 
> e) do all the loading myself with <dlfcn.h> and a minimal custom booter (I am 
> actually doing something like this already on OS X too, because of Rosetta :( 
> )

If you require explicit ordering - which, as I said, no *NIX platform including 
OS X guarantees - then you must implement the explicit nature in some way.  
This can be either in a custom linker or in your code.  

For example, in EtoileFoundation we need to run some code at run time but after 
a set of classes in the framework has loaded.  Each of these classes decrements 
a counter in its +load method and then performs the initialisation when the 
counter reaches 0.  You can add a +load method in a category on classes in 
other frameworks that must be loaded too, since the +load method in the 
category will not run until after the class is loaded.

> But I am open to suggestions. :)

I suggest:

a) You don't depend on undefined behaviour.
b) When you have done so, you fix your own code rather than trying to get 
documented behaviour changed.

David

--
This email complies with ISO 3103




reply via email to

[Prev in Thread] Current Thread [Next in Thread]