80x86 Assembly Language and Computer Architecture

   The ASCII code assignments may seem rather arbitrary, but there are certain patterns. The codes for uppercase letters are contiguous, as are the codes for the lowercase letters. The codes for an uppercase letter and the corresponding lowercase letter differ by exactly one bit. Bit 5 is 0 if an uppercase letter and 1 for the corresponding lowercase letter while other bits are the same.
   The printable characters are grouped together from 2016 to 7E16. (A space is considered a printable character.)
   The characters from 0016 to 1F16, along with 7F16, are known as control characters
   The abbreviation ESC stands for extra services control but most people say "escape". (p.7)
   0D16, and 0A16, for carriage return (CR) and line feed (LF). The 0D16 code is generated by an ASCII keyboard when the Return or Enter key is pressed. When it is sent to an ASCII display, it causes the cursor to move to the beginning of the current line without going down to a new line. When carriage return is sent to an ASCII printer, it causes the print head to move to the beginning of the line. The line feed code 0A16 causes an ASCII display to move the cursor straight down, or a printer to roll the paper up one line, in both cases without going to the beginning of the new line. (p.8)
   In a computer, subtraction a - b of numbers a and b is usually performed by taking the 2's complement of b and adding the result to a. (p.19)
   In binary coded decimal (BCD) schemes, each decimal digit is coded with a string of bits whith fixed length, ... Most frequently four bits are used for each decimal digit. (p.22)
   The ESI and EDI registers are index register, where SI stands for source index and DI stands for destination index.
   ...
   The ESP register is the stack pointer for the system stack. 
   ...
   The EBP register is the base pointer register. 
   ...
   In the older 16-bit segemented model, the CS register contains the segment number of the code segment, the area of memory where the instructions currently being excuted are stored.
   ...
   Similarly DS contains the segment number of the data segment, the area of memory where most data is stored. The SS register contains the segment number of the stack segment, where the stack is maintained. The ES register contains the segment number of the extra data segment that could have multiple uses. The FS and GS registers were added with the 80386 and make possible easy access to two additional data segments. 
   ...
   instruction pointer, EIP register. 
   
   ...
   In addition to prefetching instructions, an 80x86 CPU actually starts execution of an instruction before it finishes execution of prior instructions. (p.32 ~ 33) 
   The 80x86 architectrure has 64K port addresses, and a typical I/O divice uses three to eight ports. (p.37)
   There are three types of functional assembly language statements: instructions, direcrives, and macros. An instruction is translate by the assembler into one or more bytes of object code (machine code), which will be executed at run time. 
   ...
   A directive tells the assembler to take some action. Such an action does not result in machine instructions and often has no effect on the object code. 
   ...
   A macro is "shorthand" for a sequence of other statements, be they instructions, directives, or even other macros. The assembler expands a macro to the statements it represents and then assembles these new statements. (p.42)
   A statement that is more than just a comment almost always contains a mnemonic that identifies the purpose of the statement, and may have three other fields: name, operand, and comment. These components must be in the following order:(p.43)
name          mnemonic   oeprand(s)                   ;commnet
For example, a program might contain the statement
ZeroCount: mov ecx, 0 ; initialize count to zero
   A string delimited with apostrophes can contain quotation marks, and one delimited with quotation marks can contain apostrophes, making it possible to have string s containing these special characters. (p.70)
   An operand of a BYTE, DWORD, WORD, or other statement can be expression involving arithmetic or other operators. These expressions are evaluated by the assembler at assembly time, not at run time. (p.71)
Tow common addressing modes: (p.73)
            Mode                  Location of data
             immediate                in the instruction itself 

             register                 in a register
             memory                   at some address in memory
Two memory mode: (p.74)
            Memory mode                 Location of data
             direct                          at a memory location whose address(offset) is built into the instruction

             Register indirect               at a memory location whose address is in a register 
The three types of assembly language statements are: (p.82)
  • instructions --- each corresponds to a CPU instruction
  • directives    --- tell the assembler what to do
  • macros       --- expand into additional statements 
   No mov instruction changes any flag. (p.88)
