Writing an Android application in assembler

Original author: Uri Shaked
  • Transfer
image

This story is about a non-standard approach to the development of Android applications. It’s one thing to install Android Studio and write “Hello, World” in Java or Kotlin. But I will show how the same task can be performed differently.

We remind you: for all readers of “Habr” - a discount of 10,000 rubles when registering for any Skillbox course using the “Habr” promo code.

Skillbox recommends: The on-line educational course "Profession Java-developer" .

How does my smartphone work with Android OS?


First, a little background. One evening a friend called Ariella called me. She asked me: “Listen, how does my smartphone work? What is inside it? How does electric energy and ordinary ones and zeros allow all of this to function? ”

My friend is not a noob in development, she created several projects on Arduino, which consisted of both software and hardware. Maybe that's why she wanted to know more. I managed to answer with the help of knowledge obtained at one of the computer science courses taken at the university.

Then we worked a couple of weeks together, as Ariella wanted to find out how the bricks of electronic technology work, that is, semiconductor elements, including transistors. Next, we went to a higher level: I showed her how to create logic gates, for example, NAND (logical AND) plus NOR (logical OR) using a specific combination of transistors.

We investigated logical elements of different types, combined them to perform calculations (for example, adding two binary numbers) and memory cells (triggers). When everything became clear, they began to develop a simple processor (imaginary), in which there were two general-purpose registers and two simple instructions (adding these registers). We even wrote a simple program that multiplies these two numbers.

By the way, if you are interested in this topic, then read the instructions for creating an 8-bit computer from scratch. It explains almost everything, from the very basics. I wish I read it earlier!

Hello Android!


After completing all the stages of the study, it seemed to me that Ariella had enough knowledge to understand how the smartphone processor works. Her smartphone is the Galaxy S6 Edge, whose base is the ARM architecture (as, in fact, with most smartphones). We decided to write a “Hello, World” application for Android, but in assembly language.

.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

If you have never encountered assembler code before, this block may scare you. But it's okay, let's parse the code together.

So, our program consists of two parts. The first is text with machine code instructions, and the second is variables, lines, and other information (starting with line 15). The .text section is usually read-only, and .data is also writable.

In line 2, we define a global function called _start. It is the entry point to the application. The OS starts to execute the code from this point. The function definition is declared in line 4.

In addition, the function does two more things. In lines 5–9, the message is displayed on the screen; in lines 11–13, the program ends. Even if you delete lines 11–13, the program will output our “Hello, World” line and exit. However, the output will not be correct, because the program will end with an error. Without lines 11–13, the application will try to execute an invalid instruction.

Printing is displayed using the system function "System call" of the operating system. In the application, we call the write () function. We indicate it when we load the value 4 into the processor register with the name r7 (line 8). Next, the swi $ = 0 instruction (line 9) is executed, where there is a transition directly to the Linux kernel, which is the basis of Android.

As for the parameters for the system call, they are transmitted through other registers. For example, r0 shows the number of the file descriptor that we need to print. We put the value 1 there (line 5), indicating standard output (stdout), that is, output to the screen.

r1 indicates the memory address of the data we want to write, so we just load the address of the string “Hello, World” (line 6) into this area, and the register r2 shows how many bytes we want to write. In our program, it is set to message_len (line 7), calculated on line 18 using special syntax: the dot symbol indicates the current memory address. For this reason. - message indicates the current memory address minus the message address. Well, since we declare message_len immediately after message, all this is calculated as the length of message.

If you write the code for lines 5–9 using C, you get the following:

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

Shutting down the program is a bit easier. To do this, we simply register the exit code in the register r0 (line 11), after which we add the value 1, which is the number of the exit () system function call, to r7 (line 12), then call the kernel again (line 13).

A complete list of Android system calls and their numbers can be found in the source code of the operating system . There is also an implementation of write () and exit () that call the corresponding system functions.

Putting the program together


In order to compile our project, you will need Android NDK (Native Development Kit). It contains a set of compilers and build tools for the ARM platform. You can download it from the official site, install it, for example, through Android Studio.



After the NDK is installed, we need the arm-linux-androideabi-as file, this is assembler for ARM. If you downloaded via Android Studio, then look for it in the Android SDK folder. Usually its location is

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

After the assembler is found, save what is written in a file called hello.s, and then run the following command to convert it to machine code:

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

This operation creates an ELF object file called hello.o. In order to convert it to a binary file that can work on your device, call the linker:

arm-linux-androideabi-ld -o hello hello.o

Now we have a hello file that contains a program that is ready to use.

Launch the application on your device


Android applications are usually distributed in .apk format. This is a special kind of compressed file that includes Java classes (yes, you can write with C / C ++, but Java must be the entry point).

In order to avoid problems when starting the application, adb was used in the example, which allowed us to copy it to the temporary folder of our Android device. After that we launch the adb shell in order to launch the application and evaluate the result:

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


And finally, run the application:

adb shell / data / local / tmp / hello

What do you write?


Now you have a working environment similar to the one Ariella had. She spent several days studying the ARM assembler, then came up with a simple project - this is the game Sven Boom (a variation of Fizz Buzz originally from Israel). Players count in turn and each time the number is divided by 7 or contains the number 7, they must say “boom” (hence the name of the game).

It is worth noting that the game program is not such an easy task. Ariella wrote a whole method that displays numbers, one digit at a time. Since she wrote everything in assembler without calling the standard C library functions, it took several days to solve.

Ariella's first Adnroid program posted here. By the way, some code identifiers in the application are actually Hebrew words (for example, _sifra_ahrona).

Writing an Android application in assembler is a good way to get to know the ARM architecture better, and also to better understand the inner kitchen of the gadget you use daily. I suggest you do this closely and try to create a small assembler application for your device. It could be a simple game or something else.

Skillbox recommends:


Also popular now: