Respuestas:
=====> COMPILATION PROCESS <======
|
|----> Input is Source file(.c)
|
V
+=================+
| |
| C Preprocessor |
| |
+=================+
|
| ---> Pure C file ( comd:cc -E <file.name> )
|
V
+=================+
| |
| Lexical Analyzer|
| |
+-----------------+
| |
| Syntax Analyzer |
| |
+-----------------+
| |
| Semantic Analyze|
| |
+-----------------+
| |
| Pre Optimization|
| |
+-----------------+
| |
| Code generation |
| |
+-----------------+
| |
| Post Optimize |
| |
+=================+
|
|---> Assembly code (comd: cc -S <file.name> )
|
V
+=================+
| |
| Assembler |
| |
+=================+
|
|---> Object file (.obj) (comd: cc -c <file.name>)
|
V
+=================+
| Linker |
| and |
| loader |
+=================+
|
|---> Executable (.Exe/a.out) (com:cc <file.name> )
|
V
Executable file(a.out)
El preprocesamiento de C es el primer paso de la compilación. Lo maneja:
#define
declaraciones.#include
declaraciones.El propósito de la unidad es convertir el archivo fuente C en un archivo de código C puro.
Hay seis pasos en la unidad:
Combina caracteres en el archivo fuente para formar un "TOKEN". Un token es un conjunto de caracteres que no tiene 'espacio', 'tabulación' y 'nueva línea'. Por lo tanto, esta unidad de compilación también se denomina "TOKENIZER". También elimina los comentarios, genera la tabla de símbolos y las entradas de la tabla de reubicación.
Esta unidad verifica la sintaxis en el código. Por ejemplo:
{
int a;
int b;
int c;
int d;
d = a + b - c * ;
}
El código anterior generará el error de análisis porque la ecuación no está equilibrada. Esta unidad verifica esto internamente generando el árbol del analizador de la siguiente manera:
=
/ \
d -
/ \
+ *
/ \ / \
a b c ?
Por lo tanto, esta unidad también se llama PARSER.
Esta unidad verifica el significado de las declaraciones. Por ejemplo:
{
int i;
int *p;
p = i;
-----
-----
-----
}
El código anterior genera el error "Asignación de tipo incompatible".
Esta unidad es independiente de la CPU, es decir, existen dos tipos de optimización
Esta unidad optimiza el código en las siguientes formas:
Por ejemplo:
{
int a = 10;
if ( a > 5 ) {
/*
...
*/
} else {
/*
...
*/
}
}
Aquí, el compilador conoce el valor de 'a' en tiempo de compilación, por lo tanto, también sabe que la condición if siempre es verdadera. Por lo tanto, elimina la parte else del código.
Por ejemplo:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = a + b + c;
/*
...
*/
}
se puede optimizar de la siguiente manera:
{
int a, b, c;
int x, y;
/*
...
*/
x = a + b;
y = x + c; // a + b is replaced by x
/*
...
*/
}
Por ejemplo:
{
int a;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
a = 10;
/*
...
*/
}
}
En el código anterior, si 'a' es local y no se usa en el ciclo, entonces se puede optimizar de la siguiente manera:
{
int a;
a = 10;
for (i = 0; i < 1000; i++ ) {
/*
...
*/
}
}
Aquí, el compilador genera el código ensamblador para que las variables más utilizadas se almacenen en los registros.
Aquí la optimización depende de la CPU. Supongamos que si hay más de un salto en el código, se convierten en uno como:
-----
jmp:<addr1>
<addr1> jmp:<addr2>
-----
-----
El control salta directamente.
Luego, la última fase es la vinculación (que crea un ejecutable o biblioteca). Cuando se ejecuta el ejecutable, se cargan las bibliotecas que requiere.
Representación ASCII:
[Source Code] ---> Compiler ---> [Object code] --*
|
[Source Code] ---> Compiler ---> [Object code] --*--> Linker --> [Executable] ---> Loader
| |
[Source Code] ---> Compiler ---> [Object code] --* |
| |
[Library file]--* V
[Running Executable in Memory]
Espero que esto te ayude un poco más.
Primero, repase este diagrama:
(img source->internet)
Crea un fragmento de código y guarda el archivo (código fuente), luego
Procesamiento previo : - Como sugiere el nombre, no forma parte de la compilación. Indican al compilador que realice el preprocesamiento necesario antes de la compilación real. Puede llamar a esta fase sustitución de texto o interpretar directivas de preprocesador especiales indicadas por #.
Compilación : - La compilación es un proceso en el que un programa escrito en un idioma se traduce a otro idioma de destino. Si hay algunos errores, el compilador los detectará y los informará.
Ensamblar : - El código de ensamblaje se traduce a código de máquina. Puede llamar a ensamblador un tipo especial de cumplidor.
Vinculación : - Si esta pieza de código necesita que se vincule algún otro archivo fuente, vincularlos para convertirlo en un archivo ejecutable.
Hay muchos procesos que ocurren después. Sí, lo adivinó, aquí viene el papel del cargador:
Cargador : - Carga el código ejecutable en la memoria; se crean el programa y la pila de datos, se inicializa el registro.
Pequeña información adicional: - http://www.geeksforgeeks.org/memory-layout-of-c-program/ , puede ver el diseño de la memoria allí.
Compilador: Es un programa que traduce un programa de lenguaje de alto nivel a un programa de lenguaje máquina. Un compilador es más inteligente que un ensamblador. Comprueba todo tipo de límites, rangos, errores, etc. Pero el tiempo de ejecución de su programa es mayor y ocupa una mayor parte de la memoria. Tiene velocidad lenta. Porque un compilador pasa por todo el programa y luego traduce el programa completo a códigos de máquina. Si un compilador se ejecuta en una computadora y produce los códigos de máquina para la misma computadora, entonces se conoce como autocompilador o compilador residente. Por otro lado, si un compilador se ejecuta en una computadora y produce los códigos de máquina para otra computadora, entonces se conoce como compilador cruzado.
Vinculador: en los lenguajes de alto nivel, se almacenan algunas bibliotecas o archivos de encabezado integrados. Estas bibliotecas están predefinidas y contienen funciones básicas que son esenciales para ejecutar el programa. Estas funciones están vinculadas a las bibliotecas mediante un programa llamado Linker. Si el vinculador no encuentra una biblioteca de una función, informa al compilador y luego el compilador genera un error. El compilador invoca automáticamente al enlazador como último paso en la compilación de un programa. No está integrado en bibliotecas, sino que también vincula las funciones definidas por el usuario con las bibliotecas definidas por el usuario. Por lo general, un programa más largo se divide en subprogramas más pequeños llamados módulos. Y estos módulos deben combinarse para ejecutar el programa. El proceso de combinar los módulos lo realiza el enlazador.
Loader: Loader es un programa que carga códigos de máquina de un programa en la memoria del sistema. En informática, un cargador es la parte de un sistema operativo que se encarga de cargar programas. Es una de las etapas esenciales en el proceso de inicio de un programa. Porque coloca programas en la memoria y los prepara para su ejecución. La carga de un programa implica leer el contenido del archivo ejecutable en la memoria. Una vez que se completa la carga, el sistema operativo inicia el programa pasando el control al código del programa cargado. Todos los sistemas operativos que admiten la carga de programas tienen cargadores. En muchos sistemas operativos, el cargador reside permanentemente en la memoria.
Wikipedia debería tener una buena respuesta, aquí están mis pensamientos:
*
*
Linkers and Loaders de LinuxJournal explica este concepto con claridad. También explica cómo surgió el nombre clásico a.out. (salida del ensamblador)
Un breve resumen,
c program --> [compiler] --> objectFile --> [linker] --> executable file (say, a.out)
tenemos el ejecutable, ahora entregue este archivo a su amigo o cliente que necesite este software :)
cuando ejecuten este software, digamos escribiéndolo en la línea de comando ./a.out
execute in command line ./a.out --> [Loader] --> [execve] --> program is loaded in memory
Una vez que el programa se carga en la memoria, el control se transfiere a este programa haciendo que la PC (contador de programa) apunte a la primera instrucción de a.out
Leerá el archivo fuente que puede ser de tipo .co .cpp, etc. y lo traduce a un archivo .o llamado archivo objeto.
Combina varios archivos .o que se pueden generar para múltiples archivos fuente en un archivo ejecutable (formato ELF en GCC). Hay dos tipos de enlaces:
Un programa que carga el archivo ejecutable en la memoria principal de la máquina.
Para un estudio detallado sobre estas tres etapas de ejecución del programa en Linux, lea esto .
Los cambios del compilador comprueban su código fuente en busca de errores y lo cambia a código objeto. Este es el código que ejecuta el sistema operativo.
A menudo, no escribe un programa completo en un solo archivo, por lo que el vinculador vincula todos sus archivos de código objeto.
su programa no se ejecutará a menos que esté en la memoria principal
El enlazador y el intérprete son intérpretes mutuamente excluyentes que obtienen el código línea por línea y lo ejecutan línea por línea.
Compilador Convierte el código fuente en código objeto.
Vinculador Combina los archivos de objetos múltiples en un solo archivo de programa ejecutable.
Cargador Carga el archivo ejecutable en la memoria principal.
Un compilador es un programa especial que procesa declaraciones escritas en un lenguaje de programación particular y las convierte en lenguaje de máquina o "código" que usa el procesador de una computadora.
Un compilador traduce líneas de código del lenguaje de programación al lenguaje de máquina.
Un vinculador crea un vínculo entre dos programas.
Un cargador carga el programa en la memoria de la base de datos principal, programa, etc.
Compilador: es un software del sistema que corrige el error de programas, archivos de objetos, mensajes, etc.
Linker: es un software de sistema que combina uno o más archivos de objetos y posiblemente algún código de biblioteca en alguna biblioteca exiguable o en una lista de errores
Cargador: un programa que carga el archivo ejecutable en la memoria principal de la máquina