CS计算机代考程序代写 scheme x86 assembly assembler Microsoft PowerPoint – 23_X86_Assembly_Language_Part4

Microsoft PowerPoint – 23_X86_Assembly_Language_Part4

O
SU

C
SE

2
42

1

J.E.Jones

calling functions, caller/callee saved registers

O
SU

C
SE

2
42

1

J. E. Jones

 stdlinux is running hundreds of processes for hundreds
of different people

 Everyone doesn’t get a private CPU, so how does this
work?
◦ When considering multiple processes (executables), the

operating system takes care of this
◦ Uses a construct called a Process Control Block (PCB) and a

boatload of code
◦ This is a topic that CSE 2431 (Systems 2) addresses
◦ For now, you can consider this part of the puzzle to be magic

(next semester, not so much)

O
SU

C
SE

2
42

1

J. E. Jones

%rsp

◦ Can reference low-order 4 bytes (also low-order 1 & 2 bytes)
• *See Figure 3.2, page 180 of Bryant/O’Halloran for 1-byte register names

%eax

%ebx

%ecx

%edx

%esi

%edi

%esp

%r8d

%r9d

%r10d

%r11d

%r12d

%r13d

%r14d

%r15d

%r8

%r9

%r10

%r11

%r12

%r13

%r14

%r15

%rax

%rbx

%rcx

%rdx

%rsi

%rdi

%rbp

%ax

%bx

%cx

%dx

%si

%di

%sp

%r8w

%r9w

%r10w

%r11w

%r12w

%r13w

%r14w

%r15w%ebp %bp

O
SU

C
SE

2
42

1

J. E. Jones

 We’ve discussed how to separate space on the stack for
each function (within a specific process) using stack
frames

 If main(), or some other function, fills many (all?) of the
14* integer registers with valid data, then calls another
function, what happens to that data?

 Coordinating/Organizing this part of the problem is our
responsibility rather than the OS’s.

 What registers can the called function use to perform its
work?

What to do? What to do? 

*%rbp and %rsp are always used for the stack

O
SU

C
SE

2
42

1

J. E. Jones

1. The function that is performing the call has to save every, single register
it’s using to the stack prior to making the call, then pop them back into the
appropriate registers upon return.

2. The function that is called has to save every, single register it plans to use
to the stack prior to doing any “real” work, then pop the values back into
the correct registers before returning to the calling function.

Both seem a little harsh! Can’t we both just get along???
How about a little cooperation?

O
SU

C
SE

2
42

1

J. E. Jones

 Although only one procedure can be active at a given time, the 16 registers
are “shared” by all functions.

 Therefore, we need a way to ensure that when one function (the caller)
calls another (the callee), values that the caller needs after return will not
be overwritten.

 To ensure this, conventions have been adopted as to which function, the
caller or callee, is responsible for preserving a given register (other than
%rsp).

 We must use the register save conventions used by X86-64 in a C
programming environment.

O
SU

C
SE

2
42

1

J. E. Jones

Register Allocation

 What can be used?
 When do you save?

 Linux uses what is call System V ABI to define this, in
addition to many other things…most of which we
won’t need to address this semester.

O
SU

C
SE

2
42

1

J. E. Jones

 What is System V ABI? – a “bible” of sorts with respect to
how to interface to C standard libraries when not using C
code….X86-64, for example.

 Here is the link to a reasonable “draft” copy from 2013:
https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf

A bug occurs, sometimes, if you try to click on this link, it
doesn’t work. If you copy/paste the link in a browser window it
consistently comes up just fine.

There are many interface standards within the ABI, register usage
and caller/callee parameters are just a couple…

O
SU

C
SE

2
42

1

J. E. Jones

 The first six integer or pointer arguments are passed in
registers %rdi, %rsi, %rdx, %rcx, %r8, %r9 – in this
order.

 %rax is used for return values
 %rsp must be restored when control is returned to the caller

function
 If the callee wishes to use registers %rbx, %rbp or %r12-

%r15, the callee must save/then restore their original values
before returning control to the caller.
◦ %rbx, %rbp, and %r12 through %r15 are callee saved

registers
 All other registers must be saved by the caller if the caller

wishes to preserve their values
◦ All other registers are caller saved registers

O
SU

C
SE

2
42

1

J. E. Jones

 Caller Saved Registers: Registers for which the Caller function is responsible.
◦ IF the register contains data needed by the Caller after the Callee function returns, the Caller

function must preserve them by pushing them to the stack prior to calling the Callee function,.
Caller then pops them from the stack after Callee returns.

 Callee Saved Registers: Registers for which the Callee function is responsible.
◦ IF the Callee function wishes to use these registers , the Callee function must push them to the