Logical combinations in mov are not available: (p.91)
  • a move with both source and destination in memory
  • immediate source to segment register destination
  • any move to or from flag register
  • any move to the instruction pointer register
  • a move from one segment register to another segment register
  • any move where the operands are not the same size
  • a move of several objects
   Like mov instructions, xchg instructions do not alter any status flag. (p.94)
   The Intel microprocessor has add and sub instructions to perform addition and substraction using byte, word, doubleword length operands. (p. 95)
   (In add and sub) The SF, ZF, OF, PF, and AF flags are set according to the value of the result of the operation. (p.96)
; Both destination and source can be immediate, register, or memory. 
; But only one operand can be in memory at one instruction.
add destination, source
sub destination, source
   Notice that an immediate source can be a single byte even when the destination is a word or doubleword. 
   ...
   Byte-size operands are sign-extended to word or doubleword size at run time before the addition or subtraction operation. (p.99) 
inc    destination
dec destination
   The inc and dec instrucitons treat the value of the destination operand as an unsigned integer. The affect the OF, SF, and ZF flags just like addition or subtraction of one, but they do not change the carry flag CF.
   ...
   The inc and dec instructions sometimes take fewer bytes of code and execute in fewer clock cycles than corresponding addition or subtraction instructions. (p.101 ~ 102)
;  ah: al = al * source_8
;
dx: ax = ax * source_16
;
edx:eax = eax * source_32
mul source ; Non-negative

   If only non-negative numbers are to be multiplied, mul should usually be choosen instead of imul since it is a little faster. 
   ...
   With mul instructions, the carry flag CF and overflow flag OF are set to 1 if the high order half of the product is not zero; but are cleared to 0 if the high order half of the product is zero. 
   ...
   No immediate operand is allowed in a mul. ... The actual number of clock cycles for the 80836 and 80486 depends on the numbers being multiplied. (p.108 ~ 109) 

   
  1. imul source                            ; ah: al = al * source_8
    ; dx: ax = ax * source_16
    ; edx:eax = eax * source_32
  2. imul register, source                  ; Register = (al|ax|eax) * source
  3. imul register, source, immediate       ; Register = source * immediate

imul source: 
      The carry and overflow are set to 1 if the bits in the high-order half are significant, and cleared to 0 otherwise. Notice the high-order half may contain all 1 bits for a negative product(My Note: This case is not significant). 

imul register, source:

      Operands must be words or doublewords, not bytes. The product must "fit" in same size as the factors; if it does, CF and OF are cleared to 0, if not they are set to 1. 

imul register, source, immediate: 
      If the product will fit in the destination register, then CF and OF are cleared to 0, if not, they are set to 1. (p.110 ~ 112)

   The 80x86 architecture includes multiplication instrucitons in three formats. ... the destination of the product cannot be a memory operand. (p.115)
; divisor        dividend    quotient    remainder
byte ax al ah
word
dx: ax ax dx
doubleword
edx:eax eax edx

   The divisor can be in a register or memory, but not immediate.

   ...

   For all division operations, the dividend, divisor, quotient, and remainder must satisfy the equation

              dividend = quotient * divisor + remainder

   For unsigned div operations, the dividend, divisor, quotient, and remainder are all treated as non-negative numbers. For idiv operations, the sign of the quotient is determined by the signs of the dividend and divisor using the ordinary rules of signs; the sign of the remainder is always the same as the sign of the dividend. 

   The division instructions do not set flags to any significant values. They may destroy previously set values of AF, CF, OF, PF, SF, and ZF flags. 

   ...

   If an error occurs during the division operation, the 80x86 generates an exception. The routine, or interrupt handler, that services this exception may vary from system to system. ... The 80x86 leaves the destination registers undefined flollowing a division error. 

   ... 

   div operations are slightly faster than idiv operations. 

   ...

   When arigthmetic is being done with operands of a given length, the dividend is must be converted to double length before a division operation is executed. (p. 119 ~ 123) 

