© Stephen Smith 2020
S. SmithProgramming with 64-Bit ARM Assembly Languagehttps://doi.org/10.1007/978-1-4842-5881-1_3

3. Tooling Up

Stephen Smith1 
(1)
Gibsons, BC, Canada
 

In this chapter, we will learn a better way to build our programs using GNU Make. With the GNU Debugger (GDB), we will debug our programs. We’ll look at the tools required to cross-compile for ARM from an Intel computer, develop Assembly Language for Google Android, and add Assembly Language to Apple iOS apps. Also, we will quickly introduce the source control system Git and the build server Jenkins.

GNU Make

We built our programs using a simple shell script to run the GNU Assembler and then the Linux linker/loader. As we move forward, we want a more sophisticated tool to build our programs. GNU Make is the standard Linux utility to do this, and it comes preinstalled on many versions of Linux. GNU Make
  1. 1.

    Specifies the rules on how to build one thing from another

     
  2. 2.

    Lists the targets you want built and the files they depend on

     
  3. 3.

    Examines the file date/times to determine what needs to be built

     
  4. 4.

    Issues the commands to build the components

     
Let’s look at how to build our HelloWorld program from Chapter 1, “Getting Started,” using make. First of all, create a text file named makefile containing the code in Listing 3-1.
HelloWorld: HelloWorld.o
     ld -o HelloWorld HelloWorld.o
HelloWorld.o: HelloWorld.s
     as -o HelloWorld.o HelloWorld.s
Listing 3-1

Simple makefile for HelloWorld

Note

The command make is particular, and the indented lines must start with a tab not spaces, or you will get an error.

To build our file, type
make

Rebuilding a File

If we already built the program, then this won’t do anything, since make sees that the executable is older than the .o file and that the .o file is older than the .s file. We can force a rebuild by typing
make -B

Rather than specify each file separately along with the command to build it, we can define a build rule for, say, building a .o file from an .s file.

A Rule for Building .s Files

Listing 3-2 shows a more advanced version, where we define a rule for building an .o file from an .s file. We still need to specify the dependency, but we no longer need the compile rule. As we get more sophisticated and add command line parameters to the as command, we’ve now centralized the location to do this.
 %.o : %.s
     as $< -o $@
HelloWorld: HelloWorld.o
     ld -o HelloWorld HelloWorld.o
Listing 3-2

Hello World makefile with a rule

Now make knows how to create a .o file from a .s file. We’ve told make to build HelloWorld from HelloWorld.o, and make can look at its list of rules to figure out how to build HelloWorld.o. There are some strange symbols in this file and their meaning is as follows:
  • %.s is like a wildcard meaning any .s file.

  • $< is a symbol for the source file.

  • $@ is a symbol for the output file.

There’s a lot of good documentation on make, so we aren’t going to go into a lot of detail here.

Defining Variables

Listing 3-3 shows how to define variables. Here we’ll do it to centralize the list of files we want to assemble.
 OBJS = HelloWorld.o
%.o : %.s
     as $< -o $@
HelloWorld: $(OBJS)
     ld -o HelloWorld $(OBJS)
Listing 3-3

Adding a variable to the Hello World makefile

With this code, as we add source files, we just add the new file to the OBJS= line and make takes care of the rest.

This is just an introduction to GNU Make—there is a lot more to this powerful tool. As we go further into the book, we will introduce new elements to our makefiles as needed.

GDB

Most high-level languages come with tools to easily output any strings or numbers to the console, a window, or a web page. Often when using these languages, programmers don’t bother using the debugger, instead relying on libraries that are part of the language.

Later, we’ll look at how to leverage the libraries that are part of other languages, but calling these takes a bit of work. We’ll also develop a helpful library to convert numbers to strings, so we can use the techniques used in the HelloWorld program in Chapter 1, “Getting Started,” to print our work.

When programming with Assembly Language, being proficient with the debugger is critical to success. Not only will this help with your Assembly Language programming, but also it is a great tool for you to use with your high-level language programming.

GDB comes preinstalled on most Linux distributions, but if it is missing from your version and you’re running one based on Debian, like Kali, then you can install it via
sudo apt-get install gdb

Preparing to Debug

The GNU Debugger (GDB) can debug your program as it is, but this isn’t the most convenient way to go. For instance, in our HelloWorld program, we have the label helloworld. If we debug the program as is, the debugger won’t know anything about this label, since the Assembler changed it into an address in a .data section. There is a command line option for the Assembler that includes a table of all our source code labels and symbols, so we can use them in the debugger. This makes our program executable a bit larger.

