CPSC 355: Tutorial 14

Interoperability with C and assignment 5

PhD Student

Fall 2017

Outline

We'll be talking about how to approach the rest of assignment 5 (part a) today, then part b.

Another Example

#include <stdio.h>
#include <stdlib.h>

int value_array[10];
int num_vals = 10;

void fill_array();

int main(int argc, char *argv) {
    fill_array();
    for(int i = 0; i < num_vals; i++) {
        printf("value_array[%d] = %d\n", i, value_array[i]);
    }

}

void fill_array() {
    register int i;
    for(i = 0; i < num_vals; i++) {
        value_array[i] = rand() % 255;
    }
}

Again, let's selectively translate this into assembly

Another Example

// File: ex3a.c

#include <stdio.h>
#include <stdlib.h>

extern int value_array[];
extern int num_vals;

void fill_array();

int main(int argc, char *argv) {
    fill_array();
    for(int i = 0; i < num_vals; i++) {
        printf("value_array[%d] = %d\n", i, value_array[i]);
    }
}

Another Example

// File: ex3b.s
.data
.global num_vals
num_vals:    .word 10

.bss
.global value_array
value_array: .skip 10*4 // bytes

.text
.global fill_array
fill_array:
        stp     x29, x30, [sp, -48]!
        mov     x29, sp
        str     x19, [x29, 16]  // Save x19 because we need to use it
        str     x20, [x29, 24]  // Save x20
        str     x21, [x29, 32]  // Save x21

        mov     w19, wzr        // init the counter to 0

        // load the address of value_array into x1
        adrp    x20, value_array
        add     x20, x20, :lo12:value_array

        // load num vals into w21
        adrp    x21, num_vals
        add     x21, x21, :lo12:num_vals
        ldr     w21, [x21] 

loop_top:
        bl      rand
        and     w0, w0, 0xFF            // w0 = rand() & 0xFF
        str     w0, [x20, w19, SXTW 2]  // store w0 at address x1 + (w19 << 2)
                                        // i.e. value_array[w19] = w0
        add     w19, w19, 1
loop_test:
        cmp     w19, w21
        b.lt    loop_top

        ldr x19, [x29, 16]      // reload x19 for the calling function
        ldr x20, [x29, 24]      // reload x20 for the calling function
        ldr x21, [x29, 32]      // reload x21 for the calling function
        ldp x29, x30, [sp], 48
        ret

Another Example

gcc ex3a.c ex3b.s -o ex3

Compiling (let's be a bit lazier this time):

./ex3

Running:

This should be all you need for part a of assignment 5

Memory

OS
Program

Heap
 

Free memory
 

Stack
 

low

high

Let's talk about how a program sits in memory


.text
 

.data
 

.bss
 

Programs are broken into segments

Memory

low

high

Let's talk about how a program sits in memory


.text
 

.data
 

.bss
 

Code, readable not writeable .text

data, readable, writeable .data

data, readable, writeable .bss (always zero initialized)

Memory

.data
a_m: .byte     29
b_m: .hword    278
c_m: .word     200000
d_m: .dword    2000000000002

string_m: .string "Hello world"

.bss
array_m: .skip 10*4 // bytes
a_m: .skip 4

Command Line Args

Recall that our main function in C looks like 

int main(int argc, char *argv[]) 
{
    //...
}

In assembly, by convention, we know that x0 contains argc, and x1 contains argv

.global main
.balign 4
main:
    stp    x29, x30, [sp, -16]!
    mov    x29, sp

    // x0 contains argc, x1 argv

    ldp    x29, x30, [sp], 16
    ret

Command Line Args

Take this for example...

int main(int argc, char *argv[]) 
{
    register int i = 0;
    for(i = 0; i < argc; i++) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    return 0;
}
argv[]
addr1
addr2
addr3

If I call 

./ex4 Hello world

"ex4"

"Hello"

"world"

Command Line Args

Take this for example...

.data
fmt1:    .string "argv[%d] = %s\n"

.text
.global main
.balign 4
main:
    stp    x29, x30, [sp, -16]!
    mov    x29, sp

    mov    x19, x0    // save x0 and x1 in x19, x20
    mov    x20, x1    // so they don't get stomped on by printf

    mov    w21, wzr   // init the counter 'i' to 0

loop_top:
    adrp   x0, fmt1
    add    x0, x0, :lo12:fmt1

    mov    w1, w21

    // load the address at x20 + w21*8 (i.e. argv[i]) into x2
    // this is the address of the string in argv[i]
    ldr    x2, [x20, w21, SXTW 3]
    bl    printf

    add    w21, w21, 1
    cmp    w21, w19    // compare the counter 'i' and argc
    b.lt   loop_top

    ldp    x29, x30, [sp], 16
    mov    w0, wzr
    ret

One Last Example

#include<stdio.h>
#include<stdlib.h>

char *dayNames[] = {
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday"
};

void printUsage(char *exec) {
    printf("Usage: %s day\n", exec);
}

int main(int argc, char *argv[]) {
    register int day = 0;

    // check if we have enough args
    if(argc != 2) {
        printUsage(argv[0]);
        return -1;
    }

    // convert the string argv[1] to an int
    day = atoi(argv[1]);

    // make sure it's valid
    // in the range [1,7]
    if(day <= 0 || day > 7) {
        printUsage(argv[0]);
        return -1;
    }
    printf("%s!\n", dayNames[day - 1]);
    return 0;
}
.data
m_str:  .string "Monday"
t_str:  .string "Tuesday"
w_str:  .string "Wednesday"
th_str: .string "Thursday"
f_str:  .string "Friday"
sa_str: .string "Saturday"
su_str: .string "Sunday"

usage_str: .string "Usage: %s day\n"
out_str:   .string "%s!\n"

.balign 8 // These tables must be 8 byte aligned
dayNames: // create a table like the one we had for argv[]
    .dword m_str, t_str, w_str, th_str
    .dword f_str, sa_str, su_str
  
.text
.balign 4
printUsage:
    stp    x29, x30, [sp, -16]!
    mov    x1, x0
    ldr    x0, =usage_str
    bl     printf
    ldp    x29, x30, [sp], 16
    ret

.global main
main:
    stp    x29, x30, [sp, -16]!

    mov    x19, x0  //save x0, x1
    mov    x20, x1
    mov    w21, wzr // init day = 0

    cmp    w19, 2
    b.eq   else1

    // load argc[0] into x0
    ldr    x0, [x20]
    bl     printUsage
    mov    w0, -1     // set return value to -1
    b      exit_main
    // ...
else1:
    // load argc[1] into x0
    ldr    x0, [x20, 8]
    bl     atoi         // w0 =  atoi(argc[1]);
    mov    w21, w0

    cmp    w21, wzr     // if(w0 > 0 || w0 <= 7)
    b.le   not_else
    cmp    w21, 7
    b.gt   not_else

    // do the else case

    adrp   x9, dayNames            // load base addr of dayNames
    add    x9, x9, :lo12:dayNames
    sub    w21, w21, 1            // take day = day - 1

    ldr    x1, [x9, w21, SXTW 3]  // load at x9 + w20*8  i.e. dayNames[day]
    ldr    x0, =out_str
    bl     printf
    mov    w0, wzr
    b      exit_main

not_else:
    // load argc[0] into x0
    ldr    x0, [x20]
    bl     printUsage
    mov    w0, -1

exit_main:
    ldp    x29, x30, [sp], 16
    ret

Next Day

Work day

CPSC 355: Tutorial 14

By Joshua Horacsek

CPSC 355: Tutorial 14

  • 1,785