Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

“Los 8 Jinetes del Apocalipsis”

La primera vez que alguien intentó explicarme lo que eran los registros internos de un procesador me dijeron algo así como –”los registros de procesador son los caballitos de batalla del procesador”– Esto para mi no tiene sentido ni aún ahora que llevo tantos años programando en Ensamblador. La mejor definición que encontré entonces fue que los registros del CPU son “Variables de Hardware”, pero cuando avancé en ensamblador, encontré que el término ‘variable’ como se ve en matemáticas no tiene sentido en el mundo de la computación. El concepto de registro de procesador está mas bien relacionado con el concepto de celda de memoria.

Los registros generales del cpu de intel son 8. Sus nombres son EAX, ECX,EDX,EBX,ESP,EBP,ESI Y EDI. Existen otros registros con otras funciones, pero los mas importantes son estos 8. Estos pertenecen a una misma unidad llamada ALU(Arithmetic-Logic Unit, Unidad de Aritmética y Lógica). Estos registros son semejantes a las bien conocidas celdas de memoria de byte. Solo que mas grandes. Pues pueden almacenar hasta 32 bits. U 8 cifras hexadecimales que como sabemos representan 4 bits cada una. Sin embargo, estos registros nacieron con el 8086 y han evolucionado junto con este. En sus inicios medían solo 16 bits y tenían funciones muy específicas. Pero lo mejor es presentar a cada uno de estos Jinetes del Apocalipsis en detalle:

EAX.- Este es el registro que mas veremos en acción. También es conocido como el Acumulador. Una de sus habilidades mas importantes es regresarnos el resultado de una función en la mayoría de los sistemas operativos. Operaciones de multiplicación y división de enteros y comunicación con los registros de estado como EFLAGS.Puede dividir sus 16 bits mas bajos en un par de 8 pequeñas celdas de 8 bits llamadas AH y AL. Esto para manejar datos de 8 bits. Esta capacidad también la comparten los registros ECX, EDX, y EBX. En su, epoca de 16 bits era conocido como AX (se escribe igual que ‘hacha’ en inglés) y en los CPU’s de 64 bits es conocido como RAX.

ECX.- Este registro es conocido como el contador. Cuando hacemos un proceso cíclico. (Como desplegar todos los elementos de la tabla del uno) Este registro se encarga de contar las iteraciones y detener la repetición cuando queda vacío. Algunas de las instrucciones que dependen directamente de este registro son LOOP, JECXZ, LODS,STOS,CMPS,SCAS,etc. Puede manejar independientemente sus 16 bits mas bajos en los subregistros CH (el del Chapulín Colorado) y CL. El pasado era CX y el de 64 es RCX.

EDX.- Este es el especializado en DATOS. Si EAX es nuestra mano derecha, EDX es nuestra mano izquierda. (O al revés para quienes sean zurdos). Si necesitamos sumar dos números lo mas seguro es que en el acumulador se guarde el resultado y en EDX el valor a sumar. Otra de sus gracias es comunicarse con el mundo exterior por medio de las instrucciones IN, OUT, INS y OUTS. En estas instrucciones podemos leer datos que vienen de dispositivos periféricos. El acumulador guarda los datos a entrar o salir mientras que EDX indica por cual de las puertas han de hacerlo. También puede manejar sus 16 bits mas bajos de manera independiente con los subregistros DH y DL.

EBX.- Conocido como Registro BASE. Una de sus propiedades que lo distinguió en sus primeros días era que tenía la capacidad apuntar a la memoria. Esto significa que si por ejemplo EBX contiene 1234ABCD podemos leer y escribir en la celda de memoria en la posición 1234ABCD del sistema. Esta propiedad podía usarse sola o en combinación con ESI, EDI y valores constantes. De modo que podía intercambiar datos entre el CPU e intrincadas estructuras de datos sin problemas. Sin embargo. Esta habilidad que era exclusiva de EBX, ESI y EDI. (Y en menor grado de ESP Y EBP) ahora es común a TODOS los registros generales. Al igual que los anteriores. También puede manejar los 16 bits mas bajos en la forma de BH y BL.

