ARM-7 Assembly: Example Programs 1 CSE 2312 Computer Organization and Assembly Language Programming Vassilis Athitsos University of Texas at Arlington.

Slides:



Advertisements
Similar presentations
Slides revised 3/25/2014 by Patrick Kelley. 2 Procedures Unlike other branching structures (loops, etc.) a Procedure has to return to where it was called.
Advertisements

COMP3221 lec16-function-II.1 Saeid Nooshabadi COMP 3221 Microprocessors and Embedded Systems Lectures 16 : Functions in C/ Assembly - II
1 ARM Movement Instructions u MOV Rd, ; updates N, Z, C Rd = u MVN Rd, ; Rd = 0xF..F EOR.
Run-time Environment for a Program different logical parts of a program during execution stack – automatically allocated variables (local variables, subdivided.
1 Procedure Calls, Linking & Launching Applications Lecture 15 Digital Design and Computer Architecture Harris & Harris Morgan Kaufmann / Elsevier, 2007.
10/6: Lecture Topics Procedure call Calling conventions The stack
1 Lecture 4: Procedure Calls Today’s topics:  Procedure calls  Large constants  The compilation process Reminder: Assignment 1 is due on Thursday.
10/9: Lecture Topics Starting a Program Exercise 3.2 from H+P Review of Assembly Language RISC vs. CISC.
Instruction Set Architecture Classification According to the type of internal storage in a processor the basic types are Stack Accumulator General Purpose.
Computer Architecture CSCE 350
MIPS Function Continued
CPS3340 COMPUTER ARCHITECTURE Fall Semester, /17/2013 Lecture 12: Procedures Instructor: Ashraf Yaseen DEPARTMENT OF MATH & COMPUTER SCIENCE CENTRAL.
Ch. 8 Functions.
The University of Adelaide, School of Computer Science
Lecture 8: MIPS Instruction Set
Functions Functions and Parameters. History A function call needs to save the registers in use The called function will use the registers The registers.
ECE 353 Introduction to Microprocessor Systems Michael G. Morrow, P.E. Week 6.
Procedures and Stacks. Outline Stack organization PUSH and POP instructions Defining and Calling procedures.
CS 536 Spring Code generation I Lecture 20.
20/06/2015CSE1303 Part B lecture notes 1 Functions, part 2 Lecture B15 Lecture notes, section B15.
Microprocessors Frame Pointers and the use of the –fomit-frame-pointer switch Feb 25th, 2002.
28/06/2015CMPUT Functions (2)  Function calling convention  Various conventions available  One is specified by CMPUT229  Recursive functions.
ARM C Language & Assembler. Using C instead of Java (or Python, or your other favorite language)? C is the de facto standard for embedded systems because.
Code Generation CS 480. Can be complex To do a good job of teaching about code generation I could easily spend ten weeks But, don’t have ten weeks, so.
ICS312 Set 11 Introduction to Subroutines. All the combinations in which a subroutine can be written 1. The subroutine may be: a. Internal or b. External.
Topic 8: Data Transfer Instructions CSE 30: Computer Organization and Systems Programming Winter 2010 Prof. Ryan Kastner Dept. of Computer Science and.
Lecture 4: Advanced Instructions, Control, and Branching cont. EEN 312: Processors: Hardware, Software, and Interfacing Department of Electrical and Computer.
Computer Organization CS345 David Monismith Based upon notes by Dr. Bill Siever and notes from the Patterson and Hennessy Text.
Discussion of Assignment 9 1 CSE 2312 Computer Organization and Assembly Language Programming Vassilis Athitsos University of Texas at Arlington.
MIPS function continued. Recursive functions So far, we have seen how to write – A simple function – A simple function that have to use the stack to save.
Topic 9: Procedures CSE 30: Computer Organization and Systems Programming Winter 2011 Prof. Ryan Kastner Dept. of Computer Science and Engineering University.
Lecture 19: 11/7/2002CS170 Fall CS170 Computer Organization and Architecture I Ayman Abdel-Hamid Department of Computer Science Old Dominion University.
Procedure Basics Computer Organization I 1 October 2009 © McQuain, Feng & Ribbens Procedure Support From previous study of high-level languages,
More on Assembly 1 CSE 2312 Computer Organization and Assembly Language Programming Vassilis Athitsos University of Texas at Arlington.
Arrays and Strings in Assembly
More on Assembly 1 CSE 2312 Computer Organization and Assembly Language Programming Vassilis Athitsos University of Texas at Arlington.
Lecture 6: Branching CS 2011 Fall 2014, Dr. Rozier.
1 CS/COE0447 Computer Organization & Assembly Language Chapter 2 Part 3.
Calling Procedures C calling conventions. Outline Procedures Procedure call mechanism Passing parameters Local variable storage C-Style procedures Recursion.
The Stack. ARMSim memory space: 0x Unused 0x x11400 Stack 0x x09400 Heap 0x?????-0x01400 Data 0x x????? Text 0x x01000.
Preocedures A closer look at procedures. Outline Procedures Procedure call mechanism Passing parameters Local variable storage C-Style procedures Recursion.
F28HS Hardware-Software Interface Lecture 11: ARM Assembly Language 5.
LECTURE 19 Subroutines and Parameter Passing. ABSTRACTION Recall: Abstraction is the process by which we can hide larger or more complex code fragments.
Computer Organization CS345 David Monismith Based upon notes by Dr. Bill Siever and notes from the Patterson and Hennessy Text.
Chapter 14 Functions.
Writing Functions in Assembly
Lecture 6: Assembly Programs
ECE 3430 – Intro to Microcomputer Systems
© Craig Zilles (adapted from slides by Howard Huang)
Procedures 101: There and Back Again
The University of Adelaide, School of Computer Science
The Stack.
143A: Principles of Operating Systems Lecture 4: Calling conventions
Chapter 4 Addressing modes
Procedures (Functions)
Writing Functions in Assembly
Pick up the handout on your way in!!
Chapter 9 :: Subroutines and Control Abstraction
ARM Assembly Programming
Stack Frame Linkage.
The University of Adelaide, School of Computer Science
MIPS Functions.
MIPS Procedures.
Multi-modules programming
Other ISAs Next, we’ll first we look at a longer example program, starting with some C code and translating it into our assembly language. Then we discuss.
Lecture 6: Assembly Programs
© Craig Zilles (adapted from slides by Howard Huang)
Procedure Support From previous study of high-level languages, we know the basic issues: - declaration: header, body, local variables - call and return.
An Introduction to the ARM CORTEX M0+ Instructions
Presentation transcript:

ARM-7 Assembly: Example Programs 1 CSE 2312 Computer Organization and Assembly Language Programming Vassilis Athitsos University of Texas at Arlington

Making a Function Why are functions useful in assembly? 2

Making a Function Why are functions useful in assembly? For the same reasons they are useful in any programming language: – Modularity, making code easy to design, write, read, debug. – Reusability. What functionality from the previous programs would be a good candidate to make a function of? 3

Making a Function Why are functions useful in assembly? For the same reasons they are useful in any programming language: – Modularity, making code easy to design, write, read, debug. – Reusability. What functionality from the previous programs would be a good candidate to make a function of? – Printing a single hexadecimal digit. – Printing an entire 32-bit number in hexadecimal. 4

Making a Function Functions are easy to define and call in languages like C and Java. In assembly, calling a function requires several steps. This reflects that the CPU can do only a limited amount of work in a single step. Note that, to correctly do a function call, both the caller and the called function must do the right steps. 5

Caller Steps Step 1: Put arguments in the right place. Specific machines use specific conventions. Figure 5-4, on textbook page 355, specifies ARM-7 conventions: – "R0-R3 hold parameters to the procedure being called". So: – Argument 1 (if any) goes to r0. – Argument 2 (if any) goes to r1. – Argument 3 (if any) goes to r2. – Argument 4 (if any) goes to r3. If there are more arguments, they have to be placed in memory. We will worry about this case only if we encounter it. 6

Caller Steps Step 2: branch to the first instruction of the function. – Here, we typically use the bl instruction, not the b instruction. – The bl instruction, before branching, saves to register lr (the link register, aka r14) the return address. – The return address is the address of the instruction that should be executed when the function is done. Step 3: after the function has returned, recover the return value, and use it. – We will follow the convention that the return value goes to r0. 7

Called Function Steps Step 1: Do the preamble: – Allocate memory on the stack (more details in a bit). – Save to memory the return address. Why? – Save to memory all registers (except possibly for r0) that the function modifies. Why? Step 2: Do the main body of the function. – Assume arguments are in r0, r1, r2, r3. – This is where the actual work is done. Step 3: Do the wrap-up: – Store the return value (if any) on r0. – Retrieve from memory the return address. Why? – Retrieve from memory, and restore to registers, the original values of all registers that the function modified (except possibly for r0). Why? – Deallocate memory on the stack. – Branch to the return address. 8

Placing Register Values in Memory Why do we need to save register values in memory at the beginning of the function? Why do we need to restore the original register values from memory at the end of the function? 9

Placing Register Values in Memory Why do we need to save register values in memory at the beginning of the function? Why do we need to restore the original register values from memory at the end of the function? Suppose function A gets calls from functions B, C, D, E,... Function A has no idea what function it got called from. Therefore, function A has no idea what registers the caller function was using. By saving register values at the beginning, and restoring them at the end, function A makes sure that, when it returns, the caller function finds all registers unchanged. This makes life more simple for the caller function, it doesn't need to worry about whether any registers got changed. 10

Placing Register Values in Memory In summary: the called function must: – Save register values at the beginning. – Restore register values at the end. In theory, we could have used a different convention (but we will not use it): – The called function does not worry about saving and restoring register values. – The caller: Saves whatever register values it needs before making the function call. Restores those register values after the function call has returned. Both conventions are okay, we just need to choose one and stick with it. 11

Placing Register Values in Memory What about r0? Why don't we restore the original value of r0 at the end of the function? 12

Placing Register Values in Memory What about r0? Why don't we restore the original value of r0 at the end of the function? Because r0 is supposed to hold the return value. This is the one register that the caller expects to find changed at the end of the function. We will follow the convention that, if the function does not return anything (returns void) then we will be restoring the original value of r0 as well. 13

Placing Register Values in Memory What about lr (the link register)? Why do we need to save it to memory at the beginning, and restore it from memory at the end of the function? 14

Placing Register Values in Memory What about lr (the link register)? Why do we need to save it to memory at the beginning, and restore it from memory at the end of the function? Every time our function calls other functions, lr changes. By restoring it at the end of the function, we make sure we get the right return address. In principle, if our function does not make any other function calls, we do not really need to save lr to memory. In practice, personally I will follow the convention to always save lr, so as to avoid possible bugs. You will probably get a bug at some point, where: – You forget to restore lr at the end of the function. – Your function branches to a weird place at the end, instead of returning to the caller. 15

Saving to Memory When does a function need to save information to memory? – At the beginning, to save the original values of the registers. – At any later time, if there are not enough registers to store useful intermediate values. A very important question: – How does the function know what memory to use? – How can the function avoid messing up memory already used by other functions? Answer: the stack, and the stack pointer. 16

The Stack Pointer The stack pointer points to the beginning of the memory space used by a specific function. When we write an assembly function, at the end, we look at all the memory that we needed. Suppose that we needed X bytes. Then, at the beginning (first line) of the function, we put this line: sub sp, sp, #X At the end of the function (right before returning), we put this line: add sp, sp, #X This way, we mark that the function uses memory addresses from [sp] to [sp+X-1]. When the function is done, it restores the original value of sp. This way, when execution goes back to the caller, sp has the appropriate value for the caller. 17

Memory Organization 18 In the simulated ARM machine we are using, memory addresses from 0 to0xffff are read-only memory. – In decimal, these are addresses from 0 to Instructions will be saved at addresses 0x10000 and up. – In decimal, this is address Typically instructions will take no more than 20K. – Therefore, instructions go up to address At the beginning of the program (NOT the beginning of each function, just the beginning of the entire program) we will hardcode the stack pointer to hexadecimal address 0x In decimal, this address is about 1.05 million. This leaves about (1.05 million - 86 thousand) bytes, i.e., roughly about 920 thousand bytes, for use by functions. By the term "stack" we simply mean these bytes, that are available for use by functions. Memory ROM code stack

Stack Pointer Example 19 At the beginning of the program, we do: mov sp, #0x This points the stack pointer to the top of the stack. Stack Top = start of program: sp 

Stack Pointer Example 20 At the beginning of the program, we do: mov sp, #0x This points the stack pointer to the top of the stack. Then, the initial function (called _start in our examples) immediately subtracts from the sp the space that it needs for its own use. Suppose it needs X1 bytes. sub sp, sp, #X1 Stack Top = Top – X start of program: sp  _start function: sp  memory for _start

Stack Pointer Example 21 At the beginning of the program, we do: mov sp, #0x This points the stack pointer to the top of the stack. Then, the initial function (called _start in our examples) immediately subtracts from the sp the space that it needs for its own use. Suppose it needs X1 bytes. sub sp, sp, #X1 Then, suppose _start calls function foo. Function foo will set the sp to an even lower value. Suppose foo needs X2 bytes. sub sp, sp, #X2 Stack Top = Top – X1 Top – X1 – X start of program: sp  _start function: sp  memory for _start foo: sp  memory for foo

Stack Pointer Example 22 Then, suppose function foo calls function qqq. Function qqq will set the sp to an even lower value. Suppose qqq needs X3 bytes. sub sp, sp, #X3 Stack Top = Top – X1 Top – X1 – X2 Top - X1 - X2 -X3 Bottom = start of program: sp  _start function: sp  memory for _start foo: sp  memory for foo qqq: sp  memory for qqq

Stack Pointer Example 23 Then, suppose function foo calls function qqq. Function qqq will set the sp to an even lower value. Suppose qqq needs X3 bytes. sub sp, sp, #X3 Then, function qqq is getting ready to return, and restores the sp to the value it was set to by the caller function (function foo). add sp, sp, #X3 Stack Top = Top – X1 Top – X1 – X2 Bottom = start of program: sp  _start function: sp  memory for _start foo: sp  memory for foo

Stack Pointer Example 24 Then, suppose function foo calls function qqq. Function qqq will set the sp to an even lower value. Suppose qqq needs X3 bytes. sub sp, sp, #X3 Then, function qqq is getting ready to return, and restores the sp to the value it was set to by the caller function (function foo). add sp, sp, #X3 Then, function foo calls function rrr. Suppose function rrr needs X4 bytes: sub sp, sp, #X4 Stack Top = Top – X1 Top – X1 – X2 Top-X1-X2-X4 Bottom = start of program: sp  _start function: sp  memory for _start foo: sp  memory for foo rrr: sp  memory for rrr

Stack Pointer Example 25 Then, function rrr is getting ready to return, and restores the sp to the value it was set to by the caller function (function foo). add sp, sp, #X4 Stack Top = Top – X1 Top – X1 – X2 Bottom = start of program: sp  _start function: sp  memory for _start foo: sp  memory for foo

Stack Pointer Example 26 Then, function rrr is getting ready to return, and restores the sp to the value it was set to by the caller function (function foo). add sp, sp, #X4 Function foo is now also getting ready to return, and restores the sp to the value it was said to by the caller function (function _start). add sp, sp, #X2 Stack Top = Top – X1 Bottom = start of program: sp  _start function: sp  memory for _start

Stack Pointer Example 27 Then, function rrr is getting ready to return, and restores the sp to the value it was set to by the caller function (function foo). add sp, sp, #X4 Function foo is now also getting ready to return, and restores the sp to the value it was said to by the caller function (function _start). add sp, sp, #X2 Finally, function _start is wrapping up, and restores the sp to point to the top of the stack: add sp, sp, #X1. Stack Top = Bottom = start of program: sp 

Summary of Caller and Callee Steps Caller steps: – Step 1: Put arguments in the registers r0, r1, r2, r3. – Step 2: Branch to the function, using the bl instruction. – Step 3: After the function has returned, recover the return value (if any), and use it. Callee (called function) steps: – Step 1 (preamble): Allocate memory on the stack, and save register rl, and other registers that the function modifies, to the stack. – Step 2: Do the main body of the function. – Step 3 (wrap-up): Store the return value (if any) on r0. Restore, from the stack, the original values of all registers that the function modified, as well as the value of register lr. Deallocate memory on the stack (increment sp). Branch to the return address using instruction bx. 28

A First Function Example In this program, we define and use a function print_digit. This function: – Takes a single argument. – Assumes that the argument is a number between 0 and 15. – Prints that number in hexadecimal. The program prints numbers 0 to 15 in hex. 29

.globl _start _start: mov sp, sp at start of program preamble sub sp, sp, #8 str r0, [sp, #0] str r5, [sp, program main body mov r5, #0x0 my_loop: cmp r5, #0xf bgt program_exit mov r0, r5 bl print_digit add r5, r5, #1 b my_loop

print_digit preamble sub sp, sp, #16 str lr, [sp, #0] str r0, [sp, #4] str r4, [sp, #8] str r5, [sp, print_digit main body ldr ASCII codes at [r4] get printed cmp r0, #10 addlt r5, r0, #48 addge r5, r0, #55 str r5, print_digit wrap-up ldr lr, [sp, #0] ldr r0, [sp, #4] ldr r4, [sp, #8] ldr r5, [sp, #12] add sp, sp, #16 bx lr program wrap-up ldr r0, [sp, #0] ldr r5, [sp, #4] add sp, sp, #8

Things to Note Structure of the source code file: – Part 1: definition of main. – Part 2: definition of all functions (the order doesn't matter). – Part 3: program exit. We treat the main program itself as a function. – We save the registers it uses, at the beginning of the program. – We restore the values of those registers at the end. Strictly speaking, these programs will run even if we don't do that. – It is just good habit to make sure that any program module leaves registers as it found them. 32

Things to Note The main program uses r5 as the loop variable. – The values of r5 range from 0 to 15. – For each of those values, print_digit is called. Function print_digit also uses r5. Why does that not mess up the value of r5 in the main program? 33

Things to Note The main program uses r5 as the loop variable. – The values of r5 range from 0 to 15. – For each of those values, print_digit is called. Function print_digit also uses r5. Why does that not mess up the value of r5 in the main program? – Because print_digit leaves the values of all registers as it found them. – Every function should do that. – It is the job of the function preamble and the function wrap-up to do that. 34

Things to Note One of the registers we save and restore is lr. Strictly speaking, it is not necessary. – Function print_digit does not modify lr at any point. If we wanted to make performance as fast as possible, we would not save and restore lr. In practice, it is a good habit, so as to avoid bugs. It is recommended that you guys always save and restore lr in any function you write. 35

How to Write a Function You can follow two approaches. Approach 1: – First, write a preamble and wrapup that save and restore all registers you may possibly need. – Second, write the main body, test, and debug the function. – Third, rewrite the preamble and wrapup, to avoid saving and restoring registers that you did not end up using. 36

How to Write a Function Approach 2: – First, write the function main body. – Second, see what registers you are using in the function main body. – Third, write the preamble and wrapup, to save and restore all registers you use. Disadvantage of second approach: – As you debug and make changes, you may use more or fewer registers. – You have to keep modifying the preamble and wrapup. Value to subtract from sp. Memory locations used for the registers. 37

A Second Function Example In this program, we define and use a function print_number. This function: – Takes a single argument, that is a 32-bit number. – Prints that number in hexadecimal. The program prints numbers 0xffffffd to 0x in hex. 38

.globl _start _start: mov sp, sp at start of program preamble sub sp, sp, #16 str r0, [sp, #0] str r4, [sp, #4] str r5, [sp, #8] str r6, [sp, program main body ldr ASCII codes at [r4] get printed mov r5, #0x0f lsl r5, r5, #8 add r5, r5, #0xff lsl r5, r5, #8 add r5, r5, #0xff lsl r5, r5, #8 add r5, r5, #0xfd mov r6, #19 my_loop: cmp r6, #0 blt my_exit mov r0, r5 bl print_number add r5, r5, #1 sub r6, r6, #1 b my_loop

print_number preamble sub sp, sp, #24 str lr, [sp, #0] str r0, [sp, #4] str r4, [sp, #8] str r5, [sp, #12] str r6, [sp, #16] str r7, [sp, print_number main body ldr ASCII codes at [r4] get printed mov r5, #28 mov r6, r0 print_number_loop: cmp r5, #0 blt print_number_exit lsr r7, r6, r5 and r7, r7, #0x f mov r0, r7 bl print_digit sub r5, r5, #4 b print_number_loop

print newline mov r5, #13 str r5, [r4] mov r5, #10 str r5, print_number wrap-up ldr lr, [sp, #0] ldr r0, [sp, #4] ldr r4, [sp, #8] ldr r5, [sp, #12] ldr r6, [sp, #16] ldr r7, [sp, #20] sub sp, sp, #24 bx lr program wrap-up ldr r0, [sp, #0] ldr r4, [sp, #4] ldr r5, [sp, #8] ldr r6, [sp, #8] add sp, sp, #16

Things to Note Function print_number uses r5. Function print_digit also uses r5. Again, this is no problem because each function leaves the values of the registers as it found them. 42

Things to Note What would happen if print_number did not save and restore the value of lr in its preamble and wrapup? 43

Things to Note What would happen if print_number did not save and restore the value of lr in its preamble and wrapup? Register lr gets modified when, from print_number, we call print_digit. At that time, lr is set to point to what instruction? – The instruction "sub r5, r5, #4" that is in the print_number function, right after the call to print_digit. – If, at the end of print_number we do not restore lr, then instruction "bx lr" will go right back to the "sub r5, r5, #4" instruction, and the program gets into an infinite loop. 44

Recursive Function Example: Factorial How do we write function factorial in C, as a recursive function? 45 How do we write function factorial in assembly?

Recursive Function Example: Factorial How do we write function factorial in C, as a recursive function? int factorial(int N) { if (N== 0) return 0; return N* factorial(N -1); } 46 How do we write function factorial in assembly?

Recursive Function Example: Factorial How do we write function factorial in C, as a recursive function? int factorial(int N) { if (N== 0) return 0; return N* factorial(N -1); } 47 How do we write function factorial in factorial main body mov r4, r0 cmp r4, #0 moveq r0, #1 beq factorial_exit sub r0, r4, #1 bl factorial mov r5, r0 mul r0, r5, r4

Recursive Function Example: factorial preamble factorial main body mov r4, r0 cmp r4, #0 moveq r0, #1 beq factorial_exit sub r0, r4, #1 bl factorial mov r5, r0 mul r0, r5, r4 factorial wrap-up ???

Recursive Function Example: factorial preamble sub sp, sp, #12 str lr, [sp, #0] str r4, [sp, #4] str r5, [sp, factorial main body mov r4, r0 cmp r4, #0 moveq r0, #1 beq factorial_exit sub r0, r4, #1 bl factorial mov r5, r0 mul r0, r5, r4 factorial wrap-up ldr lr, [sp, #0] ldr r4, [sp, #4] ldr r5, [sp, #8] add sp, sp, #12 bx lr