Skip to main content

Exercises 13.3 Programming Exercises

The functions from Exercise 13.3.2 and Exercise 13.3.4 will be used for other exercises in subsequent chapters.

1.

Enter the C program in Listing 13.2.1. Using the “-S” compiler option, compile it with differing levels of optimization, i.e., “-O1,” “-O2,” “-O3,” and discuss the assembly language that is generated. Compare the results with my solution in Listing 13.2.6. Is the optimized code easier or more difficult to read?

Solution

I suggest discussing this with your instructor and colleagues. Opinions will differ. Listen and learn.

2.

Write the function, writeStr, in assembly language. The function takes one argument, a char *, which is a pointer to a C-style text string. It displays the text string on the screen. It returns the number of characters displayed.

Demonstrate that your function works correctly by writing a main function that calls writeStr to display “Hello world” on the screen. Your main function can ignore the character count that is returned by writeStr.

Solution
@ writeStr.s
@ Writes a C-style text string to the standard output (screen).
@ Calling sequence:
@       r0 <- address of string to be written
@       bl    writestr
@ returns number of characters written
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Useful source code constants
        .equ    STDOUT,1
        .equ    NUL,0

@ The code
        .text
        .align  2
        .global writeStr
        .type   writeStr, %function
writeStr:
        sub     sp, sp, 16      @ space for saving regs
        str     r4, [sp, 0]     @ save r4
        str     r5, [sp, 4]     @      r5
        str     fp, [sp, 8]     @      fp
        str     lr, [sp, 12]    @      lr
        add     fp, sp, 12      @ set our frame pointer

        mov     r4, r0          @ r4 = string pointer
        mov     r5, 0           @ r5 = count
whileLoop:
        ldrb    r3, [r4]        @ get a char
        cmp     r3, NUL         @ end of string?
        beq     allDone         @ yes, all done

        mov     r0, STDOUT      @ no, write to screen
        mov     r1, r4          @ address of current char
        mov     r2, 1           @ write 1 byte
        bl      write

        add     r4, r4, 1       @ increment pointer var
        add     r5, r5, 1       @ count++
        b       whileLoop       @ back to top
allDone:
        mov     r0, r5          @ return count;
        ldr     r4, [sp, 0]     @ restore r4
        ldr     r5, [sp, 4]     @      r5
        ldr     fp, [sp, 8]     @         fp
        ldr     lr, [sp, 12]    @         lr
        add     sp, sp, 16      @ restore sp
        bx      lr              @ return
@ helloWorld3.s
@ Hello world program to test writeStr function
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Constant program data
        .section .rodata
        .align   2
theString:
        .asciz        "Hello World.\n"

@ The program
        .text
        .align  2
        .global main
        .type   main, %function
main:
        sub     sp, sp, 8       @ space for fp, lr
        str     fp, [sp, 0]     @ save fp
        str     lr, [sp, 4]     @   and lr
        add     fp, sp, 4       @ set our frame pointer
        
        ldr     r0, theStringAddr
        bl      writeStr

        mov     r0, 0           @ return 0;
        ldr     fp, [sp, 0]     @ restore caller fp
        ldr     lr, [sp, 4]     @       lr
        add     sp, sp, 8       @   and sp
        bx      lr              @ return

theStringAddr:
        .word    theString
3.

Write the function, readLn, in assembly language. The function takes one argument, a char *, which is a pointer to a char array, for storing a text string. It reads characters from the keyboard and stores them in the array as a C-style text string. It does not store the ‘\n’ character. It returns the number of characters, excluding the NUL character, that were stored in the array.

Demonstrate that your function works correctly by writing a main function that prompts the user to enter a text string and then echoes the user's input, using the writeStr function from Exercise 13.3.2. When testing your program, be careful not to enter more characters than the allocated space. Explain what would occur if you did enter too many characters. Your main function can ignore the character count that is returned by writeStr and readLn.

Hint

Use malloc to allocate memory for storing the user's text string. You can read how to use it by typing man malloc in your terminal window.

Solution
@ readLnSimple.s
@ Reads a line (through the '\n') from standard input. Deletes
@ the '\n' and creates a C-style text string.
@ Calling sequence:
@       r0 <- address of place to store string
@       bl    readLn
@ returns number of characters read, excluding NUL.
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Useful source code constants
        .equ    STDIN,0
        .equ    NUL,0
        .equ    LF,10     @ '\n' under Linux