ESP.- Su nombre es Stack Pointer. Este registro, junto con su hermano EBP, son los responsables del control de una importante estructura de datos llamada STACK. La explicación de lo que es una stack merece su propia entrada independiente. Por ahora solo basta decir que el stack es una estructura en memoria que sirve entre otras cosas para manejar variables locales, el correcto flujo de ejecución, paso de argumentos a las funciones y temas espantalamers como el de la mentada recursión. (se dice que ha habido ingenieros en computación que han hecho tesis doctorales sobre este tema.). ESP nos permite manejar las variables locales de manera directa en la stack.

EBP.- Esta es la contraparte de ESP. Se le conoce como Base Pointer. Se podriá decir que si ESP se encarga de lo que pasa dentro del Stack. EBP cuida la puerta. Pues su responsabilidad es el Stack Frame.(el espacio dentro del stack que permite el manejo de variables locales). Cuando veamos como llamar a una función que use argumentos, variables locales y recursión veremos al par ESP y EBP en plena acción. Aunque a diferencia de los registros anteriores. No pueden subdividir sus 16 bits mas bajos en otros mas pequeños.

ESI.- Existe otra pareja de registros que trabajan juntos. Y ESI es uno de ellos. Su nombre completo es Source Index. Al comienzo ESI era uno de los pocos que podían usarse como índice para posicionarse dentro de la memoria. Existen operaciones que por ejemplo mueven grandes cantidades de datos de un lugar a otro de la memoria. Se llama MOVS. Y en ella, la función de ESI es apuntar al byte que será leído.

EDI.- El hermano del anterior. En instrucciones de movimiento o escritura automática de celdas de memoria. EDI apunta a la celda donde se ha de escribir. Ni ESI ni EDI pueden dividir sus 16 bits mas bajos.

Pues estos son los 8 registros principales de un CPU de Intel trabajando a 32 bits. Cuando la máquina opera a 64 bits, los registros son capaces de almacenar valores de 64 bits y sus nombres cambian a RAX, RCX,RDX, RBX, RSP, RBP(no confundir con RBD), RSI, RDI. Y aparecen otros 8 registros ‘escuderos’ cuyos nombres son R8, R9, R10, R11, R12(como la mascota de los rayados de monterrey), R13, R14, R15. Los registros numerados no tienen ninguna habilidad especial hasta donde yo se. En otra nota hablaré mas detenidamente sobre el modo de 64 bits.

He aquí algunas notas sobre los Registros Generales.

*Son llamados General Registers, porque son los que van al frente en casi todas ‘las batallas’

*Intel se refiere a estos registros como REGS. Cuando en los manuales vean REGS se refieren a cualquiera de estos registros.

*Originalmente estos registros medían 16 bits, de modo que eran capaces de dividirse en 2 mitades. De modo que si escribíamos el hexadecimal 1234 en el AX, AH contenía 12 y AL 34. Sin embargo, con el tiempo estos registros evolucionaron a los 32 y 64 bits y la parte capaz de dividirse se quedó de 16 bits de tamaño. Para entenderlo mejor, podríamos decir que 1os 16 bits son la ‘cola’ del registro. (Nota para los programadores de Colombia: Aquí la palabra cola se refiere al apéndice que les cuelga a animales como los perros, gatos, etc). Dicho de otro modo, la cola forma parte del gato pero este puede mover la cola como el quiera. O como diríamos en México: Cada quien hace de sus 16 bits mas bajos un papalote y los direcciona con los datos que mejor le convengan.

*Existe una cosa llamada ‘prefijos’ que permiten usar registros de arquitecturas diferentes en un mismo código. Por ejemplo usar registros de 16 bits en programas de 32 y viceversa. Pero esto además de que resta mucha velocidad al código puede ser muy peligroso.

*El movimiento de datos entre la memoria y el CPU es mucho mas rápido si el dato se encuentra en una posición divisible entre la longitud del registro que hace la transferencia. Por ejemplo. Un registro de 32 bits debe de leer datos en posiciones divisibles entre 4.

*Los registros del CPU son mas parecidos a manos. Puedes mover datos entre registro y memoria y entre registros. Pero los datos no pueden moverse solos de una localidad de memoria a otra. Al menos no sin la ayuda de instrucciones como MOVS, Funciones de sistema como FillMemory o el controvertido dispositivo de hardware conocido como DMA. (Direct Memory Access)

