Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

La Porrista de 100 Kilos

–Direccionamiento Base con Indice Escalado y Desplazamiento–

Direccionamiento de memoria. Esta es la parte mas confusa a la hora de programar en Ensamblador. Pues los registros generales no solo sirven para contener bits. También se usan para mover datos entre la memoria y el CPU. Del mismo modo que podemos usar una mano para sostener algo o podemos señalar con el dedo. Sin embargo, un CPU de Intel es capaz de combinar sus registros generales de forma que puede guardar y recuperar datos de las estructuras mas extrañas con gran eficiencia.

Esto es muy similar a esas pirámides humanas que hacen las porristas de los eventos deportivos. Donde las mas fuertes se apoyan en cuatro en el suelo. Las de mayor equilibrio se paran sobre sus espaldas y la mas agil de todas trepa hasta la punta y salta realizando una vistosa pirueta en el aire…

Bueno. Como ya me está comenzando a sangrar la nariz mejor le sigo con el Ensamblador. Los registros del CPU pueden ser usados para ‘apuntar’ a la memoria. Quienes han programado en C de seguro escucharon alguna vez el concepto de ‘punteros‘. Los punteros son variables que contienen posiciones de memoria (que al fin y al cabo siguen siendo bits). Un CPU de Intel puede hacer aritmética de punteros ¡Por Hardware!. Aunque puede verse como algo muy complicado. Solo consiste de 3 partes: Base, indice y desplazamiento. Aunque estos nombres son los oficiales de Intel no necesariamente son los mas acertados y veremos porqué.

BASE.- Es el registro sobre el que se apoya el índice. En la pirámide, sería la porrista que está enmedio. Su contenido puede ser cambiado y con ello se pueden lograr direccionamientos relativos. Esto es lo que hace funcionar las variables locales en un Stack Frame.

INDICE.- Es el que está hasta el final. Se apoya sobre el registro base. La porrista que está en la punta de la pirámide y hace las acrobacias. Su contenido puede cambiarse y avanzar por las partes mas recónditas de las estructuras.

DESPLAZAMIENTO.- Es la parte constante del direccionamiento. Se trata de un número que puede ser una posición absoluta de la memoria o relativa a otro registro. Sin embargo, su valor no puede cambiarse sin cambiar el código máquina de la instrucción. El mejor uso de esta parte es para apuntar a posiciones fijas de la memoria como son las variables globales o el principio de un gran arreglo de estructuras. Por analogía con las porristas. El desplazamiento sería: ¡La Infame Porrista de Cien Kilos! Quien por su peso no puede moverse ni mucho menos pararse sobre la pirámide. Por seguridad, la posición que le toca a esta gorda es la de soporte de la piramide.

Un direccionamiento completo con estos tres elementos se vería así:

                        MOV    EAX, [EBX + ESI + 1234h]

Esta instrucción suma el contenido de los registros EAX, ESI y el valor 1234 hexadecimal. Esto da un número que corresponde a una posición de memoria. Entonces, el valor de 32 bits almacenado en esa posición de memoria se almacena en el registro EAX. Pero aún hay mas. Algo llamado factor escalar.

Como recordarán, el valor de las posiciones de memoria es una cantidad en bytes. Los bytes son celdas de 8 bits. No de 16, 32 ni 64. Solo 8 Entonces, ¿Que pasa cuando tenemos que trabajar con valores que no son de 8 bits? Un programador inexperto y desconfiado usaría operaciones aritméticas como ADD; Uno igual de inexperto pero con mas seguridad en si mismo recurriría a la instrucción SHL. Pero alguien que realmente separ de programación sabe que puede usar factores escalares. Un factor escalar en un direccionamiento de memoria multiplica por 2 (16 bits), 4(32 bits) u 8 (64 bits) única y exclusivamente al registro índice. De este modo, es posible recorrer todos los valores internos de una estructura.

De nuevo, con el ejemplo. El valor índice marca que tan alto es el salto que debe de dar la porrista que está hasta arriba de la pirámide.

Ahora al código máquina:

Esto parece demasiado complicado. Sin embargo. Cuando vemos el formato del código máquina todo se aclara. Y aquí es donde entra el byte SIB. Que es el acrónimo de Scalar Index Base. He aquí los bits:

Bits[7:6].- 2 bits que indican el factor escalar. 00 es 0; 01 es 2; 10 es 4 y 11 es 8. Para quien le entienda a las matemáticas, estos son las potencias de 2: 2 ^ 0= 1; 2^1 = 2; 2^2 = 4 y 2^4 = 8.

Bits [5:3].- 3 bits que indican el registro índice. Se interpretan de manera CASI igual que el campo REG de ModR/M. Pero hay pequeñas diferencias que pueden meternos en lios. Recuerden que solo el Indice se puede escalar. Nótese que ESP no puede ser un Indice escalado.

