Implementing simple sort algorithms in ARM Assembly (part 2)

I haven’t completed the code yet, but I wanted to share my progress learning ARM assembly by implementing a simple sort algorithm (part 1 is here). I’m committing my changes as you go so if you’re interested you can also pull the code form github here.

The simple sort that I’m implementing is a ‘comparison sort‘. You start at lowest end of the array of values, iterate through to find the smallest value and then switch the smallest found value to the front. You then repeat the loop starting at the next index in the array, search again for the smallest, switch, and then continue repeating this until you’ve looped through and compared all values.

I’ll make clear that as I’m learning ARM ASM I’ve no idea at this point if my approach to implementing this algorithm is optimal, but I’m finding it a useful learning exercise. At this point I’m also finding debugging the code in Eclipse C++ indispensable – I don’t think a this point I could debug the code without an IDE (or to try would be difficult and error prone). Once you’ve walked through the steps to crosscompile in Eclipse C++ you can use the same setup to remove debug in Eclipse C++ too, with the executable running remote on the Raspberry Pi.

So far I have the outer and inner loops working, so can iterate through the values, and compare to find the smallest value on each iteration. I’ll post another update once I’ve got the swapping done. In the meantime if you’re interested you can take a look at my latest commit in my github repo above.

Uncle Bob: “Make the Magic Go Away” – why you should learn some Assembly

I’ve been spending some spare time learning some ARM Assembly (and sharing from of my experiences here, here and here).

In the early 90s at college I did a module on 68000 Assembly on the Atari ST, but I haven’t done any since. I remember being amazed at how complicated and it was to implement even the most simplest of code, since you’re dealing with a very limited set of instructions, using instructions that the CPU itself understands. At the same time though you gained an insight into what goes on under the covers, how the computer itself works – how the CPU’s registers are used, and how data is transferred from registers to memory and vice versa. It’s computing at it’s most elemental level, you’re working with the bare metal hardware.

Since I’ve also recently been playing around with random stuff on the Raspberry Pi, I thought I’d take a look at the ARM CPU and learn some ARM Assembly. I felt a need to get back to basics and learn about the architecture of ARM CPUs and what makes them tick. As much as this sounds pretty hardcode and crazy, ARM CPUs are showing up pretty much everywhere and you probably don’t even know it. There’s a good chance at least one if not more of you mobile devices you currently and have owned over the past few years has been powered by an ARM CPU. So given the memory and CPU contraints of small form factor devices, and also IoT type devices, it’s not completely off the wall to be interested in learning some ARM Assembly.

