1179 lines
27 KiB
Plaintext
1179 lines
27 KiB
Plaintext
|
#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 what’s 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 what’s 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 what’s 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 what’s 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 what’s 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 what’s 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
|
|||
|
```
|
|||
|
],
|
|||
|
)
|
|||
|
]
|