Bits[2:0].- 3 bits que representan la base. De nuevo se interpreta CASI igual que REG en ModR/M. Sin embargo. La combinación binaria 101 (5 decimal) y que correspondría a ESP, se interpreta diferente dependiendo de los 2 bits [5:7] Del byte ModR/M. Para mas detalles vean el dibujo.

Para terminar, cabe mencionar que los bytes ModR/M y SIB trabajan juntos. La existencia e interpretación de SIB depende directamente de ModR/M y este a su vez del OpCode. Además, algunas instrucciones utilizan una parte de ModR/M como parte del código de operación. Un ejemplo de esto es la instrucción DEC cuyo equivalente en C sería el “- -”. El campo REG del byte ModR/M de esta instrucción siempre es 001. Aunque tiene una forma que solo usa un byte.

Mas adelante explicaré como conectar OpCode, ModR/M y SIB. Pero por ahora, ya tienen suficiente para explorar por cuenta propia el código máquina de un programa para los procesadores de Intel. Y ahí si, si logran comprender, no necesitarán a nadie que les eche porras (espero que los programadores brasileños no se ofendan por esta expresión), y mucho menos a una porrista de cien kilos.

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

4 comentarios »

  1. Esta parte esta un poco confusa:

    Bits[7:6].- 2 bits que indican el factor escalar. 00 es 0; 01 es 2; 10 es 4 y 11 es 8. Para quien le entienda a las matemáticas, estos son las potencias de 2: 2 ^ 0= 1; 2^1 = 2; 2^2 = 4 y 2^4 = 8.

    Dice que 00 es 0, y despues dices que son potencias de 2, pero 2 ^ 0 = 1. Podrias aclararnos un poco esto

    Comentarios por blackpig | abril 7, 2009 | Responder

    • Aclaro que estaba mas dormido que despierto cuando lo escibi. En realidad 00 es la potencia cero y 2 a la cero es uno. Tan solo espera a que acabe los dibujos en paint para que la nota quede un poco mas entendible.

      Comentarios por asm86 | abril 7, 2009 | Responder

  2. Table 17-4. 32-Bit Addressing Forms with the SIB Byte

    r32 EAX ECX EDX EBX ESP [*] ESI EDI
    Base = 0 1 2 3 4 5 6 7
    Base = 000 001 010 011 100 101 110 111

    +Scaled Index+ +SS Index+ +——–ModR/M Values in Hexadecimal——–+

    [EAX] 000 00 01 02 03 04 05 06 07
    [ECX] 001 08 09 0A 0B 0C 0D 0E 0F
    [EDX] 010 10 11 12 13 14 15 16 17
    [EBX] 011 18 19 1A 1B 1C 1D 1E 1F
    none 00 100 20 21 22 23 24 25 26 27
    [EBP] 101 28 29 2A 2B 2C 2D 2E 2F
    [ESI] 110 30 31 32 33 34 35 36 37
    [EDI] 111 38 39 3A 3B 3C 3D 3E 3F

    [EAX*2] 000 40 41 42 43 44 45 46 47
    [ECX*2] 001 48 49 4A 4B 4C 4D 4E 4F
    [ECX*2] 010 50 51 52 53 54 55 56 57
    [EBX*2] 011 58 59 5A 5B 5C 5D 5E 5F
    none 01 100 60 61 62 63 64 65 66 67
    [EBP*2] 101 68 69 6A 6B 6C 6D 6E 6F
    [ESI*2] 110 70 71 72 73 74 75 76 77
    [EDI*2] 111 78 79 7A 7B 7C 7D 7E 7F

    [EAX*4] 000 80 81 82 83 84 85 86 87
    [ECX*4] 001 88 89 8A 8B 8C 8D 8E 8F
    [EDX*4] 010 90 91 92 93 94 95 96 97
    [EBX*4] 011 98 89 9A 9B 9C 9D 9E 9F
    none 10 100 A0 A1 A2 A3 A4 A5 A6 A7
    [EBP*4] 101 A8 A9 AA AB AC AD AE AF
    [ESI*4] 110 B0 B1 B2 B3 B4 B5 B6 B7
    [EDI*4] 111 B8 B9 BA BB BC BD BE BF

    [EAX*8] 000 C0 C1 C2 C3 C4 C5 C6 C7
    [ECX*8] 001 C8 C9 CA CB CC CD CE CF
    [EDX*8] 010 D0 D1 D2 D3 D4 D5 D6 D7
    [EBX*8] 011 D8 D9 DA DB DC DD DE DF
    none 11 100 E0 E1 E2 E3 E4 E5 E6 E7

    Comentarios por El Julio | abril 7, 2009 | Responder

    • Esta es la tabla original de los manuales de Intel. Aunque se veria mejor con la etiqueta PRE de html y con el \ultimo renglon.

      Comentarios por asm86 | abril 7, 2009 | Responder


Deja un comentario