Escribir una aplicación de Android en ensamblador

imagen

Esta historia trata sobre un enfoque no estándar para el desarrollo de aplicaciones de Android. Una cosa es instalar Android Studio y escribir "Hello, World" en Java o Kotlin. Pero mostraré cómo se puede realizar la misma tarea de manera diferente.

Le recordamos: para todos los lectores de "Habr": un descuento de 10.000 rublos al registrarse en cualquier curso de Skillbox con el código de promoción "Habr".

Skillbox recomienda: El curso educativo en línea "Profession Java-developer" .

¬ŅC√≥mo funciona mi tel√©fono inteligente con el sistema operativo Android?


Primero, un poco de historia. Una tarde una amiga llamada Ariella me llam√≥. Ella me pregunt√≥: "Escucha, ¬Ņc√≥mo funciona mi tel√©fono inteligente? ¬ŅQu√© hay dentro? ¬ŅC√≥mo la energ√≠a el√©ctrica y las unidades ordinarias y ceros hacen que todo funcione?

Mi amiga no es una novata en desarrollo, creó varios proyectos en Arduino, que consistían tanto en software como en hardware. Tal vez por eso quería saber más. Logré responder con la ayuda del conocimiento obtenido en uno de los cursos de informática tomados en la universidad.

Luego trabajamos un par de semanas juntas, ya que Ariella quería descubrir cómo funcionan los ladrillos de la tecnología electrónica, es decir, los elementos semiconductores, incluidos los transistores. Luego pasamos a un nivel superior: le mostré cómo crear puertas lógicas, por ejemplo, NAND (lógico Y) más NOR (lógico OR) usando una combinación específica de transistores.

Investigamos elementos l√≥gicos de diferentes tipos, los combinamos para realizar c√°lculos (por ejemplo, agregar dos n√ļmeros binarios) y celdas de memoria (disparadores). Cuando todo qued√≥ claro, comenzaron a desarrollar un procesador simple (imaginario), en el que hab√≠a dos registros de prop√≥sito general y dos instrucciones simples (agregar estos registros). Incluso escribimos un programa simple que multiplica estos dos n√ļmeros.

Por cierto, si está interesado en este tema, lea las instrucciones para crear una computadora de 8 bits desde cero. Explica casi todo, desde lo más básico. ¡Ojalá lo hubiera leído antes!

Hola android


Después de completar todas las etapas del estudio, me pareció que Ariella tenía suficiente conocimiento para comprender cómo funciona el procesador del teléfono inteligente. Su teléfono inteligente es el Galaxy S6 Edge, cuya base es la arquitectura ARM (como, de hecho, con la mayoría de los teléfonos inteligentes). Decidimos escribir una aplicación "Hello, World" para Android, pero en lenguaje ensamblador.

.text .globl _start _start: mov %r0, $1 // file descriptor number 1 (stdout) ldr %r1, =message mov %r2, $message_len mov %r7, $4 // syscall 4 (write) swi $0 mov %r0, $0 // exit status 0 (ok) mov %r7, $1 // syscall 1 (exit) swi $0 .data message: .ascii "Hello, World\n" message_len = . - message 

Si nunca antes ha encontrado código de ensamblador, este bloque puede asustarlo. Pero está bien, analicemos el código juntos.

Entonces, nuestro programa consta de dos partes. El primero es texto con instrucciones de código de máquina, y el segundo son variables, líneas y otra información (comenzando con la línea 15). La sección .text generalmente es de solo lectura y .data también se puede escribir.

En la línea 2, definimos una función global llamada _start. Es el punto de entrada a la aplicación. El sistema operativo comienza a ejecutar el código desde este punto. La definición de la función se declara en la línea 4.

Adem√°s, la funci√≥n hace dos cosas m√°s. En las l√≠neas 5‚Äď9, el mensaje se muestra en la pantalla; en las l√≠neas 11‚Äď13, el programa finaliza. Incluso si elimina las l√≠neas 11‚Äď13, el programa mostrar√° nuestra l√≠nea "Hola, Mundo" y saldr√°. Sin embargo, la salida no ser√° correcta, porque el programa terminar√° con un error. Sin las l√≠neas 11‚Äď13, la aplicaci√≥n intentar√° ejecutar una instrucci√≥n no v√°lida.

La impresión se muestra utilizando la función del sistema "Llamada del sistema" del sistema operativo. En la aplicación, llamamos a la función write (). Lo indicamos cuando cargamos el valor 4 en el registro del procesador con el nombre r7 (línea 8). A continuación, se ejecuta la instrucción swi $ = 0 (línea 9), donde hay una transición directamente al kernel de Linux, que es la base de Android.

En cuanto a los par√°metros para la llamada al sistema, se transmiten a trav√©s de otros registros. Por ejemplo, r0 muestra el n√ļmero del descriptor de archivo que necesitamos imprimir. Ponemos el valor 1 all√≠ (l√≠nea 5), ‚Äč‚Äčindicando salida est√°ndar (stdout), es decir, salida a la pantalla.

