A better way

13.2 A better way

That was fun, but who wants a 500+ KB file that only displays something to the screen? Recall that the –static flag links in the essentials for running the application, includ- ing the input/output routines required for actually printing a message to the screen. If you are thinking there must be a better way, you are correct; we need to link our application to existing system libraries rather than including all of that code in our application’s executable file.

13.2.1 The static flag, revisited When an application is built with the –static flag, it is entirely self-contained, mean-

ing that all of the routines it requires are linked directly into the application. This is not new information; we have already discussed this. It has another important implica- tion beyond just the size of the code: it also means that using Android resident code libraries is a bigger challenge. Let’s dig deeper to understand why. In order to do this, we have to look at the filesystem of Android/Linux.

System libraries in Android/Linux are stored in the directory /system/lib. This directory contains important functionality, such as OpenGL, SQLite, C standard rou- tines, Android runtime, UI routines, and much more. Figure 13.3 shows a list of the available libraries in the Android Emulator. In short, everything that is specific to the

C HAPTER 13 Hacking Android

Android platform is found in /system/lib, so if we are going to build an application that has any signif- icant functionality, we cannot rely on the libraries that ship with CodeSourcery alone. We have to write an application that can interact with the Android system libraries. This calls for a side trip to discuss the functionality of the linker application.

When building an application that requires the use of the linker, a few things change. First, the gcc command is no longer responsible for invoking the linker. Instead, the –c option is used to inform the tool to simply compile the application and leave the link step to a subsequent build step. Here is an example:

arm-none-linux-gnueabi-gcc –c hello.c -o hello.o This command tells the compiler to compile the file

hello.c and place the resulting object code into the file hello.o.

This process is repeated for as many source files as necessary for a particular application. For our sample application, we have only this single source file. However, in order to get an executable applica- tion, we must employ the services of the linker.

Another important change in the build environ-

Figure 13.3 Available libraries in /

ment is that we need to get a copy of the Android/

system/lib

Linux libraries. We are compiling on the Windows platform (or Linux if you prefer), so we need to get access to the Android Emulator’s /system/lib contents in order to properly link against the library files. Just how do we go about this? We use the adb utility, of course! Listing 13.3 shows a Windows batch file used to extract the system libraries from a running instance of the Android Emulator. A few of the libraries are pointed out.

Listing 13.3 pullandroid.bat

adb pull /system/lib/libdl.so m:\android\system\lib

libdl.so, dynamic loading

adb pull /system/lib/libthread_db.so m:\android\system\lib adb pull /system/lib/libc.so m:\android\system\lib

libc.so, C runtime

adb pull /system/lib/libm.so m:\android\system\lib

libm.so, math library

adb pull /system/lib/libGLES_CM.so m:\android\system\lib adb pull /system/lib/libssl.so m:\android\system\lib

libGLES_CM.so,

OpenGL

adb pull /system/lib/libhardware.so m:\android\system\lib adb pull /system/lib/libsqlite.so m:\android\system\lib many entries omitted for brevity

libsqlite.so, SQLite database

Figure 13.4 shows these files now copied over to the development machine.

A better way

Figure 13.4 Android libraries pulled to the development machine

Once these files are available on the development machine, we can proceed with the build step using the linker.

13.2.2 Linking The name for the linker is arm-none-linux-gnueabi-ld. In most Linux environments the

linker is named simply ld. When using the linker, many command-line options are available for controlling the output. There are so many options that an entire book could be written covering no other topic. Our interest in this chapter is writing appli- cations, and we are taking as streamlined an approach as possible. So while there may

be other options available to get the job done, the aim here is to learn how to build an application that enables us as much flexibility as possible to employ the Android system

C HAPTER 13 Hacking Android

libraries. To that end, listing 13.4 shows the build script for building a dynamic version of Hello Android.

Listing 13.4 Build script for dynamically linked Android application

arm-none-linux-gnueabi-gcc -c hello.c -o hello.o arm-none-linux-gnueabi-ld -entry=main -dynamic-linker /system/bin/linker

-nostdlib -rpath /system/lib -rpath-link /android/system/lib -L /android/system/lib -l android_runtime -l c -o hellodynamic hello.o

C Link

Compile only B

g:\tools\adb push hellodynamic /data/ch13

D Copy and change

g:\tools\adb shell "chmod 777 /data/ch13/hellodynamic"

permissions

This build script passes the –c compiler option B when compiling the source file,

hello.c. This way gcc does not attempt to link the application. The link command,

arm-none-linux-gnueeabi-ld , has a number of options C . These options are more

fully described in table 13.1. As in the previous example, adb is used to push the exe-

cutable file D over to the Android Emulator. The permissions are also modified to

mark the application as executable.

Table 13.1 Linker options

Description -entry=main

Linker option

Indicates the entry point for the application, in this case, the function named main .

-dynamic-linker /system/bin/linker Tells the application where the dynamic linker appli- cation may be found at runtime. The /system/bin/

linker path is found on the Android Emulator, not the development environment.

-nostdlib Tells linker to not include standard C libraries when attempting to resolve code during the link process.

-rpath /system/lib Tells the executable where libraries can be found at runtime. This works in a manner similar to the envi-

ronment variable LD_LIBRARY_PATH . -rpath-link /android/system/lib Tells the linker where libraries can be found when

linking. -L /android/system/lib Tells the linker where libraries can be found. This is

the linker import directory. -l android_runtime Tells the linker that this application requires rou-

tines found in the library file libandroid_runtime.so. -l c Tells the linker that this application requires rou-

tines found in the library file libc.so. -o hellodynamic Requests an output filename of hellodynamic.

hello.o Includes hello.o as an input to the link process.

A better way

If our application required routines from the Open GL or SQLite library, the link command would have additional parameters of –l GLES_CM or –l sqlite, respec- tively. Leaving those library options off the link command prevents the application from linking properly because certain symbols (functions, data) cannot be found.

So, did it work? The hellodynamic binary is now only 2504 bytes. That’s a great improvement. Figure 13.5 shows a listing of the two Hello Android files for a remarkable comparison. Each program is run, first the static version, then the dynamic version.

Figure 13.5 Hello Android, static and dynamically linked

This looks great, except for one little problem. Note the last line in figure 13.5, which says, “Killed.” Is there a problem with our dynamic version? Let’s look closer.

13.2.3 Exit, not return While our application has successfully linked with the Android system libraries of

libc.so and libandroid_runtime.so and can actually run, there are missing pieces that cause the application to not properly execute. When we build an application in this manner, without letting the linker do all of its magic of knitting the entire application together, we have to do some housekeeping ourselves. Looks like there was something to that 500 KB application after all!

For one thing, if our application’s entry point is the main function, and the main function executes a return statement, just where does it return to? Let’s replace the return statement with an exit() call, as shown in listing 13.5.

Listing 13.5 Add an exit() call

#include <stdio.h> int main(int argc,char * argv[])

{ printf("Hello, Android!\n"); exit(0);

B Add exit

C HAPTER 13 Hacking Android

//return 0;

C Remove return call

Add a call B to the function exit(). This should return execution to the operating system. Comment out the call to return() C . A return call in this location causes a

stack underflow because there is nowhere within this application to return to!

This fixed the problem—no more killed messages! Look at figure 13.6, where we see that the dynamic version of Hello, Android! now runs just fine.

Figure 13.6 A better-behaving dynamic version of Hello Android

Unfortunately we are not finished. It turns out that our application does not properly interact with other libraries, nor does it properly handle the argc and argv[] argu- ments to the main function. The C library (remember, we are linking against libc.so) has certain expectations for application structure and stack location. We’re closer but still not quite ready for prime time.

What our application requires is a start routine, which is called by the operating system when our application is invoked. This function in turn calls our application’s main function. This start routine must set up the necessary structures to allow the application to properly interact with the operating system and the core C libraries.

13.2.4 Startup code We have surmised that our application is missing the proper startup code, but just

what does startup code for an Android/Linux application on ARM look like? Where do we turn to get this kind of information? Let’s look deeper into the bag of Code- Sourcery tricks for a clue.

A number of executable applications ship with Android. Let’s pull one of those over to the desktop and see what we can learn. Perhaps we can extract information from that file that can assist in solving this puzzle.

The tool we are going to use to assist us in this effort is the object dump command, arm-none-linux-gnueabi-objdump . This utility has a number of options for tearing apart an ELF (Executable and Linkable Format) file for examination. This is the kind of file structure used by applications in the Android/Linux environment. Using the –d option of the objdump command results in a disassembly of the executable file, showing the assembly language equivalent of the code in each executable section. Our interest is in the first .text section of the disassembly, as this ought to be the entry point of the application. Listing 13.6 shows the .text section from the ping pro- gram taken from the Android Emulator (via adb pull).

A better way

Listing 13.6 Disassembly of ping

000096d0 <dlopen-0x60>: 96d0: e1a0000d mov r0, sp

B Stack pointer

96d4: e3a01000 mov r1, #0; 0x0

C mov instruction

96d8: e28f2004 add r2, pc, #4; 0x4

add instruction

96dc: e28f3004 add r3, pc, #4; 0x4

96e0: eaffff8b b 9514 <dlopen-0x21c>

E Branch instruction

96e4: ea000e03 b cef8 <dlclose+0x37bc>

F Branch instruction

96e8: 0000e408 andeq lr, r0, r8, lsl #8

G Conditional expressions

96ec: 0000e410 andeq lr, r0, r0, lsl r4 96f0: 0000e418 andeq lr, r0, r8, lsl r4 96f4: 0000e420 andeq lr, r0, r0, lsr #8 96f8: e1a00000 nop (mov r0,r0)

H nop instruction

96fc: e1a00000 nop (mov r0,r0)

The first instruction assigns the value of the stack pointer (sp) to register 0 (r0) B . Next the literal value of zero is assigned to register r1 C . The address counter plus four memory location spaces is stored in registers r2 and r3 D .The b instruction tells the code to branch to a specific address E . In this case, the address is 0x21c bytes

prior to the address of the dlopen function. This value is 9514 in decimal. The next

branch is to an address that is 0x37bc bytes beyond the dlclose label F . The next few instructions G are conditional operations. The code snippet finishes up with a pair of nop instructions H . Note that the address of each instruction is shown to the very left

of each line. Each instruction occurs at a 4-byte offset from its predecessor. Four bytes times eight bits per byte equals a 32-bit address bus, which makes sense because the ARM processor family is 32-bit.

Okay, so that looks a little different from the rest of the code in this chapter—and just what does it do? Unfortunately, other than some basic interpretation of the op codes used, there is little to tell us why those instructions are there. After doing some research on the internet, we found a better example of this code, shown in listing 13.7.

Listing 13.7 crt.S

.text

B .text directive

.global _start

C global directive

_start:

D start label

mov r0, sp

E Set up stack pointer

mov r1, #0 add r2, pc, #4 add r3, pc, #4

F Branch to initialization

b __libc_init

b main

G Branch to main

.word __preinit_array_start .word __init_array_start

H Jump table

.word __fini_array_start

C HAPTER 13 Hacking Android

.word __ctors_start .word 0 .word 0 .section .preinit_array

__preinit_array_start:

I Required sections

.word 0xffffffff .word 0x00000000

.section .init_array __init_array_start:

.word 0xffffffff .word 0x00000000

.section .fini_array __fini_array_start:

.word 0xffffffff .word 0x00000000

.section .ctors __ctors_start:

.word 0xffffffff .word 0x00000000

The .text directive indicates that this code should be placed in the .text section of

the resulting executable B . The global start directive C makes the start routine vis- ible to the rest of the application and the linker. The start: D label indicates the first

location of the start routine. The mov and add instructions perform some housekeep-

ing E with the stack pointer, sp, just as seen in the extracted code from the ping pro- gram. Initialization takes place via a branch instruction to call the __libc_init

routine F . This routine is found in the library libc.so. When this routine is complete, execution returns to the next instruction, another branch of the main routine G .

This is the main() routine implemented by our C application. The next instruc-

tions H set up a jump table to the sections required by a C language executable appli- cation. A pair of nop instructions round out the table. The sections preinit_array,

init_array , fini_array, and .ctors are defined I . Note that it appears that these

sections are required and that the values provided are an allowable address range for these sections. The linker takes care of putting these sections into the resulting exe- cutable file. Attempting to run the application without these sections results in code that crashes. I know—I tried!

NOTE All credit for this crt.S file belongs to the author of a blog found at http:

//honeypod.blogspot.com/2007/12/initialize-libc-for-android.html . Ad- ditional reference material for low-level Android programming informa- tion can be found at http://benno.id.au .

Now that we have found an adequate startup routine, let’s take a quick look at how to add this routine to our application. The assembly file is handled just like a C language file by the compiler:

arm-none-linux-gnueabi-gcc -c -o crt0.o crt.S

What time is it?

The resulting object file, crt0.o, is passed to the linker as an input file, just as any other object file would be. Also, the entry switch to the linker must now specify _start rather than main:

arm-none-linux-gnueabi-ld --entry=_start --dynamic-linker /system/bin/linker - nostdlib -rpath /system/lib -rpath-link \android\system\lib -L \android\system\lib -l c -l android_runtime -l sqlite -o executablefile csourcefile.o crt0.o

At this point, we are comfortable that we can build applications for Android/Linux, so it’s time to build something useful. The next section walks through the construc- tion of a daytime server.