65
Carnegie Mellon Slides Courtesy of: Randy Bryant and Dave O’Hallaron Machine-Level Programming III: Switch Statements and IA32 Procedures

Machine-Level Programming III: Switch Statements and IA32 Procedures

  • Upload
    yuki

  • View
    22

  • Download
    0

Embed Size (px)

DESCRIPTION

Carnegie Mellon. Machine-Level Programming III: Switch Statements and IA32 Procedures. Slides Courtesy of: Randy Bryant and Dave O’Hallaron. Carnegie Mellon. Today. Switch statements IA 32 Procedures Stack Structure Calling Conventions Illustrations of Recursion & Pointers. - PowerPoint PPT Presentation

Citation preview

Introduction to Computer Systems 15-213/18-243, spring 2009

Carnegie MellonSlides Courtesy of: Randy Bryant and Dave OHallaronMachine-Level Programming III:Switch Statements and IA32 Procedures

Carnegie MellonTodaySwitch statementsIA 32 ProceduresStack StructureCalling ConventionsIllustrations of Recursion & Pointers#Carnegie MellonSwitch Statement ExampleMultiple case labelsHere: 5 & 6Fall through casesHere: 2Missing casesHere: 4long switch_eg (long x, long y, long z){ long w = 1; switch(x) { case 1: w = y*z; break; case 2: w = y/z; /* Fall Through */ case 3: w += z; break; case 5: case 6: w -= z; break; default: w = 2; } return w;}#Carnegie MellonJump Table StructureCode Block0Targ0:Code Block1Targ1:Code Block2Targ2:Code Blockn1Targn-1:Targ0Targ1Targ2Targn-1jtab:target = JTab[x];goto *target;switch(x) { case val_0: Block 0 case val_1: Block 1 case val_n-1: Block n1}Switch FormApproximate TranslationJump TableJump Targets#Carnegie MellonSwitch Statement Example (IA32)Setup:long switch_eg(long x, long y, long z){ long w = 1; switch(x) { . . . } return w;}switch_eg:pushl%ebp# Setupmovl%esp, %ebp# Setupmovl8(%ebp), %eax# %eax = xcmpl$6, %eax# Compare x:6ja.L2 # If unsigned > goto defaultjmp*.L7(,%eax,4)# Goto *JTab[x]What range of values takes default?Note that w not initialized here#Carnegie MellonSwitch Statement Example (IA32)long switch_eg(long x, long y, long z){ long w = 1; switch(x) { . . . } return w;}Indirect jumpJump table.section.rodata.align 4.L7:.long.L2# x = 0.long.L3# x = 1.long.L4# x = 2.long.L5# x = 3.long.L2# x = 4.long.L6# x = 5.long.L6# x = 6Setup:switch_eg:pushl%ebp# Setupmovl%esp, %ebp# Setupmovl8(%ebp), %eax# eax = xcmpl$6, %eax# Compare x:6ja.L2 # If unsigned > goto defaultjmp*.L7(,%eax,4)# Goto *JTab[x]#Carnegie MellonAssembly Setup ExplanationTable StructureEach target requires 4 bytesBase address at .L7

JumpingDirect: jmp .L2Jump target is denoted by label .L2

Indirect: jmp *.L7(,%eax,4)Start of jump table: .L7Must scale by factor of 4 (labels have 32-bits = 4 Bytes on IA32)Fetch target from effective Address .L7 + eax*4Only for 0 x 6Jump table.section.rodata.align 4.L7:.long.L2# x = 0.long.L3# x = 1.long.L4# x = 2.long.L5# x = 3.long.L2# x = 4.long.L6# x = 5.long.L6# x = 6#.section.rodata.align 4.L7:.long.L2# x = 0.long.L3# x = 1.long.L4# x = 2.long.L5# x = 3.long.L2# x = 4.long.L6# x = 5.long.L6# x = 6Carnegie MellonJump TableJump table switch(x) { case 1: // .L3 w = y*z; break; case 2: // .L4 w = y/z; /* Fall Through */ case 3: // .L5 w += z; break; case 5: case 6: // .L6 w -= z; break; default: // .L2 w = 2; }#Carnegie MellonHandling Fall-Through long w = 1;. . . switch(x) { . . . case 2: w = y/z; /* Fall Through */ case 3: w += z; break; . . . }case 3: w = 1; goto merge; case 2: w = y/z;merge: w += z;#Carnegie MellonCode Blocks (Partial).L2:# Defaultmovl$2, %eax# w = 2jmp.L8# Goto done

.L5:# x == 3movl$1, %eax# w = 1jmp.L9# Goto merge

.L3:# x == 1movl16(%ebp), %eax # zimull12(%ebp), %eax # w = y*zjmp.L8# Goto done switch(x) { case 1: // .L3 w = y*z; break; . . . case 3: // .L5 w += z; break; . . . default: // .L2 w = 2; }#Carnegie MellonCode Blocks (Rest).L4:# x == 2movl12(%ebp), %edxmovl%edx, %eaxsarl$31, %edxidivl16(%ebp)# w = y/z

.L9:# merge:addl16(%ebp), %eax # w += zjmp.L8# goto done

.L6:# x == 5, 6movl$1, %eax # w = 1subl16(%ebp), %eax # w = 1-z switch(x) { . . . case 2: // .L4 w = y/z; /* Fall Through */ merge: // .L9 w += z; break; case 5: case 6: // .L6 w -= z; break; }#Carnegie MellonSwitch Code (Finish)Noteworthy FeaturesJump table avoids sequencing through casesConstant time, rather than linearUse jump table to handle holes and duplicate tagsUse program sequencing to handle fall-throughDont initialize w = 1 unless really need it return w;.L8:# done:popl%ebpret#Carnegie Mellonx86-64 Switch Implementation.section.rodata.align 8.L7:.quad.L2# x = 0.quad.L3# x = 1.quad.L4# x = 2.quad.L5# x = 3.quad.L2# x = 4.quad.L6# X = 5.quad.L6# x = 6Jump TableSame general idea, adapted to 64-bit codeTable entries 64 bits (pointers)Cases use revised code.L3:movq%rdx, %raximulq%rsi, %raxret switch(x) { case 1: // .L3 w = y*z; break; . . . }#Carnegie MellonIA32 Object CodeSetupLabel .L2 becomes address 0x8048422Label .L7 becomes address 0x804866008048410 : . . . 8048419:77 07 ja 8048422 804841b:ff 24 85 60 86 04 08 jmp *0x8048660(,%eax,4)switch_eg: . . .ja.L2 # If unsigned > goto defaultjmp*.L7(,%eax,4)# Goto *JTab[x]Assembly CodeDisassembled Object Code#Carnegie MellonIA32 Object Code (cont.)Jump TableDoesnt show up in disassembled codeCan inspect using GDB gdb switch(gdb) x/7xw 0x8048660Examine 7 hexadecimal format words (4-bytes each)Use command help x to get format documentation0x8048660:0x080484220x080484320x0804843b0x080484290x8048670:0x080484220x0804844b0x0804844b#Carnegie MellonIA32 Object Code (cont.)Deciphering Jump Table0x8048660:0x080484220x080484320x0804843b0x080484290x8048670:0x080484220x0804844b0x0804844bAddressValuex0x80486600x804842200x80486640x804843210x80486680x804843b20x804866c0x804842930x80486700x804842240x80486740x804844b50x80486780x804844b6#Carnegie MellonDisassembled Targets 8048422:b8 02 00 00 00 mov $0x2,%eax 8048427:eb 2a jmp 8048453 8048429:b8 01 00 00 00 mov $0x1,%eax 804842e:66 90 xchg %ax,%ax # noop 8048430:eb 14 jmp 8048446 8048432:8b 45 10 mov 0x10(%ebp),%eax 8048435:0f af 45 0c imul 0xc(%ebp),%eax 8048439:eb 18 jmp 8048453 804843b:8b 55 0c mov 0xc(%ebp),%edx 804843e:89 d0 mov %edx,%eax 8048440:c1 fa 1f sar $0x1f,%edx 8048443:f7 7d 10 idivl 0x10(%ebp) 8048446:03 45 10 add 0x10(%ebp),%eax 8048449:eb 08 jmp 8048453 804844b:b8 01 00 00 00 mov $0x1,%eax 8048450:2b 45 10 sub 0x10(%ebp),%eax 8048453:5d pop %ebp 8048454:c3 ret #Carnegie MellonMatching Disassembled Targets 8048422:mov $0x2,%eax 8048427:jmp 8048453 8048429:mov $0x1,%eax 804842e:xchg %ax,%ax 8048430:jmp 8048446 8048432:mov 0x10(%ebp),%eax 8048435:imul 0xc(%ebp),%eax 8048439:jmp 8048453 804843b:mov 0xc(%ebp),%edx 804843e:mov %edx,%eax 8048440:sar $0x1f,%edx 8048443:idivl 0x10(%ebp) 8048446:add 0x10(%ebp),%eax 8048449:jmp 8048453 804844b:mov $0x1,%eax 8048450:sub 0x10(%ebp),%eax 8048453:pop %ebp 8048454:ret Value0x80484220x80484320x804843b0x80484290x80484220x804844b0x804844b#Carnegie MellonSummarizingC Controlif-then-elsedo-whilewhile, forswitchAssembler ControlConditional jumpConditional moveIndirect jumpCompiler generates code sequence to implement more complex controlStandard TechniquesLoops converted to do-while formLarge switch statements use jump tablesSparse switch statements may use decision trees#Carnegie MellonTodaySwitch statementsIA 32 ProceduresStack StructureCalling ConventionsIllustrations of Recursion & Pointers#Carnegie MellonIA32 StackRegion of memory managed with stack disciplineGrows toward lower addresses

