Assembly Language Tutorial 3

Raspberry Pi LogoIn this tutorial we will finally create a Real Assembly Language Program! We will learn about Stacks, How to Use C Functions and How to Create Custom Functions in Assembly Language. After this tutorial you’ll know most of what you need to make many programs. If you didn’t watch part 1 though watch it first to avoid confusion.

All of the code and a template follows the video below. Refer to it as you pause your way through the video for best results.

If you like videos like this consider throwing a dollar at me on Patreon.

[googleplusone]

Code & Transcript

XXV. The Stack (Slide)

	1. With a stack you are literally stacking data on top of other data. Think of a stack of paper. When you want to retrieve data you would take off the last page you put on top. This is called Last In First Out (LIFO).
	
	2. A stack is implemented by keeping track of 2 pointers. 
	
		a. Base Pointer : Place in memory where the stack begins
		
		b. Stack Pointer : Memory location of the top of the stack. 
		
	3. The addresses assigned to data either ascend or descend in value. If it ascends we have to increase the value of the Stack Pointer. If it descends we have to decrease. We will increase / decrease the stack pointer address as we move through the stack.
	
	4.
	.global _start
	_start:
	  	MOV R1, #1
	  	MOV R2, #2
	  	
	  	@ Store 1 in stack pointer, move 4 bytes
	  	@ The ! (Write-Back) updates the register so it can be used 
		@ for another push onto the stack for example
		STR R1, [sp, #-4]!
		STR R2, [sp, #-4]!
		
		@ Remove the value and ascend towards the beginning of the stack
		LDR R0, [sp], #+4
		LDR R0, [sp], #+4
		
	end:
		MOV R7, #1
		SWI 0	
	
	5. We can use STM (Store Multiple) to push data onto the stack and LDM (Load Multiple) to pull data off. 
	
	6. There are 4 types of stacks depending on if the address the Stack Pointer points to has a value or not (Full or Empty). And, whether addresses ascend or descend (Ascending / Descending).
	
	7. (Slide) STM and LDM is postfixed with 2 character codes depending on the type of stack. 
	
		a. LDMIA / STMIA : Increment After
		
		b. LDMIB / STMIB : Increment Before
		
		c. LDMDA / STMDA : Decrement After
		
		d. LDMDB / STMDB : Decrement Before	
		
		e. When used to push and then pull you want to use the opposite code for LDM and STM. Ex. If you use STMDB to push, then use LDMIA to pull.
	
	8. 
	.global _start
		_start:
			MOV R4, #1
			MOV R5, #2
			
			@ We can refer to the Stack Pointer as SP
			@ Decrease SP by 8 bytes and save R4 & R5 in those 8 bytes
			@ The ! (Write-Back) updates the register so it can be used 
			@ for another push onto the stack for example
			STMDB SP!, {R4, R5}
			MOV R4, #3
			MOV R5, #4
			ADD R0, R4, #0
			ADD R0, R0, R5
			
			@ Remove the 8 bytes of data and then increment SP by 8 bytes
			LDMIA SP!, {R4, R5}
			ADD R0, R0, R4
			ADD R0, R0, R5
			
		end:
			MOV R7, #1
			SWI 0
			
	9. The .equ directive allows you to assign a value to a name
	
		a. 
		.global _start
		_start:
			MOV R0, #two
			
		end:
			MOV R7, #1
			SWI 0
		
		.data
		.equ two, 2
	
XXVI. LIBC

	1. We can convert C into machine code and we can use functions in the libc library in are assembler code. This provides a ton of prebuilt functions for you to use. 
	
	2. You can pass parameters to them using R0, R1, R2, and R3. To pass more you will use the stack. Your function can modify any of these registers. You can modify other registers, but their values must be restored upon exiting the function. You can also modify the stack pointer (R13), but must restore its entry value upon exiting (Avoid if possible). The Link Register (R14) cannot be changed.
	
	3. @ Hello World example using printf
	.data
	.balign 4
	question: .asciz "What is your favorite number? "
	
	.balign 4
	message: .asciz "%d is a great number\n"
	
	.balign 4
	pattern: .asciz "%d"
	
	.balign 4
	number: .word 0
	
	.balign 4
	lr_bu: .word 0
	
	.text
	
	@ Used by the compiler to tell libc where main is located
	.global main
	.func main
	
	main:
		@ Store Link Register
		LDR R1, addr_lr_bu
		STR lr, [R1]
		
		@ Load and print question
		LDR R0, addr_question
		BL printf
		
		@ Define pattern for scanf and where to store name
		LDR R0, addr_pattern
		LDR R1, addr_number
		BL scanf
		
		@ Print the message with the imbedded name
		LDR R0, addr_message
		LDR R1, addr_number
		LDR R1, [R1]
		BL printf
		
		@ Restore link register
		LDR lr, addr_lr_bu
		LDR lr, [lr]
		BX lr @ Return from main
		
	@ Define addresses
	addr_question: .word question
	addr_message: .word message
	addr_pattern: .word pattern
	addr_number: .word number
	addr_lr_bu: .word lr_bu
	
	@ Define we want to use printf and scanf
	.global printf
	.global scanf
	
	4. To compile put the following in makefile
	
		a. gcc:
				gcc -o asmtut asmtut.s
				
	5. You can see the disassembled code with : objdump -d asmtut
		
XXVII. Functions
 
 	1. Functions allow you to structure and reuse code. 
	
	2. You can pass parameters to them using R0, R1, R2, and R3. To pass more you will use the stack. Your function can modify any of these registers. You can modify other registers, but their values must be restored upon exiting the function. You can also modify the stack pointer (R13), but must restore its entry value upon exiting (Avoid if possible). The Link Register (R14) cannot be changed.
	
	3. If you change values in R4 - R12 
	
		a. STMFD SP!, {R4-R12} Saves the values before the function is called
		
		b. LDMFD SP!, {R4-R12} Restores the values after the function exits
	
	4. If a function returns a value it always goes in R0
	
	5. @ Custom Function for summing inputs
	.data
	
	@ Define all the strings and data we will use
	.balign 4
	get_val_1: .asciz "Number 1 :\n"
	
	.balign 4
	get_val_2: .asciz "Number 2 :\n"
	
	@ printf and scanf use %d to represent we are using decimals
	.balign 4
	pattern: .asciz "%d"

	@ Where we will store values to sum
	.balign 4
	num_1: .word 0	
	
	.balign 4
	num_2: .word 0
	
	.balign 4
	sum: .word 0
	
	@ Output for printf
	.balign 4
	output: .asciz "%d + %d = %d\n"
	
	@ Used for backing up the link register
	.balign 4
	lr_bu: .word 0	
	
	.balign 4
	lr_bu_2: .word 0
	
	.text
	
	@ Create our custom function
	@ Can receive values R0 - R3
	sum_vals:
	
		@ Save Link Register
		LDR R2, addr_lr_bu_2
		STR lr, [R2]
		
		@ Sum values and return in R0
		ADD R0, R0, R1
		
		@ Restore link register
		LDR lr, addr_lr_bu_2
		LDR lr, [lr]
		BX lr
		
	@ Address to store link register in
	addr_lr_bu_2: .word lr_bu_2
	
	@ Tell libc where main is
	.global main
	
	main:
		
		@ Store link register
		LDR R1, addr_lr_bu
		STR lr, [R1]
		
		@ Print out message to get 1st value
		LDR R0, addr_get_val_1
		BL printf
		
		@ Save value entered
		LDR R0, addr_pattern
		LDR R1, addr_num_1
		BL scanf
		
		LDR R0, addr_get_val_2
		BL printf
		
		LDR R0, addr_pattern
		LDR R1, addr_num_2
		BL scanf
		
		@ Send values entered to our custom function
		LDR R0, addr_num_1
		LDR R0, [R0]
		LDR R1, addr_num_2
		LDR R1, [R1]
		BL sum_vals
		
		@ Store value returned from function in R3
		MOV R3, R0
		
		@ Assign values to sum for output
		LDR R0, addr_output
		LDR R1, addr_num_1
		LDR R1, [R1]
		LDR R2, addr_num_2
		LDR R2, [R2]
		BL printf
		
		@ Restore link register
		LDR lr, addr_lr_bu
		LDR lr, [lr]
		BX lr
	
	@ Define addresses
	addr_get_val_1: .word get_val_1
	addr_get_val_2: .word get_val_2
	addr_pattern: .word pattern
	addr_num_1: .word num_1
	addr_num_2: .word num_2
	addr_sum: .word sum
	addr_output: .word output
	addr_lr_bu: .word lr_bu
	
	@ Define we want to use printf and scanf
	.global printf
	.global scanf
	
Directives Review

	1. Directives help us write our programs. We have already used them and they are recognized easily because they begin with a period
	
	2. We can store strings with .ascii and .asciz. asciz differs in that it adds a zero byte at the end of the string so it is easy to find the end of the string in memory
	
		a. @ Hello World Example
		.global _start
		_start:
		MOV R7, #4 @ Syscall to output to screen
		MOV R0,  #1 @ Monitor output stream
		MOV R2, #12 @ String Length
		LDR R1, =message @ Load register with address of string
		SWI 0
		
		end:
		MOV R7, #1 @ Exit syscall
		SWI 0
		
		.data @ Signify that what follows is data
		message:
		.ascii "Hello World\n"
	
	3. .word, .byte and .hword are used to define the amount of space to set aside in memory for our data. We can separate values with commas like we did previously
	
		a. numbers:
			.word 1, 2, 3, 4

Leave a Reply

Your email address will not be published. Required fields are marked *