Ensamblaje, etc Patricia Borensztejn Organización del Computador 2 Segundo 2016 Programa Almacenado • • • • • La primera computadora digital de propósito general fue la compuadora ENIAC, construida en la Universidad de Pensilvania, Escuela de Ingeniería Eléctrica, USA. Contrato secreto firmado en 1943 entre la Escuela y el Ejército de EEUU. Sus diseñadores fueron John Mauchly y J. Presper Eckert, de dicha universidad. Era de propósito general porque era «programable», sin embargo, el programa que contenía las instrucciones no se almacenaba en memoria, sino que se introducía a mano, conectando y desconectando cables a las clavijas. Esta tarea, la realizaban las mujeres que programaron el ENIAC. Los datos si eran almacenados en tubos de vacío: solo podían almacenarse 20 números de 10 dígitos cada uno https://www.dc.uba.ar/Members/patricia/His torias%20 Programa Almacenado • Los diseñadores Mauchly y Eckert comprendieron que era necesario que las instrucciones estuvieran almacenadas pues la programación manual podía tardar varias semanas. (No había instrucciones para guardar el programa, no había unidad de control que las identificara..) • Pero la cuestión era justamente tecnológica: había que encontrar una tecnología idónea para la memoria de instrucciones. Solo había tubos de vacío! • En USA y GB suceden al mismo tiempo (1946) las siguientes dos cosas: – En Usa, Eckert inventa los líneas de retardo de mercurio, que sirven para implementar memoria. Y con ella diseñan EDVAC, el primer computador de programa almacenado – En GB, Turing diseña la ASE (Automatic Computing Engine) en el National Physical Laboratory. ASE era una computadora digital de proposito general y programa almacenado. Su primer prototipo fue conocido como The Baby y fue construido en la Universidad de Manchester por Williams, Kilburn y Tootill. Williams había inventado otra manera de contruir memorias basado en los rayos catódicos. • Sabia Usted que ….The Baby fue nada mas y nada menos que el ancestro de la Clementina, la que trajo Sadosky a la Argentina. Ferranti fue la empresa que comercializó el diseño de esta familia de computadoras Programa Almacenado • Por esas cosas de la vida, aunque fueron Mauchly y Eckert los que construyeron EDVAC , el que escribió el informe fue John von Neumann. • Ese informe dio origen a lo que hoy conocemos como arquitectura von Neumann Arquitectura llamada «Von Neumann» Arquitectura von Neumann • Caracterizada por: – Una Memoria donde se alojan tanto Datos como Instrucciones – Una Unidad de Control que las importa, decodifica e imparte las órdenes para su ejecución – Una Unidad de Proceso responsable de la ejecución – Una Unidad de Entrada / Salida conecta al exterior Entonces, los programas … • Deben estar en memoria para poder ser ejecutados • ¿Cómo se cargan en memoria? – Hay que copiarlos del disco o desde donde estén a la memoria principal • ¿Quién lo hace? – El sistema operativo, bajo demanda de alguien, que podemos ser, entre otros, nosotros • ¿Qué se carga en memoria? – Las instrucciones en lenguaje máquina del programa que el procesador va a ejecutar • ¿Cómo se generan las instrucciones en lenguaje máquina? Tipos de Archivos: .asm 16 bits en DOS nasm –l simdos.lst simdos.asm 1 org 100h 2 3 section .text 4 ;Aquí va el código 5 ;Cuando se hace int 21h se llama al sistema operativo, que ejecuta la función que indique AH 6 ;AH=9 imprime la cadena apuntada por DS:DX, terminada en "$" 7 ;AH=4Ch termina el programa, con código de salida AL 8 9 00000000 BA[0000] mov dx,cadena 10 00000003 B409 mov ah,9 11 00000005 CD21 int 21h 12 13 00000007 B8004C mov ax,0x4C00 14 0000000A CD21 int 21h 15 16 section .data 17 ;Aqui los datos inicializados 18 ;los caracteres 10 y 13 significan retorno de línea en MS-DOS. 19 00000000 5175E920706173612Ccadena DB "Qué pasa, mundo",13,10,"$" 19 00000009 206D756E646F0D0A24 20 21 section .bss 22 ;Y aqui los datos no inicializados, si los hubiera nasm –l simdos.asm • Hay dos secciones y las dos comienzan en la dirección 0 • Sección Código: todo en hexadecimal dirección Instrucción en LM 00000000 00000003 00000005 00000007 0000000 A BA[0000] B409 CD21 B8004C CD21 Instrucción en LE mov dx,cadena mov ah,9 int 21h mov ax,0x4C00 int 21h Formato de Instrucción Formato de Instrucción • Instrucción MOV DX, offset16 – Codificada asi: B8+rw: B8 + 010= BA – DX se codifica como 010 ( w=1, bit 3) – Offset: pone 0000 pues las direcciones son relativas a cero, cadena esta en la dirección cero del segmento de datos. B8+ rw MOV r16,imm16 Move imm16 to r16. Formato de Instrucción • Instrucción MOV ah, 9 – Codificada asi: B0+rb: B0 + 0100= B4 – Offset: pone 09 pues es un inmediato de 8 bits – Registro AH se codifica con 100 y w=0 (bit3) B0+ rb MOV r8,imm8 Move imm8 to r8. Formato de Instrucción • INT 21: CD 21 Formato de Instrucción • Instrucción MOV AX, 0x4C00 – Codificada asi: B8+rw: B8 + 1000= B8 – Offset: pone 4C00 pues es un inmediato de 16 bits – Registro AX se codifica con 000 y w=1 (bit3) B8+ rw MOV r16,imm16 Move imm16 to r16. Datos • La sección de datos contiene la cadena : "Qué pasa, mundo",13,10,"$ y la vemos de esta manera: 51 75 E9 20 70 61 73 61 2C 20 6D 75 6E 64 6F 0D 0A 24 Donde: 20 es el carácter ASCII espacio 2C es la coma etc Nasm simdos.asm –o sim2.com • Ese comando crea un ejecutable: sim2.com Lo miramos usando un editor hexa Direcciones Absolutas • Todo coincide con el archivo lst menos … • La dirección del string cadena que ha sido reemplazado por la dirección 0c 01. (010c) • Esto es porque el binario comienza en la dirección 0100. Ese es el motivo de la directiva org 100. Ejecutables .COM • El cargador de DOS ubica la imagen exacta del binario a partir de la dirección 0100 (hexa) • Desde la dirección 0000 a la 00FF hay una estructura de datos que construye el SO y que se llamaba PSP. Entre otros parámetros, esta la línea de comando con sus parámetros del ejecutable. • El siguiente código muestra los parámetros de la línea de comando: org 100h ; INT 21h subfunction 9 requires '$' to terminate string xor bx, bx mov bl, [80h] cmp bl, 126 ja exit mov byte [bx + 81h], '$' ; print the string mov ah, 9 mov dx, 81h int 21h exit: mov ax, 4C00h int 21h Archivo ejecutable • Nasm ha generado un ejecutable, pero si lo intento ejecutar en la ventana de comando no me lo permite Archivos .COM • Es un archivo ejecutable, que solo puede ser ejecutado en un emulador de DOS, el antiguo sistema operativo de 16 bits. • En esa época, los segmentos eran máximo de 64kbytes, y es así que un archivo .com es un ejecutable que no ocupa mas de 64kbytes. • Lo ejecutamos en una DOS-BOX (emulador de DOS) DOSBox DOSBox Lenguajes Máquina • Un programa ejecutable es una secuencia de 1´s y 0´s. Es un archivo binario • Cada máquina o arquitectura tiene su propio conjunto de instrucciones con su propia codificación binaria. (ver formato de instrucción) • Si dos máquinas distintas aceptan el mismo archivo binario para ejecutarse, entonces son compatibles binarias. Lenguaje Ensamblador • Puede haber varios lenguajes ensambladores para una misma arquitectura, pero todos ellos deben generar el mismo lenguaje máquina. AT&T: push %ebp sub $0x8,%esp movb $0x41,0xffffffff(%ebp) Intel: push ebp sub esp, 0x8h movb 0xffffffff(ebp), 0x41h Código generado (cygwin y gcc) .file "holamundo.c" .def __main; .endef .section .rdata,"dr" .scl 2; .type 32; .scl 2; .type 32; "GCC: (GNU) 5.4.0" printf; .scl 2; .type 32; .LC0: .ascii "Hola mundo\0" .text .globl main .def main; .endef .seh_proc main #include <stdio.h> int main() { printf("Hola mundo"); return 0; main: pushq .seh_pushreg movq .seh_setframe subq .seh_stackalloc .seh_endprologue call leaq call movl addq popq ret .seh_endproc .ident .def .endef %rbp %rbp %rsp, %rbp %rbp, 0 $32, %rsp 32 __main .LC0(%rip), %rcx printf $0, %eax $32, %rsp %rbp Muchos ensambladores x86 High Level Assembler • Desarrollado por Randall Hyde • Es bueno : Speed. Assembly language programs are generally the fastest programs around. Space. Assembly language programs are often the smallest. Capability. You can do things in assembly which are difficult or impossible in HLLs. Knowledge. Your knowledge of assembly language will help you write better programs even when using HLLs. • Es malo: Assembly is hard to learn. Assembly is hard to read and understand. Assembly is hard to debug. Assembly is hard to maintain. Assembly is hard to write. Assembly language programming is time consuming. Improved compiler technology has eliminated the need for assembly language. Today machines are so fast that we no longer need to use assembly. If you need more speed you should use a better algorithm rather than switch to assembly language. Machines have so much memory today saving space using assembly is not important. Assembly language is not portable. program HelloWorld; #include("stdlib.hhf") begin HelloWorld; stdout.put( "Hello World" nl ) end HelloWorld; HLA • http://www.oopweb.com/Assembly/Documen ts/ArtOfAssembly/VolumeFrames.html • https://sourceforge.net/projects/hlav1/ • Desarrollado por Randall Hyde • The High Level Assembler (HLA) is a 32-bit 80x86 assembly language that is portable between Win32, Linux, and FreeBSD Proceso para generar un ejecutable Ensamblar, Compilar, Linkeditar, Cargar • Preprocesar : Es el primer paso de la compilación en C. Procesa includes, instrucciones condicionales y macros • Ensamblar Lo mismo que Compilación pero partiendo de un fuente escrito en ensamblador • Compilar Produce código objeto , traduce instrucciones a lenguaje máquina, ubia datos. Deja direcciones sin resolver. Construye tabla de símbolos y un tabla de reubicación para el siguiente paso • Linkeditar Une uno o mas objetos y los combina para formar el ejecutable. Resuelve referencias entre módulos. Asigna direcciones a variables y funciones: este proceso se llama reubicación. • Cargar carga del ejecutable en memoria Compilación, Linkedición y Carga Compilación • Muchos compiladores actuales aplican optimizaciones de código, que van desde sencillas , como eliminación de subespresiones comunces: – x = cos(v)*(1+sin(u/2)) + sin(w)*(1-sin(u/2)) – Reemplaza por: • t = sin(u/2) • x = cos(v)*(1+t) + sin(w)*(1-t) • A optimizaciónes bastante mas complejas como loop unrolling (desenrolle de bucles), software pipelining o incluso planificación de instrucciones que altera su orden en el código fuente. • Las optimizaciones merecen ser estudiadas antes de hacer que el compilador las introduzca. Los parámetros –o1, -o2, o3… indican que optimizaciones introducirá el compilador Compilación: de fuente a código objeto • Cuando el compilador termina su trabajo, obtiene un código objeto, puede ser un código en ensamblador o no. Hay opciones para generarlo (-S). • El código binario resultante llamado normalmente código objeto tiene algunas posiciones de memoria no definidas totalmente: si yo especifico el modo directo para acceder a una variable, el offset es relativo al segmento de datos definido en el archivo compilado. Seguramente mi código tendrá también referencias a funciones externas que el compilador no conoce. • O sea que hay referencias que se resuelven en tiempo de compilación, y otras quedan pendientes para el siguiente proceso. Programas Objeto • Son archivos que contienen información sobre símbolos y direcciones que no pudo resolver el ensamblador o compilador. Enlazar, Linkeditar. Linker • El linker (ld, ln o gcc) toma uno o mas archivos objeto y los combina, resultando en un archivo ejecutable con un único segmento de código, datos, pila, etc. • Al hacer esto, resuelve algunas referencias que el compilador no pudo resolver pues eran externas. • Genera un ejecutable listo para ser cargado en memoria por el sistema operativo. Linkedición • Para poder unir todos los´objetos, dentro de ellos hay estructuras de datos tales como tablas de símbolos y tablas de reubicación Linkedición: un proceso complejo • $ ld -dynamic-linker /lib/ld-linux.so.2 \ /usr/lib/crt1.o \ /usr/lib/crti.o \ /usr/lib/gcc/i486-linux-gnu/4.3/crtbegin.o \ L/usr/lib/gcc/i486-linux-gnu/4.3 hola.o \ -lgcc -lgcc_eh \ -lc /usr/lib/gcc/i486-linuxgnu/4.3/crtend.o \ /usr/lib/crtn.o • $ gcc hola.o Comando nm • Te permite ver la Tabla de Símbolos… • nm a.out: – T indica definida en el archivo objeto. La dirección es el offset donde está. Librerías: ¿printf? • Varios programas ejecutando en un sistema pueden requerir las mismas funciones standard como printf(), malloc(), strcpy(), etc o otras • Si cada programa usa la librería standard por ejemplo, entonces tiene que contener una copia de ella en su imagen. Y esto ocupa bastante espacio y degrada el rendimiento • Es mejor tener a cada programa referenciando una sola instancia de la librería. • Esto se llama compartir objetos. • This is implemented during the linking process where some of the objects are linked during the link time whereas some done during the run time (deferred/dynamic linking). Librerías Estáticas y Dinámicas • Librerías Estáticas: – El término ‘statically linked’ significa que el programa y su librería se enlazan juntas en tiempo de linkedición – Las librerías de objetos que se enlazan estáticamente tipicamente tienen la extensión .a – libc.a es la librería standard de objetos en C • Librerías Dinámicas: – Se enlazan en tiempo de ejecución con su referencia. – Se pueden compartir entre distintos programas ejecutándose (procesos ) – El linkeditor debe almacenar en el ejecutable las ubicaciones de estas librerías externas. – Libc.o es la librería de objetos en C ¿Como verlas? • En linux: $ gcc -Wall hola.c $ ldd a.out libc.so.6 => /lib/libc.so.6 (0x40020000) /lib/ldlinux.so.2 => /lib/ld-linux.so.2 (0x40000000) Ejecutables • Son archivos binarios • Según el SO pueden tener extensiones – Windows: .exe, .com, .dll – Unix/linux: no tienen. Podemos averiguar que son con el comando file Ejecutables • Cada Sistema Operativo tiene su propio formato para ejecutables. • Por ejemplo, ELF es el formato de linux. Y PE (Portable Executable) es de windows hoy. Windows usa la extensión .exe. Linux ninguna extensión. • Todos los ejecutables, además de las secciones propiamente del programa, contienen mas datos para su carga en memoria. Carga de programas • El cargador es una herramienta del Sistema Operativo • El proceso de cargar en memoria un programa conlleva varios pasos: 1. 2. 3. 4. 5. 6. 7. Leer la cabecera del ejecutable para determinar el tamaño de sus segmentos de texto y datos y pila Crear un espacio de direcciones para el programa (memoria virtual?? No lo carga todo) Copiar instrucciones y datos del archivo a su espacio de memoria (ojo! Copia de disco a memoria RAM) También pone en el stack los argumentos del programa Inicializa los registros del procesador, y se le asigna al SP la dirección del tope de la pila Da control a una rutina de inicialización que copia argumentos del programa de la pila a los registros y que invoca al main Cuando finaliza la ejecución, el programa de inicialización devuelve control al Sistema Operativo Resumen • Cada máquina tiene su propio lenguaje máquina • Cada ensamblador/compilador entiende su propio lenguaje fuente y genera el programa objeto para la máquina donde se va a ejecutar. • Cada Sistema Operativo tiene su propio formato de ejecutable • Cualquier mala combinación de esas cosas, da: sementation fault. Por ejemplo, querer ejecutar un elf bajo windows o un PE bajo linux Resumen • Compatibilidad binaria, es cuando ejecutamos un programa compilado en otra máquina y … no da error!!! • Un programa puede ejecutar en una máquina sin error, pero …. no devolver los resultados esperados…. • Errores: – – – – – Sintácticos: tiempo de compilación o ensamblaje De librerías inexistentes: tiempo de linkedición De incompatibilidad binaria: tiempo de ejecución De lógica del programa: tiempo de ejecución De acceso a zonas prohibidas: (puntero con valor cero): tiempo de ejecución