Register %esp contains lowest stack addressaddress of top elementStack Pointer: %espStack GrowsDownIncreasingAddressesStack TopStack Bottom#Carnegie MellonIA32 Stack: Pushpushl SrcFetch operand at SrcDecrement %esp by 4Write operand at address given by %esp-4Stack GrowsDownIncreasingAddressesStack BottomStack Pointer: %espStack Top#Stack Pointer: %espStack GrowsDownIncreasingAddressesStack TopStack BottomCarnegie MellonIA32 Stack: Pop+4#Carnegie MellonProcedure Control FlowUse stack to support procedure call and returnProcedure call: call labelPush return address on stackJump to labelReturn address:Address of the next instruction right after callExample from disassembly804854e:e8 3d 06 00 00 call 8048b90 8048553:50 pushl %eaxReturn address = 0x8048553Procedure return: retPop address from stackJump to address#0x80485530x104Carnegie Mellon%esp%eip%esp%eip0x8048b900x1080x10c0x1100x1040x804854e123Procedure Call Example0x1080x10c0x1101230x108call 8048b90804854e:e8 3d 06 00 00 call 8048b90 8048553:50 pushl %eax%eip: program counter#Carnegie Mellon%esp%eip0x104%esp%eip0x80485910x1040x1080x10c0x1100x8048553123Procedure Return Example0x1080x10c0x110123ret8048591:c3 ret0x1080x80485530x8048553%eip: program counter#Carnegie MellonStack-Based LanguagesLanguages that support recursione.g., C, Pascal, JavaCode must be ReentrantMultiple simultaneous instantiations of single procedureNeed some place to store state of each instantiationArgumentsLocal variablesReturn pointerStack disciplineState for given procedure needed for limited timeFrom when called to when returnCallee returns before caller doesStack allocated in Framesstate for single procedure instantiation#Carnegie MellonCall Chain Exampleyoo(){ who(); } who(){ amI(); amI(); }amI(){ amI(); }yoowhoamIamIamIExampleCall ChainamIProcedure amI() is recursive#Carnegie MellonFrame Pointer: %ebpStack FramesContentsLocal variablesReturn informationTemporary space

ManagementSpace allocated when enter procedureSet-up codeDeallocated when returnFinish codeStack Pointer: %espStack TopPrevious FrameFrame forproc#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyooyoo(){ who(); } #yoo(){ who(); } Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhowho(){ amI(); amI(); }#yoo(){ who(); } who(){ amI(); amI(); }Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhoamIamI(){ amI(); }#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhoamIamIyoo(){ who(); } who(){ amI(); amI(); }amI(){ amI(); }amI(){ amI(); }#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhoamIamIamIyoo(){ who(); } who(){ amI(); amI(); }amI(){ amI(); }amI(){ amI(); }amI(){ amI(); }#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhoamIamIyoo(){ who(); } who(){ amI(); amI(); }amI(){ amI(); }amI(){ amI(); }#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhoamIyoo(){ who(); } who(){ amI(); amI(); }amI(){ amI(); }#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhoyoo(){ who(); } who(){ amI(); amI(); }#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhoamIyoo(){ who(); } who(){ amI(); amI(); }amI(){ amI(); }#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyoowhoyoo(){ who(); } who(){ amI(); amI(); }#Carnegie MellonExampleyoowhoamIamIamIamIyoo%ebp%espStackyooyoo(){ who(); } #Carnegie MellonIA32/Linux Stack FrameCurrent Stack Frame (Top to Bottom)Argument build:Parameters for function about to callLocal variablesIf cant keep in registersSaved register contextOld frame pointer

Caller Stack FrameReturn addressPushed by call instructionArguments for this callReturn AddrSavedRegisters+LocalVariablesArgumentBuildOld %ebpArgumentsCallerFrameFrame pointer%ebpStack pointer%esp#Carnegie MellonRevisiting swapvoid swap(int *xp, int *yp) { int t0 = *xp; int t1 = *yp; *xp = t1; *yp = t0;}int course1 = 15213;int course2 = 18243;

