DOC PREVIEW
Berkeley COMPSCI 164 - The CALL/RET Instructions and the Stack

This preview shows page 1-2-3 out of 9 pages.

Save
View full document
View full document
Premium Document
Do you want full access? Go Premium and unlock all 9 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 9 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 9 pages.
Access to all documents
Download any document
Ad free experience
Premium Document
Do you want full access? Go Premium and unlock all 9 pages.
Access to all documents
Download any document
Ad free experience

Unformatted text preview:

The CALL/RET Instructions and the StackIn the previous chapter, we explained most of the lines of the assembler file that isgenerated by the compiler for a C file, with one important exception which is the “ret”instruction at the end of the function. Let’s just review a simple example: unsigned a = 6; void f() {a = a + a;} void g() {f(); f();}The corresponding assembler file is:.file "x.c".intel_syntax.globl _a.data.align 4_a:.long 6.text.globl _f.def _f; .scl 2; .type 32; .endef_f:mov eax, DWORD PTR _aadd DWORD PTR _a, eaxret.globl _g.def _g; .scl 2; .type 32; .endef_g:call _fcall _fretMost of the lines in this file are familiar from the previous chapter. The .file directive givesthe name of the original source file for informational purposes. The .intel_sytax line tellsthe assembler we are using Intel rather than AT&T syntax. The .globl lines are used to tellthe assembler that the corresponding symbols should be marked as globally accessible fromother files. The .data directive marks the start of the data in the program, and .text marksthe start of the program. The .align directive makes sure that the variable is on a 4-byteboundary, for efficiency purposes. The .long directive actually generates four bytes of datacontaining the specified initial value. The label lines, such as _a: associate assembler labelswith specific addresses in memory. The mov instruction loads a word into a register. Theadd instruction adds the contents of a register to a word in memory.The previous paragraph identifies every line in the assembler output (see previous chapterif you need to consult the more detailed descriptions), with two notable exceptions, the callinstruction and the ret instruction. In general terms, we know what these do. The callinstruction clearly transfers control to another procedure, and the ret instruction returns tothe instruction following the call. For rough understanding of what the assembler means,this is an adequate level of explanation. That’s even a sufficient explanation for writingassembler yourself. You can just code the call and the ret following the above example andyour code will work fine.However, that’s not good enough! We are aiming here at a complete understanding of howthe machine works with no magic at all. It’s all very well to say that the ret instructionreturns past the call, but the question remains of how this works. Remember that themachine executes instructions in isolation, it does not keep a memory of all the instructionsit has executed, so it can’t use some algorithm such as “check the list of instructions youhave executed, find the most recent call instruction, and return to the instruction thatfollows the call.” That’s fine as a description of what is supposed to happen, but it isdefinitely not fine as a description of how things actually work at the machine level.When an instruction is executed, it has only the current machine environment available,consisting of the current register values (including the instruction pointer EIP) and thecurrent contents of memory.So the ret instruction must be able to do its job by consulting only the register and memorystate at the point when it is executed. From this we can conclude that somehow the callinstruction must figure out the address of the following instruction, and save that address ineither a register or a memory location in such a way that it is accessible to the retinstruction. So far, so good, the only issue that remains is how exactly does the callinstruction save this information, and how does the ret instruction retrieve the informationstashed away by the call.Using a register to hold the return pointOne way this might be accomplished is to put the address in a register. Let’s redesign theia32 architecture to use that approach. Let’s pick a register, say EDI, which will contain theso called “return point”, that is the address of the instruction immediately following thecall. Then all the ret instruction would have to do is to copy that value back into the EIPregister, to cause the instruction following the call to be executed next. The ia32 does not in fact work that way, but it is a common approach. If you have a Mac,which uses the PowerPC, and you look at the design of that machine, you will find that thisis exactly how the PowerPC works. The PowerPC has 32 registers, labeled %0 to %31, andregister %31 is used to stash the return point on a call. The equivalent of a ret instructionsimply has to copy this value into the program counter to achieve the return.To understand why the ia32 does not use this technique, consider one little problem withthis approach. Look again at the generated assembler language for function _g. Like allfunctions this also ends with a ret instruction. If call sets EDI to the return point, and retuses this return point, we have a problem. The problem is that the call within function gwill clobber the saved return point. Although this technique of using a fixed register for thereturn works fine for one level of call, it does not work so nicely for the case of multiplecalls. One way around this would be to temporarily save the return point in some otherregister in the higher level function. That’s quite reasonable on a machine like the PowerPCwith lots of registers, but it’s bad news on the ia32 with its rather miserable set of 8registers (only 7 of which can be freely used). That means that in practice we would haveto resort to having the high level function store the return point in memory, and retrieve itfor the return.How the ia32 Really Does Call/RetThe designers of the architecture, faced with this dilemma, made the decision to avoidusing registers for saving the return point, and instead to use a memory location. Thatsounds good in general terms. All we have to do is to have the call instruction save thereturn point in memory, and then the ret instruction has to retrieve this value from memoryto know where to return to.Great! Problem solved! Oops, wait a moment, there is one pesky detail we did not address.Where shall we put this value in memory? If we choose a fixed location, say location zero,then we are stuck with the problem of multiple level calls again, since a low level call willdestroy the return point required by the high level call. Let’s think for a moment about thisproblem. The way call and ret work is that control always returns to the most recentlyexecuted call when the ret is executed, or in other words, we


View Full Document

Berkeley COMPSCI 164 - The CALL/RET Instructions and the Stack

Documents in this Course
Lecture 8

Lecture 8

40 pages

Load more
Download The CALL/RET Instructions and the Stack
Our administrator received your request to download this document. We will send you the file to your email shortly.
Loading Unlocking...
Login

Join to view The CALL/RET Instructions and the Stack and access 3M+ class-specific study document.

or
We will never post anything without your permission.
Don't have an account?
Sign Up

Join to view The CALL/RET Instructions and the Stack 2 2 and access 3M+ class-specific study document.

or

By creating an account you agree to our Privacy Policy and Terms Of Use

Already a member?