#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 ``` ], ) ]