🇪🇸 Como comprender y saber si ando con little endian ?

Este texto se puede leer en francés en mi capsula Gemini en IPV6 o pasando por Gemini portal

Se trata de conocer poco a poco diferentes conceptos sobre numeración y codificación antes de ir mas tarde a por cosas en assembler (asm) o reverse.

Para probar que estoy en little endian me serviré de Unicode, os advierto que si no sabéis de que hablo, voy a intentar de aliviaros la cosa para que os sentáis mas cómodo con los ordenadores.

Venga, para empezar este post nos serviremos del valor de la eñe , el cual es el siguiente en Unicode \u00f1

Un ejemplo con este comando en bash que produce la salida Hackerñol

echo -e "Hacker\u00f1ol\n"
Hackerñol

Todos conocemos (o casi) el comando echo, el argumento -e permite de evitar de interpretar los caracteres d’escape ( los que empiezan por una barra invertida \ ), que es el terminal ? Es una manera de dar ordenes a tu ordenador, (antiguamente no había interfaces gráficas con ventanas y ratón); usando comandos puedes dialogar con el ordenador, el comando echo hace una salida por pantalla de texto. Se puede pues insertar en la cadena de texto este valor \u00f1 que es el correspondiente en el punto de código Unicode de la letra ñ

 

Que es Unicode ?

Un ordenador solo comprende una serie de cifras, no conoce ningún idioma. Ni en ingles, ni el francés ni tampoco el chino.

La únicas cifras que el ordenador comprende son el uno y el zero ( 0 ou 1 ). De hecho interiormente tampoco conoce esas cifras, digamos mejor que sabe hacer la diferencia entre dos estados en sus circuitos. La corriente eléctrica pasa o no pasa. Por comodidad se escogió el decir que si la corriente pasa, sera el 1, en cambio si la corriente no pasa se dirá que es el cero. El caso contrario también es cierto, se podría haber dicho lo contrario, es una convención. Lo cierto es que solo disponemos de dos estados; mas tarde veremos que un bit (la unidad minima de información) tiene dos estados. Se quiso pues que algo que se parecía a una bombilla de luz pudiera servir a hacer cálculos, o está en un estado encendió o en un estado apagado. Y un dia un hombre genial invento (o descubrió) los números binarios…

Si pero eso no responde a la pregunta, pues Unicode és una representación codificada de los caracteres que pueden ser utilizados por todos los idiomas, lo vamos a ver un poco mas tarde (su interés y utilización)

 

¿Sabes contar?

Los humanos disponemos de dos manos, si claro, y en general con 5 dedos cada una. Por ello es posible que se escogió la base 10 (numero de dedos) comme base de calculo. Así que nuestra forma clásica de hacer las cuentas se basa en un sistema decimal, solo se usan 10 dígitos o cifras para representar un número. Nuestro amigo el ordenador no tiene dedos y no entiende nada más que el idioma de la bombilla (encendida o apagada). Tiene por tanto una base de cálculo de dos estados (ya sea 1 o 0) por lo que esta base se denominará binaria.

Entonces, nosotros usamos decimal y la computadora usa binario.

Vamos, empecemos a contar: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 (estas son nuestras cifras), pero para ir más allá del 9, ya que solo tenemos estos 10 dígitos, pues sumaremos 1 a la izquierda y a la derecha volvemos a nuestro dígito inicial (el 0). Esto da 10, estamos acostumbrados a hacerlo y nos parece normal. Si llegamos a 19 sumamos 1 a la izquierda y por lo tanto continuamos con el 20, tenemos las cifras para eso, pero ¿qué hacemos cuando lleguemos a 99 ? Lo mismo que cuando llegamos al 9, sumamos 1 a la izquierda y ponemos el 9 a cero. Cada vez que sumamos una columna y por lo tanto al multiplicar el número de la columna por la base (10), entonces la suma de todas las columnas, nos da el número que queremos expresar.La primera columna tiene un valor de 0 para la base porque aún no hemos agregado ninguna columna. Entonces, para tomar un ejemplo simple (con el número 150) :

