510 likes | 638 Views
Traduciendo y ejecutando programas. El camino de un programa en C. Compilador. Compilador Traduce de lenguaje C a lenguaje ensamblador. Hola Mundo en C. # include <stdio.h> void main () { printf ("Hola mundo<br>"); }. Ensamblador (BCC55). ifdef ??version if ??version GT 500H
E N D
El camino de un programa en C Arquitectura de Computadoras
Compilador • Compilador • Traduce de lenguaje C a lenguaje ensamblador. Arquitectura de Computadoras
Hola Mundo en C # include <stdio.h> void main () { printf ("Hola mundo\n"); } Arquitectura de Computadoras
Ensamblador (BCC55) ifdef ??version if ??version GT 500H .mmx endif endif model flat ifndef ??version ?debug macro endm endif ?debug S "hola_mundo.c" ?debug T "hola_mundo.c" _TEXT segment dword public use32 'CODE' _TEXT ends _DATA segment dword public use32 'DATA' _DATA ends _BSS segment dword public use32 'BSS' _BSS ends DGROUP group _BSS,_DATA Arquitectura de Computadoras
Ensamblador (BCC55) _TEXT segment dword public use32 'CODE' _main proc near ?live1@0: ; ; void main () ; push ebp mov ebp,esp ; ; { ; printf ("Hola mundo\n"); ; @1: push offset s@ call _printf pop ecx ; ; } ; @2: pop ebp ret _main endp _TEXT ends Arquitectura de Computadoras
Ensamblador (BCC55) _DATA segment dword public use32 'DATA' s@ label byte ; s@+0: db "Hola mundo",10,0 align 4 _DATA ends _TEXT segment dword public use32 'CODE' _TEXT ends public _main extrn _printf:near ?debug D "c:\Borland\BCC55\Include\_nfile.h" 10459 6176 ?debug D "c:\Borland\BCC55\Include\_null.h" 10459 6176 ?debug D "c:\Borland\BCC55\Include\_defs.h" 10459 6176 ?debug D "c:\Borland\BCC55\Include\_stddef.h" 10459 6176 ?debug D "c:\Borland\BCC55\Include\stdio.h" 10459 6176 ?debug D "hola_mundo.c" 14910 22993 end Arquitectura de Computadoras
Programa Ensamblador • Acepta un programa en lenguaje ensamblador y genera un archivo objeto. • El archivo objeto contiene: • Instrucciones en lenguaje de máquina. • Datos. • Información necesaria para cargar el programa en memoria. Arquitectura de Computadoras
Típico OBJ de Unix • Encabezado. Describe el tamaño y posición de otras secciones del archivo objeto. • Segmento de texto. Contiene el código en lenguaje máquina. • Segmento de datos estáticos. Variables accesibles durante todo el programa (globales y variables static de C). • Información de relocalización. Identifica instrucciones que dependen de direcciones absolutas. Arquitectura de Computadoras
Típico OBJ de Unix • Tabla de símbolos. Etiquetas que no han sido definidas como variables externas. • Información útil para un debugger. Permite asociar instrucciones de máquina con líneas del código fuente original. Arquitectura de Computadoras
Microsoft COFF • Common Object File Format. • Inicialmente definido para Unix V, fue extendido por Microsoft para Windows 3.1. • Se usa en todas las versiones de Windows de 32 y 64 bits. Arquitectura de Computadoras
Encabezado Encabezados de sección Código Datos Información para relocalizar Información para depuración Microsoft COFF Arquitectura de Computadoras
Linker • Pega (link) varios archivos objeto compilados posiblemente por separado. • Resuelve referencias externas e internas. • En algunos sistemas como Windows, el linker relocaliza el código. • Produce un solo archivo ejecutable. Arquitectura de Computadoras
Relocalización • Ensamblador bne $t0, $t1, brinco ; if t0 != t1 goto brinco … brinco: etc. • Lenguaje máquina 1000 bne $8, $9, 1020 … 1020 etc. Arquitectura de Computadoras
Relocalización • La instrucción 1000 bne $8, $9, 1020 está asumiendo que va ser cargada en la dirección 1000. • Los sistemas operativos modernos (multiusuario y/o multitarea) cargan en memoria varios programas a la vez y pueden ser colocados en áreas distintas cada vez que corren. Arquitectura de Computadoras
Relocalización • La solución (para este caso) es hacer el brinco relativo. 1000 bne $8, $9, +20 • En general, hay que guardar información sobre dependencias en el código. Arquitectura de Computadoras
Ejemplo – archivo objeto A Arquitectura de Computadoras
Ejemplo – archivo objeto B Arquitectura de Computadoras
Ejemplo - relocalizando • El procedimiento A necesita encontrar la dirección de la variable X y del procedimiento B. • El procedimiento B necesita encontrar la dirección de la variable Y y del procedimiento A. • En MIPS, el segmento de texto comienza en la dirección 400,00016. • A se carga a partir de 400,00016 y como el código de A mide 10016, B se carga a partir de 400,10016. Arquitectura de Computadoras
Ejemplo - relocalizando • El segmento de datos comienza en la dirección 10,000,00016. • Los datos de A se cargan en 10,000,00016 y como miden 2016, los datos de B se cargan en 10,000,02016. • El registro $gp se inicializa en 10,008,00016. • Los datos de A se accesan con $gp – 8,00016. • Los datos de B se accesan con $gp – 7,98016. • Con esta información, el linker puede relocalizar el código y generar un archivo ejecutable. Arquitectura de Computadoras
Ejemplo - ejecutable Arquitectura de Computadoras
Referencias externas • Se generan al compilar archivos por separado. • Archivo “hola.c” void foo (void); // prototipo void main () { foo (); // referencia externa } Arquitectura de Computadoras
Referencias externas • Archivo “mundo.c” #include <stdio.h> void foo () { printf ("hola mundo\n"); } Arquitectura de Computadoras
Referencias externas Compilación usando Borland C 5.5 • bcc32 –c hola.c Compila sin ligar y genera hola.obj • bcc32 –c mundo.c Compila sin ligar y genera mundo.obj • bcc32 hola.obj mundo.obj Invoca al linker y genera hola.exe Arquitectura de Computadoras
Archivos ejecutables • Definición del Merriam-Webster: Archivo que hace que una computadora “realice tareas de acuerdo a instrucciones codificadas.” • Formatos más comunes: • a.out (Unix) • .com (CP/M y MS-DOS) • .exe (MS-DOS y Windows) formalmente llamado PE (Portable executable). Arquitectura de Computadoras
Microsoft PE • Portable Executable. • Formato: • Encabezado EXE de MS-DOS (por compatibilidad). • Mini-programa MS-DOS: “This program cannot be run in DOS mode”. • Encabezado PE. • Encabezados de las secciones. • Sección .text: código. • Sección .data: datos estáticos. Arquitectura de Computadoras
Microsoft PE • Sección .edata: tabla de símbolos exportados (usado por DLLs). • Sección .idata: tabla de símbolos importados. • Sección .rdata: datos de solo lectura (constantes y strings). • Sección .tls: variables globales que pueden ser accesadas como variables locales por hilos (threads). • Sección .rsrc: recursos como menús y diálogos. • Sección .reloc: información de relocalización. Arquitectura de Computadoras
Microsoft PE Arquitectura de Computadoras
Cargadores • Conocidos en inglés como “loaders”. • Carga el programa ejecutable en la memoria y le cede el control. • En algunos sistemas operativos como MS-DOS el cargador es el que relocaliza el código. Arquitectura de Computadoras
Cargador típico de Unix • Lee el ejecutable y determina el tamaño de los segmentos de texto y datos. • Crea un espacio de direcciones suficientemente grande para el texto y los datos. • Copia las instrucciones y datos a la memoria. • Copia los parámetros del programa principal (si es que existen) en la pila. Arquitectura de Computadoras
Cargador típico de Unix • Inicializa los registros incluyendo el apuntador a la pila (sp). • Brinca a una rutina de start-up que copia los parámetros en los registros y llama a la rutina principal. • Cuando la rutina principal regresa, la rutina de start-up termina el programa con una llamada al sistema de exit. Arquitectura de Computadoras
Resumen • Compilador. Traduce el programa a lenguaje ensamblador. • Ensamblador. Genera un archivo objeto por cada archivo en ensamblador. • Linker. Resuelve referencias, relocaliza y genera un ejecutable. • Cargador. Carga el ejecutable en memoria y lo corre. • El compilador típico incluye los 3 primeros pasos. • El cargador es parte del sistema operativo. Arquitectura de Computadoras
Camino de un programa en Java Arquitectura de Computadoras
Compilador • El compilador de Java genera un archivo class por cada clase compilada. • El archivo class contiene: • Tabla de métodos válidos con sus bytecodes. • Información extra, como la clase padre. • Los bytecodes son las instrucciones de la máquina virtual de Java (JVM) y son independientes del hardware. • “Compila una vez, corre donde sea” (compile once, run anywhere). Arquitectura de Computadoras
JVM • La máquina virtual de Java interpreta y ejecuta los bytecodes. • Algunas JVMs incluyen un compilador JIT (just-in-time) que compila los bytecodes a código máquina conforme el programa está corriendo. Arquitectura de Computadoras
Explicación • Algunos mnemónicos usan un prefijo: • a – dirección. • b – byte (8 bits). • i – entero (32 bits). • s – short (16 bits). • I8 es una constante de 8 bits. • I16 es una constante de 16 bits. Arquitectura de Computadoras
Explicación • La JVM usa una pila para guardar resultados intermedios. • Los operandos se guardan en la pila, se hace la operación y se sacan. • El compilador sabe el tamaño máximo de la pila de operandos para cada método y le asigna espacio en el frame actual. Arquitectura de Computadoras
Explicación • TOS = tope de la pila. • NOS = siguiente posición debajo del TOS. • NNOS = siguiente posición debajo del NOS. • pop. Quita el TOS. • pop2. Quita el TOS y el NOS. • push. Agrega un elemento a la pila. • Const[] se refiere al pool de constantes de la clase creado por la JVM al momento de correr. • Frame[] a las variables en el frame local del método. Arquitectura de Computadoras
Diferencias entre JVM y MIPS • Para guardar resultados temporales: MIPS usa registros, JVM una pila. • Tamaño de instrucción: MIPS 4 bytes, JVM de 1 a 5 bytes para ahorrar espacio. • JVM tiene seguridad integrada. Por ejemplo, en un arreglo, la JVM checa que la referencia al arreglo sea válida y que el índice esté dentro del límite. Arquitectura de Computadoras
Diferencias entre JVM y MIPS • Para que el recolector de basura encuentre los apuntadores “vivos”, JVM tiene instrucciones distintas para operar con direcciones y para operar con enteros. • JVM tiene instrucciones complejas como crear espacio para un arreglo o invocar un método. Arquitectura de Computadoras
Comparación entre JVM y MIPS • Compilar el siguiente código en C/Java a MIPS y JVM: while (save[i] == k) i += 1; Arquitectura de Computadoras
MIPS ; s3 = i, s5 = k, s6 = dirección de save ciclo: sll $t1, $s3, 2 ; t1 = i * 4 / t1 = tiene el offset add $t1, $t1, $s6 ; t1 apunta a save[i] lw $t0, 0($t1) ; t0 = save[i] bne $t0, $s5, Exit ; if save[i] k goto Exit add $s3, $s3, 1 ; i++ j ciclo ; goto ciclo Exit: Arquitectura de Computadoras
JVM ; i, k y save son las primeras tres variables locales. 0 aload_3 ; push variable local 3 (save) 1 iload_1 ; push variable local 1 (i) 2 iaload ; pop TOS y NTOS y push save[i] 3 iload_2 ; push variable local 2 (k) 4 if_icompne, Exit ; compara TOS y NTOS, los saca y; brinca si no son iguales 7 iinc, 1, 1 ; i++ 10 go to 0 ; brinca al inicio (byte 0) Arquitectura de Computadoras
Comparación entre JVM y MIPS • MIPS: 6 instrucciones, 24 bytes. • JVM: 7 instrucciones, 13 bytes. • La diferencia es mayor si tomamos en cuenta que la JVM checa automáticamente que los accesos al arreglo estén dentro del rango. • Ciclo while modificado en MIPS para checar rangos ocupa 11 instrucciones, es decir, 44 bytes. Arquitectura de Computadoras
Ciclo while en MIPS ; s3 = i, s5 = k, s6 = dirección de save ; s6 apunta a la lista de métodos legales para save ; s6 + 4 apunta al tamaño del arreglo ; s6 + 8 apunta a save[0] (primer elemento) lw $t2, 4($s6) ; t2 = tamaño del arreglo ciclo: slt $t0, $s3, 0 ; if i < 0 bne $t0, $zero, IndexOutOfBounds ; goto Error slt $t0, $s3, $t2 ; if i tamaño beq $t0, $zero, IndexOutOfBounds ; goto Error Arquitectura de Computadoras
Ciclo while en MIPS sll $t1, $s3, 2 ; t1 = i * 4 / t1 = tiene el offset add $t1, $t1, $s6 ; t1 apunta a save[i] lw $t0, 8($t1) ; t0 = save[i] bne $t0, $s5, Exit ; if save[i] k goto Exit add $s3, $s3, 1 ; i++ j ciclo ; goto ciclo Exit: Arquitectura de Computadoras
Invocando métodos en Java • El compilador escoge el método apropiado dependiendo del tipo (clase) del objeto. • El compilador genera código para: • Revisar que objeto no sea nulo, y en su caso brincar a una rutina de error. • Cargar la lista de métodos válidos para ese objeto. La primera palabra guarda un apuntador a esa tabla. • Cargar la dirección del método apropiado, dejando la dirección de regreso en la pila. • Brincar al inicio del método. Arquitectura de Computadoras
Compilado vs. Interpretado • Ventaja de un programa interpretado: portabilidad. • Ventaja de un programa compilado: rapidez de ejecución. • Los compiladores JIT tratan de reducir esa ventaja. Arquitectura de Computadoras
Compilado vs. Interpretado Arquitectura de Computadoras