stack prior to using them. Callee must assume there is data in each of these registers that is
important to the Caller function. Callee function must pop these registers back prior to returning
to the Caller.

 Passing Parameters: The first 6 parameters are passed from the Caller to the Callee in
registers %rdi, %rsi, %rdx, %rcx, %r8 and %r9, respectively. (We won’t address
passing more than 6 parameters in this class.)
◦ Caller must assume Callee will trash all values in these registers prior to return.
◦ So, if Caller needs any of the parameters after the call, must push registers to stack before call

and pop back after call

 Return Value: If the Callee function returns a value to the Caller, it is returned in
register %rax.

 Confused? Check out Figure 3.2, p 180 of Bryant/O’Halloran

O
SU

C
SE

2
42

1

J. E. Jones

%rsp

%r8

%r9

%r10

%r11

%r12

%r13

%r14

%rax

%rbx

%rcx

%rdx

%rsi

%rdi

%rbp %r15

Stack Pointer

Return value
Caller Saved

Callee Saved

4th parameter
Caller Saved

3rd parameter
Caller Saved

2nd parameter
Caller Saved

1st parameter
Caller Saved

Callee Saved

5th parameter
Caller Saved

6th parameter
Caller Saved

Caller Saved

Caller Saved

Callee Saved

Callee Saved

Callee Saved

Callee Saved

O
SU

C
SE

2
42

1

J. E. Jones

 It depends!
◦ On what parameters our function is passed
◦ On what registers our function wants to use
◦ On what other functions our function might call
◦ How we can minimize save/restore activity
 Efficiency is why we got here in the first place, remember?

O
SU

C
SE

2
42

1

J. E. Jones

 Must save and restore any of these registers a function
plans to use:

◦ %rbp: used as part of the stack frame and planned to restore it
anyway

◦ %rsp: if we don’t restore it, the program will probably crash.
Assume all functions deal with %rsp correctly.

◦ %rbx and %r12-%r15: Must save these before we use them

O
SU

C
SE

2
42

1

J. E. Jones

 Leaf functions make no calls to any other function

 Can freely use %rdi, %rsi, %rdx, %rcx, %r8 and
%r9 even when passed fewer than 6 parameters.

 Can freely use %r10 and %r11 since these are caller
saved registers

 Can freely use %rax as long as function fills it with the
return value prior to returning to the caller.

O
SU

C
SE

2
42

1

J. E. Jones

 Trade-offs to be made:

◦ If we make many calls to other functions, we must save and
restore any of the parameter registers as well as %r10/%r11
before and after each call if we still want to use the values
they contained prior to the call.

◦ If we use %rbx, %rbp, %r12-%r15 for our function’s work,
we only save them one time (at the beginning) and restore
them one time (at the end) of our function.

O
SU

C
SE

2
42

1

J. E. Jones

 Because the stack frame for the procedure is set up at the beginning of its
code, a procedure which calls itself recursively will get a new stack frame
each time it is called.

 The stack frame for the second call of the procedure will be above the stack
frame for the first (i.e., higher in the stack, but at a lower-numbered
address), and so on.

 When each call returns, the frame pointer of the previous call will be
restored, and at that point, what is at the top of the stack will be the return
address from the previous call.

 Therefore, when the ret instruction is executed at the end of the recursive
function’s assembly code, execution will return to the point in the code of
the function from which the call was made.

 So, just how deep of a recursive procedure do you want to have in your
code given all the resources each call is going to use? Hmmm?

O
SU

C
SE

2
42

1

J. E. Jones

 We can call any C-Library function that we used in our
C-language programs from any x86-64 program that we
write
◦ Seems kinda odd to call a C function from an assembler one

doesn’t it?
 Parameters must be passed using the caller/callee/return

value paradigm described previously

 Assume that all caller saved registers will be trashed
after return and plan accordingly 
◦ Push values you want to keep to the stack

O
SU

C
SE

2
42

1

J. E. Jones

 From section 3.5.7 Variable Argument Lists:
Some otherwise portable C programs depend on the argument passing scheme, implicitly
assuming that all arguments are passed on the stack, and arguments appear in increasing order
on the stack. Programs that make these assumptions never have been portable, but they have
worked on many implementations. However, they do not work on the AMD64 architecture
because some arguments are passed in registers. Portable C programs must use the header file
in order to handle variable argument lists. When a function taking variable-arguments is
called, %rax must be set to the total number of floating-point parameters passed to the
function in vector registers.

 Since we won’t be passing any floating-point parameters
(we’re only using integers in this class), we will always have
to set %rax to zero before calling a function that allows a
variable argument list.