@ The code
        .text
        .align  2
        .global readLn
        .type   readLn, %function
readLn:
        sub     sp, sp, 16      @ space for saving regs
        str     r4, [sp, 4]     @ save r4
        str     r5, [sp, 8]     @      r5
        str     fp, [sp, 12]    @      fp
        str     lr, [sp, 16]    @      lr
        add     fp, sp, 12      @ set our frame pointer

        mov     r4, r0          @ r4 = string pointer
        mov     r5, 0           @ r5 = count

        mov     r0, STDIN       @ read from keyboard
        mov     r1, r4          @ address of current storage
        mov     r2, 1           @ read 1 byte
        bl      read
whileLoop:
        ldrb    r3, [r4]        @ get just read char
        cmp     r3, LF          @ end of input?
        beq     endOfString     @ yes, input done
        add     r4, r4, 1       @ no, increment pointer var
        add     r5, r5, 1       @ count++
        mov     r0, STDIN       @ read from keyboard
        mov     r1, r4          @ address of current storage
        mov     r2, #1          @ read 1 byte
        bl      read
        b       whileLoop       @ and check for end
endOfString:
        mov     r0, NUL         @ string terminator
        strb    r0, [r4]        @ write over '\n'
        
        mov     r0, r5          @ return count;
        ldr     r4, [sp, 4]     @ restore r4
        ldr     r5, [sp, 8]     @      r5
        ldr     fp, [sp, 12]    @      fp
        ldr     lr, [sp, 16]    @      lr
        add     sp, sp, 16      @ space for saving regs
        bx      lr              @ return
@ echoString1.s
@ Prompts user to enter a string, then echoes it.
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Constant for assembler
        .equ    nBytes,50  @ amount of memory for string
@ Constant program data
        .section .rodata
        .align  2
prompt:
        .asciz        "Enter some text: "

@ The program
        .text
        .align  2
        .global main
        .type   main, %function
main:
        sub     sp, sp, 16      @ space for saving regs
                                @ (keeping 8-byte sp align)
        str     r4, [sp, 4]     @ save r4
        str     fp, [sp, 8]     @      fp
        str     lr, [sp, 12]    @      lr
        add     fp, sp, 12      @ set our frame pointer
        
        mov     r0, nBytes      @ get memory from heap
        bl      malloc
        mov     r4, r0          @ pointer to new memory

        ldr     r0, promptAddr  @ prompt user
        bl      writeStr
        
        mov     r0, r4          @ get user input
        bl      readLn
        
        mov     r0, r4          @ echo user input
        bl      writeStr
        
        mov     r0, r4          @ free heap memory
        bl      free
        
        mov     r0, 0           @ return 0;
        ldr     r4, [sp, 4]     @ restore r4
        ldr     fp, [sp, 8]     @         fp
        ldr     lr, [sp, 12]    @         lr
        add     sp, sp, 16      @         sp
        bx      lr              @ return

promptAddr:
        .word    prompt
4.

Modify the readLn function in Exercise 13.3.3 so that it takes a second argument, the maximum length of the text string, including the NUL character. Excess characters entered by the user are discarded.

Demonstrate that your function works correctly by writing a main function that prompts the user to enter a text string and then echoes the user's input, using the writeStr function from Exercise 13.3.2. When testing your program, be careful not to enter more characters than the allocated space. Your main function can ignore the character count that is returned by writeStr and readLn.

Hint 1

When testing the character limit of your readLn function, use a small number.

Hint 2

When testing if your character limit algorithm works in your readLn function, use the debugger. Set a breakpoint at your cmp instruction and single step to see which way the conditional branch goes.

Solution
@ readLn.s
@ Reads a line (through the '\n') from standard input. Has
@ a size limit. Extra characters and '\n' are ignored. Stores
@ NUL-terminated C string.
@ Calling sequence:
@       r0 <- address of place to store string
@       r1 <- string size limit
@       bl    readLn
@ returns number of characters read, excluding NUL.
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Useful source code constants
        .equ    STDIN,0
        .equ    NUL,0
        .equ    LF,10     @ '\n' under Linux

@ The code
        .text
        .align  2
        .global readLn
        .type   readLn, %function
