Steps involved in compiling a c program using gcc

Steps involved in converting the C source code to executable:
Now, we are going to see how to convert a C source code to executable and also about the steps involved in compiling a C program.  C program compilation involves 4 steps which are as follows.
  • Converting C source code to Preprocessed code
  • Converting preprocessed code to assembly code
  • Converting assembly code to object code
  • Converting object code to binary


Steps involved in compiling a C Program

Here, we have two c files main.c and add.c.

Below is the source code for main.c
 
#define NUM1 10
#define NUM2 20

int main() {
int a, b;
a = NUM1;
b = NUM2;
add(a, b);
return 0;
}


Below is the source code for add.c
 
#include <stdio.h>
#define STRING "Result:"

void add(int a, int b) {
int c;
c = a + b;
printf("%s %d\n", STRING, c);
return;
}


As I mentioned earlier, compiling a C program involves 4 phases.  They are preprossesing, compilation, assembly and linking.  We don't need to go through all the above four steps one by one to get final executable for the given source code.  Because, compiler can do all the above operation implicitly and provide us the final binary or executable in one single command(see below).

gcc <file_name.c> -o <execuable_name>

Please note that the above command itself can get us the executable for the given source code.  Just to understand whole compilation process, we are going to go through all the steps involved in compilation one by one.