150 = 1 x 10² + 5 x 10¹ + 0 x 10⁰

Para los curiosos: ¿cómo se escribe esto de aquí arriba con un poco de Unicode y el comando echo?

echo -e "150 = 1 x 10\u00b2 + 5 x 10\u00b9 + 0 x 10\u2070"

Ahora le toca el turno a nuestro amigo el ordenador. 0, 1 (estas son sus cifras), entonces, ¿qué hace cuando llega al 1? Pues sí, como nosotros, agrega una columna a la izquierda con un 1 y vuelve a colocar la primera columna en 0. Seguimos la misma lógica que con la base décimal; el orden de las columnas nos da el número a poner en potencia de su base (aquí sera 2), luego sumamos los resultados de cada columna.

Ejemplo (en base 2) 1101

1 + 2³ + 1 x 2² + 0 x 2¹ + 1 x 2⁰
= 8 + 4 + 0 + 1
= 13

Un poco más de Unicode ;)

echo -e "1 + 2\u00b3 + 1 x 2\u00b2 + 0 x 2\u00b9 + 1 x 2\u2070"
1 + 2³ + 1 x 2² + 0 x 2¹ + 1 x 2⁰

Compararemos contando con la computadora para ver (a la izquierda somos nosotros en decimal, a la derecha la computadora en binario):

0 -> 0
1 -> 1
2 -> 10
3 -> 11
4 -> 100
5 -> 101
6 -> 110
7 -> 111
8 -> 1000
9 -> 1001

10 -> 1010
11 -> 1011
12 -> 1100
13 -> 1101
14 -> 1110
15 -> 1111
… etc …

Vale eso es genial, descubrimos cómo cuenta una computadora \o/

 

¿Sabes escribir?

Los humanos tenemos letras además de números, así que podemos escribir cosas como este texto que estás leyendo. Nuestro amigo el ordenador no tiene letras, entonces ¿cómo lo hace?
Bueno, para eso inventamos convenciones que hacen que ciertos números en la computadora siempre se correspondan con ciertas letras o caracteres. Esto se ha llamado “codificación de caracteres”. Los primeros no eran compatibles entre sí pero finalmente encontramos un estándar: este fué el código ASCII.

El código ASCII es el antepasado del famoso Unicode del que hablo al principio de este texto, por ejemplo la letra ñ no existe en ASCII pero si en Unicode.

En pocas palabras, diremos que la memoria de la computadora se compone de filas que tienen 8 ranuras cada una. 8 bombillas por fila, por lo tanto 8 dígitos binarios que pueden ser 0 o 1 y que se llaman bits. Usamos 7 bits para codificar los caracteres, y por lo tanto, por ejemplo, el código binario 0100 0001 siempre representará la letra A en código ASCII. Y el octavo ? pues sirve para hacer verificaciones de errores de transmisión.

Este código, a pesar de haber sido un estándar, no fue lo suficientemente evolucionado para tener en cuenta todos los caracteres de todos los idiomas del planeta tierra. Había códigos adicionales para completar el código ASCII, por ejemplo para tener letras acentuadas u otros caracteres que no se habían previsto. Pero empezamos a tener incompatibilidades de codificación entre estos códigos.

Hoy en día, esta codificación ha evolucionado, el estándar actual es Unicode. Unicode incluye ASCII, lo que significa que se respetan los primeros códigos ASCII, pero como Unicode tiene más códigos (porque hay más caracteres para cifrar) ocupa más espacio en la memoria de la computadora. Por poner un ejemplo si tomamos UTF-8 que es una de las tres posibilidades reconocidas por Unicode y prácticamente generalizadas en todo el planeta, las posiciones de memoria requeridas para codificar los caracteres van de 1 a 4 bytes (es decir de 8 a 32 bit ). Para los curiosos, UTF-8 fue creado por Robert C. Pike y Kenneth L. Thompson. El primero también creó el lenguaje Go y el segundo es considerado uno de los padres de UNIX con el Sr. Dennis Ritchie quien fue el creador del lenguaje C.

 

¿Sabes cómo ordenar?

