Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: THEend8_
CMPT 295
Assignment 4 Objectives: Hand tracing assembly code Translating assembly code into C code Writing x86-64 assembly code
Submission: Assignment 4 is a little unusual Doing Assigment 4 will help you to prepare for Midterm 1 even though Assigment 4 is due after our Midterm 1. On Thursday, Feb. 25 at 3pm, submit the following 3 documents on CourSys: o Assignment_4.pdf which is to contain only your solution to Question 2. You do not have to submit your solution to Question 1. o main.c and calculator.s, i.e., your solution to Question 3. Late assignments will receive a grade of 0, but they will be marked in order to provide feedback to the student.
Marking scheme: This assignment will be marked as follows: o Question 1 is not marked. o Questions 2 and 3 will be marked for correctness. The amount of marks for each question is indicated as part of the question. A solution to Question 1 has been posted. Solutions to Question 2 and Question 3 will be posted after Assignment 4’s due date.
1. [0 marks] For study purposes only - Hand tracing assembly code Consider the following code: CMPT 295 – Spring 2021
C function abs(…) abs(…)version 1 (based on abs(…)version 2 the non-optimized gcc's version) (optimized gcc version) The left column contains the C function abs(…), the middle column contains the assembly code version of the C function abs(…) we wrote in class (we shall call it “version 1”) and the right column contains the assembly code version of abs(…) the gcc compiler produces when it assembles the C function abs(…) using level 2 optimization (“–O2”). We shall call it “version 2”. Notice how gcc assembles abs(…) without branching, i.e., without affecting the execution flow (without using the jump instructions). We shall see in our next Unit (Chapter 4 of our textbook) that branching is rather unpredictable and may cause problem in the execution pipeline. For this reason, the assembly code version (version 1) of abs(…) which branches may run more slowly. In this question, you are asked to hand trace both versions of abs(…) using 2 test cases Test case 1: x = 7, expected result: 7 Test case 2: x = -7, expected result: 7 and show the result of executing each instruction. In doing so, complete the tables below: Note: The first table has been completed as an example. Remember that x – (-y) = x + y.
abs(…) version 1 Test case 1: x = 7 Expected result: 7 Result of executing instruction in the left column movl %edi, %eax %edi <- 00000000000000000000000000000111 <- 29 0’s -> %eax <- 00000000000000000000000000000111 <- 29 0’s -> CMPT 295 – Spring 2021 cmpl $0, %eax Since it is false that x – 0 < 0 => 7 – 0 < 0 i.e., 00000000000000000000000000000111 - 00000000000000000000000000000000 > 00000000000000000000000000000000 ... jge endif ... then jump instruction is executed negl %eax and this instruction is not executed endif: ret and this instruction is executed
abs(…) version 1 Test case 2) x = -7 Expected result: 7 Result of executing instruction in the left column movl %edi, %eax cmpl $0, %eax jge endif negl %eax endif: ret
abs(…) version 2 Test case 1) x = 7 Expected result: 7 Result of executing instruction in the left column movl %edi, %edx movl %edi, %eax sarl $31, %edx xorl %edx, %eax subl %edx, %eax ret CMPT 295 – Spring 2021
abs(…) version 2 Test case 2) x = - 7 Expected result: 7 Result of executing instruction in the left column movl %edi, %edx movl %edi, %eax sarl $31, %edx xorl %edx, %eax subl %edx, %eax ret
CMPT 295 – Spring 2021 2. [8 marks] For study purposes as well as Assignment 4 submission - Translating assembly code into C code Read the entire question before answering it! Consider the following assembly code: # long func(long x, int n) # x in %rdi, n in %esi, result in %rax func: movl %esi, %ecx movl $1, %edx movl $0, %eax jmp cond loop: movq %rdi, %r8 andq %rdx, %r8 orq %r8, %rax salq %cl, %rdx # shift left %rdx by content of %cl* cond: testq %rdx, %rdx # %rdx <- %rdx & %rdx jne loop # jump if not zero (when %rdx & %rdx != 0) # fall thru to ret (when %rdx & %rdx == 0 ret * Section 3.5.3 of our textbook explains how a shift instruction works when it has the register %cl as one of its operands. The preceding code was generated by compiling C code that had the following overall form: long func(long x, int n) { long result = _________; long mask;
for (mask = _________ ;mask _________ ;mask = _________ ) result |= ___________________________ ; return result; }
CMPT 295 – Spring 2021 Your task is to fill in the missing parts of the C function above to get a program equivalent (note: it may not be exactly the same) to the generated assembly code displayed above it. You will find it helpful to examine the assembly code before, during, and after the loop to form a consistent mapping between the registers and the C function variables. You may also find the following questions helpful in figuring out the assembly code. Note that you do not have to submit these answers as part fo Assignemnt 4 as these answers will be reflected in the C function you are asked to complete and submit. a. Which registers hold program values x, n, result, and mask? b. What is the initial value of result and of mask? c. What is the test condition for mask? d. How is mask updated? e. How is result updated?
3. [12 marks] For study purposes as well as Assignment 4 submission - Writing x86-64 assembly code Download Assn4_Q3_Files.zip, in which you will find a makefile, main.c and an incomplete calculator.s. The latter contains four functions implementing arithmetic and logical operations in assembly code. Your task is to complete the implementation of the three incomplete functions, namely, plus, minus and mul. In doing so, you must satisfy the requirements found in each of the functions of calculator.s. You must also satisfy the requirements below. You will also need to figure out what the function XX does and once you have done so, you will need to change its name to something more descriptive (in main.c and in calculator.s) and add its description in the indicated place in calculator.s. Requirements: Your assembly program must follow the following standard: Your code must be commented such that others (i.e., TA’s) can read your code and understand what each instruction does. Also, describe the algorithm you used to perform the multiplication in a comment at the top of mul function. Your code must compile (using gcc) and execute on the target machine. Each of your code files (main.c and calculator.s) must contain a header comment block including the filename, the purpose/description of your program, your name and the date. For all of the four functions, the register %edi will contain the argument x and the register %esi will contain the argument y. The register %eax will carry the return value. You may use registers %rax, %rcx, %rdx, %rsi, %rdi, %r8, %r9, %r10 and %r11 as temporary registers. You must not modify the values of registers %rbx, %rbp, %rsp, %r12, %r13, %r14 and %r15. We shall soon see why. You cannot modify the given makefile. Hint for the implementation of the mul function: Long ago, computers were restricted in their arithmetic prowess and were only able to perform additions and subtractions. Multiplications and divisions needed to be implemented by the programmer using the arithmetic operations available.