does gcc link order affect speed of the program execution - performance

I know the linkage order in gcc is important for symbols to be correctly determined; but
now I am seeing a weird speed issue on the resulting executable. I am linking objects and archieves as
g++ -m32 a.o b.o ar1.a ar2.a -lm -lpthread -lcrypt -lz -pthread -o afast.out
vs
g++ -m32 a.o ar1.a b.o ar2.a -lm -lpthread -lcrypt -lz -pthread -o aslow.out
The second version runs 2x slower. b.o is actually in the ar1.a archieve, but ar2.o has references to it, thus linker complains, thus I had to put the b.o. In the beginning, I was putting b.o all the way to the end of the linkage to make the correct dependency order, though then figured out it even works at beginning, and even faster.
Has anyone experienced this? Is object file linkage order different than archieve order? How can there be any speed impact?
getting similar results with gcc3.4.6 or gcc4.1.2

There could be significant differences in execution speed depending on how the object code is laid out in memory. In general, you want hot functions to be close together, so they are not mixed up with cold functions, and so your Icache and TLB are not polluted by cold functions. It is however very unlikely that you are affected by this.
Most likely, you have some symbols that are resolved one way in the "fast" executable, and another way in the "slow" executable. The order of archive libraries and object files on command line matters, and you can end up pulling some object from ar1.a in the "fast" link, whereas you'll pull an equivalent object from ar2.a in the "slow" link. Perhaps there is some un-optimized code in ar2.a ?
Running nm -A ar1.a ar2.a and checking to see if there are any symbols that occur in both would be the first step. You can then ask the linker to produce a link map (with -Wl,-M,map.out) and check where these symbols are actually coming from in the two links.

Related

gcc - linker error that makes no sense

Using the Makefile provided by the Pi GPIO library, I made the libpigpio.so shard object using:
# from line 119 in make file
make libpigpio.so
The shared object is created fine. The Makefile first created the pigpio.o object, then the command.o object, and links them together as a shared object. So far so good!
I wrote a very small main function that calls the gpioInitialise and gpioGetPWMfrequency.
It doesn't really matter which functions, what's important is they are defined in pigpio.h and written in pigpio.c.
Meaning the shared object should have them.
The compile command for my code is:
gcc -Wall -pthread -fpic -L. -lpigpio -o drive drive.c
Still I get the undefined reference error to both those functions.
It makes no sense! If it didn't find the shared object, it would reject the command. I also tried it -l:libpigpio.so and still the same problem.
I am compiling directly on the Rpi A+ (not using a cross compiler). So it should work!
What am I missing here?
It is a link order question. Please try the flowing command.
gcc drive.c -Wall -pthread -fpic -o drive -L. -lpigpio
you can read Why does the order in which libraries are linked sometimes cause errors in GCC? for more details.

Disabling -Werror for -Wimplicit-interface

What is the right flag or order of flags to disable treating particular warning as error in GCC? I want to do that for -Wimplicit-interface.
>cat test.f90
call s
end
> gfortran -c -Werror -Wimplicit-interface -Wno-error=implicit-interface test.f90 -o test.o
test.f90:1.7:
call s
1
Warning: Procedure 's' called with an implicit interface at (1)
>ls test*
test.f90
No test.o was generated.
Without -Werror it works
> gfortran -c -Wimplicit-interface -Wno-error=implicit-interface test.f90 -o test.o
test.f90:1.7:
call s
1
Warning: Procedure 's' called with an implicit interface at (1)
> ls test*
test.f90 test.o
GCC version is gcc version 4.9.2 20141030 (Cray Inc.) (GCC).
This is not an explicit answer to the question. I found it educative enough and too long to be put as comment.
As you just found, you might not be able to achieve what you want if you combine -Werror and -Wno-error=implicit-interface. Let me explain: as opposed to what we have in the doc, especially the following sentence,
The combined effect of positive and negative forms is that more specific options have priority over less specific ones, independently of their position in the command-line.
It seems that it is not the case in the actual implementation. I had a similar problem recently, and by googling, I found this which contains this sentence:
'-w' permanently sets all warnings off no matter what specific warning is set on
It actually suggests that by using some non specific options, the actual implementation does not allow you to change specific option included in the non specific one.
As #innoSPG points out, the actual behaviour does not conform to what is claimed in the manual.
The comment by #MarkGlisse revealed that this have changed with GCC 5. Therefore it was probably a bug.
The solution is therefore to use the recent version, or to not use one of the -Werror and -Wimplicit-interface.
Or to really provide explicit interfaces everywhere, but that can be problematic, as MPI libraries differ in the amount of explicit interfaces provided in the mpi modules.

How can a segfault happen at runtime only because of linking unused modules?