cbw    ; Signed extended byte to word:                 al ->      ax
cwd ; Signed extended word to double word: ax -> dx: ax
cwde ; Signed extended word to double word: ax -> eax
cdq ; Signed extended double word to quad word: dx: ax -> edx:eax

   None of these instructions affect flags. (p.124)

; source could be register_8 or register_16 or memory byte or memoryword
movzx register, source ; Zero extended
movsx register, source ; Sign extended

   Neigher instruction changes any flag value. (p.125)

   The 8-bit displacement in an relative short jump can serve for a target statement up to 128 bytes before or 127 bytes after the jmp itself since at the time an instruction is being executed, ... The 32-bits displacement in a relative near jump can serve for a target statement up to 2,147,483,648 bytes before or 2,147, 483,647 bytes after the jmp instruction. 
   There is no difference in the coding for a relative short jump and for a relative near jump. The assembler uses a short jump if the target is within the small range in order to generate more compact code. A near jump is automatically if the target is more than 128 bytes away. 
   The indirect jump instructions use a 32-bits address for the target rather than a displacement. (p.142) 
   Conditional jump instructions do not modify the flags. (p.144)
   Multiple labels can reference the same spot in memory. Labels are not part of obejct code, so extra labels do not add the length of object code or to execution time. (p.146)
   (My Note: cmp)Note that an immediate operand must be the second operand. (p.149)
   Each conditional jump instruction take a single clock cycle for execution.
   No conditional jump instruction changes any flag value. Each instruction has a short version and a near version. (p.151) 
if (total >= 100) or (count = 10)
then
add value
to total;
end if;

Assume that total and value reference doublewords in memory and count is stored in the CX register. (p.152 ~ 153)

            cmp    total, 100     ; total >= 100 ?
jge addValue
cmp cx, 10 ; count = 10 ?
jne endAddCheck
addValue: mov ebx, value ; copy value
add total, ebx ; add value to total
endAddCheck:
if (count > 0) and (ch = backspace)
then
subtract
1 from count;
end if;

Assume that count is in the CX register, ch is in the AL register and that backspace has been equated to 0816, the ASCII backspace character. (p.153)

    cmp    cx, 0            ; count > 0 ?
jng endCheckCh
cmp al, backspace ; ch a backspace ?
jne endCheckCh
dec count ; subtract 1 from count
endCheckCh: 
The loop instruciton has the format 
loop    statementLabel

  where statementLabel is the label of a statement that is a short displacement(128 bytes backward or 127 bytes forward) from the loop instrution. The loop instruciont causes the following actions to take place:

  • the value in ECX is decremented
  • if the new value in ECX is zero, then, execution continues with the statement following the instruction loop
  • if the new value in ECX is nonzero, then a jump to the instruction at statementLabel takes place 
   None of these instructions changes any flag. (p.174 ~ 175)
   Although the ECX register is a general register, it has a special place as a counter in the loop instruction and in serveral other instructions. No other register can be substitted for ECX in these instructions. (p.174)
   Way to guard a for loop so that it is executed when the value in ECX is zero. (p.176)
        mov      ecx, number      ; number of iterations
jecxz endFor ; skip loop if number = 0
forIndex:.
.
.
loop forIndex
; repeat body number times
endFor:
   The jecxz instruction can be used to code a backwaord for loop when the loop body is longer than 127 bytes. (p.176 ~ 177)
for counter := 50 downto 1 loop
...
{body of loop}
end for;

could be coded as

        mov    ecx, 50       ; number of iterations