readLn:
        sub     sp, sp, 24      @ space for saving regs
                                @ (keeping 8-byte sp align)
        str     r4, [sp, 4]     @ save r4
        str     r5, [sp, 8]     @      r5
        str     r6, [sp,12]     @      r6
        str     fp, [sp, 16]    @      fp
        str     lr, [sp, 20]    @      lr
        add     fp, sp, 20      @ set our frame pointer

        mov     r4, r0          @ r4 = string pointer
        mov     r5, 0           @ r5 = count
        mov     r6, r1          @ r6 = max chars
        sub     r6, 1           @ for NUL

        mov     r0, STDIN       @ read from keyboard
        mov     r1, r4          @ address of current storage
        mov     r2, 1           @ read 1 byte
        bl      read
whileLoop:
        ldrb    r3, [r4]        @ get just read char
        cmp     r3, LF          @ end of input?
        beq     endOfString     @ yes, input done
        cmp     r5, r6          @ max chars?
        bge     ignore          @ yes, ignore rest
        add     r4, r4, 1       @ no, increment pointer var
        add     r5, r5, 1       @ count++
ignore:
        mov     r0, STDIN       @ read from keyboard
        mov     r1, r4          @ address of current storage
        mov     r2, 1           @ read 1 byte
        bl      read
        b       whileLoop       @ and check for end
endOfString:
        mov     r0, NUL         @ string terminator
        strb    r0, [r4]        @ write over '\n'
        
        mov     r0, r5          @ return count;
        ldr     r4, [sp, 4]     @ restore r4
        ldr     r5, [sp, 8]     @      r5
        ldr     r6, [sp,12]     @      r6
        ldr     fp, [sp, 16]    @      fp
        ldr     lr, [sp, 20]    @      lr
        add     sp, sp, 24      @      sp
        bx      lr              @ return
@ echoString2.s
@ Prompts user to enter a string, then echoes it.
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Constant for assembler
        .equ    nBytes,5  @ amount of memory for string
@ Constant program data
        .section .rodata
        .align  2
prompt:
        .asciz        "Enter some text: "

@ The program
        .text
        .align  2
        .global main
        .type   main, %function
main:
        sub     sp, sp, 16      @ space for saving regs
                                @ (keeping 8-byte sp align)
        str     r4, [sp, 4]     @ save r4
        str     fp, [sp, 8]     @      fp
        str     lr, [sp, 12]    @      lr
        add     fp, sp, 12      @ set our frame pointer
        
        mov     r0, nBytes      @ get memory from heap
        bl      malloc
        mov     r4, r0          @ pointer to new memory

        ldr     r0, promptAddr  @ prompt user
        bl      writeStr
        
        mov     r0, r4          @ get user input
        mov     r1, nBytes      @ limit input size
        bl      readLn
        
        mov     r0, r4          @ echo user input
        bl      writeStr
        
        mov     r0, r4          @ free heap memory
        bl      free
        
        mov     r0, 0           @ return 0;
        ldr     r4, [sp, 4]     @ restore r4
        ldr     fp, [sp, 8]     @         fp
        ldr     lr, [sp, 12]    @         lr
        add     sp, sp, 16      @         sp
        bx      lr              @ return

promptAddr:
        .word    prompt
5.

One problem with using writeStr in the solution to Exercise 13.3.4 is that it needs a newline after echoing the user's input string. Correct this problem. I do not recommend adding the newline character to the string before echoing it. See if you can solve the problem some other way.

Solution

There are multiple ways to solve this problem. I chose to write a separate function, newLine to give good flexibility in how I display text for users. It is a given that users will want you to change your program's display.

@ newLine.s
@ Writes a newline character to the standard output (screen).
@ Calling sequence:
@       bl    newLine
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Useful source code constants
        .equ    STDOUT,1

@ Constant program data
        .section .rodata
        .align   2
theChar:
        .ascii        "\n"

@ The code
        .text
        .align  2
        .global newLine
        .type   newLine, %function
newLine:
        sub     sp, sp, 8       @ space for fp, lr
        str     fp, [sp, 0]     @ save fp
        str     lr, [sp, 4]     @   and lr
        add     fp, sp, 4       @ set our frame pointer

        mov     r0, STDOUT      @ write to screen
        ldr     r1, theCharAddr @ address of newline char
        mov     r2, 1           @ write 1 byte
        bl      write

        mov     r0, 0           @ return 0;
        ldr     fp, [sp, 0]     @ restore caller fp
        ldr     lr, [sp, 4]     @       lr
        add     sp, sp, 8       @   and sp
        bx      lr              @ return

theCharAddr:
        .word   theChar