Lecture Notes: 05 More Assembly Examples
·4 mins
Assembly Steps #
For each function
- Variable mapping
- Skeleton (prologue; including stack allocs, body, epilogue)
Example 1: Fives #
Key point here: Dealing with individual characters in strings.
.global main
.data
all_fives: .string "all fives"
not_all: .string "not all fives"
intfmt: .string "%d\n"
/*
- take a string as argv[1]
- determine if all characters are 5's
- print "all fives" if so
- print "not all fives" if not
*/
.text
/*
int
all_match(char c, char* text)
{
if (*text == 0) {
return 1;
}
if (*text == c) {
return all_match(c, text + 1);
}
return 0;
}
*/
/* variable mapping:
- c: %rdi
- text: %rsi
*/
all_match:
enter $0, $0
push %rdi
push %rsi
mov %rsi, %rdi
call puts
pop %rsi
pop %rdi
cmpb $0, (%rsi)
jne am1_done
am1_then:
mov $1, %rax
jmp all_match_done
am1_done:
cmpb %dil, (%rsi)
jne am2_done
am2_then:
// correct value in %rdi
add $1, %rsi
call all_match
// mov %rax, %rax
jmp all_match_done
am2_done:
mov $0, %rax
all_match_done:
push %rax
push %rax
mov $intfmt, %rdi
mov %rax, %rsi
mov $0, %al
call printf
pop %rax
pop %rax
leave
ret
/*
int
all_match(char c, char* text)
{
for (long ii = 0; text[ii] != 0; ++ii) {
if (text[ii] != c) {
return 0;
}
}
return 1;
}
*/
/*
int
main(int argc, char* argv[])
{
if (all_match('5', argv[1])) {
say "all fives";
}
else {
say "not all fives";
}
return 0;
}
*/
/* variable mapping for main:
- %r12 is the result of all_match
*/
main:
push %r12
enter $8, $0
mov $'5, %rdi
mov 8(%rsi), %rsi
call all_match
mov %rax, %r12
cmp $0, %r12
je main_else
main_then:
mov $all_fives, %rdi
jmp main_done
main_else:
mov $not_all, %rdi
main_done:
call puts
mov $0, %rax
leave
pop %r12
ret
Distraction: Address Space #
int glo = 5;
const char* ro_glo = "read only global";
int
main(int argc, char* argv[])
{
int loc = 5;
int* heap = malloc(sizeof(int));
printf("&glo = %lx\n", &glo);
printf("ro_glo = %lx\n", ro_glo);
printf("main = %ld\n", main);
printf("&loc = %lx\n", &loc);
printf("heap = %lx\n", heap);
free(heap);
return 0;
}
Then draw the address space diagram.
Example 2: Sum Array #
#include <stdio.h>
#include <stdlib.h>
long
sum_array(long* xs, long nn)
{
long yy = 0;
for (long ii = 0; ii < nn; ++ii) {
yy += xs[ii];
}
return yy;
}
int
main(int argc, char* argv[])
{
if (argc != 2) {
puts("usage: ./sum_array N");
return 1;
}
long nn = atol(argv[1]);
long* xs = malloc(nn * sizeof(long));
for (long ii = 0; ii < nn; ++ii) {
int count = scanf("%ld", &(xs[ii]));
if (count != 1) { abort(); }
}
printf("sum = %ld\n", sum_array(xs, nn));
free(xs);
return 0;
}
And in assembly:
.global main
.text
main:
push %r12 /* n */
push %r13 /* xs */
/* rcx is temp and ii */
enter $0, $0
cmp $2, %rdi
je args_ok
call abort
args_ok:
/* long n = atol(argv[1]); */
mov 8(%rsi), %rdi
call atol
mov %rax, %r12
/* long* xs = alloca(n * sizeof(long)) */
mov $8, %rcx
imul %rcx
/* alloca */
sub %rax, %rsp
mov %rsp, %r13
/* end alloca */
/*
mov %rax, %rdi
call malloc
mov %rax, %r13
*/
/* align stack, reguardless of value of n */
mov $15, %rcx
not %rcx
and %rcx, %rsp
/* for (ii = 0; ii < n; ++ii) { xs[ii] = ii } */
mov $0, %rcx
fill_loop_cond:
cmp %r12, %rcx
jge fill_loop_done
push %rcx
push %rcx
mov $longfmt, %rdi
lea (%r13,%rcx,8), %rsi
mov $0, %al
call scanf
pop %rcx
pop %rcx
cmp $1, %rax
je scanf_ok
call abort
scanf_ok:
inc %rcx
jmp fill_loop_cond
fill_loop_done:
/* printf("...", sum_array(xs)); */
mov %r13, %rdi
mov %r12, %rsi
call sum_array
mov $fmt, %rdi
mov %rax, %rsi
mov $0, %al
call printf
/*
mov %r13, %rdi
call free
*/
leave
pop %r13
pop %r12
ret
sum_array:
/* %rdi is xs */
/* %rsi is nn */
/* %rcx is ii */
/* %rax is yy */
enter $0, $0
mov $0, %rax
mov $0, %rcx
sum_loop_cond:
cmp %rsi, %rcx
jge sum_loop_done
add (%rdi,%rcx,8), %rax
inc %rcx
jmp sum_loop_cond
sum_loop_done:
leave
ret
.data
fmt: .string "sum = %ld\n"
longfmt: .string "%ld"