r1 indica la dirección de memoria de los datos que queremos escribir, por lo que simplemente cargamos la dirección de la cadena "Hola, Mundo" (línea 6) en esta área, y el registro r2 muestra cuántos bytes queremos escribir. En nuestro programa, está configurado en message_len (línea 7), calculado en la línea 18 usando una sintaxis especial: el símbolo de punto indica la dirección de memoria actual. Por esta razón - mensaje indica la dirección de memoria actual menos la dirección del mensaje. Bueno, como declaramos message_len inmediatamente después del mensaje, todo esto se calcula como la longitud del mensaje.

Si escribe el c√≥digo para las l√≠neas 5‚Äď9 usando C, obtendr√° lo siguiente:

 #define message "Hello, World\n" write(1, message, strlen(message)); 

Cerrar el programa es un poco m√°s f√°cil. Para hacer esto, simplemente registramos el c√≥digo de salida en el registro r0 (l√≠nea 11), despu√©s de lo cual agregamos el valor 1, que es el n√ļmero de la llamada a la funci√≥n del sistema exit (), a r7 (l√≠nea 12), luego llamamos nuevamente al n√ļcleo (l√≠nea 13).

Puede encontrar una lista completa de las llamadas al sistema Android y sus n√ļmeros en el c√≥digo fuente del sistema operativo . Tambi√©n hay una implementaci√≥n de write () y exit () que llama a las funciones del sistema correspondientes.

Poniendo el programa juntos


Para compilar nuestro proyecto, necesitará Android NDK (Native Development Kit). Contiene un conjunto de compiladores y herramientas de compilación para la plataforma ARM. Puede descargarlo desde el sitio oficial, instalarlo, por ejemplo, a través de Android Studio.



Despu√©s de instalar el NDK, necesitamos el archivo arm-linux-androideabi-as, este es el ensamblador para ARM. Si descargaste a trav√©s de Android Studio, b√ļscalo en la carpeta del SDK de Android. Por lo general, su ubicaci√≥n es

ndk-bundle \ toolchains \ arm-linux-androideabi-4.9 \ prebuilt \ windows-x86_64 \ bin.

Después de encontrar el ensamblador, guarde lo que está escrito en un archivo llamado hello.s, y luego ejecute el siguiente comando para convertirlo en código de máquina:

arm-linux-androideabi-as -o hello.o hello.s

Esta operación crea un archivo de objeto ELF llamado hello.o. Para convertirlo a un archivo binario que pueda funcionar en su dispositivo, llame al vinculador:

arm-linux-androideabi-ld -o hola hola.o

Ahora tenemos un archivo de saludo que contiene un programa que est√° listo para usar.

Inicie la aplicación en su dispositivo


Las aplicaciones de Android generalmente se distribuyen en formato .apk. Este es un tipo especial de archivo comprimido que incluye clases Java (sí, puede escribir con C / C ++, pero Java debe ser el punto de entrada).

Para evitar problemas al iniciar la aplicación, se utilizó adb en el ejemplo, que nos permitió copiarlo en la carpeta temporal de nuestro dispositivo Android. Después de eso, lanzamos el shell adb para iniciar la aplicación y evaluar el resultado:

adb push hello / data / local / tmp / hello
adb shell chmod + x / data / local / tmp / hello

Y finalmente, ejecute la aplicación:

adb shell / data / local / tmp / hello

Que escribes


Ahora tiene un entorno de trabajo similar al que ten√≠a Ariella. Pas√≥ varios d√≠as estudiando el ensamblador ARM, luego se le ocurri√≥ un proyecto simple: este es el juego Sven Boom (una variaci√≥n de Fizz Buzz originario de Israel). Los jugadores cuentan por turno y cada vez que el n√ļmero se divide por 7 o contiene el n√ļmero 7, deben decir "boom" (de ah√≠ el nombre del juego).

Vale la pena se√Īalar que el programa del juego no es una tarea tan f√°cil. Ariella escribi√≥ un m√©todo completo que muestra n√ļmeros, un d√≠gito a la vez. Como ella escribi√≥ todo en ensamblador sin llamar a las funciones est√°ndar de la biblioteca C, le llev√≥ varios d√≠as resolverlo.

El primer programa de Ariella para Adnroid está disponible aquí . Por cierto, algunos identificadores de código en la aplicación son en realidad palabras hebreas (por ejemplo, _sifra_ahrona).

Escribir una aplicaci√≥n de Android en ensamblador es una buena manera de conocer mejor la arquitectura ARM, y tambi√©n de comprender mejor la cocina interna del dispositivo que usa a diario. Le sugiero que haga esto de cerca e intente crear una peque√Īa aplicaci√≥n de ensamblador para su dispositivo. Podr√≠a ser un juego simple o algo m√°s.

Skillbox recomienda:

Source: https://habr.com/ru/post/441798/


All Articles