• No results found

user multiplied by 5. We want it to be the third parameter so we move it to r2. Then we load the value of the number entered by the user into r1. Finally we load inr0 the address to the format message of printf. Note that here the order of preparing the arguments of a call is not relevant as long as the values are correct at the point of the call. We use the fact that we will have to overwrite r0, so for convenience we first copy

r0 tor2.

$ ./printf02

Hey, type a number: 1234<CR> 1234 times 5 is 6170

9.5

Unified Assembler Language

As we write functions in the future, we will find that an efficient programming technique is to divide up the processes we wish to encode into individual functions that perform, if possible, just one of the needed operations. We can then test each part of the program separately and when we are done have many useful, already tested, functions to use in other programs. This technique is called Functional Programming.

One problem arises when we combine many well-tested functions into one larger pro- gram: repeated use of the same label. Looking ahead we see programs with loops and often the label loop:. Other common labels are exit:, error:, and next:. If we use the same label in different functions, we will get an assembler error.

A modern syntax called Unified Assembler Language (UAL) allows for numerical labels that may be repeated throughout a program.

The syntax is to add the directive.syntax unified as in the following trivial example:

/* -- numericalLabels.s */

.global main /* entry point must be global */

.syntax unified /* modern syntax (UAL=Unified Assembler Language) */ .text

main: /* This is main */

push {r4, lr} ldr r0, =message1 bl puts

b 1f /* Goto the first label 1 forward */ b 2f /* Goto the first label 2 forward */ 1:

ldr r0, =message2 bl puts

1:

9. Functions

pop {r4, pc} /* Return from main */

2:

ldr r0, =errmessage bl puts

b 1b /* Goto the first label 1 backward */

.data

message1: .asciz "Numerical Label Test\n" message2: .asciz "Success\n"

errmessage: .asciz "Failure!\n"

.global puts

Projects

1. Simplify the rest of the comments in the above example.

2. Write some other simple functions and test them. In particular, include some functions that operate on strings (Section 8.6).

3. Interchange lines 5 and 8 in hello01.s and show that there is no need for extra alignment. Does this give a general rule for more efficient coding? Can you think of any disadvantages of doing that?

4. Look up details of the prototypes for such functions asprintfandscanf. Justify what is placed in the registers r0 and r1.

5. There are many other C functions we may use in the same way as printf and

scanf. Look up their prototypes and write simple programs using them.

6. The.data sections in bothprintf01.s and printf02.s have many unnecessary

.align statements. Rewrite them without any such statements. [Hint: .word

before .asciz.]

10 Searching and Sorting

We now have enough background to program some more complicated functions in as- sembler. One very important need is to be able to search through a file of information to find a particular item. In general, we look for a key which is a unique identifier such as a social security number. If a file has N elements in it, on average it will take N/2 accesses to find the key if the file is randomly arranged. We will first consider the

Binary Search that finds a key in a sorted list in about log2(N) accesses which is a great improvement for large files. Having seen that improvement, we will then consider methods of sorting files so that the Binary Search can be performed.

10.1

Binary Search

Having the list sorted allows us to use the Binary Search method to find the key. At each stage we cut in half the number of places at which the key could appear. Since that can only happen about log2N times, even in the case where the key does not appear, this method is far superior to a sequential search (particularly for large values of N). Should the list contain 220 = 1,048,576 elements, at worst 21 accesses would be necessary rather than an average of 524,288 when it appears in the unsorted list and 1,048,576 when it does not appear in the list.

Our code follows directly from some C/C++/Java code such as

int binary_search(int[] array, int size, int key) { int low = 0, high = size - 1;

while( low <= high)

{int mid = (low + high) / 2; if( array[ mid ] < key )

low = mid + 1;

elseif( key < array[ mid ] ) high = mid -1; else return mid; } return NOT_FOUND; }

10. Searching and Sorting

Since the input of the values is not significant in this example, we will “hard-wire” into our code the list of integers using the .word directive. The line

array: .word 2,5,11,23,47,95,191,383,767,998

both reserves 10 words in memory labeled by the name “array”, but also initializes those words to the given values.

1 @ BinarySearch.s 2 @

3 @ Demonstrates binary search on a fixed list of integers 4 .data @ Data declaration section

5 return: .word 0

6 array: .word 2,5,11,23,47,95,191,383,767,998 7 num_read: .word 0

8 prompt: .asciz "\nInsert integer key (key < 0 to quit): " 9 scanFMT: .asciz "%d" @ Format pattern for scanf

10 echo: .asciz "\nYou entered: %d\n"

11 ymsg: .asciz "\nKey was found at position %d\n"

12 nmsg: .asciz "\nKey not found! a near index is: %d\n" 13

14 .text @ Start of code section 15 .global main

16 main:

17 ldr r1, =return @ r1 <- &return

18 str lr, [r1] @ *r1 <- lr save return address 19

20 input:

21 ldr r0, =prompt @ r0 <- &prompt

22 bl puts @ Print prompt

23

24 ldr r0, =scanFMT @ r0 <- &scanFMT 25 ldr r1, =num_read @ r1 <- &num_read

26 bl scanf @ Call to scanf; puts value in num_read 27 @echo

28 ldr r0, =echo

29 ldr r1, =num_read

30 ldr r1, [r1]

31 bl printf @ echo the key

32

33 @check sentinal

34 ldr r1, =num_read @ r1 <- &num_read 35 ldr r1, [r1] @ r1 <- *r1

36 cmp r1, #0 @ Look for sentinal (negative) 37 blt exit @ quit if num_read is negative

10.1. Binary Search

38

39 mov r6, r1 @ Put key in r6

40 ldr r7, =array @ Address of array in r7 41

42 mov r0, #0 @ r0 = low = 0 (index) 43 mov r1, #9 @ r1 = high = 10 - 1 44

45 Loop:

46 cmp r1, r0 @ test high - low

47 blt fail @ while( low <= high ) 48 @get middle

49 add r3, r0, r1 @ r3 <- low + high 50 mov r3, r3, ASR #1 @ r3 <- r3 / 2 = mid 51 mov r8, r3 @ save index for printing 52 add r5, r7, r3, LSL #2 @ r5 <- &array[4*mid] 53 ldr r5, [r5] @ r5 <- array[4*mid] 54 cmp r5, r6 @ test array[4*mid] - key 55 blt RH @ if (array[4*mid] < key) 56 bgt LH @ if (array[4*mid] > key)

57 b found

58 RH: add r0, r3, #1 @ low = mid + 1 (index)

59 b Loop

60 LH: sub r1, r3, #1 @ high = mid - 1 (index)

61 b Loop

62 @ found 63 found:

64 add r1, r8, #1 @ get index in normal count

65 ldr r0, =ymsg

66 bl printf @ Print yes message

67

68 b input @ begin again

69

70 @ not found 71 fail:

72 add r1, r8 , #1 @ get index in normal count

73 ldr r0, =nmsg

74 bl printf @ Print not found message 75

76 b input @ try again!

77 @ exit 78 exit:

79 ldr r1, =return @ r1 <- &return

80 ldr lr, [r1] @ lr <- *r1 saved return address

10. Searching and Sorting 82 83 /* External */ 84 .global puts 85 .global printf 86 .global scanf

As often happens in moving from C/C++/Java to assembler, we must take special pains to distinguish between indexes in the high level language and memory addresses (4 bytes to each word). In particular, in line 52 we shift left two places in order to multiply by four thus counting in words instead of bytes. In addition, we have to watch for alignment problems.