Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

.file \"swap.c\" .section .rodata .align 8 .LC0: .string \"Welcome to the 223 Sw

ID: 3681965 • Letter: #

Question

.file "swap.c"
.section .rodata
.align 8
.LC0:
.string "Welcome to the 223 Swap Program!"
.align 8
.LC1:
.string "Please enter your first number to swap: "
.LC2:
.string "%d"
.align 8
.LC3:
.string " Please enter your second number to swap: "
.align 8
.LC4:
.string " Thank you! Your numbers are: a = %d and b = %d "
.LC5:
.string "Calling swap1 function."
.align 8
.LC6:
.string "Following the swap1 function, your numbers are now: a = %d and b = %d"
.LC7:
.string "Calling swap2 function."
.align 8
.LC8:
.string "Following the swap2 function, your numbers are now: a = %d and b = %d "
.align 8
.LC9:
.string "Thank you for using the 223 Swap Program"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
leaq -32(%rbp), %rax
movq %rax, -24(%rbp)
leaq -28(%rbp), %rax
movq %rax, -16(%rbp)
movl $.LC0, %edi
call puts
movl $.LC1, %edi
movl $0, %eax
call printf
leaq -32(%rbp), %rax
movq %rax, %rsi
movl $.LC2, %edi
movl $0, %eax
call __isoc99_scanf
movl $.LC3, %edi
movl $0, %eax
call printf
leaq -28(%rbp), %rax
movq %rax, %rsi
movl $.LC2, %edi
movl $0, %eax
call __isoc99_scanf
movl -28(%rbp), %edx
movl -32(%rbp), %eax
movl %eax, %esi
movl $.LC4, %edi
movl $0, %eax
call printf
movl $.LC5, %edi
call puts
movl -28(%rbp), %edx
movl -32(%rbp), %eax
movl %edx, %esi
movl %eax, %edi
call swap1
movl -28(%rbp), %edx
movl -32(%rbp), %eax
movl %eax, %esi
movl $.LC6, %edi
movl $0, %eax
call printf
movl $.LC7, %edi
call puts
movq -16(%rbp), %rdx
movq -24(%rbp), %rax
movq %rdx, %rsi
movq %rax, %rdi
call swap2
movl -28(%rbp), %edx
movl -32(%rbp), %eax
movl %eax, %esi
movl $.LC8, %edi
movl $0, %eax
call printf
movl $.LC9, %edi
call puts
movl $0, %eax
movq -8(%rbp), %rcx
xorq %fs:40, %rcx
je .L3
call __stack_chk_fail
.L3:
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.globl swap1
.type swap1, @function
swap1:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
movl -20(%rbp), %eax
movl %eax, -4(%rbp)
movl -24(%rbp), %eax
movl %eax, -20(%rbp)
movl -4(%rbp), %eax
movl %eax, -24(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size swap1, .-swap1
.globl swap2
.type swap2, @function
swap2:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -24(%rbp)
movq %rsi, -32(%rbp)
movq -24(%rbp), %rax
movl (%rax), %eax
movl %eax, -4(%rbp)
movq -32(%rbp), %rax
movl (%rax), %edx
movq -24(%rbp), %rax
movl %edx, (%rax)
movq -32(%rbp), %rax
movl -4(%rbp), %edx
movl %edx, (%rax)
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size swap2, .-swap2
.ident "GCC: (Ubuntu 4.9.2-10ubuntu13) 4.9.2"
.section .note.GNU-stack,"",@progbits

General Directions: This is a simple homework intended to give you practice understanding the three main types of operand specifiers: Immediate Type, Register Type, and Memory Type. The source code has been pro- vided for you, along with the dumped assembly code. There is one part that counts for a total of 100 possible points. Please follow the directions closely, as any omission will result in a point deduction. Do your best. Partial credit is always awarded for honest effort Part 1 (100 possible points): There are two files swap.c and swap.s. The file swap.c is provided solely for your convenience. It is a good idea to follow along best you can in the original C source code while you proceed through the assembly code (It will certainly benefit you in the future very soon). All of your work must be submitted to olemiss.blackboard.edu no later than 11:59 p.m on Thursday, April 7, 2016 nd specifier, perform the following: write the instruction Part 1 Directions: For each line containing an being performed (also known as the opcode), and which type we are dealing with in operand 1, and operand 2 You may have to consult the book for instructions that are not obvious to you (Chapter 3) opera Submit only your newly commented swap.s code back to blackboard Below is an example for the first three comment-able lines are: pushq %rbp \Instruction: Push Quadword, Register Type movq %rsp, %rbp \Instruction: Move Quadword, Register Type-Register Type subq $32, %rsp \Instruction: Subtract Quadword, Immediate Type-Register Type

Explanation / Answer

cfi_startproc-

Is used at the beginning of each function that should have an entry in .eh_frame. It initializes some internal data structures.

cfi_def_cfa_offset offset

modifies a rule for computing CFA. Register remains the same, but offset is new. Note that it is the absolute offset that will be added to a defined register to compute CFA address.

cfi_def_cfa register, offset

cfi_def_cfa defines a rule for computing CFA as: take address from register and add offset to it.

cfi_endproc - is used at the end of a function where it closes its unwind entry previously opened by .cfi_startproc, and emits it to .eh_frame.

pushq %rbp          - save the base pointer

popq   %rbp          - recover previous base pointer

ret                            - return to the caller

subq $32, %rsp    - Allocate 32-byte stack frame

movq    %rsp, %rbp - the %rbp is set to the value of the new %rsp

movq      %fs:40, %rax -    canary from %fs:40 to rax

Registers and Data Types

X86-64 has sixteen (almost) general purpose 64-bit integer registers:

%rax

%rbx

%rcx

%rdx

%rsi

%rdi

%rbp

%rsp

%r8

%r9

%r10

%r11

%r12

%r13

%r14

%r15

We say almost general purpose because earlier versions of the processors intended for each register to be used for a specific purpose, and not all instructions could be applied to every register. As the design developed, new instructions and addressing modes were added to make the various registers almost equal. A few remaining instructions, particularly related to string processing, require the use of %rsi and %rdi. In addition, two registers are reserved for use as the stack pointer (%rsp) and the base pointer (%rbp). The final eight registers are numbered and have no specific restrictions.

The architecture has expanded from 8 to 16 to 32 bits over the years, and so each register has some internal structure that you should know about:

%ah
8 bits

%al
8 bits

%ax
16 bits

%eax
32 bits

%rax
64 bits

The lowest 8 bits of the %rax register are an 8-bit register %al, and the next 8 bits are known as %ah. The low 16 bits are collectively known as %ax, the low 32-bits as %eax, and the whole 64 bits as %rax.

The numbered registers %r8-%r15 have the same structure, but a slightly different naming scheme:

%r8h
8 bits

%r8l
8 bits

%r8w
16 bits

%r8d
32 bits

%r8
64 bits

To keep things simple, we will focus our attention on the 64-bit registers. (C-minor was designed explicitly to use 64-bit arithmetic to help you out.) However, most production compilers use a mix of modes: The 32-bit registers are generally used for integer arithmetic, since most programs don't need integer values above 2^32 (4.2 billion). The 64-bit registers are generally used to hold memory addresses (pointers), enabling addressing up to 16EB (exa-bytes) of virtual memory.

The following names are used to describe data values of various sizes:

Suffix

Name

Size

B

BYTE

1 byte (8 bits)

W

WORD

2 bytes (16 bits)

L

LONG

4 bytes (32 bits)

Q

QUADWORD

8 bytes (64 bits)

So, MOVB moves a byte, MOVW moves a word, MOVL moves a long, MOVQ moves a quad-word. Generally, the size of the locations you are moving to and from must match the suffix. It is possible to leave off the suffix, and the assembler will attempt to choose the right size based on the arguments. However, this is not recommended, as it can have unexpected effects.

The following is a simplified explanation for registers:

This table summarizes what you need to know:

Register

Purpose

Saved?

%rax

result

not saved

%rbx

scratch

callee saves

%rcx

argument 4

not saved

%rdx

argument 3

not saved

%rsi

argument 2

not saved

%rdi

argument 1

not saved

%rbp

base pointer

callee saves

%rsp

stack pointer

callee saves

%r8

argument 5

not saved

%r9

argument 6

not saved

%r10

scratch

CALLER saves

%r11

scratch

CALLER saves

%r12

scratch

callee saves

%r13

scratch

callee saves

%r14

scratch

callee saves

%r15

scratch

callee saves

There is a lot to keep track of here: the arguments given to the function, the information necessary to return, and space for local computations. For this purpose, we use the base register pointer %rbp. Whereas the stack pointer %rsp points to the end of the stack where new data will be pushed, the base pointer %rbp points to the start of the values used by this function. The space between %rbp and %rsp is known as the "stack frame" or the "activation record" of the function call.

There is one more complication: each function needs to use a selection of registers to perform computations. However, what happens when one function is called in the middle of another? We do not want any registers currently in use by the caller to be clobbered by the called function. To prevent this, each function must save and restore all of the registers that it uses by pushing them onto the stack at the beginning, and popping them off of the stack before returning. According to the System V ABI, each function must preserve the values of %rsp, %rbp, %rbx, and %r12-%r15 when it completes.

Consider the stack layout for func, defined above:

Contents

Address

old %rip register

8(%rbp)

old %rbp register

(%rbp)

<-- %rbp points here

argument 0

-8(%rbp)

argument 1

-16(%rbp)

argument 2

-24(%rbp)

local variable 0

-32(%rbp)

local variable 1

-40(%rbp)

saved register %rbx

-48(%rbp)

saved register %r12

-56(%rbp)

saved register %r13

-64(%rbp)

saved register %r14

-72(%rbp)

saved register %r15

-80(%rbp)

<-- %rsp points here

("top" of the stack)

To define more useful structures such as terminating loops and if-then statements, we must have a mechanism for evaluating values and changing program flow. In most assembly languages, these are handled by two different kinds of instructions: compares and jumps.

All comparisons are done with the CMP instruction. CMP compares two different registers and then sets a few bits in an internal EFLAGS registers, recording whether the values are the same, greater, or lesser. You don't need to look at the EFLAGS register directly. Instead a selection of conditional jumps examine the EFLAGS register and jump appropriately:

Instruction

Meaning

JE

Jump If Equal

JNE

Jump If Not Equal

JL

Jump If Less Than

JLE

Jump If Less or Equal

JG

Jump if Greater Than

JGE

Jump If Greater or Equal

Note- the above explanation can help for the given question.

%rax

%rbx

%rcx

%rdx

%rsi

%rdi

%rbp

%rsp

%r8

%r9

%r10

%r11

%r12

%r13

%r14

%r15