How the source code gets translated into binaries for a target Micro-controller.

Photo by S. Tsuchiya on Unsplash

How the source code gets translated into binaries for a target Micro-controller.

The step by step process of translating source code into machine code for micro-controller.

As we all are familiar with the fact that every digital computer needs instructions in the format a machine understands, obviously which is binary. In this article I will try to elaborate the process how our source code get converted into executable binaries for the target micro-controller we use in our embedded system.

transformation.png

The figure above explains the step by step procedure how our source code gets converted into executable binary after going through various stages.

First Step : Compilation of Source Code

The first step in this process is translating the source code written in any high level language, like C or C++ into machine understandable opcodes. These opcodes are different for different machines (processors) depending upon the architecture and word-length. It is the duty of compiler to translate source code into proper binary opcodes. Since every machine have different opcodes this translation may vary from processor to processor.

Cross Compilation

We write our source code on a PC for a particular embedded board having our target processor. Since we need to generate the executable binary on the native machine where we have developed the source program, we need a compiler that can translate this source code into binary executable for the target processor and not for the native machine in which we have designed the source program, this is known as cross compilation.

Second Step: Linking the Object Code

The figure above shows that the job of compiler or cross compiler is just to translate the source code into object code and store in object files. These object files contains the instructions that are to be executed by the target processor.

Our source code is generally divided into three sections :

  • .text : The actual code.
  • .data : Initialized global variables.
  • .bss : Uninitialized global variables.

This organization of high level language makes it easier to code but at the end we need a single binary to get executed on the target machine. This is done by the linker. The linker combines all object files into a single binary file.

Third Step: Locating the correct memory addresses.

It is very important to locate or stamp the exact addresses of the code so that .text section can be loaded to the micro-controller's flash memory, and .data section to the RAM as soon as the we power up the micro-controller. This is the duty of locator.

Before the main() function starts many nationalizations are made, these includes initialization of various peripherals, copying initialized variables from flash memory to RAM, initializing the stack and heap and finally calling the main(). This is all done by a startup code which takes control to the main() as soon as machine is powered on. The startup code resides in a special file and generally resides at location 0x0000. As soon as the machine is powered on it get executed and takes control to the point where main() function resides.

The locating process is applicable in embedded programs only as on PC the operating system does this for us, known as program loading.