simonmar at microsoft.com
Tue Aug 10 06:59:06 EDT 2004
Many thanks for all this. We should copy it into a section of the
commentary at some point (probably best to wait until it's settled
One question about the ELF stuff: how does the loader know whether it's
dealing with PIC or non-PIC code? I've seen the shenannigans that the
linker plays with non-PIC code, but I assumed that it was just
standalone binaries that got this treatment. (and I thought this was a
show-stopper for shared libraries on Linux/x86, but maybe not if you can
convince the linker not to play these games).
On 09 August 2004 17:08, Wolfgang Thaller wrote:
> Simon Marlow wrote:
>> Hi Wolfgang,
>> Thanks for all the details. I understand more stuff, but probably
>> not all of it yet.
>> We should measure the perf hit from PIC code. If it's not too bad,
>> then using PIC by default is a reasonable option, and will simplify
>> a lot of things.
> Estimated costs:
> Mac OS X:
> For each CmmTop: 2 additional instructions (8 bytes), one of which
> serializes the pipeline.
> For each reference to a non-static symbol: one additional memory
> PPC Linux:
> For each CmmTop: 4 additional instructions (16 bytes), one of which
> serializes the pipeline
> and one of which accesses memory; 4 bytes of static data.
> For each reference to any symbol: one additional memory access
> x86 Linux:
> For each CmmTop: One call, one popl and one add instruction (with 4
> byte immediate).
> Also, we need one register to hold the GOT address, and that might
> hurt on Intel.
> So I fear that the impact will definitely be measurable; I don't know
> where your personal threshold for "too bad" is...
>> On Linux, I believe it is possible to link a bunch of .o files into a
>> .so using 'ld -dynamic', which can then be loaded using the system's
>> linker. The linker will link it regardless of whether it's PIC or
>> not, right?
> It's 'ld -shared', not -dynamic. 'gcc -shared' also includes some
> static support code that might be needed if we use gcc-generated code.
> On Linux, ld won't complain if you use non-PIC .o files; the resulting
> .so will be relocated at run-time (no sharing). However, I think the
> evil things that the ELF loader does to non-PIC code will cause
> Mac OS:
> You have to use 'gcc -dynamiclib' or 'gcc -bundle' here to generate a
> dynamic library or a loadable module - the difference is hardly
> noticable and I haven't entirely understood it.
> Apple's Linker complains if the code has any relocations for read-only
> sections; I've recently discovered an obscure option to override that
> and to allow runtime relocations of read-only sections.
>> I assume you're using the convention that a package corresponds to a
>> single DLL for the purposes of generating the right kind of calls,
>> ie. labelDynamic still returns True for a label in another package,
>> or False otherwise, right? But this only makes a difference on
> Yes. It makes a difference on all platforms, but it makes more of a
> difference on Windows:
> On Windows, we get a linker error if labelDynamic returns True for a
> locally-defined label.
> On other platforms, the worst that can happen is that we waste a few
> cycles by following an unnecessary indirection.
>> I think I'd appreciate a description of *exactly* what -fPIC and
>> -dynamic do, on each platform. If you have time to write this down,
>> that'd be great.
> If -dynamic is specified, labelDynamic and isDllName (module Name)
> return True for labels that come from a different package.
> (Incidentally, this will be another small problem with compiling the
> RTS via the NCG: the RTS isn't really a package, RtsLabels are always
> considered to be 'in a different package').
> On Windows, -dynamic means that every package *must* be in it's own
> DLL; on other platforms, -dynamic means that each package *may* be in
> it's own DLL. Not specifying -dynamic (-static, the default) means
> that all Haskell modules and libraries from all packages *must* be in
> the same executable or .dll/.so/.dylib on all platforms.
> labelDynamic is used by PositionIndependentCode.hs (new module) to
> find out whether the label must be accessed indirectly. isDllName is
> also used in some earlier passes of the compiler (coreToStg, I think,
> but I don't really know that part of ghc yet) to prevent creating
> static closures with cross-DLL references. Cross-DLL references in
> Data work everywhere except on Windows, but it might be a good idea
> to avoid them nonetheless, as they would all need to be initialized
> at load time.
> -dynamic also currently causes GHC to link to -lHSfoo_imp instead of
> -lHSfoo when it does linking. The idea is that libHS*_imp.a are the
> import libraries for libHS*.dll on Windows. I haven't touched this
> logic yet.
> Ignored on Windows, triggers position independent code generation on
> other platforms.
> For via-C codegen, this means that -fPIC is passed to gcc on PowerPC
> Linux (it's not yet done for other linux versions), and that
> "-mdynamic-no-pic" is *not* passed on Mac OS X. The mangler takes care
> of the rest for these two platforms.
> And of course, the NCG now does everything that's necessary to avoid
> absolute addresses. The only thing that's missing for it to work on
> intel is about ten lines of code to teach it how to get the current
> value of %eip. In the PowerPC version, I've got two or three special
> cases to make sure it generates optimal code for the PIC calculations,
> but that's strictly optional.
> Using position-independent code on Linux decreases the risk that the
> ELF loader will do evil things (see below).
> A word about the Evil ELF Loader:
> Non-PIC code on ELF platforms is not only position-dependent, it is
> also expected to be unaware of dynamic linking.
> In order to link such code to symbols imported from dynamic libraries,
> the loader will do two evil things:
> a) Copy data objects from the library to the fixed address where the
> application code expects them.
> 'ld' needs to know the object's size at static link time to make that
> possible; GHC doesn't supply a .size directive, so 'ld' prints a
> warning and assumes 0. Bad.
> b) Transparently replace references to imported code things with
> pointers to stub code. Really bad if you're actually looking for the
> attached info table.
> Summary of the interactions between -dynamic and -fPIC code:
> -fPIC is ignored on Windows.
> -dynamic code can be used instead of -static code on Linux and Mac OS
> -fPIC code can be used instead of non-PIC.
> -fPIC code can be put into a .so or a .dylib.
> non-PIC code can be put into a MacOS .dylib if a special linker flag
> is specified; it can be put into a .so, but it probably won't work
> thanks to ELF.
> -dynamic doesn't work properly without -fPIC on ELF platforms.
> OK, that's all for today.
More information about the Cvs-ghc