Often, we set a debug flag while we are developing the program, then remove the debug flag before releasing the program. Unlike some high-level programming languages, the debug flag doesn’t affect the machine code generated, so the program behaves exactly the same in both debug and non-debug mode.

We don’t want to leave the debug information in our program for release, because besides making the program executable larger, it is a wealth of information for hackers to help them reverse engineer your program. There are several cases where hackers caused mischief because the program still had debugging information present.

To add debug information to our program, we must Assemble it with the -g flag. In Listing 3-4, we add a debug flag to our makefile. For the first program we’ll debug, let’s use our examples of the MOV statements, since we didn’t see the operations working on the various registers.
 OBJS = movexamps.o
ifdef DEBUG
DEBUGFLGS = -g
else
DEBUGFLGS =
endif
%.o : %.s
     as $(DEBUGFLGS) $< -o $@
movexamps: $(OBJS)
     ld -o movexamps $(OBJS)
Listing 3-4

Makefile with a debug flag

This makefile sets the debug flag if the variable DEBUG is defined. We can define it on the command line for make with
make DEBUG=1
or, from the command line, define an environment variable with
export DEBUG=1
To clear the environment variable, enter
export DEBUG=

When switching between DEBUG and non-DEBUG, run make with the -B switch to build everything.

Tip

Create shell scripts buildd and buildr to call make with and without DEBUG defined.

Beginning GDB

To start debugging our movexamps program, enter the command
gdb moveexamps
This yields the abbreviated output:
GNU gdb (Debian 8.3.1-1) 8.3.1
Copyright (C) 2019 Free Software Foundation, Inc.
...
Reading symbols from movexamps...
(gdb)
  • gdb is a command line program.

  • (gdb) is the command prompt where you type commands.

  • (hit tab) for command completion. Enter the first letter or two of a command as a shortcut.

To run the program, type
run

(or r).

The program runs to completion, as if it ran normally from the command line.

To list our program, type
list

(or l).

This lists ten lines. Type
l
for the next ten lines. Type
list 1,1000

to list our entire program.

Notice that list gives us the source code for our program, including comments. This is a handy way to find line numbers for other commands. If we want to see the raw machine code, we can have gdb disassemble our program with
disassemble _start

This shows the actual code produced by the Assembler with no comments. We can see whether MOV or MVN were used among other commands this way.

To stop the program, we set a breakpoint. In this case, we want to stop the program at the beginning to single step through, examining registers as we go. To set a breakpoint, use the breakpoint command (or b):
b _start
We can specify a line number, or a symbol for our breakpoint, as in this example; now if we run the program, it stops at the breakpoint:
(gdb) b _start
Breakpoint 1 at 0x400078: file movexamps.s, line 7.
(gdb) r
Starting program: /home/smist08/asm64/Chapter 2/movexamps
Breakpoint 1, _start () at movexamps.s:7
7       _start: MOV     X2, #0x6E3A
We can now step through the program with the step command (or s). As we go, we want to see the values of the registers. We get these with info registers (or i r):
(gdb) s
8               MOVK    X2, #0x4F5D, LSL #16
(gdb) i r
x0             0x0                 0
x1             0x0                 0
x2             0x6e3a              28218
x3             0x0                 0
x4             0x0                 0
x5             0x0                 0
...
x29            0x0                 0
x30            0x0                 0
sp             0x7ffffff230        0x7ffffff230
pc             0x40007c            0x40007c <_start+4>
cpsr           0x200000            [ EL=0 SS ]
fpsr           0x0                 0
fpcr           0x0                 0
(gdb)

We see 0x6E3A put in X2 as expected.

We can continue stepping or enter continue (or c), to continue to the next breakpoint or to the end of the program. We can set as many breakpoints as we like. We can see them all with the info breakpoints (or i b) command. We can delete a breakpoint with the delete command, specifying the breakpoint number to delete.
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000400078 movexamps.s:7
        breakpoint already hit 1 time
(gdb) delete 1
(gdb) i b
No breakpoints or watchpoints.
(gdb)
We haven’t dealt with memory much, but gdb has good mechanisms to display memory in different formats, the main command being x. It has the following format:
x /Nfu addr
where
  • N is the number of objects to display

  • f is the display format where some common ones are
    • t for binary

    • x for hexadecimal

    • d for decimal

    • i for instruction

    • s for string

  • u is unit size and is any of
    • b for bytes

    • h for halfwords (16 bits)

    • w for words (32 bits)

    • g for giant words (64 bits)

