First, log in to your account on SNOWBALL. You will use the command "ssh your_account@snowball.cs.gsu.edu"
cascade:Desktop> ssh snowball.cs.gsu.edu
mweeks@snowball.cs.gsu.edu's password:
Last login: Tue Jan 14 13:38:52 2025 from 131.96.221.170
+
| GSU Computer Science
| Instructional Server
| SNOWBALL.cs.gsu.edu
+
[mweeks@gsuad.gsu.edu@snowball ~]$ vi loop.c
Next, get the
"loop.c" file.
You could copy and paste it from
this assignment, or you could even type it yourself. We are looking
at how a "for" loop works here. In the "for" loop, we have
initialization statement, test expression and update statement.
Initialization statement is executed only once. Then, test expression
is evaluated. If the test expression is evaluated to false then "for"
loop is terminated. However if the test expression is evaluated to
true then, statements inside the "for" loop body are executed and
the update expression is updated. Again the test expression is
evaluated to continue for the next iteration. This process goes on
until the test expression is false. When the test expression is
false, the loop terminates.
If you have not started the log, start it now.
[mweeks@gsuad.gsu.edu@snowball ~]$ script lab3.log
Script started, file is lab3.log
Next,
we use the "cat" command to display the contents of the
"loop.c" file.
[mweeks@gsuad.gsu.edu@snowball ~]$ cat loop.c
// Print numbers from 0 to 5
#include <stdio.h>
int main() {
int i;
for (i = 0; i < 6; i++) {
printf("%d ", i);
}
printf("\n");
return 0;
}
In
the next step, we compile the "loop.c" program. "gcc"
is the GNU C compiler, and "-o loop" specifies that we want
the output to be a new file called "loop". Be careful with
this step; if you were to type "-o loop.c", it would
over-write the C file, and you would have to start over.
[mweeks@gsuad.gsu.edu@snowball ~]$ gcc loop.c -o loop
The
file "loop" is executable, and so we run it in the next
command. The "./" specifies where to find the file, and "."
is short-hand for the current
directory.
[mweeks@gsuad.gsu.edu@snowball ~]$ ./loop
0 1 2 3 4 5
The
program ran as expected, and gave us the line of output. Here, in the
program "i" is the initialization variable assigned with 0. As
the test expression is i<6, the "for" loop executed from 0 to
5, incrementing i value at every iteration.
We gave the update statement as i++, which means i=i+1.
At i=6, i<6 expression failed
as 6 is not less than 6,
so "for" loop terminated. As we see, the output is 0 1 2 3 4 5.
So far, we have obtained a C program, showed its contents, compiled
it, and run it.
Next, we will compile it again. Notice the "-S" (and yes, that is a capital S). This generates a new file, "loop.s". We then "cat" its contents, like before.
[mweeks@gsuad.gsu.edu@snowball ~]$ gcc loop.c -S
[mweeks@gsuad.gsu.edu@snowball ~]$ cat loop.s
.file "loop.c"
.section .rodata
.LC0:
.string "%d "
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0, -4(%rbp)
jmp .L2
.L3:
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
addl $1, -4(%rbp)
.L2:
cmpl $5, -4(%rbp)
jle .L3
movl $10, %edi
call putchar
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
.section .note.GNU-stack,"",@progbits
At this point, we have an assembly-language program for the "for"
loop.
You may wonder what this code does:
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
Effectively, it prints out the number stored in a local variable.As an exercise, we can try changing the test expression to see decrementing expression which is i--, which is evaluated as i=i-1. Create a loop_decrement.c file. You can add program contents as below:
[mweeks@gsuad.gsu.edu@snowball ~]$ vi loop_decrement.c
[mweeks@gsuad.gsu.edu@snowball ~]$ cat loop_decrement.c
// Print numbers from 5 to 1
#include <stdio.h>
int main() {
int i;
for (i = 5; i > 0; i--) {
printf("%d ", i);
}
printf("\n");
return 0;
}
As
you can see, here we are initializing i with 5 and then decrementing
its value with every iteration. Here, the test expression is i>0 so
the loop will continue from 5 to 1 until i=1.
As the test expression is i>0
(means 1>0) after the final iteration, the test expression is false so
the loop terminates. Thus, the output is 5 4 3 2 1.
Next, we can follow the similar steps as above to compile using "gcc" and executing it.
[mweeks@gsuad.gsu.edu@snowball ~]$ gcc loop_decrement.c -o loop_decrement
[mweeks@gsuad.gsu.edu@snowball ~]$ ./loop_decrement
5 4 3 2 1
[mweeks@gsuad.gsu.edu@snowball ~]$ gcc loop_decrement.c -S
[mweeks@gsuad.gsu.edu@snowball ~]$ cat loop_decrement.s
.file "loop_decrement.c"
.section .rodata
.LC0:
.string "%d "
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $5, -4(%rbp)
jmp .L2
.L3:
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
subl $1, -4(%rbp)
.L2:
cmpl $0, -4(%rbp)
jg .L3
movl $10, %edi
call putchar
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
.section .note.GNU-stack,"",@progbits
We have assembly language program of "for" loop with decrementing
test expression. Notice the difference in assembly language code for
incrementing and decrementing test expressions.
You can see this plainly with the "diff" command, as below.
[mweeks@gsuad.gsu.edu@snowball ~]$ diff loop.s loop_decrement.s
1c1
< .file "loop.c"
---
> .file "loop_decrement.c"
17c17
< movl $0, -4(%rbp)
---
> movl $5, -4(%rbp)
25c25
< addl $1, -4(%rbp)
---
> subl $1, -4(%rbp)
27,28c27,28
< cmpl $5, -4(%rbp)
< jle .L3
---
> cmpl $0, -4(%rbp)
> jg .L3
Notice what the "diff" command outputs. The line "1c1" means to change
line 1. The line after has < meaning that it is how it looks in
the first file. Then "---" separates the entries.
The line after that starts with > meaning that it is how it looks in
the second file. Taking the first 4 lines together,
we can say that the text in file 1 is "loop" while the text in file 2
has "loop_decrement" instead, for that line.
Looking at the differences, explain the others. You can write your explanations as a text file. You should recall that "movl" is a "long" move, that moves a 32 bit value to a 64 bit register, with zeros for the high bits. Similarly, "addl", "subl", and "cmpl" are the "long" versions of "add", "sub" (subtract) and "cmp" (compare). The dollar sign ("$") is used to indicate an immediate value, e.g. $7 simply means the number 7. ".L3" is a label, specifiing a point in the code to go to. "jle" means "jump less than or equal to" while "jg" is for "jump if greater".
Next, run the original "loop" program. Then run the "loop_decrement" program.
[mweeks@gsuad.gsu.edu@snowball ~]$ ./loop
0 1 2 3 4 5
[mweeks@gsuad.gsu.edu@snowball ~]$ ./loop_decrement
5 4 3 2 1
As an exercise, create assembly language code for the tasks below.
You are welcome to copy and change the .s file directly, especially for the
first one. For the second and third, you may want to try changing the
C file to get the assembly language code.
Questions: What did you change in the program to print numbers from 1 to 20? How difficult was it to figure out what to change? How difficult was it to make the change once you knew what to do, especially in relation to figuring out what to change?
Questions: If the loop variable is an integer, and you divide it by 2, is the result also an integer? Why or why not?
Question: Once you had it working for odd numbers, how easy was it to print the even numbers? (Use relative terms like "much more difficult", "somewhat more difficult", "about the same", "somewhat easier, and "much easier". Then state why.
Use in-line comments within the programs (starting with the # character) to say what lines you changed. Show the contents of the .s programs from above (use "cat"). Also, compile them, and run them to show that they work.
Finally, we exit from the script command. This informs the "script" utility that we are done.
[mweeks@gsuad.gsu.edu@snowball ~]$ exit
exit
Script done, file is lab3.log
You
might want to next use "cat" on the "lab3.log"
file, copy the output, and paste it into a text file called
"lab3.txt". This should get rid of any extraneous (control)
characters, though you should look it over to make sure. There are
other ways to do this: one would be to make your own filtering
program, that only allows characters with ASCII values
32 to 126, along with the newline (linefeed) character (10). Tab,
character 9, might be useful too, maybe mapped to 4 spaces.
Then we exit (log out) from the server. You can use "sftp" to get your log file from the server.
[mweeks@gsuad.gsu.edu@snowball ~]$ exit
logout
Connection to snowball.cs.gsu.edu closed.
Important note: When turning this in (as with all other labs), you should submit the cleaned-up .txt file, as well as the lab report (i.e. a .pdf file). We will grade the lab based on the report, and look at the .txt file if the report is not clear or if there is a problem.
In this lab, we have seen :