Aneesh Barthakur
Aneesh Barthakur

Reputation: 113

Preprocessing vs Linking

Everywhere I look for what a linker actually does (besides relocation, which some seem to put under "loading") people give examples of two (say) C modules which call functions from each other.

As far as I understand , this should be taken care of by preprocessing (#include etc). I can understand that if I want to assemble two modules at different times I would need to link them later. But when I use say gcc, it directly outputs the executable , so in this context I don't really see the point of linking except when the preprocessing (which will be recursive I'd guess) final hits object code.

Note : I'm referring to static linking here. I can see the point when it comes to dynamic linking.

Upvotes: 0

Views: 818

Answers (1)

Harry
Harry

Reputation: 11678

gcc is using a lot of tools to create the executable, the compiler is one of them and so is the linker, preprocessor etc, to see what it's actually doing pass it the -v option. If you want to see the intermediate files use -save-temps ie once you've created the files below try this...

gcc-5 -save-temps -v -std=c11 -Wall -pedantic-errors main.c foo.c 

If you look in your directory you'll see several extra files...

a.out // Executable when no name is specified
foo.c // original foo.c
foo.h // original foo.h
foo.i // Preprocessed ouput of foo.c and foo.h
foo.o // foo Object file
foo.s // foo assembler
main.c // original main.c
main.i // main preprocessed
main.o // main object file
main.s // main assembler

If you look in main.i you'll notice that it contains this

# 1 "foo.h" 1


int foo(int i);

but it doesn't know what the function foo actually does. That's all in foo.i. This also means that when the object files are created main.o knows it needs a foo function. Connecting symbol foo in main.o with the foo in foo.o is what the linker is doing.

Here's an example, create the following three files

foo.h

#ifndef FOO_H
#define FOO_H
int foo(int i); 
#endif

foo.c

#include "foo.h"
int foo(int i) {
  return i - 1729;
}

main.c

#include "foo.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
  printf("%d\n", foo(1));
  return 0;
}

Create their Object files ie not the executable as follows, note I've added the verbose flags to this..

gcc-5 -v -std=c11 -Wall -pedantic-errors main.c foo.c -c

If you had used the -o flag you would see the actual linker command that gcc called to link the objects into an executable ie

gcc-5 -v -std=c11 -Wall -pedantic-errors main.c foo.c -o fooer

At this point you will find two object files in your directory. You can create the executable using ld as follows (note this is mac specific, use the output from gcc -v to find the correct command for your machine).

ld -dynamic -arch x86_64 -macosx_version_min 10.11.3 -lSystem main.o foo.o -o fooer

Upvotes: 1

Related Questions