Ahora sabemos que el lenguaje de las computadoras es binario, es el código de máquina que el procesador procesará cuando ejecute un programa de computadora. Es una serie de bits que componen instrucciones para el procesador y cada familia de procesadores tiene la suya. Estas instrucciones son únicas con funcionalidades bien definidas, cuando ha terminado de ejecutar una instrucción pasa a la siguiente. Pero para poder decirle a la computadora qué hacer, los humanos no podemos perder nuestro tiempo contando y escribiendo secuencias interminables de 0 y 1. Por lo tanto, debemos encontrar una manera de ordenar las instrucciones de tal manera que podamos reconocerlas y que podamos ponernos de acuerdo con la computadora para decirle qué hacer.

Entonces comenzamos dando nombres simples a estas instrucciones que el procesador sabe cómo procesar. Por ejemplo, el procesador cuando encuentra esto: 10110000 01100001 reconocerá la instrucción a ejecutar. Por lo tanto, hemos asignado nombres significativos para los humanos a este tipo de instrucciones que llamamos mnemotécnicos, por lo que la instrucción anterior se convierte en esta (en un lenguaje más comprensible para nosotros):

movb $0x61,%ali

Por otro lado, podemos ver claramente que los bits están por lo tanto separados en grupos de 8 bits (bytes), esto ya es una primera puesta en orden (o arreglo). Podemos ver que no es muy fácil interpretar esto a primera vista, así que usaremos otra forma de contar para visualizar mejor la cosa. Y ahí, para poner más orden, pasaremos por un sistema digital en base 16 en lugar del binario que ya hemos visto (en base 2). ¿Cómo es esto posible? bien diremos que los números que definen los 16 elementos irán del 0 al 9 como en decimal, pero como necesitamos otros y que deben ser diferentes a los anteriores los simbolizaremos con letras que van de la A a la F. Esto proporciona lo que serian estos dígitos o cifras (si se les puede llamar asi ): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F

Cómo lo hacemos entonces ? Contamos de la misma forma que con las demás bases, de 0 a F y llegados a F ponemos una segunda columna a la izquierda y ponemos a cero a la derecha ;)

A esto se le llamara numeración hexadecimal.

Ejemplo con el número 2BD (en hexadecimal):

Aquí representaremos las potencias como en un lenguaje llamado Python, es decir que (16**2) es equivalente a 16², quizás tenga más sentido:

2BD = 2 × (16 ** 2) + 11 × (16 ** 1) + 13 × (16 ** 0)
512 + 176 + 13
701

Entonces, para simplificar, dado que (255) en base 10 es igual a (FF) en base 16 y, de hecho, con dos dígitos en base 16 es lo mismo que 8 bits en binario \o/. O que una columna en hexadecimal representara hasta 4 bits.

En otras palabras: dado que un byte puede tomar 256 valores (es decir, 2^8), podemos describir cada byte con dos dígitos hexadecimales.

¡Es mejor leer FF que 11111111! ¿No es cierto ?

Por lo tanto, ordenaremos nuestros bytes en pares de números hexadecimales, para que sea más visible. Pregunta: ¿Notaste esto ($0x61) en varias líneas arriba con el codigo assembler?

 

Finalmente llegamos a little endian

Eso está muy bien, pero… ¿qué tiene que ver con little endian?

Hablamos de instrucciones un poco más arriba y del hecho de que cada procesador tiene las suyas. Como todas están en binario, debe haber un tamaño determinado para que el procesador las identifique (no todos los procesadores tienen el mismo tamaño de procesamiento) Bueno, este tamaño es lo que se llama “un word” (una palabra en inglés), estamos hablando de procesadores de 8, 16, 32 o 64 bits pero hay otros.

Existen por tanto dos tendencias para saber en qué sentido se escriben los words para ser procesadas en las diferentes memorias de la computadora, little endianness o big endianness, “En informática, endianness es el orden o secuencia de bytes de una palabra de datos digitales en memoria de la computadora.

Aquí está nuestro ejemplo: vamos a escribir la palabra Hackerñol en la pantalla, pero tenemos un teclado francés…

1) primer intento:

echo "Hackernol"