void call_swap() { swap(&course1, &course2);}call_swap: subl$8, %espmovl$course2, 4(%esp)movl$course1, (%esp)callswap &course2&course1Rtn adr%espResultingStackCalling swap from call_swap%esp%espsublcall#Carnegie MellonRevisiting swapvoid swap(int *xp, int *yp) { int t0 = *xp; int t1 = *yp; *xp = t1; *yp = t0;}swap:pushl%ebpmovl%esp, %ebppushl%ebx

movl8(%ebp), %edxmovl12(%ebp), %ecxmovl(%edx), %ebxmovl(%ecx), %eaxmovl%eax, (%edx)movl%ebx, (%ecx)

popl%ebxpopl%ebpretBodySetUpFinish#Carnegie Mellonswap Setup #1swap:pushl %ebpmovl %esp,%ebppushl %ebxResulting Stack&course2&course1Rtn adr%espEntering Stack%ebpypxpRtn adrOld %ebp%ebp%esp#Carnegie Mellonswap Setup #2swap:pushl %ebpmovl %esp,%ebppushl %ebxResulting Stack&course2&course1Rtn adr%espEntering Stack%ebpypxpRtn adrOld %ebp%ebp%esp#Carnegie Mellonswap Setup #3swap:pushl %ebpmovl %esp,%ebppushl %ebxResulting Stack&course2&course1Rtn adr%espEntering Stack%ebpypxpRtn adrOld %ebp%ebp%espOld %ebx#Carnegie Mellonswap Bodymovl 8(%ebp),%edx # get xpmovl 12(%ebp),%ecx # get yp. . .Resulting Stack&course2&course1Rtn adr%espEntering Stack%ebpypxpRtn adrOld %ebp%ebp%espOld %ebxOffset relative to %ebp1284#Carnegie Mellonswap FinishStack Before Finishpopl%ebxpopl%ebp

ypxpRtn adrOld %ebp%ebp%espOld %ebxResulting StackypxpRtn adr%ebp%espObservationSaved and restored register %ebxNot so for %eax, %ecx, %edx#Carnegie MellonDisassembled swap08048384 : 8048384:55 push %ebp 8048385:89 e5 mov %esp,%ebp 8048387:53 push %ebx 8048388:8b 55 08 mov 0x8(%ebp),%edx 804838b:8b 4d 0c mov 0xc(%ebp),%ecx 804838e:8b 1a mov (%edx),%ebx 8048390:8b 01 mov (%ecx),%eax 8048392:89 02 mov %eax,(%edx) 8048394:89 19 mov %ebx,(%ecx) 8048396:5b pop %ebx 8048397:5d pop %ebp 8048398:c3 ret 80483b4:movl $0x8049658,0x4(%esp)# Copy &course2 80483bc:movl $0x8049654,(%esp)# Copy &course1 80483c3:call 8048384 # Call swap 80483c8:leave # Prepare to return 80483c9:ret # ReturnCalling Code#Carnegie MellonTodaySwitch statementsIA 32 ProceduresStack StructureCalling ConventionsIllustrations of Recursion & Pointers#Carnegie MellonRegister Saving ConventionsWhen procedure yoo calls who:yoo is the callerwho is the calleeCan register be used for temporary storage?

Contents of register %edx overwritten by whoThis could be trouble something should be done!Need some coordinationyoo: movl $15213, %edx call who addl %edx, %eax retwho: movl 8(%ebp), %edx addl $18243, %edx ret#Carnegie MellonRegister Saving ConventionsWhen procedure yoo calls who:yoo is the callerwho is the calleeCan register be used for temporary storage?ConventionsCaller SaveCaller saves temporary values in its frame before the callCallee SaveCallee saves temporary values in its frame before using#Carnegie MellonIA32/Linux+Windows Register Usage%eax, %edx, %ecxCaller saves prior to call if values are used later

%eaxalso used to return integer value

%ebx, %esi, %ediCallee saves if wants to use them

%esp, %ebpspecial form of callee saveRestored to original values upon exit from procedure%eax%edx%ecx%ebx%esi%edi%esp%ebpCaller-SaveTemporariesCallee-SaveTemporariesSpecial#Carnegie MellonTodaySwitch statementsIA 32 ProceduresStack StructureCalling ConventionsIllustrations of Recursion & Pointers#Carnegie Mellon/* Recursive popcount */int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1);}

