Compiler, Linker, Loader and Program

The description we give here is very simplified, but it will give you an idea of what happens at each step.

Let's imagine a computer that has memory and four registers. The registers will consist of two general purpose scratchpad registers (A and B), a program counter(PC) and a stack pointer(SP). Let's start with a simple program source text consisting of two files, prog.c and sub.c. Here is prog.c

extern int a;
int c();

void main(){
    int d = 5;
    a = 23;
    d = c();
}

Compiler
This can be compiled. The compiler is a translator that takes the source code and turns it into code - an object file - for the linker to use. Call the object file prog.obj. This code must keep any names that will be visible outside the object file. So it would look something like this.
 

  1. main starts here
  2. push constant 5 on the stack
  3. move constant 2 to register A
  4. move register A's value to address of external name a
  5. push return address (two instructions below) on stack
  6. jump to address of external name c
  7. pop top value on stack to register A
  8. pop top of stack
  9. move value in register A to location pointed to by SP
  10. jump back to system
Instruction 8 just throws away the return address that is going to be used by function c. Instruction 9 does the "d=".

Now imagine waiting several days before writing the other source file; call it other.cpp.

int a;

int c(){
    return a + 3;
}

We compile this, and we get an object file named other.obj that would contain code like this.
 

  1. a is here
  2. c is next
  3. move value of a to register A.
  4. add 3 to register A.
  5. push value of register A on stack.
  6. look up return address at (stack pointer - 1) and then jump there.
Linker
Now we link these files together to build an executable file, which might look something like the Contents column of this table. I am adding a Comments column that would not appear in the file, just to describe what each thing is about. The linker sticks the two pieces together. I will make the other.obj piece first, just to emphasize a point or two.
 
 
Address Contents (symbolic form) Comment
0 7 Address to start program
1 5 Size of stack
2 0 a variable
3 MOVE A,2 move value at address 2 to A
4 ADD A,'3'  
5 PUSH A
6 JUMP (SP-1) return
7 PUSH 5 Set up variable local to function
8 MOVE A,'23'
9 MOVE 2,A Finishes a = 23
10 PUSH PC+2 Push return address
11 JUMP 3  Call of function
12 POP A
13 POP
14 MOVE (SP),A Finishes d = c(5)
15 JUMP (SP-1) Return to system

Loader

The loader is responsible for loading a memory image of the executable file and starting the program. The program would not be loaded at address 0, so the program  might look like this in memory. The loader might also be responsible for setting up the stack. I have put the stack in addresses 1014-1018.
 
 
Address Contents
1000 0
1001 MOVE A,2
1002 ADD A,'3'
1003 PUSH A
1004 JUMP (SP-1)
1005 PUSH 5
1006 MOVE A,'23'
1007 MOVE 2,A
1008 PUSH PC+2
1009 JUMP 3 
1010 POP A
1011 POP
1012 MOVE (SP),A
1013 JUMP (SP-1)
1014 200
1015 0
1016 0
1017 0
1018 0

The loader essentially does a function call to branch to the start location in the program, and then we have run-time.

Run-time
Each instruction changes our mythical machine's state - the contents of its registers and memory. For example, if we take a snapshot of the program and registers just after the instruction at address 1007 (which finishes a=23)  is executed, we would see
 
 
Address Contents
1000 23
1001 MOVE A,2
1002 ADD A,'3'
1003 PUSH A
1004 JUMP (SP-1)
1005 PUSH 5
1006 MOVE A,'23'
1007 MOVE 2,A
1008 PUSH PC+2
1009 JUMP 3 
1010 POP A
1011 POP
1012 MOVE (SP),A
1013 JUMP (SP-1)
1014 200
1015 5
1016 0
1017 0
1018 0

Registers:
 
A B PC SP
23 0 1008 1015