[llvm-commits] patch: teach deadargelim to work on externally visible functions!

Török Edwin edwintorok at gmail.com
Sat Jan 9 01:56:08 PST 2010


On 2010-01-09 11:50, Török Edwin wrote:
> On 2010-01-09 03:48, Chris Lattner wrote:
>   
>> On Jan 5, 2010, at 2:58 AM, Török Edwin wrote:
>>     
>>>>> then why not do further optimizations based on this assumption, and
>>>>> really call the function we see
>>>>> (instead of going through the .plt and calling whatever that
>>>>> resolves to
>>>>> at runtime).
>>>>>
>>>>>           
>>>> Can you elaborate?
>>>>
>>>>         
>>> Currently an externally visible function is called like this (with
>>> -fPIC), even when we know
>>> the function is in the current module:
>>> callq   foo at PLT
>>>
>>> Which does allow for an override at runtime (see example at bottom), but
>>> that is not what the optimizer assumed.
>>>       
>> Does GCC do this?  This seems "bad".  Neither gcc or llvm does the
>> equivalent on darwin.
>>     
>
> Yes, try compiling my example on Linux, you'll see that you *can*
> override those functions.
> Its useful if you do hooking via LD_PRELOAD, and you want to intercept
> calls from a shared lib to itself,
> but not for much else.
>
>   
>>> My suggestion is:
>>>   - why go through all the trouble of calling it via PLT, and allowing
>>> runtime override, when what we really want
>>> is call the function we see? We could call it directly, i.e.:
>>>        callq foo
>>>       
>> This makes sense to me, this is what I thought we did already. :)
>>
>>     
>>>   - from an ELF symbol visibility point of view this would mean the
>>> symbols should get protected visibility, instead of default visibility
>>>       
>> How does this affect visibility?
>>     
>
> From the gcc manual:
> "On ELF, default visibility means that the declaration is  visible to
> other modules and, in shared libraries,
> means that the declared entity may be overridden."
> "Protected visibility is like default visibility except that it
> indicates that references within the defining module will
> bind to the definition in that module.  That is, the declared entity
> cannot be overridden by another module."
>
> I don't know if "default" is something needed to respect an ABI, or its
> default because gcc chose it to be.
>
> So I had a look here:
> http://people.redhat.com/drepper/dsohowto.pdf
>
> It says (refering to -fvisibility):
> "The default is unsurprisingly 'default' since that is the behavior of
> the compiler before the introduction of this option"
>
> Also "protected" visibility (i.e. not going through the PLT) doesn't
> seem like a good idea:
> "The generic ELF ABI defines another visibility mode:
> protected [...] This sounds like an ideal mechanism to optimize DSO by
> avoiding the
> use of exported symbols but it isn’t.
>
> Processing references to protected symbols is even more
> expensive than normal lookup. The problem is a require-
> ment in the ISO C standard. The standard requires that
> function pointers, pointing to the same function, can be
> compared for equality. This rule would be violated with a
> fast and simple-minded implementation of the protected
> visibility. Assume an application which references a pro-
> tected function in a DSO. Also in the DSO is another
> function which references said function. The pointer in
> the application points to the PLT entry for the function
> in the application’s PLT. If a protected symbol lookup
> would simply return the address of the function inside
> the DSO the addresses would differ."
>
> Since Darwin already does the optimization I was talking about, how does
> it solve the above issue?
> (functions from outside DSO referencing function inside DSO via PLT, and
> those inside the DSO
> referencing it directly, thus yielding different addresses).
>
>   

On a second thought, this could be solved by going through the PLT
when taking the address of a function, but when calling the function
directly
we skip the PLT.

>>>   - then we would get consistent behavior from optimized and
>>> non-optimized code
>>>   - you get same behavior regardless which file you place your function
>>> into, it will always get called directly, instead of indirectly via
>>> the PLT
>>>
>>> Here is an example where the link order of shared libs causes a
>>> different function to be called:
>>>       
>> ...
>>
>> This example has undefined behavior, so it doesn't matter what we
>> produce.  We should just always generate the faster code.  This sounds
>> like a pretty serious performance bug on ELF systems.
>>     
>
> Agreed, thats why I brought this up.
>
>   

On 2010-01-09 04:34, Dan Gohman wrote:
> It may be as simple as this:
>
> --- lib/Target/X86/X86ISelLowering.cpp	(revision 93032)
> +++ lib/Target/X86/X86ISelLowering.cpp	(working copy)
> @@ -1984,6 +1984,7 @@
>        // we don't need to use the PLT - we can directly call it.
>        if (Subtarget->isTargetELF() &&
>            getTargetMachine().getRelocationModel() == Reloc::PIC_ &&
> +          (GV->isDeclaration() || GV->isWeakForLinker()) &&
>            GV->hasDefaultVisibility() && !GV->hasLocalLinkage()) {
>          OpFlags = X86II::MO_PLT;
>        } else if (Subtarget->isPICStyleStubAny() &&
>
> At least, this does the right thing on the most trivial testcase,
> and it's the same logic that the Darwin code uses, 5 lines later. Can
> someone familiar with this check this?
>   

Do function pointers still get the address foo at PLT?
If yes then it should address my concern above.

Best regards,
--Edwin




More information about the llvm-commits mailing list