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,767