*Por último, a diferencia de las variables, los Registros Generales siempre están ahí. Sin importar que programa corra. Porque no ‘viven’ en la memoria, sino que son parte del CPU. En aplicaciones multitarea guardan su contenido en memoria y toman el de la siguiente aplicación del mismo modo como los actores de teatro cambian de vestuario entre una escena y otra para representar personajes diferentes. Esto último va para esos lamercillos de java que creen que los registros del CPU no poseen la propiedad de encapsulamiento.

Pues eso es todo por hoy, espero que el dibujo que acompaña a esta entrada les explique mejor el concepto de lo que son los Registros Generales REGS.

Anuncios

enero 7, 2009 - Posted by | Uncategorized | , ,

6 comentarios »

  1. encontre esta pagina buscando info acerca de los registros.
    y parece que tienes una pag muy completa.
    este semestre estoy llevando lenguaje ensamblador,
    ahora estoy haciendo un programa que te diga que numeros son primos dentro de un arreglo,bastante dificil en comparacion a un lenguaje de alto nivel.
    ahora ya me aclare unas dudas.
    muy buena pagina. la estare siguiendo

    Comentario por pablo juarez | noviembre 23, 2009 | Responder

    • La manera mas sencilla que se me ocurre de identificar que valores son primos en un arreglo es precalcular una lista de numeros primos entre uno y el mayor valor del arreglo. Luego ya calculada esta secuencia intentas dividir cada uno de los elementos del arreglo por cada uno de esa lista de numeros primos. Si el valor a evaluar no tiene residuo entero entonces es primo.

      Aunque una optimizacion mas o menos cochina es comparar cada numero del arreglo con la lista precalculada de numeros primos. Si usas una tabla de boleanos donde el valor a evaluar se usa como indice tendrias un algoritmo sumamente rapido. Prueba con las instrucciones XLAT y TEST y SET.

      Comentario por asm86 | noviembre 23, 2009 | Responder

    • Esto me sono como
      “porfavor hazme la tarea mario sino el sensei me va a mandar a segunda oportunidad y mis papas no me van a dar mi domingo”
      Ahorita estas en el nivel Lamer Fase Dependo de los demas.

      De seguro pensaras, ya no me hicieron la tarea estos (@b#0n35!

      Ahorita tienes un problema peor que el que te encargaron –> el que te estas conviertiendo en lamer.

      Pero, no te preocupes por cochinadas(uik uik) no me aguante las ganas en dejarte la SOLUCION para salir de lamer y al MISMO TIEMPO saques tu tarea.

      Checa lo siguiente:

      La verdad el tema es interesante, para un seccion titulada :”Los problemas matematicos para programadores que no tienen idea de las matematicas”
      Esto es un poco curioso, como hay problemas matematicos que en la historia(googlea euler, gauss, etc) han tratado de resolver fisicos-matematicos, se lo den a jovenes entusiastas que desean aprender programacion pero que no tienen idea de las matematicas. Esto me di cuenta una vez que entre en un concurso de programacion que organizo la facultad, yo dije todos me la van a pelar, al llegar nos dieron 5 problemas, el que resolviera mas problemas en menos de 3 horas era el que ganara. hecho que despues de abrir el sobre, no m@m3n, descubri que eran problemas sencillos matematicos pero que no se podrian resolver con metodos sencillos porque podrian consumir mucha memoria y tiempo en resolverlo, para esto, una de las reglas era que el programa no tardara menos de 1 minuto. (todavia me acuerdo de uno, era sacar el numero fibonacci para un numero grande, pero el resultado era tan grande con no lo podrias representar con un numero de doble presicion).

      Despues de esa desepcion sali, y me puse a estudiar mas matematicas, para dejar de ser lamer.

      En esa investigacion, descubri que existen problemas que aparentemente son simples para resolver y que son trampas maliciosas. Hasta la fecha no se que matematico chistoso fue el que establecio esos problemas y los maestros se los dejan de tarea a sus pupilos sin tener idea del mismo problema, son como una burla para los programadores, son como una forma de detectar quien es un lamer o y quien no. Los primeros programadores de computadoras en la historia eran egrasados de escuelas de matematicas (alias matematicos) tenian bien amarrado conceptos matematicos y problemas de la actualidad. (te recomiendo la pelicula “Good Will Hunting” para que veas el ambiente de los matematicos)

      Uno de estos problemas es este, Genera un programa que determine quien es primo o no.

      Primero hay dos metodos simples para resolver que numero es primo o no?(trampa maliciosas):
      1. Por medio de ciclos anidados que cheque TODOS los divisores(apartir del 2) y ver que ninguno es divisible.
      2. Atravez de funciones recursivas.

      Te los dejo de tarea para que googlees.
      El problema de esas 2 soluciones es, que pasa si yo deseo verificar un numero grande (4,123,498,379). Imaginate por cada divisor el tiempo que consumes y si es por funciones recursivas, el gasto de memoria. Te truenas el windows

      hay un 3er metodo que me gusto que es llenando un arreglo(array) con ceros los primos y con unos los que no son. Muy rapido, pero te gastas mucha memoria, de hecho para 4,123,498,379 gastarias 4,123,498,379 bytes de memoria, casi 4 gigas.

      Pero esto ya se habia resuelto antes desde que existieran las computadoras, gracias a travez del siguiente algoritmo, pero primero las definiciones:

      Numero Primo:
      Es un número natural que tiene únicamente dos divisores naturales distintos: él mismo y el 1.

      Numero Compuesto:
      Todo número natural no primo se denomina compuesto, es decir, tiene uno o más divisores distintos a 1 y a sí mismo.

      El número 1, por convenio, no se considera ni primo ni compuesto

      El metodo:
      1. Todos los numeros que tenga terminacion 0,2,4,5,6,8 son numeros compuestos. Los que terminan en 0 o 5 son divibles entre 5 y los que terminan en 0,2,4,6,8 son divisibles entre 2.
      2. Si la suma de los digitos es divisible entre 3 entonces es un numero compuesto,(gracias a esto descartas todos los divisibles de 3), Ejemplo, 2,331 es 2+3+3+1 = 9, y 9 es divisible entre 3

      Con los pasos 1 y 2 descartas muchos numeros,pero si pasan estos pasos, se pone grueso.
      Aqui aplica los metodos lentos y sucios –> checando por cada divisor(me salio el tiro por lo culata)
      ..pero no os preucopeis,

      Descartamos los divisores 2,3,5 (obviamente) y buscamos a partir de numeros primos del 7 hasta el numero primo anterior de la raiz cuadrada del numero a buscar.

      Es imposible que encuentres divisibles mayores a la raiz cuadrada por que ya todos los resultados serian 0 y puro residuo. Entonces reduces la cantidad de divosores, para la busqueda de divisores primos podrias aplicar el metodo del arreglo ya que solo gastarias 64,214 bytes de memoria en vez de los 4,123,498,379. como esta en funcion de la raiz cuadrada, graficamente entre mas grande sea el numero incrementa muy poco el uso de memoria, en pocos palabras una grafica exponencial.

      3. Saca la raiz del numero, si la raiz es entera entonces es un numero compuesto.
      4. Divide el numero por todos los primos a partir del 7 hasta el numero primo anterior a la raiz cuadrada del numero a buscar.
      5. si el numero no es divisible entonces es primo

      Hay un paso 3.5 seria el metodo para sacar la raiz cuadrada, una seria usando funciones logaritmicas y la otra es usando numeros primos(un caso redundante)

      Metodo para salir de lamer:

      Para salir de lamer es encarar al maestro que te dejo el problema ante todos los alumnos y decirle la magnitud del problema.

      Saludos y que te diviertas

      Comentario por b1ackpig | noviembre 25, 2009 | Responder

      • Esta respuesta es genial, deberias hacer copy-paste y publicarla en la seccion de BLOGS de la Red Social de Programadores de Ensamblador. Sirve que le echas un ojo a la que escribi sobre el reloj-lamer.

        Comentario por asm86 | noviembre 25, 2009

  2. :O justo ahora un año después vengo a ver esto jejeje,
    y mi finalidad nunca fue que me hicieran la tarea ni nada, y al final pues termine sacando la solución solito, luego hice el de serie de fibonacci también solito ;)
    que se me complico por no borrar un registro.

    pero aun así gracias por la ayuda, que por cierto no leei en su tiempo.

    Comentario por pablo | septiembre 21, 2010 | Responder

    • De nada, aqui estamos para servirle.

      Es bueno saber que con nuestra ayuda mucha gente ve las ventajas del ensamblador.

      Un Saludo Cochino para todos uik uik

      Comentario por b1ackpig | septiembre 21, 2010 | Responder


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: