IA32 Addressing Modes Chapter 5 The ISA Level cont’d. addressing • Opcode indicates what operation is to be performed. • Operands specify the location of data. • Example of addressing modes that we have already used: A B = 12 dword 52 mov mov mov mov eax, 1 ebx, eax ecx, A edx, B ; immediate ; register ; immediate ; direct memory IA32 addressing modes 1. Immediate 2. Direct memory 3. Register 4. Register indirect 5. Indexed 6. Based-indexed (new) (new) (new) REGISTER INDIRECT Register indirect • Consider the following: B dword 52 … mov eax, B ; eax now equals 52 • In the above example, the operand actually contains the address of B. • That’s not very flexible. Register indirect • Say B is located at memory location (address) 400. We load the address of B into a register. mov ebx, 400 ;load the address of B mov eax, ebx ;eax is now 400 mov eax, [ebx] ;eax now equals 52 • This is the register indirect addressing mode. The register does not contain the value but contains a reference to (pointer to/location of) the value in memory. Register indirect • But how do we get the address of something into a register to start with? • We don’t know where the assembler and linker place A in memory! • Just as we have instructions that load values from memory, we have instructions that load the address of values in memory. lea eax, A mov eax, offset A ;store addr of A in eax ;lea = load effective addr ;same result HOW CAN WE USE THE REGISTER INDIRECT ADDRESSING MODE TO SUM UP THE VALUES IN A TABLE? Sum up values in a table tbl dword 1, 2, 7, 22, 59, 100 mov eax, offset tbl ;eax points to the first table entry mov ebx, [eax] ;ebx contains the first table entry ;how can we make eax point to the next table entry? Sum up values in a table tbl dword 1, 2, 7, 22, 59, 100 mov mov add eax, offset tbl ;eax points to the first table entry ebx, [eax] ;ebx contains the first table entry eax, 4 ;eax now points to next table entry Sum up values in a table tbl dword 1, 2, 7, 22, 59, 100 mov mov add eax, offset tbl ;eax points to the first table entry ebx, [eax] ;ebx contains the first table entry eax, sizeof dword ;even better Sum up values in a table tbl dword 1, 2, 7, 22, 59, 100 mov eax, offset tbl ;eax points to the first table entry mov ebx, [eax] ;ebx contains the first table entry add eax, 4 ;eax now points to next table entry ;how can we sum the next entry? Sum up values in a table tbl dword 1, 2, 7, 22, 59, 100 mov mov add add … eax, offset tbl ebx, [eax] eax, 4 ebx, [eax] ;eax points to the first table entry ;ebx contains the first table entry ;eax now points to next table entry ; sum the second entry Sum up values in a table tbl dword 1, 2, 7, 22, 59, 100 mov mov add add add add add add add add add add eax, offset tbl ebx, [eax] eax, 4 ebx, [eax] eax, 4 ebx, [eax] eax, 4 ebx, [eax] eax, 4 ebx, [eax] eax, 4 ebx, [eax] ;eax points to the first table entry ;ebx contains the first table entry ;eax now points to next table entry ;sum the second entry ;sum the third ;sum the fourth ;sum the fifth ;sum the sixth Note: If we know that we have N entries in the table, we can use a loop instead. INDEXED Indexed Used to: 1. reference memory at a constant offset from a register • when register points to object and data member is a know offset from start of object 2. reference memory using a register as an additional offset • when register is used as an offset to an array element Indexed A dword 592h, 50h, 60h, 70h, 80h, 90h mov mov mov eax, 4 ebx, A[eax] ecx, [A+eax] ;what’s in ebx? ;what’s in ecx? Indexed A dword 592h, 50h, 60h, 70h, 80h, 90h mov mov mov eax, 4 ebx, A[eax] ecx, [A+eax] ;what’s in ebx? ;what’s in ecx? Using indexed addressing to sum up values in a table tbl dword 1, 2, 7, 22, 59, 100 mov mov add add add add add add add add add add eax, 0 ebx, tbl[eax] eax, 4 ebx, tbl[eax] eax, 4 ebx, tbl[eax] eax, 4 ebx, tbl[eax] eax, 4 ebx, tbl[eax] eax, 4 ebx, tbl[eax] ;eax is offset from start of table ;ebx contains the first table entry ;eax now is offset to next table entry ;sum the second entry ;sum the third ;sum the fourth ;sum the fifth ;sum the sixth BASED-INDEXED Based-indexed • Address is computed by adding two registers (base and index) plus an optional offset (displacement). • One of the two registers (but not both) may also be optionally scaled. • Offset = base + (index*scale) + displacement Based-indexed Using based-indexed addressing to sum up values in a table (approach #1) tbl dword 1, 2, 7, 22, 59, 100 mov mov inc add inc add inc add inc add inc add eax, 0 ebx, tbl[eax*4] eax ebx, tbl[eax*4] eax ebx, tbl[eax*4] eax ebx, tbl[eax*4] eax ebx, tbl[eax*4] eax ebx, tbl[eax*4] ;offset from start of table ;get first table entry ;subscript of next table entry ;sum the second entry ;sum the third ;sum the fourth ;sum the fifth ;sum the sixth Using based-indexed addressing to sum up values in a table (approach #2) tbl dword mov mov mov inc add inc add inc add inc add inc add 1, 2, 7, 22, 59, 100 eax, offset tbl ;point to start of table ebx, 0 ;offset from start of table ecx, [eax+ebx*4] ;get first table entry ebx ;subscript of next table entry ecx, [eax+ebx*4] ;sum the second entry ebx ecx, [eax+ebx*4] ;sum the third ebx ecx, [eax+ebx*4] ;sum the fourth ebx ecx, [eax+ebx*4] ;sum the fifth ebx ecx, [eax+ebx*4] ;sum the sixth Using based-indexed addressing to sum up values in a table (approach #3) tbl dword mov mov mov add add add add add add add add add add 1, 2, 7, 22, 59, 100 eax, offset tbl ;points to start of table ebx, 0 ;offset from start of table ecx, [eax+ebx] ;get first table entry ebx, 4 ;offset of next table entry ecx, [eax+ebx] ;sum the second entry ebx, 4 ecx, [eax+ebx] ;sum the third ebx, 4 ecx, [eax+ebx] ;sum the fourth ebx, 4 ecx, [eax+ebx] ;sum the fifth ebx, 4 ecx, [eax+ebx] ;sum the sixth USING THESE ADDRESSING MODES Methods of passing arguments to functions • Methods: 1. Use registers. 2. Use stack. 3. Use one register which points to a parameter block. Stack temporarily keeps return address. main PROC ;program execution begins here mov eax, offset afterCall ;addr of inst after call f call dump ;show contents of regs call f afterCall: mov eax, input(prompt) ;prompt the user exit ;end of program main ENDP ;---------------------------------------------------------------------f PROC mov eax, [esp] ;gets return address call dump ret f ENDP main PROC mov call call eax, offset afterCall dump f ;program execution begins here ;addr of inst after call f ;show contents of regs afterCall: mov eax, input(prompt) ;prompt the user exit ;end of program main ENDP Note: In f, esp points to ;---------------------------------------------------------------------return address which is location of afterCall. f PROC f mov call ret ENDP eax, [esp] dump ;gets addr of return address Passing arguments to functions via the stack main PROC ;program execution begins here mov eax, 7 push eax ;push the contents of eax on the stack push 4 ;push the value 4 on the stack call f pop eax ;must clean up stack! pop eax ;must clean up stack! mov eax, input(prompt) ;prompt the user exit ;end of program main ENDP ;---------------------------------------------------------------------f PROC mov eax, [esp+4] ;eax = 4 mov ebx, [esp+8] ;ebx = 7 call dump ret f ENDP Passing arguments to functions via the stack main PROC ;program execution begins here mov eax, 7 push eax ;push the contents of eax on the stack push 4 ;push the value 4 on the stack call f Can you suggest pop eax ;must clean up stack! another way to perform this clean pop eax ;must clean up stack! up? mov eax, input(prompt) ;prompt the user exit ;end of program main ENDP ;---------------------------------------------------------------------f PROC mov eax, [esp+4] ;eax = 4 mov ebx, [esp+8] ;ebx = 7 call dump ret f ENDP Passing arguments to functions via the stack main PROC ;program execution begins here mov push push call add eax, 7 eax 4 f esp, 8 ;push the contents of eax on the stack ;push the value 4 on the stack ;must clean up stack! mov eax, input(prompt) ;prompt the user exit ;end of program main ENDP ;---------------------------------------------------------------------f PROC mov eax, [esp+4] ;eax = 4 mov ebx, [esp+8] ;ebx = 7 call dump ret f ENDP Another way to perform this clean up. Passing arguments to functions via the stack main PROC ;program execution begins here mov push push call add eax, 7 eax 4 f esp, 8 ;push the contents of eax on the stack ;push the value 4 on the stack ;must clean up stack! mov eax, input(prompt) ;prompt the user exit ;end of program main ENDP ;---------------------------------------------------------------------f PROC mov eax, [esp+4] ;eax = 4 mov ebx, [esp+8] ;ebx = 7 call dump ret f ENDP But this functions modifies eax and ebx. How can we modify this function to NOT change any registers? Passing arguments to functions via the stack f PROC f push push mov mov . . . pop pop ret ENDP eax ebx eax, [esp+12] ebx, [esp+16] ;save reg used ;save reg used ;get arg ;get another arg We modified this to NOT change any registers. ebx eax ;restore reg used ;restore reg used CALCULATING FACTORIAL n! (n factorial) • • The number of ways n objects can be permuted (arranged). For example, consider 3 things, A, B, and C. 1. 2. 3. 4. 5. 6. • 3! = 6 ABC ACB CAB CBA BCA BAC The first few factorials for n = 0, 1, 2, 3, 4, 5 are 1, 1, 2, 6, 24, 120. n! (n factorial) • n! for some non negative integer n is defined as: – n! = n * (n-1) * (n-2) * … * 2 * 1 – 0! is defined as 1. – from http://mathworld.wolfram.com/Factorial.html Java version (iterative) public static int fact1 ( int n ) { int result = 1; for (int ecx=n; ecx>0; ecx--) { result = result * ecx; } return result; } fact1 proc push mov mov cmp jle ;input: eax contains n (value to calculate n!) ;output: eax contains the result (n!) ;all other registers except edx are preserved ecx ;save register used ecx, eax ;init loop counter to n eax, 1 ;to accumulate result (also n! = 1 for n<=1) ecx, 1 ;check for 1! fact1Done ;br if 1! mul jo dec jnz ecx fact1Error ecx fact1Loop Iterative factorial fact1Loop: fact1Done: pop ret fact1Error: fact1 pushad print popad pop ret endp ecx ;accumulate the result of n! ;br if result is larger than 32 bits ;dec our loop counter Two things to note: ;br if not finished 1. This is a common version of the for-loop. ;restore register used ;return to caller 2. How can we also ;handle errors preserve edx? (Where ;save all registers does edx change?) SADD("fact1: overflow",CR,LF) ;output error message ;restore all registers ecx ;restore register used ;return to caller BUT CAN WE DO IT RECURSIVELY? n! (n factorial) • n! for some non negative integer n can be rewritten as: – 0! = 1 – 1! = 1 – n! = n * (n-1)! for n = 0 for n = 1 for all other n > 1 Mathematical induction • • • The idea of sequences in which later terms are deduced from earlier ones, which is implicit in the principle of mathematical induction, dates to antiquity. The truth of an infinite sequence of propositions Pi for i=1, ..., is established if 1. P1 is true, and 2. Pk implies Pk+1 for all k. This principle is sometimes also known as the method of induction. – from http://mathworld.wolfram.com/RecursiveSequence.html and http://mathworld.wolfram.com/PrincipleofMathematicalInduction. html Mathematical induction • The idea of sequences in which later terms are deduced from earlier ones, which is implicit in the principle of mathematical induction, dates to antiquity. • The truth of an infinite sequence of propositions Pi for i=1, ..., is established if 1. P1 is true, and 2. Pk implies Pk+1 for all k. base case(s) inductive case(s) Back to n! (n factorial) • n! for some non negative integer n can be rewritten as: – 0! = 1 – 1! = 1 – n! = n * (n-1)! for n = 0 for n = 1 for all other n > 1 base cases inductive case Let’s code n! (n factorial) • n! for some non negative integer n can be rewritten as: – 0! = 1 – 1! = 1 – n! = n * (n-1)! for n = 0 for n = 1 for all other n > 1 public static int nFactorial ( int n ) { } base cases inductive case Let’s code n! (n factorial) • n! for some non negative integer n can be rewritten as: – 0! = 1 – 1! = 1 – n! = n * (n-1)! for n = 0 for n = 1 for all other n > 1 public static int nFactorial ( int n ) { //base cases if (n==0) return 1; } base cases inductive case Let’s code n! (n factorial) • n! for some non negative integer n can be rewritten as: – 0! = 1 – 1! = 1 – n! = n * (n-1)! for n = 0 for n = 1 for all other n > 1 public static int nFactorial ( int n ) { //base cases if (n==0) return 1; if (n==1) return 1; } base cases inductive case Let’s code n! (n factorial) • n! for some non negative integer n can be rewritten as: – 0! = 1 – 1! = 1 – n! = n * (n-1)! for n = 0 for n = 1 for all other n > 1 base cases inductive case public static int nFactorial ( int n ) { //base case if (n<=1) return 1; //more generic/robust } Let’s code n! (n factorial) • n! for some non negative integer n can be rewritten as: – 0! = 1 – 1! = 1 – n! = n * (n-1)! for n = 0 for n = 1 for all other n > 1 public static int nFactorial ( int n ) { //base case if (n<=1) return 1; return n * nFactorial( n-1 ); } base cases inductive case Let’s code n! (n factorial) • n! for some non negative integer n can be rewritten as: – 0! = 1 – 1! = 1 – n! = n * (n-1)! for n = 0 for n = 1 for all other n > 1 public static int nFactorial ( int n ) { //base case This is an example of a if (n<=1) return 1; recursive function (a return n * nFactorial( n-1 ); } function that calls itself)! To use this function: int result = nFactorial( 10 ); fact2 proc cmp jle push mov dec call mul jo pop ret ;input: eax contains n (value to calculate n!) ;output: eax contains the result (n!) ;all other registers except edx are preserved eax, 1 ;base case when eax=1 fact2One ;br if 1 (actually <=1) ebx ;save reg used ebx, eax ;save copy of n so we can calculate (n-1)! eax ;get ready to calculate (n-1)! fact2 ;calculate (n-1)! ebx ;calculate n*[(n-1)!] fact2Error ;br if result is larger than 32 bits ebx ;restore reg used ;return to caller Recursive factorial fact2One: mov ret fact2Error: fact2 pushad print popad pop ret endp eax, 1 ;1! = 1 ;return to caller ;handle errors ;save all registers SADD("fact2: overflow",CR,LF) ;output error message ;restore all registers ebx ;restore reg used ;return to caller Summary of IA32 addressing modes 1. Immediate 2. Direct memory 3. Register 4. Register indirect 5. Indexed 6. Based-indexed mov mov mov mov mov mov mov eax, 12 eax, X ebx, eax ebx, [eax] ebx, T[eax] ebx, [T+eax] ecx, [eax + ebx*2 + T] Methods of passing arguments to functions • Methods: 1. Use registers. 2. Use stack. 3. Use one register which points to a parameter block. .data Point3D struct x dword 0 y dword 0 z dword 0 Point3D ends //structure defn. p1 p2 //p1 w/ default values //p2 w/ specified values Point3D Point3D {} {1, 2, 3} .data Point3D struct x dword 0 y dword 0 z dword 0 Point3D ends p1 p2 //structure defn. Point3D { } Point3D {1, 2, 3} mov mov mov call eax, p2.x ebx, p2.y ecx, p2.z dump //p1 w/ default values //p2 w/ specified values ;get x value ;get y value ;get z value .data Point3D struct x dword 0 y dword 0 z dword 0 Point3D ends p1 p2 //structure defn. Point3D { } Point3D {1, 2, 3} lea mov call eax, p2 ebx, offset p2 dump //p1 w/ default values //p2 w/ specified values ;get addr of p2 ;get addr of p2 via another method .data Point3D struct x dword 0 y dword 0 z dword 0 Point3D ends p1 p2 //structure defn. Point3D { } Point3D {1, 2, 3} //p1 w/ default values //p2 w/ specified values lea mov call eax, p2 ebx, offset p2 dump mov mov mov mov mov call Point3D.x[eax], 5 Point3D.z[eax], 10 eax, p2.x ebx, p2.y ecx, p2.z dump ;get addr of p2 ;get addr of p2 via another method eax contains the base address of structured data that can be referenced by called functions! (Point3D.x is simply the offset to x ;get x from the start of the struct.) ;get y ;get z