Some examples using our code stored at memory location _start, or 0x10054:
(gdb) x /4ubft _start
0x400078 <_start>:    01000010   11000111   10001101   11010010
(gdb) x /4ubfi _start
   0x400078 <_start>:   mov     x2, #0x6e3a          // #28218
=> 0x40007c <_start+4>: movk    x2, #0x4f5d, lsl #16
   0x400080 <_start+8>: movk    x2, #0xfedc, lsl #32
   0x400084 <_start+12>: movk    x2, #0x1234, lsl #48
(gdb) x /4ubfx _start
0x400078 <_start>:      0x42    0xc7    0x8d    0xd2
(gdb) x /4ubfd _start
0x400078 <_start>:      66      -57     -115    -46

To exit gdb, type q (for quit or type control-d).

Table 3-1 provides a quick reference to the GDB commands we introduced in this chapter. As we learn new things, we’ll need to add to our knowledge of gdb. It is a powerful tool to help us develop our programs. Assembly Language programs are complex and subtle, and gdb is great at showing us what is going on with all the bits and bytes.
Table 3-1

Summary of useful GDB commands

Command (Short Form)

Description

break (b) line

Set breakpoint at line

run (r)

Run the program

step (s)

Single step program

continue (c)

Continue running the program

quit (q or control-d)

Exit gdb

control-c

Interrupt the running program

info registers (i r)

Print out the registers

info break

Print out the breakpoints

delete n

Delete breakpoint n

x /Nuf expression

Show contents of memory

It’s worthwhile single stepping through our three sample programs and examining the registers at each step to ensure you understand what each instruction is doing.

Even if you don’t know of a bug, many programmers like to single step through their code to look for problems and to convince themselves that their code is good. Often two programmers do this together as part of the pair programming agile methodology.

Cross-Compiling

So far, we’ve been compiling and running our programs on an ARM-based computer like the Raspberry Pi or NVidia Jetson Nano; however, we can also compile and run our programs on an Intel-based computer. In this section, we’ll see how to compile and run the Hello World program from Chapter 1, “Getting Started,” on Ubuntu Linux running on an Intel-based laptop.

The GNU Assembler and the Linux linker/loader are both open source programs and can be compiled to run on any system. The GNU Assembler source code contains support for many CPU architectures, and the code it is written in compiles on all sorts of systems. Ubuntu Linux on Intel comes with all the GNU tools installed, but they compile Intel Assembly Language code instead of ARM. It would be nice if the GNU Assembler had a command line switch to tell it to compile ARM code, but that isn’t how it works. You need to specify the type of Assembly code to process at compile time.

The solution is to obtain all the necessary GNU and Linux tools to compile for ARM, but run on Intel and then install them in a different location. We can add them to our Ubuntu Linux with the command
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
This will install them to /usr/aarch64-linux-gnu/bin. We don’t want to add this to our PATH variable because we won’t know whether the Intel or ARM version will be run. Instead we add this path in our makefile. One way to do this is in Listing 3-5.
TOOLPATH = /usr/aarch64-linux-gnu/bin
HelloWorld: HelloWorld.o
     $(TOOLPATH)/ld -o HelloWorld HelloWorld.o
HelloWorld.o: HelloWorld.s
     $(TOOLPATH)/as -o HelloWorld.o HelloWorld.s
Listing 3-5

Makefile to build Hello World on an Intel CPU

If we then run this, we see
stephen@stephenubuntu:~/asm64/Chapter 3$ make
/usr/aarch64-linux-gnu/bin/as -o HelloWorld.o HelloWorld.s
/usr/aarch64-linux-gnu/bin/ld -o HelloWorld HelloWorld.o

We’ve now built our Hello World program for ARM on an Intel CPU. This is called cross-compiling. This is most used when programming embedded ARM processors that don’t run a full Linux kernel and hence don’t have all the development tools available. The workflow is to build the program on a full development system and then transfer the program to the target processor using a USB cable, serial cable, or via Ethernet. You can copy the resulting program to a Raspberry Pi or NVidia Jetson computer to run it. Even if your target platform supports all the development tools, it can be faster to do your builds on a more powerful laptop or desktop.

Emulation

