2010-04-03 18 views
6

Estoy tratando de comprender completamente el código pro process de escritura en algún idioma para la ejecución por el sistema operativo. En mi caso, el idioma sería C y el sistema operativo sería Windows. Hasta ahora, he leído muchos artículos diferentes, pero no estoy seguro, si entiendo el proceso correctamente, y me gustaría preguntarle si conoce algunos buenos artículos sobre algunos temas que no pude encontrar.Algunas preguntas generales C

Por lo tanto, lo que creo que sé de C (y, básicamente, otros idiomas):

C propio compilador sólo se ocupa de los tipos de datos, operaciones básicas de matemáticas, operaciones de punteros, y trabajar con funciones. Al trabajar con funciones, me refiero a cómo transmitirle argumentos y cómo obtener resultados de la función. Durante la compilación, la llamada a función se reemplaza por pasar argumentos a la pila, y que si la función no está en línea, su llamada se reemplaza por algún símbolo para el vinculador. Enlazar que encontrar la definición de función, y reemplazar el símbolo para saltar a esa función (y por supuesto que saltar de nuevo al programa).

Si lo anterior es generalmente cierto y lo hago bien, ¿dónde está el archivo .exe final realmente vinculador guarda las funciones? Después de la función main()? ¿Y qué crea el encabezado .exe? Compilador o enlazador?

Ahora, las capacidades adicionales de C, hoy conocidas como biblioteca estándar C, son un conjunto de funciones y las declaraciones de ellas, que otros programadores escribieron para extender y simplificar el uso del lenguaje C. Pero estas funciones como printf() fueron (¿o podrían ser?) Escritas en diferentes idiomas o ensambladores. Y llega mi siguiente pregunta, ¿puede ser, por ejemplo, la función printf() escrita en C puro sin usar ensamblador?

Sé que esta es una gran pregunta, pero solo quiero saber si tengo razón o no. Y créeme, leí muchos artículos en la web y no te preguntaría si podría encontrar estas informaciones juntas en un solo lugar, en un artículo. Insistido, debo recopilar información pormenorizada, así que no estoy seguro de si estoy en lo cierto. Gracias.

+1

Le recomiendo que aprenda a programar primero. Cualquier buen libro de programación le dirá el flujo de trabajo general de vinculación y compilación. –

Respuesta

6

Creo que está expuesto a cierta información que es menos relevante como programador principiante C y que podría confundirlo: parte del objetivo de utilizar un lenguaje de nivel superior como este es no tener que pensar inicialmente cómo funciona este proceso Con el tiempo, sin embargo, es importante comprender el proceso. Creo que por lo general lo entiendes bien.

El compilador de C simplemente toma el código C y genera archivos de objetos que contienen lenguaje de máquina. La mayor parte del archivo objeto está ocupado por el contenido de las funciones. Una llamada de función simple en C, por ejemplo, se representaría en el formulario compilado como operadores de bajo nivel para insertar elementos en la pila, cambiar el puntero de instrucción, etc.

La biblioteca C y cualquier otra biblioteca que use son ya disponible en este formulario compilado.

El vinculador es lo que combina todos los archivos de objeto relevantes, resuelve todas las dependencias (por ejemplo, un archivo de objeto que invoca una función en la biblioteca estándar) y luego crea el ejecutable.

En cuanto a las bibliotecas de idiomas están escritas en: Piense en cada función como una caja negra. Siempre que el recuadro negro tenga una interfaz estándar (la convención de llamadas C, es decir, toma argumentos de cierta manera, devuelve valores de cierta manera, etc.), no importa la forma en que se escribe internamente. Lo más típico es que las funciones se escriban en C o directamente en el ensamblaje. En el momento en que lo convierten en un archivo objeto (o como una biblioteca compilada), realmente no importa cómo se crearon inicialmente, lo que importa es que ahora están en la forma compilada de la máquina.

El formato de un archivo ejecutable depende del sistema operativo, pero gran parte del cuerpo del archivo ejecutable en Windows es muy similar al de los archivos objeto. Imagínese como si alguien hubiera combinado todos los archivos del objeto y luego hubiera agregado un poco de pegamento. El pegamento carga cosas relacionadas y luego invoca el principal(). Cuando era niño, por ejemplo, a la gente le gustaba "cambiar el pegamento" para agregar otra función antes de la pantalla principal() que mostraba una pantalla de bienvenida con su nombre.

Sin embargo, una cosa a tener en cuenta es que, independientemente del idioma que utilice, con el tiempo tendrá que hacer uso de los servicios del sistema operativo. Por ejemplo, para mostrar cosas en la pantalla, para administrar procesos, etc. La mayoría de los sistemas operativos tienen una API que también se puede llamar de una manera similar, pero sus contenidos no están incluidos en su EXE. Por ejemplo, cuando ejecuta su navegador, es ejecutable, pero en algún momento hay una llamada a la API de Windows para crear una ventana o cargar una fuente. Si esto fue parte de tu EXE, tu EXE sería enorme. Entonces, incluso en su ejecutable, hay "referencias faltantes". Por lo general, estos se tratan en tiempo de carga o tiempo de ejecución, dependiendo del sistema operativo.

+0

Muchas gracias. Entonces, solo para estar seguro, cuando tengo call para funcionar en la función principal, ¿el enlazador agrega salto a esa función y agrega esa función al final del archivo exe, o son las funciones ubicadas en diferentes partes del archivo exe, y que loader en realidad los conecta juntos? –

+0

Becouse en el ensamblador 8051, acabo de agregar rutinas al final del programa, y ​​por instrucciones de salto y retitulación ingresadas a ellas y regresé. Pero para usar el compilador de salto necesita conocer la dirección de la primera instrucción en la rutina. Pero cuando Windows carga el programa en la RAM, el compilador no puede saber cuál será la dirección de la primera instrucción de la rutina dada. –

+0

No estoy seguro de cómo funciona actualmente en Windows, pero el cargador generalmente hace mucho y puede reubicar cosas. Por ejemplo, en los viejos tiempos de MS DOS, solía haber un límite en el tamaño de los ejecutables, por lo que si tenía un montón de código adicional, se necesitaban trucos especiales para cargar y eliminar el código en tiempo de ejecución. – Uri

0

El compilador es responsable de traducir todas sus funciones escritas en C al conjunto, que guarda en el archivo del objeto (DLL o EXE, por ejemplo). Por lo tanto, si escribe un archivo .c que tiene una función principal y algunas otras funciones, el compilador las traducirá a ensamblado y las guardará juntas en el archivo EXE. Luego, cuando ejecuta el archivo, el cargador (que es parte del sistema operativo) sabe que primero debe ejecutar la función principal. De lo contrario, la función principal es como cualquier otra función para el compilador.

El vinculador es responsable de resolver cualquier referencia entre funciones y variables en un archivo de objeto con las referencias en otros archivos. Por ejemplo, si llama a printf(), ya que usted no define la función printf() usted mismo, el enlazador es responsable de asegurarse de que la llamada a printf() vaya a la biblioteca del sistema derecha donde se define printf(). Esto se hace en tiempo de compilación.

printf() se escribe en puro C. Lo que hace es llamar al sistema en el sistema operativo que sabe cómo enviar caracteres a la salida estándar (como un terminal de ventana). Cuando llama a printf() en su programa, en tiempo de compilación, el enlazador es responsable de vincular su llamada a la función printf() en las bibliotecas estándar de C. Cuando la función se pasa en tiempo de ejecución, printf() formatea los argumentos correctamente y luego llama a la llamada del sistema operativo apropiada para mostrar realmente los caracteres.

Cuestiones relacionadas