A ver .... vamos por partes, por que el código no tiene comentarios, lo que requiere leerlo más detenidamente.
1) elf_read_hdr()Es una función que lee el encabezado de un fichero en formato binario ELF (el análogo en Windows es .exe o mejor dicho: PE), el código es medio feito por que tiene funciones helpers que no están descritas y con nombres "feos".
Pero básicamente esas funciones convierten de diversas notaciones (como un array de unsigned chars a un unsigned de 32 bits ... misma cantidad de bits y mismos bits per sé, diferente forma de almacenar en memoria .. por ejemplo)
Por lo que tendrías que leer, es algo sobre el formato ELF (
acá tenés una ayuda con eso ... pero nótese que es una lectura BÁSICA y que tenés que sumar otras)
2) be16(), be32(), be64()2.A) Vamos a la declaración:static inline u16 be16(u8 *p)
voy a ignorar static e inline, y vamos a lo que importa.
la función toma un puntero a u8 (u8 está definido como unsigned char ... lógico, u8 significa unsigned 8 bits, bits es justamente lo que pesa un char en memoria) y retorna un unsigned de 16 bits (un "short", 2 bytes, el doble de un char).
Así que, para juntar los 16 bits para retornarlos en u16, desde el vamos sabemos que necesitamos 2 u8 ... 2 elementos de 8 bits suman 16.
Ahora, ¿por qué unsigned pensarás? bien, acá quiero hacer un stop y primero hacemos una clase básica sobre los tipos de datos y el signo:
2.B) Hagamos un inciso sobre tipos y signos Las variables que tienen signo (todas lo tienen, el compilador lo asume salvo que las marques unsigned), en memoria, se le "roba" un bit mara marcar el signo (ese bit si está como 1, o true, es negativo, sino no). Por ejemplo, un byte son 8 bits, y si tuviese o no signo, nos deja con esta situación:
0 0 0 0 0 0 0 0 =
8 bits para usar (2^8 es nuestro rango de números ... lógico, 256 !) ... y ni un bit usado para el signo
0 0 0 0 0 0 0 0 =
7 bits para usar y
uno reservado para el signo (2^7 es nuestro "rango" de números ... con 7 bits representamos un rango de 128, sin importar el signo, que eso lo marca el bit restante )
Ese "bit reservado" para el signo puede estar de un lado y otro, depende del "endianess", y es algo que no pienso cubrir acá, pero te lo nombro para que lo busques.
2.C) RetomemosSabiendo que u8 representa 8 bits precisos (por eso el unsigned, no "robamos" un bit para el signo) y u16 representa 16. ahora pasemos a analizar el código:
1) u8 es un puntero, como ves más abajo, en realidad se espera que este puntero albergue dos elementos (algo equivalente a "u8 dato[2]"), bien ... 2 unsigned de 8 bits (son 16)
2) Operaciones con bits (lo resaltado)
u16 a;
a = p[0] << 8;
a |= p[1];
return a;
La primer línea resaltada lo que usa es el operador de
bit shift, básicamente tenemos dos operadores de bit shift :
Básicamente, lo que hacen es "correr" los bits para un lado u otro (¿las flechitas te sugirieron algo?), y todo lo que "quede afuera" (por que podés correr hasta donde aguante el tipo de dato sin perder nada), se trunca, veamoslo de manera gráfica con este pseudocódigo con una variable de 8 bits:
X = 0 1 1 0 0 0 0 1
X << 3
Tenemos que "corremos" los bits de X tres lugares a la izquierda, el nuevo X vale esto:
Todos los otros 1, se corrieron "de más" a la izquierda, y se perdieron ... se entiende el concepto? Otro ejemplo menos radical con el destino de los bits:
X = 0 1 1 0 0 0 0 1
X << 1
X queda :
Ok, avanzamos ... Como no podemos hacer "a = p", tenemos que meter los dos 8 bits en la variable de 16 bits.
por lo que tenemos que "correr" bits para encajarlos en la parte izquierda y derecha de "a".
básicamente metemos los primeros 8 bits, los enviamos a la izquierda, y metemos los otros 8 bits, veamoslo:
A = 0 1 1 0 1 0 1 0 (8bits)
B = 0 0 0 0 0 1 0 1 (8bits)
C = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 (16 bits)
C = A (C vale A, y todos los bits de A pensa que estan a la derecha)
C << 8 (los corremos a la izquierda, ahora A quedo en el lado izquierdo de C, el resto es 0, obvio)
C |= B // Esto nos interesa
Lo que marqué ahí es un operador con bits, y es un operador de suma (or), básicamente esto significa C es igual a C, más los bits ( | ) de B, que pensá que irían a la derecha ... vuelan los 8 bits de la derecha (que no tenían nada importante), y los 8 de la izquierda que dejamos desde el shift, quedan ... se entiende?
C quedaría compuesto de A y B ... A llendo a la izquierda y B a la derecha.
Un sumario de los operadores de bit y bit shift →
http://www.cprogramming.com/tutorial/bitwise_operators.htmlY con eso podrías entender las otras funciones.
Saludos.