.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
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
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.