CPSC 355: Tutorial 15

Syscalls and Assignment 6

PhD Student

Fall 2017

Outline

Assignment 6 (Newton's method) and System Calls

Assignment 6

Assignment 6 is a little more free form than the previous assignments

Basically, you have to read a list of numbers (from a file) and take their cube root.

  • File I/O, note that we do this with syscalls, and you're not allowed to use fopen().
  • Floating point arithmetic and registers

This assignment isn't that big, but has no starting C code.

Newton's Method

Newton's method finds zeros of a function \(f(x)\). Starting with some initial guess \(x_0\), we iteratively search for a zero of \(f(x)\).

\(x_{n+1} = x_n - \frac{f(x_n)}{f^\prime(x_n)}\)

\(f(x_{n}) \approx 0 \)

After some amount of iterations we have

How do we use this to calculate \(\sqrt[3]{a}\)?

Newton's Method

Let's state the problem slightly differently 

\sqrt[3]{a} = x
a3=x\sqrt[3]{a} = x

We know \(a\), let's try to find \(x\). We don't know how to 'cube root' in a computer, but we can raise each side to the power of 3.

a = x^3
a=x3a = x^3

But now finding \(x\) is equivalent to finding zeros of the equation

x^3 - a = 0
x3a=0x^3 - a = 0

Newton's Method

Now, if we define \(f(x) = x^3 - a\), and apply newton's method, we get

\(x_{n+1} = x_n - \frac{f(x_n)}{f^\prime(x_n)}\)

\(x_{n+1} = x_n - \frac{x_n^3 - a}{3x_n^2}\)

We take \(x_0 = \frac{a}{3} \) and stop iterating when \(\left|x_n^3 - a\right| < 1.0\times 10^{-10}\)

Newton's Method

x = a / 3.0
x=a/3.0x = a / 3.0
do
dodo
y = x^3
y=x3y = x^3
dy = y - a
dy=yady = y - a
dydx = 3x^2
dydx=3x2dydx = 3x^2

If you follow the instructions on the A6 handout, your code will look something like this

x = x - dy / dydx
x=xdy/dydxx = x - dy / dydx
while(\left|dy \right| > a 1.0\times 10^{-10})
while(dy>a1.0×1010)while(\left|dy \right| > a 1.0\times 10^{-10})
return \ x
return xreturn \ x

Let's do this in C now...

System Calls

We've used the standard library to do simple I/O (printf, putch, scanf, etc..)

At the end of the day, we really have no idea how these functions interacted with the hardware.

In fact, we don't have permission to directly manipulate I/O. We have to ask the operating system to do this for us.

We do this via system calls

System Calls

We put the system call number into x8, the system call arguments into x0-x5, and execute a system call with the instruction svc.

x8 Service Request
56 openat
57 close
63 read
64 write

These all have equivalent C functions as well. 

System Calls

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>


int main(int argc, char *argv[]) 
{
    int fd = openat(AT_FDCWD, "input.bin", O_RDONLY, 0666);
    int bytes_read = 0;
    double value = 0.0;

    if(fd == -1) {
        printf("Cannot open input.bin for reading!");
        return -1;
    }

    bytes_read = read(fd, &value, sizeof(double));
    printf("Read %f from input\n", value);
    close(fd);
}

System Calls

.data
filename_str: .string "input.bin"
fmt1:         .string "Cannot open input.bin for reading!\n"
fmt2:         .string "Read %f from input\n" 

.text
.balign 4
.global main

// Local variables
fd_o         = 16
bytes_read_o = 20
value_o      = 24

main:
    stp x29, x30, [sp, -32]!
    mov x29, sp

    mov w0, -100             // mov AT_FDCWD = -100 into w0
    ldr x1, =filename_str
    mov w2, 0                // w2 = 0 (O_RDONLY)   
    mov w3, 0666             // w3 = permissions

    mov x8, 56               // set x8 as 56 (openat) system call
    svc 0                    // openat(-100, filename_str, 0, 0666)

System Calls


    str w0, [x29, fd_o]      // store the handle
    cmp w0, -1
    b.gt read_value          // if successful, jump to read value

    // print the error message
    ldr x0, =fmt1
    bl printf
    mov x0, -1               // setup return value of -1

    b exit_main
read_value:
    
    // setup for a read
    ldr w0, [x29, fd_o]      // w0 = fd
    add x1, x29, value_o     // x1 = address of value on the stack
    mov w2, 8                // w2 = size to read (8 bytes)
    
    mov x8, 63               // set x8 as 63 (read) system call
    svc 0                    // read(fd, &value, 8)

    str w0, [x29, bytes_read_o] // store the bytes read
    
    ldr x0, =fmt2            // Load format string
    ldr d0, [x29, value_o]   // load value into d0 register (we'll talk about 
                             // these next day)
    bl printf                // printf("..", value);

System Calls

    
    mov x0, xzr              // setup return value of 0

exit_main:
    // close the file
    ldr w0, [x29, fd_o]
    mov x8, 57
    svc 0

    ldp x29, x30, [sp], 32
    ret

We used a double precision register d0 in this example. We have 32 double precision registers (d0-d31) and 32 single precision registers (s0-s31). But we'll talk about those next day.

Next Day

Floating point registers, and floating point arithmetic.

CPSC 355: Tutorial 15

By Joshua Horacsek

CPSC 355: Tutorial 15

  • 1,729