Anyway, back to my original point. If you want to understand what makes a computer tick (literally), you can’t go far wrong by learning some Assembly. You’ll get a far better understanding of what goes on under the covers, and a new appreciation of just how much abstraction there is in today’s high level languages (Java, C#, Objective-C etc) – how much they do for you without you even really have to know what’s going on under the covers. But if you really want to get a deeper understanding, you lift the hood/bonnet and start poking around in the engine, right?

It surprised me when I came across this post by Uncle Bob recently:

http://blog.8thlight.com/uncle-bob/2015/08/06/let-the-magic-die.html

Bob comments on the continual search within the industry to find the perfect language or library. We’re continually re-inventing languages and frameworks, but there’s really nothing revolutionary different being ‘invented’ – they’re all solving the same problems, and not really offering anything new. Bob even goes as far to say there really hasn’t been anything new in computer languages for 30 years.

The unusual thing is that we seem to get caught up in the promise that maybe the next big language or framework ‘solves all problems’ and does it better than all other languages and frameworks before, but there’s still really nothing new.

Bob’s point:

But there is no magic. There are just ones and zeros being manipulated at extraordinary speeds by an absurdly simple machine. And that machine needs discrete and detailed instructions; that we are obliged to write for it.

And continues:

I think people should learn an assembly language as early as possible. I don’t expect them to use that assembler for very long because working in assembly language is slow and painful (and joyous!). My goal in advocating that everyone learn such a language is to make sure that the magic is destroyed.

And here’s it is, the reason why you should learn Assembler:

If you’ve never worked in machine language, it’s almost impossible for you to really understand what’s going on. If you program in Java, or C#, or C++, or even C, there is magic. But after you have written some machine language, the magic goes away. You realize that you could write a C compiler in machine language. You realize that you could write a JVM, a C++ compiler, a Ruby interpreter. It would take a bit of time and effort. But you could do it. The magic is gone.

I don’t know exactly what prompted me recently to start learning Assembler, but these comments from Uncle Bob resonated with me. If you don’t know how a computer works, how do you expect to understand what is going on when you develop code to run on it?

So there you go. Bob said it. Go learn Assembler. Maybe you’ll learn something.

 

Fixing the Eclipse C++ remote execution “Error during file upload” error

Yesterday I posted the steps I had followed to get Eclipse C++ up and running on Ubuntu under VirtualBox on the Mac, to build and deploy ARM Assembly executables to the Raspberry Pi.

One of the errors that I encountered along the way wasUpload error this one: “Error during file upload”:

While following another post trying to get remote debugging setup, I noticed that the paths to the executable in the config dialog didn’t look like what I had used, so I took a closer look.

 

 

When setting up the remote connection for run and debug looks like this:

Remote execution dialog

If either the ‘remote absolute path’ or ‘commands to execute’ values are pointing to invalid paths, it seems that you get the ‘Error during file upload’ error.

The ‘Remote absolute path’ value should be the absolute path to the executable including the executable file name too.

If you need to chmod the file after uploading, that also needs a full path to the executable file.

Once this is sorted, success!

Remote execution

 

Cross-compiling ARM ASM on the Mac for the Raspberry Pi

I’ve posted recently about my experience learning some ARM assembly, and in particular, attempting to develop a simple sorting algorithm. Initially I had just been using Atom and TextMate editors on my Mac and then ftp’ing the source over to the Pi to compile and run, but I had got to a point where I realized this wasn’t going to cut it for working on anything slightly larger, so I started looking at getting Eclipse C++ working with cross compiler toolchains (cross compiling allows you to compile code on one hardware architecture type to run on another)

I actually looked into getting this working on Windows several months back, but I hadn’t used it or pursued it any further, so rather than trying to retrace my steps, I started again from scratch (I also wanted to get it working on my Mac rather than on Windows).

The First Attempt – Compiling in Eclipse C++ on the Mac

Skipping a few steps to get to the more interesting details, assuming Eclipse for C++ is already downloaded and installed along with the GNU toolchain for ARM, here’s what I got building my project for the first time:

 11:54:51 **** Build of configuration arm cross compile for project ASMCrossCompile ****
 make all
 Building file: ../test.S
 Invoking: Cross GCC Assembler
 /Applications/EclipseIDEs/gcc-arm-none-eabi-4_9-2015q2/bin/arm-none-eabi-as-o "test.o" "../test.S"
 Finished building: ../test.S
 Building target: ASMCrossCompile
 Invoking: Cross GCC Linker
 /Applications/EclipseIDEs/gcc-arm-none-eabi-4_9-2015q2/bin/arm-none-eabi-gcc-L/Applications/EclipseIDEs/gcc-arm-none-eabi-4_9-2015q2/arm-none-eabi/lib -o "ASMCrossCompile" ./test.o
 /Applications/EclipseIDEs/gcc-arm-none-eabi-4_9-2015q2/arm-none-eabi/lib/libc.a(lib_a-exit.o): In function `exit':
 exit.c:(.text.exit+0x2c): undefined reference to `_exit'
 collect2: error: ld returned 1 exit status
 make: *** [ASMCrossCompile] Error 1

This error “undefined reference to `_exit'” is described in this SO post here:
http://stackoverflow.com/questions/19419782/exit-c-text0x18-undefined-reference-to-exit-when-using-arm-none-eabi-gcc

This issue is apparently directly related to cross compiling on a different hardware architecture, and the solution is to add the –specs=nosys.specs option to the loader config. I added this in Eclipse in project properties, C/C++ Build/Settings/Cross GCC Linker and added into the Expert Settings Command Line Pattern and this fixed this issue.

Transferring the Executable to the Pi

In Eclipse C++, in the Run Configuration settings you can select ‘New Connection’ and configure a ssh connection to your Pi. You need to also set a full path on the Pi for where the file is going to be dropped.

At this point I get this error: “Error during upload : File system input or output error”. Executing the file on the Pi itself I get a Seg Fault.

Searching around, the general suggestion seems to run ‘file’ against the executable to check that it was compiled and linked against the right architecture.

For my newly cross compile file, I get this:

pi@raspberrypi~/asm $ file ASMCrossCompile
ASMCrossCompile: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped

And for an executable running correctly on the Pi I get this:

pi@raspberrypi~/asm $ file loopNums
loopNums: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0x91189f47c9216e8d281238cba56b56042bcf8e6b, not stripped

Ok, so clearly I’m close but not there yet.

From other posts like this one (some of the key screenshots in this one seem missing) and this one, it seems it far easier and more direct to use the ready to go compiler crosschain from the RaspberryPi project available from github here  (and not just a more generic toolchain for ARM processors but not specifically for the Pi and/or Raspbian). This is compiled for Linux, so following the tips in the prior two articles, this was my next attempt.

Second Attempt: Eclipse C++ plus Raspberry Pi Tools toolchain … on Ubuntu … on VirtualBox … on the Mac

Clone the Tools.git project from the above github project url.

Creating a C Project

Create a new C Project, select the defaults per this screenshot:Create Project

Next through to this dialog – point to where you cloned the Raspberry Pi Tools source:


Configure toolchain path

 

  • Set the compiler prefix to:arm-linux-gnueabihf-
  • Set the path to /rpi_tools_download_dir/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin

To build the project, select Build and Build All.

Done.

You should see a Binaries entry in your Project Explorer tree view appear.

To deploy the code over to the Pi we can set up the Run Configuration selecting the Remote Application option again, use ssh and point it to your Pi.

Now I’m still getting the same generic input/output error that I was before, so I Input/Output errorssh’d over to the Pi to take a look at the new file that had appeared over there, and noticed that it wasn’t executable, so on the Remote Execution step you still need to do a chmod +x on it.

Doing a file on it though shows settings that are the same as what I had on executables compiled and linked on the Pi, so now we’re looking good:

pi@raspberrypi ~/asm $ file asm_test
asm_test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0x9f6ace58f6cc2d036ea113e69dc40a5f7fc5521d, not stripped

Now we’re getting somewhere!

A quick hello world calling syscall 4 to do write to the console:

.global main
 main:
 MOV R7, #4 @ Syscall 4 = write to screen
 MOV R0, #1 @ 1=stdout: move 1 to R0
 MOV R2, #13 @ length of string to R2
 LDR R1, =string
 SWI 0
 BX lr
 string:
 .asciz "hello world!\n"

Adding the chmod seems to get us an executable on the Pi side, but still get the i/o error.

However! ssh’ing over to Pi and executing the newly transferred file:

pi@raspberrypi ~/asm $ ./asm_test
hello world!

Success! I can now use Eclipse on my Mac to develop asm for the Pi! (Although having to run it on Ubuntu on VirtualBox on the Mac, but I can live with that 🙂