Summary
Highlights
The process starts with a program written in a high-level language, like C. The first step, compilation, translates this high-level code into assembly language specific to the target machine. Following this, the assembler organizes these individual objects. The linker then combines the object code of the program with other necessary objects, such as libraries. This produces a single executable file, which is then loaded into memory to begin execution.
The assembler translates the high-level language into assembly code, which includes instructions (text segment) and data (static data segment). The object file also contains relocation information to handle undefined addresses (labels) and dependencies between different modules. Debugging information is also embedded to allow mapping the source code to the executable for testing and analysis.
The linker combines all compiled object files and libraries, resolving all references and dependencies to create a complete executable. The loader's role is to load this executable from storage into the computer's RAM. It reads the program's header to understand its structure, allocates memory, copies instructions and static data, initializes program arguments on the stack, sets up registers, and finally starts the program's execution.
Unlike compiled languages like C, Java is typically interpreted. Java code is compiled into bytecode, which is then interpreted by the Java Virtual Machine (JVM). This interpretation process adds overhead, making Java generally slower than C. Just-In-Time (JIT) compilers can improve Java performance by translating frequently executed bytecode into native machine code at runtime, but it still often trails behind highly optimized compiled C code.
Compiler optimization flags significantly influence program performance. For a C program, different optimization levels (e.g., O1, O2, O3) can drastically reduce the number of instructions and execution cycles. The performance gain is not always directly proportional to the instruction count, as the CPI (Cycles Per Instruction) can vary. O3 optimization, for example, might increase instructions but result in fewer cycles, leading to better performance.
The choice of algorithm and computing architecture also profoundly impacts performance. For instance, Quick Sort generally outperforms Bubble Sort. Comparing architectures like MIPS and ARM reveals differences in addressing modes and registers, affecting how efficiently programs run. Intel's x86 architecture, characterized by its CISC design and a strong emphasis on backward compatibility, has a growing instruction set over time, allowing older programs to run on new hardware but also leading to a more complex instruction set.