What is preprocessor?
It converts the C source code to preprocessed code or expanded c source code. In other words, its a program which runs on our C source code before compilation process.  And it provides facility to handle named constant, macros and file inclusion.  Preprocessor begins with the preprocessor directive hash symbol(#).  During preprocessing the following operation would take place.
  • macro substitution
  • File inclusion
  • Conditional compilation
We will see more about the above operations in-detail in the forth coming chapters.

How to convert C source code to preprocessed code?
We can use -E option to perform preprocessing alone.  The below command converts the C source code to preprocessed code.  The -o option is used to redirect the preprocessed code to the given file.

gcc -E main.c -o main.i -> redirects the preprocessed code to the file main.i
gcc -E add.c -o add.i    -> redirects the preprocessed code to the file add.i

  jp@jp-VirtualBox:~/$ gcc -E main.c -o main.i
  jp@jp-VirtualBox:~/$ gcc -E add.c -o add.i
  jp@jp-VirtualBox:~/$ ls
  add.c  add.i  main.c  main.i

Below is the preprocessed code(main.i) of main.c
 
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"

int main() {
int a, b;
a = 10;
b = 20;
add(a, b);
return 0;
}



Below is the preprocessed code(add.i) of add.c
 
# 936 "/usr/include/stdio.h" 3 4
# 2 "add.c" 2

void add(int a, int b) {
int c;
c = a + b;
printf("%s %d\n", "Result:", c);
return;
}


Note:  In the above preprocessed source codes, you could find that the macros are replaced by values.

What is a compiler?
Compiler converts the preprocessed(or C) source code to assembly language code.

How to convert preprocessed source code to assembly language code?
The -S option tells the compiler to generate assembly language code alone.  The below command converts the preprocessed source code to assembly language code.   The -o option is used to redirect the assembly language code to the given file.

gcc -S main.i -o main.s -> redirects the assembly code for main.i to the file main.s
gcc -S add.i -o add.s    -> redirects the assembly code for add.i to the file add.s

  jp@jp-VirtualBox:~/$ gcc -S main.i -o main.s
  jp@jp-VirtualBox:~/$ gcc -S add.i -o add.s
  jp@jp-VirtualBox:~/$ ls
  add.c  add.i  add.s  main.c  main.i  main.s


Below is the assembly code(main.s) for main.i
 
.file "main.c"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $10, 28(%esp)
movl $20, 24(%esp)
movl 24(%esp), %eax
movl %eax, 4(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call add
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
.section .note.GNU-stack,"",@progbits



Below is the assembly code(add.s) for add.i
 
.file "add.c"
.section .rodata
.LC0:
.string "%s %d\n"
.LC1:
.string "Result:"
.text
.globl add
.type add, @function
add:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
movl %eax, -12(%ebp)
movl $.LC0, %eax
movl -12(%ebp), %edx
movl %edx, 8(%esp)
movl $.LC1, 4(%esp)
movl %eax, (%esp)
call printf
leave
ret
.size add, .-add
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
.section .note.GNU-stack,"",@progbits



What is assembler?
Assembler converts the assembly language code to object code.

How to convert assembly language code to object code?
The -c option tells the compiler to generate object code(machine codes).  The below command converts the assembly language code to object codes.  The -o option is used to redirect the object code to the given file.

gcc -c main.s -o main.o -> redirects the object code for main.s to the file main.o
gcc -c add.s -o add.o    -> redirects the object code for add.s to the file add.o

  jp@jp-VirtualBox:~/$ gcc -c add.s -o add.o
  jp@jp-VirtualBox:~/$ ls
  add.c  add.i  add.o  add.s  main.c  main.i  main.o  main.s


What is linker?
Linker links one or more object files and generates a single executable.

How to convert objects codes to an executable?
The below command links the given object files and generates an executable file.  The -o option is used to mention the name of the executable file.

gcc main.o add.o -o output -> output is the executable file

  jp@jp-VirtualBox:~/$ gcc main.o add.o -o output
  jp@jp-VirtualBox:~/$ ls
  add.c  add.i  add.o  add.s  main.c  main.i  main.o  main.s  output
  jp@jp-VirtualBox:~/$ ./output
  Result: 30

./output - "./" indicates current directory.  And "output" is the name of the executable.

So, our program prints the sum value of two numbers 10 and 20.


How to convert c source code to assembly language code?

Covert c program to assembly language program

Compiler uses -S option to generate assembly language code for the given c source code.

Below is the c source code(program.c).

  #include <stdio.h>
  int main() {
        int a, b, c;
        a = 20, b = 30;
        c = a + b;
        printf("Sum of two numbers is %d\n", c);
        return 0;
  }



C source code can be converted to assembly code using the following command.

  jp@jp-VirtualBox:~/$ gcc -S program.c 
  jp@jp-VirtualBox:~/$ ls
  program.c  program.s


Below is the assembly code for the above given c source code.

        .file   "program.c"
        .section        .rodata
  .LC0:
        .string "Sum of two numbers is %d\n"
        .text
  .globl main
        .type   main, @function
  main:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movl    $20, 28(%esp)
        movl    $30, 24(%esp)
        movl    24(%esp), %eax
        movl    28(%esp), %edx
        leal    (%edx,%eax), %eax
        movl    %eax, 20(%esp)
        movl    $.LC0, %eax
        movl    20(%esp), %edx
        movl    %edx, 4(%esp)
        movl    %eax, (%esp)
        call    printf
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5.1) 4.4.5"
        .section        .note.GNU-stack,"",@progbits



Let us compile the assembly code to get the executable "program".  And this executable can be used to get the output of the given c program.

  jp@jp-VirtualBox:~/$ gcc -o program program.s 
  jp@jp-VirtualBox:~/$ ls
  program  program.c  program.s
  jp@jp-VirtualBox:~/$ ./program 
  Sum of two numbers is 50


restorecrtmode example in c

Header file:
    graphics.h

Synopsis:
      void restorecrtmode();
     
Description:
     restorecrtmode() restores screen mode to text mode.


restorecrtmode function in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>

  int main(void) {
        /* request auto detection */
        int gd = DETECT, gmode, err;
        int midx, midy;

        /* initialize graphics and local variables */
        initgraph(&gd, &gmode, "C:/TURBOC3/BGI");

        /* read result of initialization */
        err = graphresult();

        if (err != grOk) {
                /* an error occurred */
                printf("Graphics error: %s\n", grapherrormsg(err));
                getch();
                return 0;
        }

        /* mid position in x and y-axis */
        midx = getmaxx() / 2;
        midy = getmaxy() / 2;

        /* output a message */
        settextjustify(CENTER_TEXT, CENTER_TEXT);
        outtextxy(midx, midy - 100, "GRAPHICS MODE");

        /* draw a rectange at the given position */
        rectangle(midx - 50, midy - 50, midx + 50, midy + 50);
        getch();

        /* restore system to text mode */
        restorecrtmode();
        printf("Restored system to text mode");
        getch();

        /* return to graphics mode */
        setgraphmode(getgraphmode());

        /* output a message */
        settextjustify(CENTER_TEXT, CENTER_TEXT);
        outtextxy(midx, midy - 100, "BACK TO GRAPHIC MODE!!");

        /* draws a rectangle at the given postion */
        rectangle(midx - 50, midy - 50, midx + 50, midy + 50);

        /* clean up */
        getch();
        closegraph();
        return 0;
  }





Output: (restorecrtmode built-in function in c graphics.h)


_graphgetmem & _graphfreemem examples in c

Header file:
    graphics.h

Synopsis:
      void far * far _graphgetmem(unsigned size);
     void far _graphfreemem(void far *ptr, unsigned size);
     
Description:
     User hooks which can be used for memory allocation and deallocation.


_graphgetmem & graphfreemem functions in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>
  #include <alloc.h>

  /* called by the graphics kernel to allocate memory */
  void far * far _graphgetmem(unsigned sz) {
        printf("Inside _graphgetmem to allocate %d bytes\n", sz);
        delay(500);
        /* allocate memory from far heap */
        return farmalloc(size);
  }

  /* called by the graphics kernel to free memory */
  void far _graphfreemem(void far *ptr, unsigned sz) {
        printf("Inside _graphfreemem to deallocate %d bytes\n", sz);
        delay(500);
        /* free ptr from far heap */
        farfree(ptr);
  }

  int main(void) {
        /* request auto detection */
        int graphicDriver = DETECT;
        int graphicMode, err;

        /* initialize graphics and local variables */
        initgraph(&graphicDriver, &graphicMode,
                                        "C:/TURBOC3/BGI");

        /* read result of initialization */
        err = graphresult();

        if (err != grOk) {
                /* an error occurred */
                printf("Graphic Error: %s\n",
                                grapherrormsg(err));
                getch();
                return 0;
        }

        /* display a message */
        settextjustify(CENTER_TEXT, CENTER_TEXT);
        outtextxy(getmaxx() / 2, getmaxy() / 2, "Closing graphics");

        /* clean up */
        closegraph();
        return 0;
  }





Output: (_graphgetmem & _graphfreemem built-in functions in c graphics.h)


setwritemode example in c

Header file:
    graphics.h

Synopsis:
      void setwritemode(int mode);
     
Description:
     setwritemode() sets the current writing mode for line drawing.  Mode can be COPY_PUT or XOR_PUT.

COPY_PUT - overwrites with the line on screen
XOR_PUT  - uses XOR command to mix line with the screen


setwritemode function in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>

  int main() {
        /* request auto detection */
        int graphicDriver = DETECT, graphicMode, err;

        /* initialize graphics and local variables */
        initgraph(&graphicDriver, &graphicMode,
                                        "C:/TURBOC3/BGI");

        /* read result of initialization */
        err = graphresult();

        if (err != grOk) {
                /* an error occurred */
                printf("Graphics error: %s\n",
                                grapherrormsg(err));
                getch();
                return 0;
        }

        /* select XOR drawing mode */
        setwritemode(XOR_PUT);

        /* draw a line */
        line(0, 0, getmaxx(), getmaxy());
        getch();

        /* erase the line by drawing over it */
        line(0, 0, getmaxx(), getmaxy());
        getch();

        /* select overwrite drawing mode */
        setwritemode(COPY_PUT);

        /* draw a line */
        line(0, 0, getmaxx(), getmaxy());

        /* clean up */
        getch();
        closegraph();
        return 0;
  }





Output: (setwritemode built-in function in c graphics.h)


setviewport example in c

Header file:
    graphics.h

Synopsis:
      void setviewport(int left, int top, int right, int bottom, int clip);
     (left, top) - top left corner
     (right, bottom) - bottom right corner
     clip - If the clip value is non-zero, all drawings will be truncated to current view port
     
Description:
     setviewport() sets a new view port for graphics output.


setviewport function in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>

  int main(void) {
        /* request auto detection */
        int graphicDriver = DETECT, graphicMode;
        int err, midx, midy;

        /* initialize graphics and local variables */
        initgraph(&graphicDriver, &graphicMode, "C:/TURBOC3/BGI");

        /* read result of initialization */
        err = graphresult();

        if (err != grOk) {
                /* an error occurred */
                printf("Graphic Error: %s\n",
                                grapherrormsg(err));
                getch();
                return 0;
        }

        /* draws a rectangle using current drawing color */
        setcolor(9);
        setfillstyle(SLASH_FILL, 9);
        rectangle(0, 0, 50, 50);
        floodfill(1, 1, 9);

        /* mid position in x and y axis */
        midx = getmaxx() / 2;
        midy = getmaxy() / 2;

        /* create a smaller viewport */
        setviewport(midx - 100, midy - 100,
                        midx + 100, midy + 100, 1);

        /* draws a rectangle using current drawing color */
        setcolor(11);
        setfillstyle(BKSLASH_FILL, 11);
        rectangle(0, 0, 50, 50);
        floodfill(1, 1, 11);

        /* clean up */
        getch();
        closegraph();
        return 0;
  }





Output: (setviewport built-in function in c graphics.h)


installuserfont example in c

Header file:
    graphics.h

Synopsis:
      int installuserfont(char *name);
     
Description:
     installuserfont() installs a user defined font file and returns the font ID which can be used as the font style parameter for settextstyle().


installuserfont function in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>

  int main(void) {
        /* request auto detection */
        int graphicDriver = DETECT, graphicMode;
        int font, err, midx, midy;

        /* initialize graphics and local variables */
        initgraph(&graphicDriver, &graphicMode,
                                "C:/TURBOC3/BGI");

        /* read result of last graphics operation */
        err = graphresult();

        if (err != grOk) {
                printf("Graphic Error: %s\n",
                                grapherrormsg(err));
                getch();
                return 0;
        }

        /* mid position in x and y axis */
        midx = getmaxx() / 2;
        midy = getmaxy() / 2;

        /* install a user defined font file */
        font = installuserfont("USER.CHR");

        err = graphresult();

        if (err != grOk) {
                /* error occurred */
                printf("Error in installing user font:%s",
                                                grapherrormsg(err));
                return 0;
        }

        /* select the user font */
        settextstyle(font, HORIZ_DIR, 10);

        /* output some text */
        settextjustify(CENTER_TEXT, CENTER_TEXT);
        outtextxy(midx, midy, "Hello World!");

        /* clean up */
        getch();
        closegraph();
        return 0;
  }





Output: (installuserfont built-in function in c graphics.h)


setusercharsize example in c

Header file:
    graphics.h

Synopsis:
      void setusercharsize(int multx, int divx, int multy, int divy);
     multx : divx - width magnification factor
     multy  : divy  - height magnification factor

Description:
     setusercharsize() sets user defined character magnification factor for stroked fonts.  To make the text twice as wide as default text, set 2 to multx and 1 to divx.
     multx : divx <=> 2 : 1

To make the text half the height of default, set 1 to multy and 2 to divy.
     multy : divy  <=> 1 : 2


setusercharsize function in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>

  int main(void) {
        /* request autodetection */
        int graphicDriver = DETECT, graphicMode, err;

        /* initialize graphics and local variables */
        initgraph(&graphicDriver, &graphicMode,
                                "C:/TURBOC3/BGI");

        /* read result of initialization */
        err = graphresult();

        if (err != grOk) {
                /* an error occurred */
                printf("Graphics error: %s\n",
                                grapherrormsg(err));
                getch();
                return 0;
        }

        /* select a text style */
        settextstyle(GOTHIC_FONT, HORIZ_DIR, 4);

        /* move to the text starting position */
        moveto(0, getmaxy() / 2);

        /* output some normal text */
        outtext("Normal ");

        /* make the text 1/3 the normal width */
        setusercharsize(1, 2, 1, 2);
        outtext("Slim ");

        /* make the text 3 times normal width */
        setusercharsize(5, 1, 5, 1);
        outtext("Fat");

        /* clean up */
        getch();
        closegraph();
        return 0;
  }





Output: (setusercharsize built-in function in c graphics.h)


setgraphbufsize example in c

Header file:
    graphics.h

Synopsis:
      unsigned setgraphbufsize(unsigned bufsize);
     
Description:
     setgraphbufsize() returns size of the previous buffer and set the given size for the internal graphic buffer.


setgraphbufsize function in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>

  #define BUFSZ 1024 /* internal graphics buffer size */

  int main(void) {
        /* request auto detection */
        int graphicDriver = DETECT, graphicMode;
        int err, midx, midy, prevsz;
        char str[64];

        /* setting the size of the interal graphic buffer */
        prevsz = setgraphbufsize(BUFSZ);

        /* initialize graphics and local variables */
        initgraph(&graphicDriver, &graphicMode,
                                        "C:/TURBOC3/BGI");

        /* read result of initialization */
        err = graphresult();

        if (err != grOk) {
                /* an error occurred */
                printf("Graphic Error: %s\n", grapherrormsg(err));
                getch();
                return 0;
        }

        /* mid position in x and y axis */
        midx = getmaxx() / 2;
        midy = getmaxy() / 2;

        /* output some messages */
        sprintf(str, "Current Graphics Buffer Size: %d", BUFSZ);
        settextjustify(CENTER_TEXT, CENTER_TEXT);
        outtextxy(midx, midy, str);

        sprintf(str, "Previous Graphics Buffer Size: %d", prevsz);
        outtextxy(midx, midy+textheight("H"), str);

        /* clean up */
        getch();
        closegraph();
        return 0;
  }





Output: (setgraphbufsize built-in function in c graphics.h)


setgraphmode example in c

Header file:
    graphics.h

Synopsis:
      void setgraphmode(int mode);
     
Description:
     setgraphmode() sets the system to graphic mode.


setgraphmode function in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>

  int main(void) {
        /* request auto detection */
        int gd = DETECT, gmode, err;
        int midx, midy;

        /* initialize graphics and local variables */
        initgraph(&gd, &gmode, "C:/TURBOC3/BGI");

        /* read result of initialization */
        err = graphresult();

        if (err != grOk) {
                /* an error occurred */
                printf("Graphics error: %s\n", grapherrormsg(err));
                getch();
                return 0;
        }

        /* mid position in x and y axis */
        midx = getmaxx() / 2;
        midy = getmaxy() / 2;

        /* output a message */
        settextjustify(CENTER_TEXT, CENTER_TEXT);
        outtextxy(midx, midy, "In graphics mode!! press any key to exit");
        getch();

        /* restore system to text mode */
        restorecrtmode();
        printf("Inside text mode!! press any key to exit");
        getch();

        /* setting graphic mode */
        setgraphmode(getgraphmode());

        /* output a message */
        settextjustify(CENTER_TEXT, CENTER_TEXT);
        outtextxy(midx, midy, "Back to graphic mode!!");

        /* clean up */
        getch();
        closegraph();
        return 0;
  }





Output: (setgraphmode built-in function in c graphics.h)


getgraphmode example in c

Header file:
    graphics.h

Synopsis:
      int getgraphmode (void);
     
Description:
     getgraphmode() returns the current graphic mode number.


getgraphmode function in c graphics



  #include <graphics.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <conio.h>

  int main(void) {
        /* request auto detection */
        int gd = DETECT, gmode, err;
        int midx, midy, mode;
        char str[64];

        /* initialize graphics and local variables */
        initgraph(&gd, &gmode, "C:/TURBOC3/BGI");

        /* read result of initialization */
        err = graphresult();

        /* an error occurred */
        if (err != grOk) {
                printf("Graphics error: %s\n", grapherrormsg(err));
                getch();
                return 0;
        }

        /* mid positions in x and y axis */
        midx = getmaxx() / 2;
        midy = getmaxy() / 2;

        /* get mode number and name strings */
        mode = getgraphmode();

        sprintf(str, "Current graphic mode number: %d", mode);

        /* display the information */
        settextjustify(CENTER_TEXT, CENTER_TEXT);
        outtextxy(midx, midy, str);
        midy = midy + textheight("H") + 2;

        sprintf(str, "Current graphic mode name:%s", getmodename(mode));
        outtextxy(midx, midy, str);

        /* clean up */
        getch();
        closegraph();
        return 0;
  }





Output: (getgraphmode built-in function in c graphics.h)