*the section above references AMD64 architecture, but x86-64 is equivalent

O
SU

C
SE

2
42

1

J. E. Jones

 What functions did we use in C that had variable
argument lists?
◦ printf() family
◦ scanf() family

 You have to make a point to set %rax to zero prior to
calling printf() or scanf(), because if you do not, expect
your program to seg fault.

 No only that, but fully expect the information in all
“caller saved registers” to be totally trashed upon
return

O
SU

C
SE

2
42

1

J. E. Jones

 Consider the following simple C program, with two functions. It illustrates
the X86 conventions for parameter passing, return value, and use of caller
and callee save registers.

 First, main:
long sum(long count, long *array);
int main() {

static long array[4] = {10, 12, 15, 19};
long count= 4; /* number of array elements */
long result;
result = sum(count, array);
printf(“The sum of the array is %i\n”, result);

}

O
SU

C
SE

2
42

1

J. E. Jones

 Now, sum():
long sum(long count, long *array) {

long result = 0;
long i;
for (i = 0; i < count; i++) { result = result + array[i]; } return(result); } O SU C SE 2 42 1 J. E. Jones The next slide shows X86 assembler directives to set up space in memory for: 1. the static array, 2. output, and 3. defining main() as a function All of the following code is in a single file called sumprog.s. O SU C SE 2 42 1 J. E. Jones .file “sumprog.s” # Assembler directives to allocate storage for static array .section .rodata printf_line: .string “The sum of the array is %i\n” .data .align 8 # guarantee that we are starting on an 8-byte boundary array: # this is a LABEL .quad 10 .quad 12 .quad 15 .quad 19 .globl main .type main, @function O SU C SE 2 42 1 J. E. Jones .text main: pushq %rbp # save caller’s %rbp movq %rsp, %rbp # copy %rsp to %rbp so our stack frame is ready to use movq $array, %rsi # set %rsi (2nd parameter) to point to start of array movq $4, %rdi # set %rdi (1st parameter) to count = 4 # (i.e. caller saved registers) # since we aren’t using %rsi or %rdi values or the # value in any other caller saved registers, # we don’t have to push them call sum movq %rax, %rsi # Write return value to 2nd parameter movq $printf_line, %rdi # Write string literal to 1st parameter movq $0, %rax # Need 0 in %rax for System V ABI requirement call printf leave ret .size main, .-main O SU C SE 2 42 1 J. E. Jones .globl sum .type sum, @function sum: pushq %rbp #save caller’s rbp movq %rsp, %rbp #set function’s frame pointer # register %rdi contains count (1st parameter) # register %rsi contains address to array (2nd parameter) movq $0, %rax # initialize sum to 0, by putting 0 in %rax, # it’s where return value # needs to be when we return loop: # loop to sum values in array decq %rdi # decrement number of remaining elements by 1 jl exit # jump out of loop if no elements remaining addq (%rsi,%rdi,8), %rax # add element to sum jmp loop # jump to top of loop exit: # sum already in register %rax so ready to return leave ret #return to caller’s code at return address .size sum, .-sum O SU C SE 2 42 1 J. E. Jones  The following slides show what would change if sum() wasn’t a “leaf function”.  Let’s see how the code would change if we called printf()… O SU C SE 2 42 1 J. E. Jones .file “sumprog.s” # Assembler directives to allocate storage for static array .section .rodata printf_line: .string “The sum of the array is %i\n” printf_literal1: .string “We are in the sum() function.\n” .data .align 8 # guarantee that we are starting on an 8-byte boundary array: # this is a LABEL .quad 10 .quad 12 .quad 15 .quad 19 .globl main .type main, @function O SU C SE 2 42 1 J. E. Jones . sum: pushq %rbp #save caller’s rbp movq %rsp, %rbp #set function’s frame pointer # register %rdi contains count (1st parameter) # register %rsi contains address to array (2nd parameter) movq $0, %rax # initialize sum to 0, by putting 0 in %rax, # it’s where return value # needs to be when we return pushq %rax # %rax, %rdi, %rsi have values in them that our program needs pushq %rdi pushq %rsi movq $printf_literal1, %rdi # some literal string with no % entries, so no other parameters movq $0, %rax # no Mr. Resetti today! call printf popq %rsi # get values back so my loop still works popq %rdi # Note that the pop instructions are in the opposite order of the pushes popq %rax loop: # loop to sum values in array decq %rdi # decrement number of remaining elements by 1 jl exit # jump out of loop if no elements remaining addq (%rsi,%rdi,8), %rax # add element to sum jmp loop # jump to top of loop exit: # sum already in register %rax so ready to return leave ret #return to caller’s code at return address .size sum, .-sum