Left over from last time: Binary point ====================================================================== Instruction Set Architecture = ISA Pretend to be sequential But they are not - topic of chapters 4 and 8 Pretend to have memory in a bit flat array 32 bit = addresses are 32 bits long = 4GB memory 64 bit = addresses are 64 bits long = 8EB memory But it is not - topic of chapters 6 and 9 IA32 "Intel Architecture 32-bit" = x86 (8086, 80286, i386, i486, TM) ======================================================================= Endianness Memory is an array of bytes (8 bits, 2 hex) Consider the number three hundred twenty five; we could list it as 5 2 3 <- the little end comes first. Little Endian 3 2 5 <- the big end comes first. Big Endian Same with bytes. 0xdeadbeef could be de ad be ef (big) ef be ad de (little) x86 is little-endian. That made the computer slightly faster back in the day. It is just annoying now. ======================================================================= IA: a Simple World Program Counter What to do next (finger on the page) Register file Just bit vectors, no type attached Condition codes Bits like "was negative", "overflowed" Floating point registers Separate planet in x86… ======================================================================= > gcc -Og -c code.c # or -O1 > objdump -d code.o ... > gcc -Og -S code.c # or -O1 Observations Instructions vary in length (CISC) Bytes unambiguously define assembly flags -S and -c make unfinished code (addresses wrong or 0) ======================================================================= Register names [----- %eax -----] [--%ax --] [%ah][%al] ax, cd, dx, bx -> have h/l pairs si, di, sp, bp -> don't Operands have endings b = byte = %al w = word = %ax l = long = double word = %eax If two endings, order matches operands order ======================================================================= Operand types: (table 3.3, page 169) $number -> literal %register -> value in register address -> value at that address (load) offset(%r1, %r2, num) -> Memory[offset + r1 + (r2 * num)] Note: num must be 1, 2, 4, or 8 ======================================================================= Operators mov S, D movs sign extends; movz zero extends push S Reduces %esp by 4 and stores S at new (%esp) pop D reads from (%esp) and increases %esp by 4 Stack grows toward smaller addresses We draw them upside down (small address at bottom) leal S, D D = &S Created for addresses but used to single-op literal + register + register*{2, 4, 8} inc D ++d dec D --d neg D d = -d not D d = ~d add S, D D += S sub S, D D -= S imul S, D D *= S (no idiv; see messy operators below) xor S, D D ^= S or S, D D |= S and S, D D &= S sal k, D D <<= k sal = shl shl k, D D <<= k k is either a literal (0..31) or %cl (only) sar k, D D >>= k shr k, D D >>>= k ======================================================================= Messy Operators imull S %edx = ( %eax * S )>>32; %eax *= S; (signed) mull S %edx = ( %eax * S )>>32; %eax *= S; (unsigned) idivl S %edx = (%edx<<32 + %eax) % S; (signed) %eax = (%edx<<32 + %eax) / S; (signed) divl S %edx = (%edx<<32 + %eax) % S; (unsigned) %eax = (%edx<<32 + %eax) / S; (unsigned) ctld %edx = signExtend(%eax) ======================================================================= Control Four 1-bit registers, called flags or condition codes: CF - a carry past the top bit (unsigned overflow) ZF - last op resulted in a 0 SF - last op resulted in a negative value OF - last op resulted signed overflow Two comparison operators cmp s2, s1 Set condition codes as if performed s2 - s1 test s2, s1 Set condition codes as if performed s2 & s1 Lots of condition code reading operators of the form set__ D where __ is a shorthand for how the last cmp operands were related [n] not [gl] signed greater/less [ab] unsigned greater/less (above/below) [e] equal e.g. setnae means "not (above or equal)" an unsigned !>= or, just < Also sets (negative) and setns (not-negative) Jump operators jmp label go to that code (direct) jmp *D go to code indexed by operand (indirect) j___ for all the ___ that set had Indirect used for switch statements (arrays of code locations) ======================================================================= Goto considered harmful (in source code) but all we have (in assembly) if (G) { X } else { Y } becomes test G j___ .else X jmp .endif .else: Y .endif: while (G) { X } becomes .while: test G j___ .endwhile X jmp .while .endwhile: do (G) while { X } becomes .do: X test G j___ .do ======================================================================= Conditional Move Don't branch, just only do op if code is true cmov__ S, R If code __ holds, load S into register R