Even if you don’t have an ARM-based computer, you can still run most of the programs in this book using an ARM CPU emulator. The emulator will interpret the ARM machine code and simulate it using the local processor. Again, we are using Ubuntu Linux running on an Intel CPU. There are quite a few different emulators available; here we’ll walk through setting up and using the QEMU emulator. To install it, type
sudo apt-get install qemu qemu-user
We can now execute the Hello World program we compiled in the previous section:
stephen@stephenubuntu:~/asm64/Chapter 3$ qemu-aarch64 HelloWorld
Hello World!

We have now successfully compiled and run our ARM 64-bit Assembly Language program on an Intel PC.

Android NDK

To run our HelloWorld program from Chapter 1, “Getting Started,” is surprisingly easy. This is because Android is based on Linux, and as time has gone by, Google has moved Android closer and closer to standard Linux. The main thing we need to do is install the official tools, compile our program, and copy it over to an Android device to run. You can’t develop for Android on an ARM-based system like a Raspberry Pi or an Android-based laptop; you must develop on an Intel system under either Linux, MacOS, or Windows.

Note

Not all Android devices are based on ARM CPUs. Ensure your Android device contains an ARM CPU and that you are running a 64-bit version of Android.

You must install Android Studio, the Integrated Development Environment for Android development. Once you have this installed, you need to install the NDK; this is the Native Code Development Kit for Android. Android Studio by default creates applications that can run on any Android device, no matter what type of CPU they contain. With the NDK, you can write processor-specific code like the Assembly Language we want to run. To install the NDK, go to the “Settings” menu in Android Studio, select “System Settings,” and select the NDK as shown in Figure 3-1.
../images/494415_1_En_3_Chapter/494415_1_En_3_Fig1_HTML.jpg
Figure 3-1

Android Studio’s System Settings showing the NDK installed

The NDK installs special Android versions of the GNU Assembler and the Linux linker/loader. On my Ubuntu Linux laptop, these were installed to
/home/stephen/Android/Sdk/ndk/20.1.5948944/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin

As you can see, these will move as the NDK or Android is updated to new version. This is like what we did when cross-compiling; only the tools have separate names, namely, aarch64-linux-android-as and aarch64-linux-android-ld. Since the commands have unique names, we can add the preceding path to our system PATH in our .bashrc file without conflicting with our system’s default applications.

Listing 3-6 shows how to create a makefile to add an option to build HelloWorld for Android.
ifdef ANDROID
AS = aarch64-linux-android-as
LD = aarch64-linux-android-ld
else
AS = as
LD = ld
endif
OBJS = HelloWorld.o
%.o : %.s
     $(AS) $< -o $@
HelloWorld: $(OBJS)
     $(LD) -o HelloWorld $(OBJS)
Listing 3-6

Makefile to build HelloWorld for Android

If we save this in makefile2, then we need to run
make -f makefile2 ANDROID=y

to build our program for Android.

We now have our HelloWorld program built for Android but sitting on our Intel-based laptop. How do we copy it to our device and run it? Android is a locked down version of Linux and expects people to only run programs downloaded from the Google Play Store. To run our programs, we need to put the Android device into developer mode. This is usually accomplished by tapping on the build number in the settings menu multiple times. Once the device is in developer mode, a developer menu will be added to the settings menu; from here, we need to enable USB debugging. I find it convenient to disable sleep mode while charging as well.

Next, we need to install the Android Debug Bridge (adb). We do this with
sudo apt-get install adb
With this all done and our Android device connected to our laptop, we can copy over the program and run it. To copy the program, use
adb push HelloWorld /data/local/tmp/HelloWorld
This copies HelloWorld to the indicated folder on the Android device. Now we can use adb to open a remote command prompt to the Android device, make the file executable, and run it:
adb shell
cd /data/local/tmp
chmod +x HelloWorld
./HelloWorld
Here is the whole build, copy, and run procedure with the various prompts and responses:
stephen@stephenubuntu:~/asm64/Chapter 3$ make -B -f makefile2 ANDROID=y
aarch64-linux-android-as HelloWorld.s -o HelloWorld.o
aarch64-linux-android-ld -o HelloWorld HelloWorld.o
stephen@stephenubuntu:~/asm64/Chapter 3$ adb push HelloWorld /data/local/tmp/HelloWorld
HelloWorld: 1 file pushed. 0.2 MB/s (1104 bytes in 0.007s)
stephen@stephenubuntu:~/asm64/Chapter 3$ adb shell
T7:/ $ cd /data/local/tmp
T7:/data/local/tmp $ chmod +x HelloWorld
T7:/data/local/tmp $ ./HelloWorld
Hello World!
T7:/data/local/tmp $ ^D
stephen@stephenubuntu:~/asm64/Chapter 3$