I get a segmentation fault from a memory allocation statement just because I have linked some unrelated procedures to the binary.
I have a very simple Fortran program:
program whatsoever
!USE payload_modules
double precision,allocatable:: Vmat(:,:,:)
allocate(Vmat(2,2,2))
Vmat=1
write(*,*) Vmat
deallocate (Vmat)
! some more lines of code using procedures from payload_module
end program whatsoever
Compiling this using gfortran whatsoever.f95 -o whatsoever leads to a program with the expected behaviour. Of course, this program is not made to print eight times 1.000 but to call the payload_modules, yet hidden in the comments. However, if I compile and link the program with the modules issuing
gfortran -c -g -fPIC -ffpe-trap=overflow -pedantic -fbounds-check \
-fimplicit-none payload_module1.f90 payload_module2.f90 whatsever.f95
gcc -g -nostdlib -v -Wl,--verbose -std=gnu99 -shared -Wl,-Bsymbolic-functions \
-Wl,-z,relro -o whatsoever whatsoever.o payload_module1.o payload_module2.o
the program whatsoever doesn't run any more. I get a segmentation fault at the allocate statement. I have not yet uncommented the lines related to the modules (however, uncommenting them leads to the same behaviour)!
I know that the payload modules' code is not buggy because I ran it before from R and wrapped this working code into a f90-module. There are no name collisions; nothing in the modules is called Vmat. There is only one other call to allocate in the modules. It never caused any trouble. There is still plenty of memory left. gdb didn't give me any hints expect a memory address.
How can linking routines that are actually not called crash a program?
Compiling your code with
gfortran whatsoever.f95 -o whatsoever
is working because you link against the system libraries, everything is in place. This would correspond to
gfortran whatsoever.f95 payload_module1.f90 payload_module2.f90 -o whatsoever
which would also work. The commands you used instead omit the system libraries, and the code fails at the first time you call a function from there (the allocation). You don't see that you are missing the libraries, because you create a shared object (which is typically linked against the libraries later on).
You chose to separate compiling the objects and linking them into an executable. Doing this for Fortran program using gcc you need to specify the Fortran libraries, so there's a -lgfortran missing.
I'm not sure about that particular choice of compile options... -shared is usually used for libraries, are you sure you want a shared binary (whatever that is)?
With -nostdlib you tell the compiler not to link against the system libraries. You would then need to specify those libraries (which you don't).
For the main program test.F90 and a module payload.F90, I run
gfortran -c -g -fPIC -ffpe-trap=overflow -pedantic -fbounds-check \
-fimplicit-none payload.F90 test.F90
gcc -g -v -Wl,--verbose -std=gnu99 -Wl,-Bsymbolic-functions \
-Wl,-z,relro -lgfortran -o whatsoever test.o payload.o
This compiles and executes correctly.
It might be easier to use the advance options with gfortran:
gfortran -g -fPIC -ffpe-trap=overflow -pedantic -fbounds-check \
-fimplicit-none -Wl,-Bsymbolic-functions -Wl,-z,relro \
payload.F90 test.F90 -o whatsoever
The result is the same.

GCC Command-Line Argument Pickiness

GCC can get pretty picky about the order in which it accepts its arguments:
# Works.
g++ Foo.cpp -L. -I. -lBar -o Foo
# Linker errors.
g++ -o Foo -I. -L. -lBar Foo.cpp
What, specifically, are the ordering requirements for command-line options?
Libraries are loaded on demand based on the symbols required from them, so the library which provides a symbol needed by something else must follow that something else. This is historical; arguably a modern system should resolve symbols automatically, handling loops sensibly (that being the reason for the rule; you broke dependency cycles manually by specifying libraries in order and as many times as needed), but g++ follows the traditional rule so it will work with vendor lds. (GNU ld doesn't work everywhere, so it wouldn't be possible to rely on it to resolve symbol dependency loops. There are also bootstrapping concerns even on platforms where GNU ld does work.) Similarly, other linker-oriented options must be specified in the correct order relative to the things they affect (for example, a -L option must precede a library which lives in the specified directory; this can be important if a library in one directory shadows a library of the same name in a standard directory).

gcc/ld: undefined reference to unused function

I'm using gcc 4.3.4 and ld 2.20.51 in Cygwin under Windows 7. Here's a simplified version of my problem:
foo.o contains function foo_bar() which calls bar() in bar.o
bar.o contains function bar()
main.c calls functions in foo.o, but foo_bar() is not in the call chain
If I try to compile main.c and link it to foo.o, I get an undefined reference to _foo_bar error from ld. As you can see from my Makefile except below, I've tried using flags for putting each function in its own section and having the linker discard unused sections.
COMPILE_CYGWIN = gcc -iquote$(INCDIR)
COMPILE = $(COMPILE_CYGWIN) -g -MMD -MP -Wall -ffunction-sections -Wl,-gc-sections $(DEFINE)
main_OBJECTS = main.o foo.o
main.exe : $(main_OBJECTS)
$(COMPILE) -o main.exe $(main_OBJECTS)
The function foo_bar() is a short function that provides a connection between two networking layers in a protocol stack. Some programs don't need it, so they won't link in the other object files related to the upper layer of the stack. It's a small function, and seems inappropriate to put it into its own .o file.
I don't understand why ld throws the error -- nothing is calling foo_bar(), so there's no need to include bar() in the final executable. A coworker has just told me that ld is not a "smart linker", so maybe what I'm trying to do isn't possible?
Unless the linker is from Cyberdyne Systems it has no way to know exactly which functions will actually be called. It only knows which ones are referenced. Even Skynet's linker can't predict what run-time decisions will be made or what will happen if you load a module dynamically at run-time and it starts calling various global functions1.
So, if you link in module m and it references function f, you will need to link with whatever module has f.
1. This problem is related to the Halting Problem and has been proven undecidable.
I hit the similar issue and I find this page:
http://lists.gnu.org/archive/html/bug-gnu-utils/2004-09/msg00098.html
Highligt:
The GNU linker still works at .o file granularity.
Gcc pulls in foo.o and then find bar() was undefined.
You'd better put foo_bar() into another .o file.

Resources