Recursive FunctionRegisters %eax, %edx used without first saving %ebx used, but saved at beginning & restored at endpcount_r:pushl%ebpmovl%esp, %ebppushl%ebxsubl$4, %espmovl8(%ebp), %ebxmovl$0, %eaxtestl%ebx, %ebxje.L3movl%ebx, %eaxshrl%eaxmovl%eax, (%esp)callpcount_rmovl%ebx, %edxandl$1, %edxleal(%edx,%eax), %eax.L3:addl$4, %esppopl%ebxpopl%ebpret#Carnegie Mellon/* Recursive popcount */int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1);}

Recursive Call #1ActionsSave old value of %ebx on stackAllocate space for argument to recursive callStore x in %ebxpcount_r:pushl%ebpmovl%esp, %ebppushl%ebxsubl$4, %espmovl8(%ebp), %ebx xRtn adrOld %ebp%ebp%espOld %ebx x%ebx#Carnegie Mellon/* Recursive popcount */int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1);}

Recursive Call #2ActionsIf x == 0, returnwith %eax set to 0 movl $0, %eaxtestl %ebx, %ebxje.L3 .L3: ret

x%ebx#Carnegie Mellon/* Recursive popcount */int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1);}

Recursive Call #3ActionsStore x >> 1 on stackMake recursive callEffect%eax set to function result%ebx still has value of x movl %ebx, %eaxshrl %eaxmovl %eax, (%esp)call pcount_r

Rtn adrOld %ebp%ebp%espOld %ebx x >> 1x%ebx#Carnegie Mellon/* Recursive popcount */int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1);}

Recursive Call #4Assume%eax holds value from recursive call%ebx holds xActionsCompute (x & 1) + computed valueEffect%eax set to function result movl %ebx, %edxandl $1, %edxleal (%edx,%eax), %eax x%ebx#Carnegie Mellon/* Recursive popcount */int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1);}

Recursive Call #5Actions Restore values of %ebx and %ebpRestore %esp L3:addl$4, %esppopl%ebxpopl%ebpret

Rtn adrOld %ebp%ebp%espOld %ebx Old %ebx%ebx%ebp%esp#Carnegie MellonObservations About RecursionHandled Without Special ConsiderationStack frames mean that each function call has private storageSaved registers & local variablesSaved return pointerRegister saving conventions prevent one function call from corrupting anothers dataStack discipline follows call / return patternIf P calls Q, then Q returns before PLast-In, First-OutAlso works for mutual recursionP calls Q; Q calls P#Carnegie MellonPointer Code/* Compute x + 3 */int add3(int x) { int localx = x; incrk(&localx, 3); return localx;}

Generating Pointeradd3 creates pointer and passes it to incrk/* Increment value by k */void incrk(int *ip, int k) { *ip += k;}

Referencing Pointer#Carnegie Mellon%espCreating and Initializing Local Variableint add3(int x) { int localx = x; incrk(&localx, 3); return localx;}Variable localx must be stored on stackBecause: Need to create pointer to itCompute pointer as -4(%ebp)First part of add3xRtn adrOld %ebp%ebp 0 4 8 -4 localx = xUnused-12 -8 -16 add3:pushl%ebpmovl%esp, %ebpsubl$24, %esp# Alloc. 24 bytesmovl8(%ebp), %eaxmovl%eax, -4(%ebp)# Set localx to x-20 -24 #Carnegie Mellon%espCreating Pointer as Argumentint add3(int x) { int localx = x; incrk(&localx, 3); return localx;}Use leal instruction to compute address of localxMiddle part of add3xRtn adrOld %ebp%ebp 0 4 8 -4 localxUnused-12 -8 -16 movl$3, 4(%esp)# 2nd arg = 3leal-4(%ebp), %eax# &localxmovl%eax, (%esp) # 1st arg = &localxcallincrk

-20 -24 3%esp+4#Carnegie Mellon%espRetrieving local variableint add3(int x) { int localx = x; incrk(&localx, 3); return localx;}Retrieve localx from stack as return valueFinal part of add3xRtn adrOld %ebp%ebp 0 4 8 -4 localxUnused-12 -8 -16 movl-4(%ebp), %eax # Return val= localxleaveret-20 -24 #Carnegie MellonIA 32 Procedure SummaryImportant PointsStack is the right data structure for procedure call / returnIf P calls Q, then Q returns before PRecursion (& mutual recursion) handled by normal calling conventionsCan safely store values in local stack frame and in callee-saved registersPut function arguments at top of stackResult return in %eaxPointers are addresses of valuesOn stack or globalReturn AddrSavedRegisters+LocalVariablesArgumentBuildOld %ebpArgumentsCallerFrame%ebp%esp#