no tenemos la tecla correcta, entonces nos decimos que el carácter existe y que debe estar en la tabla Unicode, lo buscamos y nos encontramos con el mencionado anteriormente en el artículo ( \u00f1 )

2) Segundo intento, usamos Unicode (de 1 a 4 bytes)

echo -e "Hacker\u00f1ol\n"
Hackerñol

Obtenemos un buen resultado en pantalla, pero aún no sabemos si estamos en little endian o no.

3) Tercer intento

Ahora echemos un vistazo más profundo con un programa llamado hexdump

printf "Hacker\u00f1ol\n" | hexdump
0000000 6148 6b63 7265 b1c3 6c6f 000a          
000000b

Empezamos a ver código hexadecimal :)
Pero, ¿qué significa este código? ¿Si tratamos de convertirlo a Unicode?

Vamos a ello ! empezamos con los 4 primeros dígitos en hexadecimal, es decir 6148:

echo -e "\x61\x48"
aH

¡¡¡Que raro que la a y la H estén invertidas!!!

Bien, pero ¿de qué estamos hablando al final?

En informática, algunos datos, como los números enteros, se pueden representar con varios bytes. El orden en que se organizan estos bytes en la memoria o en una comunicación, ya sea por red o en memoria se denomina endianidad. De la misma manera que algunos lenguajes humanos se escriben de izquierda a derecha, y otros se escriben de derecha a izquierda, existen dos alternativas a la organización de los bytes que representan un dato: la orientación big-endian y orientación little-endian.
También se utilizan las expresiones byte order, byte order o byte sex.

Endianness solo se refiere a datos estructurados en varios bytes, como números enteros o caracteres Unicode, codificados en UTF-16 o UTF-32. Los datos de un solo byte, como los caracteres ASCII, no se ven afectados. (Definición copiada salvajemente de Wikipedia)

Para ver algo mas avanzado (en ingles) Byte order marks (BOM) y profundizar en el tema.

La decodificación de un carácter UTF-8 se realiza de la siguiente manera:

  1. Inicialice un número binario con todos los bits establecidos en 0. Se pueden necesitar hasta 21 bits.
  2. Determine qué bits codifican el número de carácter a partir del número de octetos en la secuencia y la segunda columna de la tabla anterior (los bits marcados con x).
  3. Distribuya los bits de la secuencia al número binario, primero los bits de orden inferior del último octeto de la secuencia y siguiendo hacia la izquierda hasta que no queden x bits. El número binario ahora es igual al número de carácter.

ATENCIÓN ! aparentemente UTF-8 sería endianless, algo que no sabía, creo que la gente se confundió con BOM y el hecho de que no es obligatorio ponerlo. Lo mejor es que eches un vistazo aquí si realmente estás interesado: RFC 3629 - UTF-8, a transformation format of ISO 10646

Entonces,

  • ¿qué es la endianidad?
  • ¿Cuál es el tamaño de un word?
  • ¿Qué es la codificación? ASCII, Unicode, UTF-8
  • Decimal, Binario, Hexadecimal…

Creo que aprendimos o revisamos muchas cosas, y tal vez estaría bien releer un poco e investigar para entender y asimilar mejor ;)

Admito que es un poco hacer fuerza bruta a las neuronas para llegar a un resultado que conocemos. La mayoría de las computadoras modernas funcionan en little endian. Pero cuidado, ¡el protocolo TCP lo hace en big-endian!
Bueno, espero que está probado y entendido. Venga, para terminar os lo pongo al completo ;)

echo $'\x48\x61\x63\x6b\x65\x72\xc3\xb1\x6f\x6c'
Hackerñol

Este artículo me vino a la mente mientras leía este Understanding pointers on Drew DeVault’s blog y hablando de cosas con amigos de hispagatos.

 

Pero ¿ qué es Hackerñol ?

Hackerñol Para Hackers en Español.

 

Amfora tip of the day :

Space

  • Opens bar at the bottom - type a URL, link number, search term.
  • You can also type two dots (..) to go up a directory in the URL.
  • Typing new:N will open link number N in a new tab instead of the current one.

Happy hacking ;)