forCounter: . ; body of loop
.
.
dec ecx ; decrement loop counter
jecxz endFor ; exit if counter = 0
jmp forCounter ; otherwise repeat body
endFor:
   The loopz/loope instruction jumps if the new value in ECX is nonzero and the zero flag is set (ZF=1). The loopze/loopne instruction jumps if the new value in ECX is nonzero and the zero flag is clear (ZF=0). (p.178)
   The ESI and EDI registers are often reserved for use with strings, which are usually arrays of characters. (p.182)
   When a push instruction is executed for a word-size operand, the stack pointer ESP is decremented by 2. ... then stored at the address in ESP. ... The immediate byte operand is interesting. Although a single byte is stored in the instruction, it is sign-extended to a double-word that is actually stored on the stack. (p.194)
   ...
   No push instruction affects any flag bit. (196)
   Pop can reference .... except CS. (The push instruction does not exclude CS.) (p.197)
   The pushad instruction pushes EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, in this order. The value pushed for ESP is the address it contains before any of the registers are pushed. The popad instruction pops the same registers in the reverse order, except that the value for ESP is descarded. ... each register (except ESP) will get back its original value. (p.199)
   PROC and ENDP. Each of these directives has a label that gives the name of the procedure. ... NEAR32. This attribute says that the procedure will be located in the same code segment as the calling code and that 32-bit addresses are being used. These choices are normal for flat 32-bit memory model programming. (p.202)
   The 80x86 uses the stack to store the return address. 
   ...
   In general, a call instruction pushes the address of the next instruction(the one immediately following the call) onto the stack and then transfers control to the procedure code. 
   ...
   80x86 programming can be done using either a flag memory model or a segmented memory model. With a segmented memory model a procedure may be in a different segment from the calling code. In fact, with 16-bit segmented programming, segments were limited to 65,536 bytes, so procedures were often in separate segments. The 80x86 architecture uses a far call to transfer control to a procedure in a different memory segment: A far call pushes both EIP and CS onto the stack. A far return pops both off the stack. 
   No call instruction modifies any flag. (p.204 ~ 206)
   Funtions that return a single integer value frequently use the accumulator. (p.210)
   EBP is the normal choice for accessing values in the stack. (p.212)
   The instruction mov ebp, esp loads EBP with a fixed reference point in the stack. This fixed reference point will not change as the stack used for other purpose --- for example, to push additional registers or to call other procedures.
   ...
   
push    ebp        ; save EBP
mov ebp, esp ; establish stack framework

   make up the entry code for a procedure. However, the two instructions here are always the first entry code instructions. (p.215)   
   It may seem that the next instruction should be add sp, 4 to undo the effects of the corresponding subtracting in the entry code. However, the instruction mov esp, ebp accomplishes the same objective more effectively. (p.218)

Entry code: 

push    ebp        ; establish stack frame
mov ebp, esp
sub esp, n ; n bytes of local variables space
push ... ; save registers
...
push ...
pushf ; save flags

Exit code:

popf            ; restore flags
pop ... ; restore registers
...
pop ...
mov esp, ebp ; restore ESP if local variables used
pop ebp ; restore EBP
ret ; return 
INVOKE ExitProcess, 0        ; exit with return code 0

  INVOKE is not an instruction --- MASM references call it a directive. ... In fact, you see the expansion (p.221)

push    +00000000h
call ExitProcess
   Single bytes cannot be pushed on the 80x86 stack. (p.225)
   When a procedure is called, the address of the next instruction is stored on the stack before control transfers to the first instruction of the procedure. (p.230)
   The movs instruction does not affect any flag. (p.234)
   Repeat prefixes themselves do not affect any flag. (p.241) 
   After the search(My note: By scasb/scasw/scasd), the destination index EDI will be one greater than desired since a string instruction always increments index registers whether or not flags were set. (p.248)
   A stos instruction affects no flag. 
   A lods instrction sets no flag. 
   It is possible to use a rep prefix with lods but it si not helpful. (p.249)  
   The assembler calculates addresses as if they start at 00000000, and increments a counter every time it generates bytes of object code. The dollar sign symbol refers to the value of this counter at the time it is encountere in assembly. (p.256)
   The not instruction does not affect any flag.
   Boolean instruction affects CF, OF, PF, SF, ZF, and AF. The flag carry CF and flag overflow OF flags are both set to 0; the value of the auxiliary carry flag AF may be changed but is undefined. The parity flag PF, the sign flag SF, and the zero flag ZF are set or reset according to the value of the result. (p.269) 
