This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
RE: effect of -fPIC on code speed
- From: Jay K <jay dot krell at cornell dot edu>
- To: gcc-help <gcc-help at gcc dot gnu dot org>, <aph at redhat dot com>
- Date: Wed, 22 Sep 2010 05:15:47 +0000
- Subject: RE: effect of -fPIC on code speed
- References: <1285119859.23319.ezmlm@gcc.gnu.org>,<COL101-W218B9D81B85D1CCB70AAD2E6600@phx.gbl>
[again as plain text, slightly augmented]
>> It's actually part of the C standard: there may only be one definition
>> of any symbol, whether that symbol refers to a function or to data. So,
>> for every visible symbol X in a program, &X must be the same, no matter
>> who is asking.
>> All manner of things break without this.
Some stuff breaks, but not much.
It's pretty rare to compare the addresses of globals/functions for equality.
This rule is sometimes broken on Windows, and it is rarely noticed/discussed.
E.g. if you import a function but don't mark it as __declspec(dllimport), or if you "static/const-ly" take the address of a __declspec(dllimport) (gets a warning about this vary thing).
windows.h uses __declspec(dllimport) pretty rigorously, so the tendency is to follow the rule.
But it is easy to break.
2.c:
#include <stdio.h>
void CreateFileA(void);
__declspec(dllimport) void CreateFileW(void);
void* p = &CreateFileA;
void* q = &CreateFileW;
__declspec(dllexport) void MyDll()
{
printf("2: a:%p w:%p m:%p a2:%p w2:%p\n", &CreateFileA, &CreateFileW, MyDll, p, q);
}
1.c
#include <stdio.h>
void CreateFileA(void);
__declspec(dllimport) void CreateFileW(void);
void MyDll();
void* p = &CreateFileA;
void* q = &CreateFileW;
int main()
{
MyDll();
printf("1: a:%p w:%p m:%p a2:%p w2:%p\n", &CreateFileA, &CreateFileW, MyDll, p, q);
return 0;
}
c:\>cl -LD 2.c
c:\>cl 2.lib 1.c
1.c : warning C4232: nonstandard extension used : 'q' : address of dllimport 'CreateFileW' is not static, identity not guaranteed
c:\>.\1
2: a:000007FEFC338A9E w:0000000077AE2A30 m:000007FEFC331000 a2:000007FEFC338A9E w2:000007FEFC338A98
1: a:000000013F9185BE w:0000000077AE2A30 m:000000013F911050 a2:000000013F9185BE w2:000000013F9185B8
See how "w" uses the usual declaration and does meet the rule, or gets a warning, and the rest don't.
__declspec(dllimport) I think of as just a nice micro optimization but I guess it is also good for a) generally making this rule more upheld b) causing a warning when the warning is also then violated.
If you don't need identity, it is easy to fix the warning with a wrapper function.
static void MyFoo() { foo(); }
void (*pfoo) = MyFoo; /* instead of foo */
Of course, such small functions may be prone to break the rule "the other way around" under over-aggressive optimization. That is:
static void MyFoo() { foo(); }
static void MyBar() { foo(); }
assert(&MyFoo != &MyBar); ?
The Visual C++ linker also has "identical comdat" folding.
template <typename T> T max(T,T);
assert(&max<int> != &max<long>); ?
- Jay
(as well, something like LTCG/LTO could make the annotations not needed but always get the optimization/conformance "for free" (for no additional cost))