college/Fall-2024/CS-3843/Assignments/12/Assignment.typ

1179 lines
27 KiB
Plaintext
Raw Normal View History

2024-12-05 22:37:44 -06:00
#import "@preview/codly:1.1.1": *
#import "@preview/codly-languages:0.1.1": *
#show: codly-init.with()
#codly(
stroke: .5pt + luma(120),
display-name: false,
number-format: none,
zebra-fill: orange.lighten(75%),
fill: orange.lighten(90%),
)
#show link: set text(blue)
#set text(font: "Calibri")
#show raw: set text(font: "Fira Code")
#set table.header(repeat: false)
#set table(stroke: (x, y) => (
left: if x > 0 {
.1pt
},
top: if y == 1 {
0.5pt
} else if y > 1 {
0.1pt
},
))
#set page(margin: (y: .25in, x: .25in))
#let solve(solution) = {
block(
outset: 3pt,
inset: 3pt,
stroke: blue + .3pt,
fill: rgb(0, 149, 255, 15%),
radius: 4pt,
)[#solution]
}
#let solvein(solution) = {
let outset = 3pt
h(outset)
box(
outset: outset,
stroke: blue + .3pt,
fill: rgb(0, 149, 255, 15%),
radius: 4pt,
)[#solution]
}
#let note(content) = {
block(
outset: 3pt,
inset: 5pt,
stroke: luma(20%) + .3pt,
fill: luma(95%),
radius: 4pt,
)[#content]
}
#let notein(content) = {
let outset = 3pt
h(outset)
box(
outset: outset,
stroke: luma(20%) + .3pt,
fill: luma(95%),
radius: 4pt,
)[#content]
}
#align(center)[
= CS 3843 Computer Organization
HW 12\
#underline[Price Hiller] *|* #underline[zfp106]
]
#line(length: 100%, stroke: .25pt)
#note[
As a note I'm skipping the "cruft" inside the assembly output for this homework (stuff like the `.text`, `.file` directive, and whatnot). That's vaguely external to our actual code for use in the assembler, not a direct one-to-one translation of our code. I am focusing on the important bits.
On some stuff, I may ignore some of the C code as the assembly generated doesn't cleanly match up at all. I've done my absolute best to keep things coherent, but I do want to apologize in advance if this proves hard to follow.
]
1. Please see below for the C version. You need to generate the assembly version of this C version.
In your submission document, you need to include the screenshot of the assembly version. Then
you need to write a discussion on the assembly version. Make sure to include whats happening
at each line of your assembly code, also you need to include how the control has been
transferred from one place to another of your program
#solve[
#table(
columns: 3,
table.header([C code], [Assembly Code], [Description]),
[
```c
long absdiff_se(long x, long y) {
```
],
[
```asm
absdiff_se:
```
],
[
Create a label named ```asm absdiff_se```, the name of our C function.
],
[
```c
if (x < y) {
```
],
[
```asm
cmpq %rsi, %rdi
jge .L2
```
],
[
Compare the two inputs of the function to each other and jump to the label `.L2` if ```c x >= y``` (by checking if the `SF` and `OF` flags are the same as a result of the ```asm cmpq``` instruction.)
],
[
```c
lt_cnt++;
```
],
[
```asm
movq lt_cnt@GOTPCREL(%rip), %rdx
movq (%rdx), %rax
addq $1, %rax
```
],
[
1. Load the value for ```c lt_cnt``` from the global offset table into ```asm %rdx```.
2. Load that derefenced value from ```asm %rdx``` into ```asm %rax```
3. Finally, increment ```asm %rax``` by `1`, equivalent to ```c lt_cnt++```
],
[
```c
result = y - x;
```
],
[
```asm
movq %rax, (%rdx)
movq %rsi, %rax
subq %rdi, %rax
ret
```
],
[
1. Copy the value of ```asm %rax``` into the value pointed to by ```asm (%rdx)```
2. Copy the value of ```asm %rsi``` into ```asm %rax```
3. Finally, subtract ```asm %rdi``` from ```asm %rax```, storing the result in ```asm %rax```
4. Return control to the caller
],
[
```c
} else {
```
],
[
```asm
.L2:
```
],
[
If the earlier ```asm jge .L2``` found that the flags `SF` and `OF` were the same, we'll jump to this label/
],
[
```c
ge_cnt++;
```
],
[
```asm
movq ge_cnt@GOTPCREL(%rip), %rdx
movq (%rdx), %rax
addq $1, %rax
```
],
[
1. Load the value for ```c ge_cnt``` from the global offset table into ```asm %rdx```.
2. Load that derefenced value from ```asm %rdx``` into ```asm %rax```
3. Finally, increment ```asm %rax``` by `1`, equivalent to ```c gt_cnt++```
],
[
```c
result = x - y;
```
],
[
```asm
movq %rax, (%rdx)
movq %rdi, %rax
subq %rsi, %rax
ret
```
],
[
1. Copy the value of ```asm %rax``` into the value pointed to by ```asm (%rdx)```
2. Copy the value of ```asm %rdi``` into ```asm %rax```
3. Finally, subtract ```asm %rsi``` from ```asm %rax```, storing the result in ```asm %rax```
4. Return control to the caller
],
)
#note[
You may have noticed I skipped over the ```c return result;``` chunk of the C code. This is because that chunk is satisfied by the early `ret` calls in both branches of the assembly. Secondly, I skipped the `xorl` instructions as they're merely clearing the registers.
]
]
#note[
#table(
columns: 2,
table.header(
[Original C Code],
[Produced Assembly via ```sh gcc -Og -S```],
),
[
```c
long lt_cnt = 0;
long ge_cnt = 0;
long absdiff_se(long x, long y) {
long result;
if (x < y) {
lt_cnt++;
result = y - x;
} else {
ge_cnt++;
result = x - y;
}
return result;
}
```
],
[
```asm
.file "t.c"
.text
.globl absdiff_se
.type absdiff_se, @function
absdiff_se:
.LFB0:
.cfi_startproc
cmpq %rsi, %rdi
jge .L2
movq lt_cnt@GOTPCREL(%rip), %rdx
movq (%rdx), %rax
addq $1, %rax
movq %rax, (%rdx)
movq %rsi, %rax
subq %rdi, %rax
xorl %edx, %edx
xorl %esi, %esi
xorl %edi, %edi
ret
.L2:
movq ge_cnt@GOTPCREL(%rip), %rdx
movq (%rdx), %rax
addq $1, %rax
movq %rax, (%rdx)
movq %rdi, %rax
subq %rsi, %rax
xorl %edx, %edx
xorl %esi, %esi
xorl %edi, %edi
ret
.cfi_endproc
.LFE0:
.size absdiff_se, .-absdiff_se
.globl ge_cnt
.bss
.align 8
.type ge_cnt, @object
.size ge_cnt, 8
ge_cnt:
.zero 8
.globl lt_cnt
.align 8
.type lt_cnt, @object
.size lt_cnt, 8
lt_cnt:
.zero 8
.ident "GCC: (GNU) 13.3.0"
.section .note.GNU-stack,"",@progbits
```
],
)
]
2. Please see below for the C version. You need to generate the assembly version of this C version.
In your submission document, you need to include the screenshot of the assembly version. Then
you need to write a discussion on the assembly version. Make sure to include whats happening
at each line of your assembly code, also you need to include how the control has been
transferred from one place to another of your program.
#solve[
#table(
columns: 3,
table.header([C code], [Assembly Code], [Description]),
[
```c
long absdiff(long x, long y) {
```
],
[
```asm
absdiff:
```
],
[
Create a label named ```asm absdiff```, the name of our C function.
],
[
```c
if (x < y) {
```
],
[
```asm
cmpq %rsi, %rdi
jge .L2
```
],
[
Compare the two inputs of the function to each other and jump to the label `.L2` if ```c x >= y``` (by checking if the `SF` and `OF` flags are the same as a result of the ```asm cmpq``` instruction.)
],
[
```c
result = y - x;
```
],
[
```asm
movq %rsi, %rax
subq %rsi, %rax
ret
```
],
[
+ Copy the value of ```asm %rsi``` into ```asm %rax```
+ Finally, subtract ```asm %rdi``` from ```asm %rax```, storing the result in ```asm %rax```
+ Return control to the caller
],
[
```c
else
```
],
[
```asm
.L2:
```
],
[
If the earlier ```asm jge .L2``` found that the flags `SF` and `OF` were the same, we'll jump to this label/
],
[
```c
result = x - y;
```
],
[
```asm
movq %rdi, %rax
subq %rsi, %rax
ret
```
],
[
1. Copy the value of ```asm %rax``` into the value pointed to by ```asm (%rdx)```
2. Copy the value of ```asm %rdi``` into ```asm %rax```
3. Finally, subtract ```asm %rsi``` from ```asm %rax```, storing the result in ```asm %rax```
4. Return control to the caller
],
)
]
#note[
#table(
columns: 2,
table.header(
[Original C Code],
[Produced Assembly via ```sh gcc -Og -S```],
),
[
```c
long absdiff(long x, long y) {
long result;
if (x < y)
result = y - x;
else
result = x - y;
return result;
}
```
],
[
```asm
.file "t.c"
.text
.globl absdiff
.type absdiff, @function
absdiff:
.LFB0:
.cfi_startproc
cmpq %rsi, %rdi
jge .L2
movq %rsi, %rax
subq %rdi, %rax
xorl %esi, %esi
xorl %edi, %edi
ret
.L2:
movq %rdi, %rax
subq %rsi, %rax
xorl %esi, %esi
xorl %edi, %edi
ret
.cfi_endproc
.LFE0:
.size absdiff, .-absdiff
.ident "GCC: (GNU) 13.3.0"
.section .note.GNU-stack,"",@progbits
```
],
)
]
3. Please see below for the C version. You need to generate the assembly version of this C version.
In your submission document, you need to include the screenshot of the assembly version. Then
you need to write a discussion on the assembly version. Make sure to include whats happening
at each line of your assembly code, also you need to include how the control has been
transferred from one place to another of your program.
#solve[
#table(
columns: 3,
table.header([C code], [Assembly Code], [Description]),
[
```c
long fact_do(long n) {
```
],
[
```asm
fact_do:
```
],
[
Create a label named ```asm fact_do```, the name of our C function.
],
[
```c
long result = 1;
```
],
[
```asm
movl $1, %eax
```
],
[
Assign ```c result``` to `1`, in assembly this means putting ```asm $1``` in the ```asm %eax``` register (the return register) as we will be returning this value after the function operation.
],
[
```c
do {
```
],
[
```asm
.L2:
```
],
[
Create a label named ```asm .L2:``` for control operations on the `do-while` loop.
],
[
```c
result *=n;
```
],
[
```asm
imulq %rdi, %rax
```
],
[
Multiply the input value by ```asm %rax``` and store the result of the multiplication in ```asm %rax```.
],
[
```c
n = n - 1;
```
],
[
```asm
subq $1, %rdi
```
],
[
Subtract `1` from our input value and store the result back in the input value's register, that being ```asm %rdi```.
],
[
```c
} while (n > 1);
```
],
[
```asm
cmpq $1, %rdi
jg .L2
```
],
[
1. Run a comparison between the value ```asm $1``` and ```asm %rdi``` to set flags.
2. If `~(SF^OF) & ~ZF`, then jump to the label ```asm .L2```. (Basically if the value stored in ```asm %rdi``` is more than `1`, jump to ```asm .L2```)
],
[
```c
return result;
```
],
[
```asm
ret
```
],
[
_Technically_ this isn't one to one. By setting our return value as `result` we've informed the compiler to insert values into ```asm %rax``` as that is our return register.
],
)
]
#note[
#table(
columns: 2,
table.header(
[Original C Code],
[Produced Assembly via ```sh gcc -Og -S```],
),
[
```c
long fact_do(long n) {
long result = 1;
do {
result *= n;
n = n - 1;
} while (n > 1);
return result;
}
```
],
[
```asm
.file "t.c"
.text
.globl fact_do
.type fact_do, @function
fact_do:
.LFB0:
.cfi_startproc
movl $1, %eax
.L2:
imulq %rdi, %rax
subq $1, %rdi
cmpq $1, %rdi
jg .L2
xorl %edi, %edi
ret
.cfi_endproc
.LFE0:
.size fact_do, .-fact_do
.ident "GCC: (GNU) 13.3.0"
.section .note.GNU-stack,"",@progbits
```
],
)
]
4. Please see below for the C version. You need to generate the assembly version of this C version.
In your submission document, you need to include the screenshot of the assembly version. Then
you need to write a discussion on the assembly version. Make sure to include whats happening
at each line of your assembly code, also you need to include how the control has been
transferred from one place to another of your program.
#solve[
#table(
columns: 3,
table.header([C code], [Assembly Code], [Description]),
[
```c
long fact_while(long n) {
```
],
[
```asm
fact_while:
```
],
[
Create a label named ```asm fact_while```, the name of our C function.
],
[
```c
long result = 1;
```
],
[
```asm
movl $1, %eax
```
],
[
Assign ```c result``` to `1`, in assembly this means putting ```asm $1``` in the ```asm %eax``` register (the return register) as we will be returning this value after the function operation.
],
[
```c
while (/* omitted */)
```
],
[
```asm
.L3:
... ; omitted
.L2:
... ; omitted
```
],
[
1. Create a label named ```asm .L3:``` for control operations on the `while` loop. This will allow access to the inner body of the loop.
2. Create a separate label to handle the comparison (`n > 1`), named ```asm .L2:```, this will be jumped to unconditionally so the comparison can be validated
],
[
```c
(n > 1)
```
],
[
```asm
cmpq $1, %rdi
jg .L3
```
],
[
1. Run a comparison between the value ```asm $1``` and ```asm %rdi``` to set flags.
2. If `~(SF^OF) & ~ZF`, then jump to the label ```asm .L3```. (Basically if the value stored in ```asm %rdi``` is more than `1`, jump to ```asm .L3```)
],
[
```c
result *=n;
```
],
[
```asm
imulq %rdi, %rax
```
],
[
Multiply the input value by ```asm %rax``` and store the result of the multiplication in ```asm %rax```.
],
[
```c
n = n - 1;
```
],
[
```asm
subq $1, %rdi
```
],
[
Subtract `1` from our input value and store the result back in the input value's register, that being ```asm %rdi```.
],
[
```c
return result;
```
],
[
```asm
ret
```
],
[
_Technically_ this isn't one to one. By setting our return value as `result` we've informed the compiler to insert values into ```asm %rax``` as that is our return register.
],
)
]
#note[
#table(
columns: 2,
table.header(
[Original C Code],
[Produced Assembly via ```sh gcc -Og -S```],
),
[
```c
long fact_while(long n) {
long result = 1;
while (n > 1) {
result *= n;
n = n - 1;
}
return result;
}
```
],
[
```asm
.file "t.c"
.text
.globl fact_while
.type fact_while, @function
fact_while:
.LFB0:
.cfi_startproc
movl $1, %eax
jmp .L2
.L3:
imulq %rdi, %rax
subq $1, %rdi
.L2:
cmpq $1, %rdi
jg .L3
xorl %edi, %edi
ret
.cfi_endproc
.LFE0:
.size fact_while, .-fact_while
.ident "GCC: (GNU) 13.3.0"
.section .note.GNU-stack,"",@progbits
```
],
)
]
5. Please see below for the C version. You need to generate the assembly version of this C version.
In your submission document, you need to include the screenshot of the assembly version. Then
you need to write a discussion on the assembly version. Make sure to include whats happening
at each line of your assembly code, also you need to include how the control has been
transferred from one place to another of your program.
#note[
Due to a lack of decent annotation tools on code in the core of Typst, the below description is kinda messy to follow. I do apologize for that, but I've done my best to ensure it's understandable.
]
#solve[
#table(
columns: 3,
table.header([C code], [Assembly Code], [Description]),
[
```c
long fact_for(long n) {
```
],
[
```asm
fact_for:
```
],
[
Create a label named ```asm fact_for```, the name of our C function.
],
[
```c
long result = 1;
```
],
[
```asm
movl $1, %edx
```
],
[
Assign ```c result``` to `1`, in assembly this means putting ```asm $1``` in the ```asm %edx``` register.
],
[
```c
for (i = 2; i <= n; i++)
```
],
[
```asm
jmp .L2
.L3:
... ; omitted
addq $1, %rax
.L2:
cmpq %rdi, %rax
jle .L3
... ; omitted
```
],
[
+ Create a label named ```asm .L3:``` for control operations on the `for` loop. This will allow access to the inner body of the loop.
+ Create a separate label to handle the comparison (`i <= 1`), named ```asm .L2:```, this will be jumped to unconditionally so the comparison can be validated
+ Run a comparison between the value ```asm $1``` and ```asm %rdi``` to set flags. (The `cmpq` instruction).
+ If `(SF^OF) | ZF`, then jump to the label ```asm .L3```. Basically if the value stored in ```asm %rdi``` is less than `2`, jump to ```asm .L3```. (The `jle .L3` instruction).
+ If we jump to the label `.L3`, we increment `%rax` (which stored `i`) by one, after executing the rest of the for loop body (see the next section).
],
[
```c
result *=n;
```
],
[
```asm
imulq %rax, %rdx
```
],
[
Multiply the input value by ```asm %rax``` and store the result of the multiplication in ```asm %rdx```.
],
[
```c
return result;
```
],
[
```asm
movq %rdx, %rax
ret
```
],
[
Ensure where we've stored the result of our operations (in this case ```asm %rdx```) is put into a valid return register for use by the caller by copying ```asm %rdx``` to ```asm %rax```.
],
)
]
#note[
#table(
columns: 2,
table.header(
[Original C Code],
[Produced Assembly via ```sh gcc -Og -S```],
),
[
```c
long fact_for(long n) {
long i;
long result = 1;
for (i = 2; i <= n; i++)
result *= i;
return result;
}
```
],
[
```asm
.file "t.c"
.text
.globl fact_for
.type fact_for, @function
fact_for:
.LFB0:
.cfi_startproc
movl $1, %edx
movl $2, %eax
jmp .L2
.L3:
imulq %rax, %rdx
addq $1, %rax
.L2:
cmpq %rdi, %rax
jle .L3
movq %rdx, %rax
xorl %edx, %edx
xorl %edi, %edi
ret
.cfi_endproc
.LFE0:
.size fact_for, .-fact_for
.ident "GCC: (GNU) 13.3.0"
.section .note.GNU-stack,"",@progbits
```
],
)
]
6. Please see below for the C version. You need to generate the assembly version of this C version.
In your submission document, you need to include the screenshot of the assembly version. Then
you need to write a discussion on the assembly version. Make sure to include whats happening
at each line of your assembly code, also you need to include how the control has been
transferred from one place to another of your program.
#note[
This is where it has gotten hilariously messy to even _try_ to track the matching C code for the given assembly output. As such, I've chosen to _not_ bother lining up C code and am instead going to go line by line on the assembly as I feel that may be a tiny bit easier to follow.
]
#solve[
#table(
columns: 2,
table.header([Assembly Code], [Description]),
[
```asm
switch_eg:
```
],
[
Define a label named ```asm switch_eg```.
],
[
```asm
subq $100, %rsi
```
],
[
Substract `100` from ```asm %rsi```, storing the result into ```asm %rsi```.
],
[
```asm
cmpq $6, %rsi
```
],
[
Compare the value `6` with the current value of ```asm %rsi```, setting the appropriate flags based on the comparison.
],
[
```asm
ja .L8
```
],
[
Jump to the label `.L8`, if the flags satisfy `~CF & ~ZF`.
],
[
```asm
leaq .L4(%rip), %rcx
```
],
[
Load the effective address from the global offset table into ```asm %rcx```
],
[
```asm
movslq (%rcx,%rsi,4), %rax
```
],
[
Copy the value at `%rcx + 4 * %rsi` into ```asm %rax```, used to calculate offset for our switch statements.
],
[
```asm
addq %rcx, %rax
```
],
[
Add the value stored in ```asm %rcx``` into ```asm %rax```
],
[
```asm
jmp *%rax
```
],
[
Do a indirect jump to load the address stored at ```asm %rax``` for our switch statements.
_Begin to cry._
],
[
```asm
.L4:
.long .L7-.L4
.long .L8-.L4
.long .L6-.L4
.long .L5-.L4
.long .L3-.L4
.long .L8-.L4
.long .L3-.L4
.text
```
],
[
Big ol' jump table.
],
[
```asm
.L7:
leaq (%rdi,%rdi,2), %rax
leaq (%rdi,%rax,4), %rdi
jmp .L2
```
],
[
Loads data based on ```asm %rdi``` and ```asm %rax``` into ```asm %rax``` and ```asm %rdi``` respectively based on offsets. _Cry even more_.
Then jump to the label ```asm .L2```
],
[
```asm
.L6:
addq $10, %rdi
```
],
[
Add `10` to ```asm %rdi```, this corresponds to our case `102`.
],
[
```asm
.L5:
addq $11, %rdi
```
],
[
Add `11` to ```asm %rdi```, this corresponds to our case `103`.
],
[
```asm
.L2:
movq %rdi, (%rdx)
... ; omitted
ret
```
],
[
Finally load our calculated value into the ```c *dest``` location via derefence. _Cry until we can't see._
Finally, _finally_, return control back to the caller.
],
[
```asm
.L3:
imulq %rdi, %rdi
jmp .L2
```
],
[
This corresponds to cases `104` — `106`.
+ Multiply ```asm %rdi``` by itself, storing the result back in itself (```asm %rdi```).
+ Jump to the label ```asm .L2```.
],
[
```asm
.L8:
movl $0, %edi
jmp .L2
```
],
[
This corresponds to the default case.
Copy the value `0` into ```asm %edi``` and jump to the label ```asm .L2```.
],
)
]
#note[Wow! That sucked.]
#note[
#table(
columns: 2,
table.header(
[Original C Code],
[Produced Assembly via ```sh gcc -Og -S```],
),
[
```c
void switch_eg(long x, long n, long *dest) {
long val = x;
switch (n) {
case 100:
val *= 13;
break;
case 102:
val += 10;
/* Fall through */
case 103:
val += 11;
break;
case 104:
case 106:
val *= val;
break;
default:
val = 0;
}
*dest = val;
}
```
],
[
```asm
.file "t.c"
.text
.globl switch_eg
.type switch_eg, @function
switch_eg:
.LFB0:
.cfi_startproc
subq $100, %rsi
cmpq $6, %rsi
ja .L8
leaq .L4(%rip), %rcx
movslq (%rcx,%rsi,4), %rax
addq %rcx, %rax
jmp *%rax
.section .rodata
.align 4
.align 4
.L4:
.long .L7-.L4
.long .L8-.L4
.long .L6-.L4
.long .L5-.L4
.long .L3-.L4
.long .L8-.L4
.long .L3-.L4
.text
.L7:
leaq (%rdi,%rdi,2), %rax
leaq (%rdi,%rax,4), %rdi
jmp .L2
.L6:
addq $10, %rdi
.L5:
addq $11, %rdi
.L2:
movq %rdi, (%rdx)
xorl %eax, %eax
xorl %edx, %edx
xorl %ecx, %ecx
xorl %esi, %esi
xorl %edi, %edi
ret
.L3:
imulq %rdi, %rdi
jmp .L2
.L8:
movl $0, %edi
jmp .L2
.cfi_endproc
.LFE0:
.size switch_eg, .-switch_eg
.ident "GCC: (GNU) 13.3.0"
.section .note.GNU-stack,"",@progbits
```
],
)
]