This demonstrates how learning Assembly Language for Linux can be directly leveraged to incorporate Assembly Language into an Android program. Android developers develop apps and not command line programs; in Chapter 9, “Interacting with C and Python,” we’ll create a true Android app and make an Assembly Language routine do some processing.

Apple XCode

All up-to-date Apple iPhones and iPads run a 64-bit version of iOS and utilize an ARM processor. All iOS apps are written in Objective-C or Swift; however, Apple’s XCode development environment does have support for incorporating Assembly Language code. In this section, we’ll look at how to run our Hello World program from Chapter 1, “Getting Started,” on either an iPhone or iPad.

To run the program in this section, you are required to have a Mac laptop or desktop running an up-to-date version of MacOS. However, if you aren’t interested in developing for iOS, you can skip this section. You also will need an iPhone or iPad to run the program on.

iOS is based on NeXTSTEP which is based on Berkeley Unix (BSD), not Linux, so things will be different than what we’ve seen so far. However, iOS does incorporate the POSIX Unix standard which Linux also supports. The result is that the changes required to make our Hello World program work on an iOS device are surprisingly minor.

iOS is a regulated environment, so we can’t just open a terminal window and run our programs from the command line. We need to create an “official” iOS app, code sign it, and then download it from our Mac to our iOS device. We’ll create an empty Objective-C project, add our Hello World file, and pass control to our program.

Run XCode and create a new project. Select Objective-C as the programming language and choose a single view app. XCode will go ahead and create the source code for a simple empty app. Next, create a file in the project folder called HelloWorld.s containing the contents of Listing 3-7.
//
// Assembler program to print "Hello World!"
// to stdout.
//
// X0-X2 - parameters to iOS function services
// X16 - iOS function number
//
.global _start        // Provide program entry point
// Setup the parameters to print hello world
// and then call Linux to do it.
_start: mov     X0, #1      // 1 = StdOut
     adr   X1, helloworld   // string to print
     mov   X2, #13          // length of our string
     mov   X16, #4          // iOS write system call
     svc   #0x80            // Call iOS to output the string
// Setup the parameters to exit the program
// and then call Linux to do it.
     mov     X0, #0     // Use 0 return code
     mov     X16, #1    // Service code 1 terminates
     svc     #0x80      // Call iOS to terminate
helloworld:      .ascii  "Hello World! "
Listing 3-7

Apple iOS HelloWorld.s

Let’s examine the differences between the iOS and Linux versions of Hello World:
  1. 1.

    The operating system function number is placed in register X16 rather than X8.

     
  2. 2.

    iOS uses software interrupt 0x80 rather than 0 to make the operating system call.

     
  3. 3.

    The function numbers are different. These are the same function numbers used in 32-bit Linux. When iOS went from 32 to 64 bits, Apple kept the operating system function numbers the same, whereas Linux rearranged them completely.

     
  4. 4.

    We use “adr X1, helloworld” rather than “ldr X1,=helloworld” to load the address of our string (also note we don’t have a .data section). We’ll discuss the difference between these in Chapter 5, “Thanks for the Memories”; for now, it is just two different ways to get the address of our string loaded into register X1. We had to make this switch since iOS prohibits the previous method.

     

Otherwise, this should all look very familiar.

Now we must cause this code to execute. iOS doesn’t run the _start label; rather there is a more complicated framework to run things. This is why we created a simple Objective-C program. To execute our code, we need to edit one of the Objective-C files, in our case ViewController.m. Near the beginning of the file, add
extern void start( void );
Then at the end of the viewDidLoad method, add
start();
which should result in Listing 3-8.
#import "ViewController.h"
extern void start( void );
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
   // Do any additional setup after loading the view.
    start();
}
@end
Listing 3-8

ViewController.m

We call start(), rather than _start(), because the Objective-C compiler will “decorate” the function name adding the “_”. Now we are ready to run.

If we just select project build at this point, we will get a large number of cryptic error messages from the Assembler. This is because by default, XCode will try to run our program in one of the iOS simulators on the Mac. Normally this is fine, but it won’t work for any app containing Assembly Language code. This is because the Mac uses an Intel processor, and to compile for the simulator, XCode will try to interpret our HelloWorld.s file as Intel Assembly language, which it isn’t.

To compile and run our program, we need to physically connect our iPad or iPhone to our Mac using a USB cable. With this done, we can select the iOS device as our destination. Once we do that, then we can compile the program. When we run it, it will download to the iPhone or iPad and our Hello World program will appear in the output window in XCode as shown in Figure 3-2.
../images/494415_1_En_3_Chapter/494415_1_En_3_Fig2_HTML.jpg
Figure 3-2