mov   edx, eax
and edx, 0000001fh ; Mod 32
   Similar instructions will work whenever the second operand of mod is a power of 2. (p.273)
   The or operation is more efficient than addition with some CPU. 
   ASCII code for an uppercase letter and the ASCII code for the corresponding lowercase letter differ only in the value of bit 5. (p.274)
   The test ... are almost the same as for and, or, and xor instructions. Only the accumulator can be the destination when the source is in memory. (275)
   (My Note: When you use shift operations )Most of the 80x86 family mask this operand(immediate second operand) by 00011112; because you cannot do over 32 meaningful shift operations to an operand no longer than a double word. (279)
   Arithmetic and logical left shifts are identical ... the very last one shifted off; it saved in the carry flag CF. The overflow flag OF is undefined for a multiple-bit shift; for a single-bit shift (count=1) it is reset to 0 if the sign bit of the result is the sameas the sign bit of the original operand value, and set to 1 if they are different.
   Arithmetic and logical right shifts are not the same. With both ... the very last one shifted off, which is saved in CF. ... With a logical right shift (shr) 0 bits fill in on the left. With an arithmetic right shift (sar) the original sign bit is userd to fill in on the left. ... SF, ZF and PF depend on the result of the operation, and AF is undefined. The overflow flag OF is undefined for a multiple-bit shift.
   Notice that the single-bit shifts are faster than the multiple-bit shifts --- often it is more time effecient to use several single-bit shifts than one multiple-bit shift. (p.279 ~ 280)
   If the dividend is an odd negative number, then the quotient is rounded down. (p.282) 
   A shift is sometimes slightly more efficient than addition and either is much more efficent than multiplication. To divide an operand by 2, a right shift is the only alternative to division and is much faster. (p.283) 
   Rotate instructions ... treats the carry flag CF as if it were a part of the destination. (p.289)
   The mod-reg-r/m always has three fields, a two-bit mod field (for "mode"), a three-bit reg field (for "register"), but sometimes used for other purposes), and a 3-bit r/m field (for "register/memory").
   ...
   The opcode 8- is one of twelve in which the reg field of the mod-reg-r/m byt actually determines the instruction. The others are 81, 82, 83, D0, D1, D2, D3, F6, F8, FE and FF.
   Each two-operand, nonimmediate 80x86 instruction has at least one register operand.
   ...
   Often the same opcode is used for an instruction that has two register opands or one register operand and one memory operand.
   ...
   The SIB byte consist of three fields, a two-bit scaling field, a three-bit index register field, and a three-bit base register field. (p.308 ~ 310)
   ESP cannot be an index register. (p.310)
   While it may seem that opcode assingments are completely random, there are actually several patterns.
   ...
   Bit 1 often serves as a direction bit, having value 1 when the first operand is in memory and 0 when the first operand is in a register.
   ...
   Bit 0 often serves as a size bit, having value 1 for doubleword (or word) operands and value 0 for byte operands. (p.315)
   Macros often execute more rapidly than procedure calls since there is no overhead for passing parameters or for call and ret instructions, but this is usually at the cost of more bytes of object code. 
   ... 
   It is good programming practice to place macro definitions near the beginning of a source file. (319 ~ 320)
   If one of the parameters is missing the macro will still be expanded.
   ...
   The assembler will report an error, but it will be the illegal ... instruction that results from the macro expansion, not directly because of the missing argument. (p.322)
   The LOCAL directive is used only within a macro definition and must be the first statement after the MACRO directive. (Not even a comment can separate the MACRO and LOCAL directive.) 
   Each time the macro is expanded and one of these symbols is needed, it is replaced by a symbol starting with two question marks and ending with four hexadecimal digits (??0000, ??0001, etc.) (p.324)
posted @ 2011-07-30 20:02  walfud  阅读(585)  评论(0编辑  收藏  举报