Coding ARM on the Raspberry Pi
Getting ahead of the class with a single Bash script
Next week, I’ll be taking an assembly programming course that requires a Raspberry Pi. I came back home a couple days ago to my Raspberry Pi complete with this case sold by Vostrostone, this book authored by Bruce Smith, and a 32 GB microSD card. After booting Raspbian for the first time and having fun with the built-in software, I installed Vim (as opposed to Vi which is already packaged with the OS) and began following the book’s coding exercises. So far, I’m having fun!
That is, except when I have to type this into the terminal every time I want to assemble and link my code:
as -o <program name>.o <program name>.s
ld -o <destination file name> <program name>.oNot only that, but linking multiple files together turns into something really tedious and cumbersome:
as -o part1.o part1.s
as -o part2.o part2.s
ld -o allparts part1.o part2.oSo I wrote a shell script that’ll handle all this for me! I named it _assemble.sh so that (1) it’ll be at the top of the file list, and (2) I can autocomplete the name by typing _ and then Tab. After a couple hours of learning some Linux Bash (and appreciating how Pythonic it can be), I eventually wrote this:
read -e -p "Path for assembly: " path
read -p "Target name for executable: " name
final="ld -o "$name
cd $path
for file in *.s
do
o=${file::-2}".o"
echo "Assembling "$file " ..."
as -o $o $file
final=$final" "$o
done
echo "Linking everything ..."
eval $final
echo "Done! :D"I saved the script and typed chmod +x _assemble.sh into the terminal. This allows me to execute the script with ./_assemble.sh so long as I’m in the same directory.
It should be noted this script works best when it shares the same parent directory as the designated folder of source files. For example, _assemble.sh and my_example_folder (which contains example1.s and example2.s) are in my ARM Projects folder, and it’s in this folder that I run the script.
This rest of the post contains: (1) an outline of the script explaining what each line does, followed by (2) the simplified summation of all the pseudocode in one paragraph, and lastly (3) a conclusion on why this script is useful for my particular applications.
I highly recommend copying and pasting the script into a text editor so you can follow along with the outline. Scrolling up and down all the time can be a real pain!
Let’s unpack what this script does starting with line 1:
read -e -p "Path for assembly: " pathread= read the user input-etells the machine that endline obtains the line of input; this allows the user to autocomplete with Tab-ptells the machine to display a prompt first"Path for assembly: "= string literal of the aforementioned promptpath= variable that the input will read into
Line 1 basically says “Read the user input after displaying a prompt, making sure to allow autocomplete, and store it into variable path.”
Here’s line 2:
read -p "Target name for executable: " nameLine 2 basically says “Read the user input after displaying a prompt, and store it into variable name.”
Here’s line 3:
final="ld -o "$namefinal== assign a value to variablefinal"ld -o "$name= string literal"ld -o"concatenated (appended) with the string value of variablename; in typical Bash:ld= load dynamically, and-otells the machine to load an object file
Line 3 basically says “Assign final with the combined values of (1) "ld -o" and (2) the value name the user gave previously.”
Here’s line 4:
cd $pathcd= change directory$= get value from variable
Line 4 basically says “Change the file directory to what’s specified in the string variable path.”
Here’s line 5:
for file in *.sfor= loop for the following number of iterationsfile in= store the next iterative value into variablefile*.s= all files in current directory that end in the.sextension
Line 5 basically says “For each .s file in the current directory, store its name (string value) into variable file.”
Here’s line 6:
doLine 6 basically says “Execute the following code until stated otherwise.” (This is necessary for all loops)
Here’s line 7:
o=${file::-2}".o"{}= access contents of an array; in this case,fileis a string which is an array of ASCII charactersfile::-2= get all contents of arrayfilewith offset 0 and length -2 (which is until the last 2 objects, or, in this case, characters); Note: another way to write this isfile:0:-2because the syntax is${parameter:offset:length}".o"= extension of the object file concatenated to the variableo
Line 7 basically says “Assign variable o with the string value of file replacing the ".s" with ".o".”
Here’s line 8:
echo "Assembling "$file" ..."echo= write the following to the console"Assembling "$file"..."= string literal concatenating"Assembling "and$fileand"..."
Line 8 basically says “Let the user know that the currently iterated file is being assembled.”
Here’s line 9:
as -o $o $fileas= assemble the following-otells the machine to assemble an object file$o $file= in this context, a.ofile named with the value of variableofrom the.sfile named with the value of variablefile
Line 9 basically says “Assemble an object file named whatever string value o has from a source file named whatever string value file has.”
Here’s line 10:
final=$final" "$oLine 10 basically says “Append " " and the string value of o to variable final.” (You can get the value of a variable from within the same variable, much like most high level languages)
Here’s line 11:
doneLine 11 basically says “Stop executing code inside this do block.”
Here’s line 12:
echo "Linking everything ..."Line 12 basically says “Let the user know that assembling has finished and the object files are being linked into an executable.”
Here’s line 13:
eval $finaleval= evaluate the following command$final= value offinal, which at this point will containld -oplus all the names of the.ofiles
Line 13 basically says “Evaluate the command denoted by the string value of variable final.”
Finally, here’s line 14:
echo "Done! :D"Line 14 basically says “Tell the user that the execution of the script is complete, and do so with a smile.”
With all of that out of the way, here’s a simplified summation of what the script does:
“Get the desired folder of the source files to assemble (path), and the name of what the executable will be called (name). Assign a variable (final) to store the command to be evaluated at the end. Now start working in said folder. Loop for each source file until there are none left to iterate through. In each pass of the loop, do the following: (1) assign a variable (o) to store the name of the current source file without the .s extension; (2) tell the user that the current source file will attempt to be assembled; (3) assemble the current source file into an object file named after the aforementioned variable; and (4) append the final command string with the necessary .o file, separated by a space. Once the loop is done, tell the user that the program will attempt to link everything to gather, and evaluate the final command. Finally, tell the user the program has finished executing.”
In conclusion, this script will save me so much more time with assembling, linking, compiling, and debugging my assembly code. Not only is this script, in my opinion, short and concise, but it can be used in any parent directory that contains folders of source files. The end user experience is simply specifying the folder to operate in, and the desired name of the executable file. If I were to make this even more extensible, I would probably make the script into a terminal command that I can use anywhere, but that’s a project for another day.
Overall, I’m happy with how the script turned out, and I’m glad to have gotten a head start in this upcoming assembly course.