XCode after running our program

I left out any steps to initialize your device or set up your developer id with Apple. These are all necessary, but if you are doing iOS development, these should already have been completed.

Note

Be careful with Assembly Language programming on iOS as if you do something that Apple doesn’t like, they will remove you from the App Store.

This section was just to give you an idea of how to add Assembly Language to an iOS app. It isn’t a realistic example, especially since it terminates the program. Typically, you write Assembly Language to implement fast functions called from the high-level language. We’ll cover how to implement functions, including taking parameters and returning values in Chapter 9, “Interacting with C and Python.”

Source Control and Build Servers

Although make is fine for our purposes in this book, there are much more sophisticated build systems. As your programs get larger, managing changes and versions becomes more challenging; to help with this, there are version control systems like Git. The source code for this book is hosted on a cloud version of Git, called GitHub. You can get a link to this book’s source code from this book’s web page on Apress.​com.

Git

As your program gets larger, consider using a source control system to manage source files. Source control systems keep all the versions of your program. With source control, it’s easy to retrieve the files that make up version 1.15 of your program; you can have multiple branches, so you can work on both version 1.16 while also working on version 2.1 and keep everything straight.

Once you have a team of programmers working on your project, you need to regulate who is editing what, so people don’t overwrite each other’s work. Git takes this to a new level, where two people can edit the same file; then Git can merge the changes to keep both people’s work. Git is a great program for doing this. Git was developed by Linus Torvalds as the source control system for all Linux development. There are cloud versions, like GitHub, that keep your files in the Cloud, and as a result, you don’t need to worry about backing them up.

Note

The SD Cards, the Raspberry Pi, and NVidia Jetson use instead of hard drives or SSDs are not as reliable. They can fail, so you should always have a backup of your work. If you don’t back up to the Cloud with a service like GitHub, back up with one of the following:

  • Copy your files to Google Drive.

  • E-mail your files to yourself.

  • Copy them to a USB hard drive.

Don’t trust the SD Card, as it will fail at some point.

Git is a sophisticated system beyond the scope of this book, but worth checking out.

Jenkins

Once you are using GNU Make and Git, you might consider checking out Jenkins. Jenkins is a build server that monitors Git, and every time you check in a new version of a program file, it kicks off a build. This is part of a continuous development system that can even deploy your program.

This is especially helpful if you have a team of programmers, where the build takes a long time, or you need the result to automatically be deployed, say, to a web server.

If you have a set of automated tests, these are run after each build. Having the automated tests run frequently helps you detect when your program is broken. The cost of fixing a bug tends to be proportional to the time that the bug exists in the code, so finding and fixing bugs quickly is a huge productivity gain.

Summary

In this chapter, we introduced the GNU Make program that we will use to build our programs. This is a powerful tool used to handle all the rules for the various compilers and linkers we need.

We then introduced the GNU Debugger that will allow us to troubleshoot our programs. Unfortunately, programs have bugs and we need a way to single step through them and examine all the registers and memory as we do so. GDB is a technical tool, but it’s indispensable in figuring out what our programs are doing.

We covered how to cross-compile our code on Intel-based computers and how to run our ARM programs in an emulator. We then covered how to set up an Android development environment for Assembler development and run our HelloWorld program on an Android device. We then covered how to create an Apple iOS app and run a modified version of our HelloWorld program on an iPad or iPhone.

Lastly, we mentioned the source control system Git and the build server Jenkins. We won’t be using these in this book, but as your needs get more sophisticated, you should check these out.

In Chapter 4, “Controlling Program Flow,” we will look at conditionally executing code, branching, and looping—the core building blocks of programming logic.

Exercises

  1. 1.

    Create a makefile for one of the small programs in Chapter 2, “Loading and Adding.”

     
  2. 2.

    Step through the small program from Chapter 2, “Loading and Adding,” to ensure you understand the changes each instruction makes to the registers.

     
  3. 3.

    If you have a computer with an Intel processor, set it up to cross-compile for ARM and compile HelloWorld. Install the emulator and run it on the Intel computer.

     
  4. 4.

    If you have an ARM-based Android 64-bit device and an Intel computer, set it up for Android Assembly development and run HelloWorld.

     
  5. 5.

    If you have a Mac and iPad or iPhone, install XCode and compile and run HelloWorld as indicated.

     
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.131.238