Getting started with GCC: Difference between revisions

From ICO wiki
Jump to navigationJump to search
Lvosandi (talk | contribs)
No edit summary
Lvosandi (talk | contribs)
No edit summary
Line 1: Line 1:
== Introduction ==
GCC (GNU Compiler Collection) is a suite of tools aimed at compiling various programming languages for different CPU architectures.
GCC (GNU Compiler Collection) is a suite of tools aimed at compiling various programming languages for different CPU architectures.
There are many competitive alternatives such as [http://llvm.org/ LLVM].
There are many competitive alternatives such as [http://llvm.org/ LLVM].
Line 14: Line 17:
You can also manually compile a compiler for foreign architectures which isn't supported out of the box for your distribution,
You can also manually compile a compiler for foreign architectures which isn't supported out of the box for your distribution,
see [http://lauri.vosandi.com/tub/computer-architecture/building-mips-toolchain.html here] for more information
see [http://lauri.vosandi.com/tub/computer-architecture/building-mips-toolchain.html here] for more information
[[File:Compiling-compilers.jpg]]


==Sample source files==
==Sample source files==

Revision as of 12:50, 15 October 2015

Introduction

GCC (GNU Compiler Collection) is a suite of tools aimed at compiling various programming languages for different CPU architectures. There are many competitive alternatives such as LLVM. Following instructions can be carried out at enos.itcollege.ee via SSH, the software is already installed there so you don't have to run apt-get install lines. On your personal Ubuntu machine you can install GCC via APT:

 apt-get install build-essential

In order to compile binaries for foreign architecure you need cross-compiler. In Ubuntu repositories you may find ARM cross compilers:

 sudo apt-get install g++-arm-linux-gnueabihf g++-arm-linux-gnueabi

The point of this article is to get familiar with tools provided by GCC toolchain. GCC, especially as a cross-compiler is widely used to compile firmware for routers and other embedded devices. You can also manually compile a compiler for foreign architectures which isn't supported out of the box for your distribution, see here for more information

Sample source files

Create a plain-text file libfib.c with following content:

 int fib(n) {
     if (n == 1 || n== 2) {
         return 1;
     } else {
         return fib(n-1) + fib(n-2);
     }
 }

Create another plain-text file to invoke the function described above:

 #include <stdio.h>

 int main(int argc, char **argv) {
   if (argc != 2) {
     printf("Please specify only one argument\n");
     return -1;
   } else {
     int n;
     sscanf("%d", argv[1], &n);
     printf("%dth fibonacci number is %d\n", n, fib(n));
     return 0;
   }
 }

Compiling native binaries

Verify that the code works:

 gcc libfib.c hello.c -o hello-simple

Invocation of the binary should result in output 42th fibonacci number is 267914296:

 ./hello-simple 42

Use file to inspect what kind of executable was created:

 file hello-simple

Compiling assembly

Generate assembly for the C file which contains fib function:

 gcc libfib.c -S -o libfib.s

Investigate the assembly corresponding to fib:

 gcc -static libfib.c hello.c -o hello-simple-static


Dynamic vs static linking

The hello-simple compiled above is dynamically linked library, you can list dependant libraries width ldd:

 ldd hello-simple

Compile the static version:

 gcc -static libfib.c hello.c -o hello-simple-static

Attempting to run ldd against such binary will result in error not a dynamic executable. List the files and their sizes, what is the difference and why?

 ls -lah hello-simple hello-simple-static


Libraries

Use the compiler to compile assembly from the C source code:

 gcc -fPIC libfib.c -S -o libfib-native.s
 gcc hello.c -S -o hello-native.s

Turn assembly into object files:

 gcc -fPIC -c libfib-native.s -o libfib-native.o
 gcc -c hello-native.s -o hello-native.o

Finally link the object file against system libraries to produce usable binary:

 mkdir mylibs
 gcc -fPIC libfib-native.o -shared -o mylibs/libfib-native.so
 gcc hello-native.o -o hello-native -L mylibs -l fib-native

Invoke the binary to test if it actually works, expect the program to print line Hello, World!:

 LD_LIBRARY_PATH=mylibs ./hello-native 42

The binary was compiled dynamically which means that during it's invocation OS is requested to load dependent libraries to the memory is necessary. You can use ldd to investigate which libraries are required to invoke the binaries:

 LD_LIBRARY_PATH=mylibs ldd hello-native

Alternatively you can compile the binary statically, in that case all the necessary machinery get's bundled into the resulting binary:

 gcc libfib-native.o hello-native.o -static -o hello-native-static


Deassembling a binary

Use objdump to locate the section corresponding to function fib.

 objdump -D mylibs/libfib-native.so


Makefiles

Create file Makefile:


Cross-compiling

Use ARM cross-compiler to compile ARM binaries on x86:

 arm-linux-gnueabihf-gcc hello.c -static -o hello-foreign

Use file and ldd to inspect the binary. Assuming binfmt-support has been set up properly and QEMU emulation layer is available a static ARM binary can be invoked on x86 host via emulation:

 ./hello-foreign

For dynamically linked binaries you need also dependant libraries, the simplest way is to bootstrap a LXC container for ARM.