CS 208 s21 — Review Worksheet SOLUTIONS

Table of Contents

1 Number Representation

Consider the binary value 0b110101:

  1. Interpreting this value as an unsigned 6-bit integer, what is its value in decimal?

25 + 24 + 22 + 20 = 32 + 16 + 4 + 1 = 53


  1. If we instead interpret it as a signed (two's complement) 6-bit integer, what would its value be in decimal?

-25 + 24 + 22 + 20 = -32 + 16 + 4 + 1 = -11


  1. Assuming these are all signed two's complement 6-bit integers, compute the result (leaving it in binary is fine) of each of the following additions. For each, indicate if it resulted in overflow.
    0 0 1 0 0 1
+   1 1 0 1 1 0
Result:   1 1 1 1 1 1

Overflow? No


    1 1 0 0 0 1
+   1 1 1 0 1 1
Result: 1 1 0 1 1 0 0

Overflow? No


    0 1 1 0 0 1
+   0 0 1 1 0 0
Result:   1 0 0 1 0 1

Overflow? Yes


    1 0 1 1 1 1
+   0 1 1 1 1 1
Result: 1 0 0 1 1 1 0

Overflow? No

2 Bitwise

bitwise-ops.png

  1. What happens when we fix/set one of the inputs to the 2-input operators? Let x be the other 1-bit input. Fill in the following blanks with either 0, 1, x, or NOT x:
    • x & 0 = 0
    • x & 1 = x
    • x | 0 = x
    • x | 1 = 1
    • x ^ 0 = x
    • x ^ 1 = NOT x
  2. Bit Extraction: Returns the value (0 or 1) of the 19th bit (counting from LSB). Use >> and &.
    int extract19(int x) {
        return x >> 18 & 0x1;
    }
    

3 Pointers

For this problem we are using a 64-bit x86-64 machine (little endian). The current state of memory (values in hex) is shown below:

review-mem-grid.png

Write the value in hexadecimal of each expression within the commented lines at their respective state in the execution of the given program. Write UNKNOWN in the blank if the value cannot be determined.

int main() {
    char *charP;
    short *shortP;
    int *intP = 0x00;
    long *longP = 0x28;

    // The value of intP is:                   0x 00 00 00 00 00 00 00 00

    // *intP                                   0x 02 ED 28 BD

    // &intP                                   UNKNOWN

    // longP[-2]                               0x 93 EE 34 25 1C 1E 78 63

    charP = 0x20;
    shortP = (short *) intP;
    intP++;
    longP--;

    // *shortP                                 0x 28 BD

    // *intP                                   0x AF 3A 72 35

    // *((int*) longP)                         0x 67 65 6C 42

    // (short*) (((long*) charP) - 2)          0x 10
}

4 Assembly

  1. Write an English description for each of the following instructions:
    x86 instruction English equivalent
    movq $351, %rax Move the number 351 into 8-byte (quad) register "rax"
    addq %rdi, %rsi Add the 64-bit value of %rdi to %rsi
    movq (%rdi), %r8 Move the 64-bit data at the address stored in %rdi to %r8
    leaq (%rax,%rax,8), %rax Compute 9 * %rax and store the 64-bit result in %rax
  2. Consider the following x86-64, (partially blank) C code, and memory diagram. Addresses and values are 64-bit. Fill in the C code based on the given assembly.
    foo:
        movl $0, %eax
    L1:
        testq %rdi, %rdi
        je L2
        movq (%rdi), %rdi
        addl $1, %eax
        jmp L1
    L2:
        ret
    
    int foo(long* p) {
        int result = 0;
        while (p != NULL) {
            p = (long*) *p;
            result = result + 1;
        }
        return result;
    }
    
  3. Follow the execution of foo in assembly, where 0x1000 is passed in to %rdi. Write the values of %rdi and %eax in the columns. If the value doesn't change, you can leave it blank. Continue writing the next instruction and any changed values until you have traced the full execution (i.e., reached ret).
    instruction %rdi (in hex) %eax (decimal)
    movl 0x1000 0
    testq    
    je    
    movq 0x1030  
    addl   1
    jmp    
    testq    
    je    
    movq 0x0  
    addl   2
    jmp    
    testq    
    je    
    ret    
    address value
    0x1000 0x1030
    0x1008 0x1020
    0x1010 0x1000
    0x1018 0x0000
    0x1020 0x1030
    0x1028 0x1008
    0x1030 0x0000
    0x1038 0x1038
    0x1040 0x1048
    0x1048 0x1040